summaryrefslogtreecommitdiff
path: root/Documentation/translations
diff options
context:
space:
mode:
Diffstat (limited to 'Documentation/translations')
-rw-r--r--Documentation/translations/index.rst6
-rw-r--r--Documentation/translations/it_IT/admin-guide/README.rst2
-rw-r--r--Documentation/translations/it_IT/admin-guide/security-bugs.rst2
-rw-r--r--Documentation/translations/it_IT/core-api/index.rst18
-rw-r--r--Documentation/translations/it_IT/core-api/symbol-namespaces.rst165
-rw-r--r--Documentation/translations/it_IT/devicetree/bindings/submitting-patches.rst11
-rw-r--r--Documentation/translations/it_IT/doc-guide/kernel-doc.rst59
-rw-r--r--Documentation/translations/it_IT/doc-guide/parse-headers.rst7
-rw-r--r--Documentation/translations/it_IT/doc-guide/sphinx.rst98
-rw-r--r--Documentation/translations/it_IT/index.rst127
-rw-r--r--Documentation/translations/it_IT/kernel-hacking/hacking.rst53
-rw-r--r--Documentation/translations/it_IT/kernel-hacking/locking.rst231
-rw-r--r--Documentation/translations/it_IT/maintainer/configure-git.rst10
-rw-r--r--Documentation/translations/it_IT/networking/netdev-FAQ.rst2
-rw-r--r--Documentation/translations/it_IT/process/2.Process.rst96
-rw-r--r--Documentation/translations/it_IT/process/3.Early-stage.rst17
-rw-r--r--Documentation/translations/it_IT/process/4.Coding.rst11
-rw-r--r--Documentation/translations/it_IT/process/5.Posting.rst45
-rw-r--r--Documentation/translations/it_IT/process/7.AdvancedTopics.rst8
-rw-r--r--Documentation/translations/it_IT/process/8.Conclusion.rst5
-rw-r--r--Documentation/translations/it_IT/process/adding-syscalls.rst22
-rw-r--r--Documentation/translations/it_IT/process/botching-up-ioctls.rst249
-rw-r--r--Documentation/translations/it_IT/process/changes.rst71
-rw-r--r--Documentation/translations/it_IT/process/clang-format.rst2
-rw-r--r--Documentation/translations/it_IT/process/coding-style.rst106
-rw-r--r--Documentation/translations/it_IT/process/deprecated.rst314
-rw-r--r--Documentation/translations/it_IT/process/development-process.rst19
-rw-r--r--Documentation/translations/it_IT/process/email-clients.rst385
-rw-r--r--Documentation/translations/it_IT/process/howto.rst32
-rw-r--r--Documentation/translations/it_IT/process/index.rst5
-rw-r--r--Documentation/translations/it_IT/process/kernel-docs.rst4
-rw-r--r--Documentation/translations/it_IT/process/magic-number.rst79
-rw-r--r--Documentation/translations/it_IT/process/maintainer-handbooks.rst24
-rw-r--r--Documentation/translations/it_IT/process/maintainer-pgp-guide.rst356
-rw-r--r--Documentation/translations/it_IT/process/maintainer-tip.rst10
-rw-r--r--Documentation/translations/it_IT/process/maintainers.rst13
-rw-r--r--Documentation/translations/it_IT/process/management-style.rst293
-rw-r--r--Documentation/translations/it_IT/process/programming-language.rst55
-rw-r--r--Documentation/translations/it_IT/process/stable-kernel-rules.rst54
-rw-r--r--Documentation/translations/it_IT/process/submit-checklist.rst25
-rw-r--r--Documentation/translations/it_IT/process/submitting-drivers.rst16
-rw-r--r--Documentation/translations/it_IT/process/submitting-patches.rst531
-rw-r--r--Documentation/translations/it_IT/process/volatile-considered-harmful.rst4
-rw-r--r--Documentation/translations/it_IT/riscv/patch-acceptance.rst40
-rw-r--r--Documentation/translations/ja_JP/SubmitChecklist12
-rw-r--r--Documentation/translations/ja_JP/SubmittingPatches60
-rw-r--r--Documentation/translations/ja_JP/howto.rst126
-rw-r--r--Documentation/translations/ja_JP/index.rst12
-rw-r--r--Documentation/translations/ko_KR/howto.rst53
-rw-r--r--Documentation/translations/ko_KR/index.rst21
-rw-r--r--Documentation/translations/ko_KR/memory-barriers.txt360
-rw-r--r--Documentation/translations/sp_SP/disclaimer-sp.rst9
-rw-r--r--Documentation/translations/sp_SP/index.rst80
-rw-r--r--Documentation/translations/sp_SP/memory-barriers.txt3134
-rw-r--r--Documentation/translations/sp_SP/process/adding-syscalls.rst632
-rw-r--r--Documentation/translations/sp_SP/process/code-of-conduct.rst97
-rw-r--r--Documentation/translations/sp_SP/process/coding-style.rst1315
-rw-r--r--Documentation/translations/sp_SP/process/contribution-maturity-model.rst120
-rw-r--r--Documentation/translations/sp_SP/process/deprecated.rst381
-rw-r--r--Documentation/translations/sp_SP/process/email-clients.rst374
-rw-r--r--Documentation/translations/sp_SP/process/embargoed-hardware-issues.rst341
-rw-r--r--Documentation/translations/sp_SP/process/handling-regressions.rst797
-rw-r--r--Documentation/translations/sp_SP/process/howto.rst617
-rw-r--r--Documentation/translations/sp_SP/process/index.rst30
-rw-r--r--Documentation/translations/sp_SP/process/kernel-docs.rst187
-rw-r--r--Documentation/translations/sp_SP/process/kernel-enforcement-statement.rst174
-rw-r--r--Documentation/translations/sp_SP/process/magic-number.rst89
-rw-r--r--Documentation/translations/sp_SP/process/management-style.rst299
-rw-r--r--Documentation/translations/sp_SP/process/programming-language.rst53
-rw-r--r--Documentation/translations/sp_SP/process/researcher-guidelines.rst150
-rw-r--r--Documentation/translations/sp_SP/process/security-bugs.rst103
-rw-r--r--Documentation/translations/sp_SP/process/submit-checklist.rst133
-rw-r--r--Documentation/translations/sp_SP/process/submitting-patches.rst894
-rw-r--r--Documentation/translations/sp_SP/wrappers/memory-barriers.rst19
-rw-r--r--Documentation/translations/zh_CN/IRQ.txt39
-rw-r--r--Documentation/translations/zh_CN/PCI/acpi-info.rst139
-rw-r--r--Documentation/translations/zh_CN/PCI/index.rst34
-rw-r--r--Documentation/translations/zh_CN/PCI/msi-howto.rst244
-rw-r--r--Documentation/translations/zh_CN/PCI/pci-iov-howto.rst169
-rw-r--r--Documentation/translations/zh_CN/PCI/pci.rst514
-rw-r--r--Documentation/translations/zh_CN/PCI/pciebus-howto.rst192
-rw-r--r--Documentation/translations/zh_CN/PCI/sysfs-pci.rst126
-rw-r--r--Documentation/translations/zh_CN/SecurityBugs50
-rw-r--r--Documentation/translations/zh_CN/accounting/delay-accounting.rst112
-rw-r--r--Documentation/translations/zh_CN/accounting/index.rst25
-rw-r--r--Documentation/translations/zh_CN/accounting/psi.rst155
-rw-r--r--Documentation/translations/zh_CN/accounting/taskstats.rst145
-rw-r--r--Documentation/translations/zh_CN/admin-guide/README.rst291
-rw-r--r--Documentation/translations/zh_CN/admin-guide/bootconfig.rst293
-rw-r--r--Documentation/translations/zh_CN/admin-guide/bug-bisect.rst81
-rw-r--r--Documentation/translations/zh_CN/admin-guide/bug-hunting.rst340
-rw-r--r--Documentation/translations/zh_CN/admin-guide/clearing-warn-once.rst9
-rw-r--r--Documentation/translations/zh_CN/admin-guide/cpu-load.rst105
-rw-r--r--Documentation/translations/zh_CN/admin-guide/cputopology.rst96
-rw-r--r--Documentation/translations/zh_CN/admin-guide/index.rst133
-rw-r--r--Documentation/translations/zh_CN/admin-guide/init.rst54
-rw-r--r--Documentation/translations/zh_CN/admin-guide/lockup-watchdogs.rst66
-rw-r--r--Documentation/translations/zh_CN/admin-guide/mm/damon/index.rst29
-rw-r--r--Documentation/translations/zh_CN/admin-guide/mm/damon/lru_sort.rst263
-rw-r--r--Documentation/translations/zh_CN/admin-guide/mm/damon/reclaim.rst228
-rw-r--r--Documentation/translations/zh_CN/admin-guide/mm/damon/start.rst124
-rw-r--r--Documentation/translations/zh_CN/admin-guide/mm/damon/usage.rst591
-rw-r--r--Documentation/translations/zh_CN/admin-guide/mm/index.rst49
-rw-r--r--Documentation/translations/zh_CN/admin-guide/mm/ksm.rst198
-rw-r--r--Documentation/translations/zh_CN/admin-guide/reporting-issues.rst1368
-rw-r--r--Documentation/translations/zh_CN/admin-guide/reporting-regressions.rst370
-rw-r--r--Documentation/translations/zh_CN/admin-guide/security-bugs.rst74
-rw-r--r--Documentation/translations/zh_CN/admin-guide/sysrq.rst280
-rw-r--r--Documentation/translations/zh_CN/admin-guide/tainted-kernels.rst157
-rw-r--r--Documentation/translations/zh_CN/admin-guide/unicode.rst170
-rw-r--r--Documentation/translations/zh_CN/arch/arm/Booting (renamed from Documentation/translations/zh_CN/arm/Booting)6
-rw-r--r--Documentation/translations/zh_CN/arch/arm/kernel_user_helpers.txt (renamed from Documentation/translations/zh_CN/arm/kernel_user_helpers.txt)4
-rw-r--r--Documentation/translations/zh_CN/arch/arm64/amu.rst100
-rw-r--r--Documentation/translations/zh_CN/arch/arm64/booting.txt (renamed from Documentation/translations/zh_CN/arm64/booting.txt)4
-rw-r--r--Documentation/translations/zh_CN/arch/arm64/elf_hwcaps.rst240
-rw-r--r--Documentation/translations/zh_CN/arch/arm64/hugetlbpage.rst45
-rw-r--r--Documentation/translations/zh_CN/arch/arm64/index.rst19
-rw-r--r--Documentation/translations/zh_CN/arch/arm64/legacy_instructions.txt (renamed from Documentation/translations/zh_CN/arm64/legacy_instructions.txt)4
-rw-r--r--Documentation/translations/zh_CN/arch/arm64/memory.txt (renamed from Documentation/translations/zh_CN/arm64/memory.txt)4
-rw-r--r--Documentation/translations/zh_CN/arch/arm64/perf.rst86
-rw-r--r--Documentation/translations/zh_CN/arch/arm64/silicon-errata.txt (renamed from Documentation/translations/zh_CN/arm64/silicon-errata.txt)4
-rw-r--r--Documentation/translations/zh_CN/arch/arm64/tagged-pointers.txt (renamed from Documentation/translations/zh_CN/arm64/tagged-pointers.txt)4
-rw-r--r--Documentation/translations/zh_CN/arch/index.rst28
-rw-r--r--Documentation/translations/zh_CN/arch/loongarch/booting.rst48
-rw-r--r--Documentation/translations/zh_CN/arch/loongarch/features.rst8
-rw-r--r--Documentation/translations/zh_CN/arch/loongarch/index.rst27
-rw-r--r--Documentation/translations/zh_CN/arch/loongarch/introduction.rst353
-rw-r--r--Documentation/translations/zh_CN/arch/loongarch/irq-chip-model.rst157
-rw-r--r--Documentation/translations/zh_CN/arch/mips/booting.rst34
-rw-r--r--Documentation/translations/zh_CN/arch/mips/features.rst13
-rw-r--r--Documentation/translations/zh_CN/arch/mips/index.rst29
-rw-r--r--Documentation/translations/zh_CN/arch/mips/ingenic-tcu.rst72
-rw-r--r--Documentation/translations/zh_CN/arch/openrisc/index.rst32
-rw-r--r--Documentation/translations/zh_CN/arch/openrisc/openrisc_port.rst127
-rw-r--r--Documentation/translations/zh_CN/arch/openrisc/todo.rst23
-rw-r--r--Documentation/translations/zh_CN/arch/parisc/debugging.rst45
-rw-r--r--Documentation/translations/zh_CN/arch/parisc/index.rst31
-rw-r--r--Documentation/translations/zh_CN/arch/parisc/registers.rst156
-rw-r--r--Documentation/translations/zh_CN/arch/riscv/boot-image-header.rst69
-rw-r--r--Documentation/translations/zh_CN/arch/riscv/boot.rst155
-rw-r--r--Documentation/translations/zh_CN/arch/riscv/index.rst31
-rw-r--r--Documentation/translations/zh_CN/arch/riscv/patch-acceptance.rst33
-rw-r--r--Documentation/translations/zh_CN/arch/riscv/vm-layout.rst104
-rw-r--r--Documentation/translations/zh_CN/core-api/assoc_array.rst473
-rw-r--r--Documentation/translations/zh_CN/core-api/boot-time-mm.rst49
-rw-r--r--Documentation/translations/zh_CN/core-api/cachetlb.rst333
-rw-r--r--Documentation/translations/zh_CN/core-api/circular-buffers.rst210
-rw-r--r--Documentation/translations/zh_CN/core-api/cpu_hotplug.rst661
-rw-r--r--Documentation/translations/zh_CN/core-api/errseq.rst145
-rw-r--r--Documentation/translations/zh_CN/core-api/genalloc.rst109
-rw-r--r--Documentation/translations/zh_CN/core-api/generic-radix-tree.rst23
-rw-r--r--Documentation/translations/zh_CN/core-api/genericirq.rst409
-rw-r--r--Documentation/translations/zh_CN/core-api/gfp_mask-from-fs-io.rst66
-rw-r--r--Documentation/translations/zh_CN/core-api/idr.rst80
-rw-r--r--Documentation/translations/zh_CN/core-api/index.rst147
-rw-r--r--Documentation/translations/zh_CN/core-api/irq/concepts.rst26
-rw-r--r--Documentation/translations/zh_CN/core-api/irq/index.rst22
-rw-r--r--Documentation/translations/zh_CN/core-api/irq/irq-affinity.rst78
-rw-r--r--Documentation/translations/zh_CN/core-api/irq/irq-domain.rst243
-rw-r--r--Documentation/translations/zh_CN/core-api/irq/irqflags-tracing.rst47
-rw-r--r--Documentation/translations/zh_CN/core-api/kernel-api.rst378
-rw-r--r--Documentation/translations/zh_CN/core-api/kobject.rst379
-rw-r--r--Documentation/translations/zh_CN/core-api/kref.rst311
-rw-r--r--Documentation/translations/zh_CN/core-api/local_ops.rst196
-rw-r--r--Documentation/translations/zh_CN/core-api/memory-allocation.rst138
-rw-r--r--Documentation/translations/zh_CN/core-api/memory-hotplug.rst122
-rw-r--r--Documentation/translations/zh_CN/core-api/mm-api.rst131
-rw-r--r--Documentation/translations/zh_CN/core-api/packing.rst160
-rw-r--r--Documentation/translations/zh_CN/core-api/padata.rst161
-rw-r--r--Documentation/translations/zh_CN/core-api/printk-basics.rst111
-rw-r--r--Documentation/translations/zh_CN/core-api/printk-formats.rst598
-rw-r--r--Documentation/translations/zh_CN/core-api/protection-keys.rst99
-rw-r--r--Documentation/translations/zh_CN/core-api/rbtree.rst391
-rw-r--r--Documentation/translations/zh_CN/core-api/refcount-vs-atomic.rst156
-rw-r--r--Documentation/translations/zh_CN/core-api/symbol-namespaces.rst144
-rw-r--r--Documentation/translations/zh_CN/core-api/this_cpu_ops.rst285
-rw-r--r--Documentation/translations/zh_CN/core-api/unaligned-memory-access.rst229
-rw-r--r--Documentation/translations/zh_CN/core-api/watch_queue.rst313
-rw-r--r--Documentation/translations/zh_CN/core-api/workqueue.rst352
-rw-r--r--Documentation/translations/zh_CN/core-api/xarray.rst373
-rw-r--r--Documentation/translations/zh_CN/cpu-freq/core.rst109
-rw-r--r--Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst257
-rw-r--r--Documentation/translations/zh_CN/cpu-freq/cpufreq-stats.rst133
-rw-r--r--Documentation/translations/zh_CN/cpu-freq/index.rst47
-rw-r--r--Documentation/translations/zh_CN/dev-tools/gcov.rst264
-rw-r--r--Documentation/translations/zh_CN/dev-tools/gdb-kernel-debugging.rst167
-rw-r--r--Documentation/translations/zh_CN/dev-tools/index.rst37
-rw-r--r--Documentation/translations/zh_CN/dev-tools/kasan.rst462
-rw-r--r--Documentation/translations/zh_CN/dev-tools/sparse.rst (renamed from Documentation/translations/zh_CN/sparse.txt)69
-rw-r--r--Documentation/translations/zh_CN/dev-tools/testing-overview.rst161
-rw-r--r--Documentation/translations/zh_CN/devicetree/changesets.rst37
-rw-r--r--Documentation/translations/zh_CN/devicetree/dynamic-resolution-notes.rst31
-rw-r--r--Documentation/translations/zh_CN/devicetree/index.rst45
-rw-r--r--Documentation/translations/zh_CN/devicetree/kernel-api.rst58
-rw-r--r--Documentation/translations/zh_CN/devicetree/of_unittest.rst189
-rw-r--r--Documentation/translations/zh_CN/devicetree/overlay-notes.rst140
-rw-r--r--Documentation/translations/zh_CN/devicetree/usage-model.rst330
-rw-r--r--Documentation/translations/zh_CN/disclaimer-zh_CN.rst2
-rw-r--r--Documentation/translations/zh_CN/doc-guide/contributing.rst238
-rw-r--r--Documentation/translations/zh_CN/doc-guide/index.rst27
-rw-r--r--Documentation/translations/zh_CN/doc-guide/kernel-doc.rst499
-rw-r--r--Documentation/translations/zh_CN/doc-guide/maintainer-profile.rst43
-rw-r--r--Documentation/translations/zh_CN/doc-guide/parse-headers.rst187
-rw-r--r--Documentation/translations/zh_CN/doc-guide/sphinx.rst412
-rw-r--r--Documentation/translations/zh_CN/driver-api/gpio/index.rst68
-rw-r--r--Documentation/translations/zh_CN/driver-api/gpio/legacy.rst (renamed from Documentation/translations/zh_CN/gpio.txt)232
-rw-r--r--Documentation/translations/zh_CN/driver-api/index.rst129
-rw-r--r--Documentation/translations/zh_CN/driver-api/io_ordering.rst60
-rw-r--r--Documentation/translations/zh_CN/filesystems/debugfs.rst221
-rw-r--r--Documentation/translations/zh_CN/filesystems/index.rst29
-rw-r--r--Documentation/translations/zh_CN/filesystems/sysfs.txt21
-rw-r--r--Documentation/translations/zh_CN/filesystems/tmpfs.rst146
-rw-r--r--Documentation/translations/zh_CN/filesystems/virtiofs.rst58
-rw-r--r--Documentation/translations/zh_CN/glossary.rst36
-rw-r--r--Documentation/translations/zh_CN/iio/ep93xx_adc.rst48
-rw-r--r--Documentation/translations/zh_CN/iio/iio_configfs.rst106
-rw-r--r--Documentation/translations/zh_CN/iio/index.rst22
-rw-r--r--Documentation/translations/zh_CN/index.rst138
-rw-r--r--Documentation/translations/zh_CN/infiniband/core_locking.rst115
-rw-r--r--Documentation/translations/zh_CN/infiniband/index.rst40
-rw-r--r--Documentation/translations/zh_CN/infiniband/ipoib.rst111
-rw-r--r--Documentation/translations/zh_CN/infiniband/opa_vnic.rst156
-rw-r--r--Documentation/translations/zh_CN/infiniband/sysfs.rst21
-rw-r--r--Documentation/translations/zh_CN/infiniband/tag_matching.rst63
-rw-r--r--Documentation/translations/zh_CN/infiniband/user_mad.rst164
-rw-r--r--Documentation/translations/zh_CN/infiniband/user_verbs.rst72
-rw-r--r--Documentation/translations/zh_CN/io_ordering.txt67
-rw-r--r--Documentation/translations/zh_CN/kernel-hacking/hacking.rst707
-rw-r--r--Documentation/translations/zh_CN/kernel-hacking/index.rst22
-rw-r--r--Documentation/translations/zh_CN/locking/index.rst43
-rw-r--r--Documentation/translations/zh_CN/locking/mutex-design.rst145
-rw-r--r--Documentation/translations/zh_CN/locking/spinlocks.rst149
-rw-r--r--Documentation/translations/zh_CN/maintainer/configure-git.rst62
-rw-r--r--Documentation/translations/zh_CN/maintainer/index.rst21
-rw-r--r--Documentation/translations/zh_CN/maintainer/maintainer-entry-profile.rst92
-rw-r--r--Documentation/translations/zh_CN/maintainer/modifying-patches.rst51
-rw-r--r--Documentation/translations/zh_CN/maintainer/pull-requests.rst148
-rw-r--r--Documentation/translations/zh_CN/maintainer/rebasing-and-merging.rst165
-rw-r--r--Documentation/translations/zh_CN/mm/active_mm.rst85
-rw-r--r--Documentation/translations/zh_CN/mm/balance.rst81
-rw-r--r--Documentation/translations/zh_CN/mm/damon/api.rst32
-rw-r--r--Documentation/translations/zh_CN/mm/damon/design.rst140
-rw-r--r--Documentation/translations/zh_CN/mm/damon/faq.rst48
-rw-r--r--Documentation/translations/zh_CN/mm/damon/index.rst32
-rw-r--r--Documentation/translations/zh_CN/mm/free_page_reporting.rst38
-rw-r--r--Documentation/translations/zh_CN/mm/highmem.rst151
-rw-r--r--Documentation/translations/zh_CN/mm/hmm.rst361
-rw-r--r--Documentation/translations/zh_CN/mm/hugetlbfs_reserv.rst437
-rw-r--r--Documentation/translations/zh_CN/mm/hwpoison.rst166
-rw-r--r--Documentation/translations/zh_CN/mm/index.rst68
-rw-r--r--Documentation/translations/zh_CN/mm/ksm.rst70
-rw-r--r--Documentation/translations/zh_CN/mm/memory-model.rst135
-rw-r--r--Documentation/translations/zh_CN/mm/mmu_notifier.rst97
-rw-r--r--Documentation/translations/zh_CN/mm/numa.rst101
-rw-r--r--Documentation/translations/zh_CN/mm/overcommit-accounting.rst86
-rw-r--r--Documentation/translations/zh_CN/mm/page_frags.rst38
-rw-r--r--Documentation/translations/zh_CN/mm/page_migration.rst228
-rw-r--r--Documentation/translations/zh_CN/mm/page_owner.rst170
-rw-r--r--Documentation/translations/zh_CN/mm/page_table_check.rst56
-rw-r--r--Documentation/translations/zh_CN/mm/remap_file_pages.rst32
-rw-r--r--Documentation/translations/zh_CN/mm/split_page_table_lock.rst96
-rw-r--r--Documentation/translations/zh_CN/mm/vmalloced-kernel-stacks.rst133
-rw-r--r--Documentation/translations/zh_CN/mm/z3fold.rst31
-rw-r--r--Documentation/translations/zh_CN/mm/zsmalloc.rst78
-rw-r--r--Documentation/translations/zh_CN/oops-tracing.txt212
-rw-r--r--Documentation/translations/zh_CN/peci/index.rst26
-rw-r--r--Documentation/translations/zh_CN/peci/peci.rst54
-rw-r--r--Documentation/translations/zh_CN/power/energy-model.rst210
-rw-r--r--Documentation/translations/zh_CN/power/index.rst56
-rw-r--r--Documentation/translations/zh_CN/power/opp.rst341
-rw-r--r--Documentation/translations/zh_CN/process/1.Intro.rst195
-rw-r--r--Documentation/translations/zh_CN/process/2.Process.rst359
-rw-r--r--Documentation/translations/zh_CN/process/3.Early-stage.rst141
-rw-r--r--Documentation/translations/zh_CN/process/4.Coding.rst285
-rw-r--r--Documentation/translations/zh_CN/process/5.Posting.rst248
-rw-r--r--Documentation/translations/zh_CN/process/6.Followthrough.rst165
-rw-r--r--Documentation/translations/zh_CN/process/7.AdvancedTopics.rst147
-rw-r--r--Documentation/translations/zh_CN/process/8.Conclusion.rst59
-rw-r--r--Documentation/translations/zh_CN/process/coding-style.rst283
-rw-r--r--Documentation/translations/zh_CN/process/development-process.rst5
-rw-r--r--Documentation/translations/zh_CN/process/email-clients.rst265
-rw-r--r--Documentation/translations/zh_CN/process/embargoed-hardware-issues.rst228
-rw-r--r--Documentation/translations/zh_CN/process/howto.rst33
-rw-r--r--Documentation/translations/zh_CN/process/index.rst66
-rw-r--r--Documentation/translations/zh_CN/process/kernel-driver-statement.rst199
-rw-r--r--Documentation/translations/zh_CN/process/kernel-enforcement-statement.rst151
-rw-r--r--Documentation/translations/zh_CN/process/magic-number.rst146
-rw-r--r--Documentation/translations/zh_CN/process/maintainer-pgp-guide.rst789
-rw-r--r--Documentation/translations/zh_CN/process/management-style.rst4
-rw-r--r--Documentation/translations/zh_CN/process/programming-language.rst3
-rw-r--r--Documentation/translations/zh_CN/process/submit-checklist.rst89
-rw-r--r--Documentation/translations/zh_CN/process/submitting-drivers.rst160
-rw-r--r--Documentation/translations/zh_CN/process/submitting-patches.rst753
-rw-r--r--Documentation/translations/zh_CN/process/volatile-considered-harmful.rst4
-rw-r--r--Documentation/translations/zh_CN/rust/arch-support.rst23
-rw-r--r--Documentation/translations/zh_CN/rust/coding-guidelines.rst192
-rw-r--r--Documentation/translations/zh_CN/rust/general-information.rst75
-rw-r--r--Documentation/translations/zh_CN/rust/index.rst28
-rw-r--r--Documentation/translations/zh_CN/rust/quick-start.rst211
-rw-r--r--Documentation/translations/zh_CN/scheduler/completion.rst256
-rw-r--r--Documentation/translations/zh_CN/scheduler/index.rst45
-rw-r--r--Documentation/translations/zh_CN/scheduler/sched-arch.rst71
-rw-r--r--Documentation/translations/zh_CN/scheduler/sched-bwc.rst204
-rw-r--r--Documentation/translations/zh_CN/scheduler/sched-capacity.rst390
-rw-r--r--Documentation/translations/zh_CN/scheduler/sched-debug.rst51
-rw-r--r--Documentation/translations/zh_CN/scheduler/sched-design-CFS.rst205
-rw-r--r--Documentation/translations/zh_CN/scheduler/sched-domains.rst72
-rw-r--r--Documentation/translations/zh_CN/scheduler/sched-energy.rst351
-rw-r--r--Documentation/translations/zh_CN/scheduler/sched-nice-design.rst99
-rw-r--r--Documentation/translations/zh_CN/scheduler/sched-stats.rst156
-rw-r--r--Documentation/translations/zh_CN/scheduler/schedutil.rst164
-rw-r--r--Documentation/translations/zh_CN/sound/hd-audio/controls.rst102
-rw-r--r--Documentation/translations/zh_CN/sound/hd-audio/index.rst14
-rw-r--r--Documentation/translations/zh_CN/sound/index.rst22
-rw-r--r--Documentation/translations/zh_CN/staging/index.rst26
-rw-r--r--Documentation/translations/zh_CN/staging/xz.rst100
-rw-r--r--Documentation/translations/zh_CN/subsystem-apis.rst110
-rw-r--r--Documentation/translations/zh_CN/userspace-api/accelerators/ocxl.rst168
-rw-r--r--Documentation/translations/zh_CN/userspace-api/ebpf/index.rst22
-rw-r--r--Documentation/translations/zh_CN/userspace-api/ebpf/syscall.rst29
-rw-r--r--Documentation/translations/zh_CN/userspace-api/futex2.rst80
-rw-r--r--Documentation/translations/zh_CN/userspace-api/index.rst47
-rw-r--r--Documentation/translations/zh_CN/userspace-api/no_new_privs.rst57
-rw-r--r--Documentation/translations/zh_CN/userspace-api/seccomp_filter.rst293
-rw-r--r--Documentation/translations/zh_CN/userspace-api/sysfs-platform_profile.rst40
-rw-r--r--Documentation/translations/zh_CN/video4linux/omap3isp.txt4
-rw-r--r--Documentation/translations/zh_CN/video4linux/v4l2-framework.txt22
-rw-r--r--Documentation/translations/zh_CN/virt/acrn/cpuid.rst56
-rw-r--r--Documentation/translations/zh_CN/virt/acrn/index.rst25
-rw-r--r--Documentation/translations/zh_CN/virt/acrn/introduction.rst52
-rw-r--r--Documentation/translations/zh_CN/virt/acrn/io-request.rst99
-rw-r--r--Documentation/translations/zh_CN/virt/guest-halt-polling.rst87
-rw-r--r--Documentation/translations/zh_CN/virt/index.rst38
-rw-r--r--Documentation/translations/zh_CN/virt/ne_overview.rst88
-rw-r--r--Documentation/translations/zh_CN/virt/paravirt_ops.rst41
-rw-r--r--Documentation/translations/zh_TW/IRQ.txt41
-rw-r--r--Documentation/translations/zh_TW/admin-guide/README.rst295
-rw-r--r--Documentation/translations/zh_TW/admin-guide/bootconfig.rst294
-rw-r--r--Documentation/translations/zh_TW/admin-guide/bug-bisect.rst85
-rw-r--r--Documentation/translations/zh_TW/admin-guide/bug-hunting.rst344
-rw-r--r--Documentation/translations/zh_TW/admin-guide/clearing-warn-once.rst16
-rw-r--r--Documentation/translations/zh_TW/admin-guide/cpu-load.rst112
-rw-r--r--Documentation/translations/zh_TW/admin-guide/cputopology.rst97
-rw-r--r--Documentation/translations/zh_TW/admin-guide/index.rst136
-rw-r--r--Documentation/translations/zh_TW/admin-guide/init.rst58
-rw-r--r--Documentation/translations/zh_TW/admin-guide/lockup-watchdogs.rst67
-rw-r--r--Documentation/translations/zh_TW/admin-guide/mm/damon/index.rst30
-rw-r--r--Documentation/translations/zh_TW/admin-guide/mm/damon/lru_sort.rst264
-rw-r--r--Documentation/translations/zh_TW/admin-guide/mm/damon/reclaim.rst229
-rw-r--r--Documentation/translations/zh_TW/admin-guide/mm/damon/start.rst125
-rw-r--r--Documentation/translations/zh_TW/admin-guide/mm/damon/usage.rst592
-rw-r--r--Documentation/translations/zh_TW/admin-guide/mm/index.rst50
-rw-r--r--Documentation/translations/zh_TW/admin-guide/mm/ksm.rst199
-rw-r--r--Documentation/translations/zh_TW/admin-guide/reporting-issues.rst1370
-rw-r--r--Documentation/translations/zh_TW/admin-guide/reporting-regressions.rst371
-rw-r--r--Documentation/translations/zh_TW/admin-guide/security-bugs.rst78
-rw-r--r--Documentation/translations/zh_TW/admin-guide/sysrq.rst281
-rw-r--r--Documentation/translations/zh_TW/admin-guide/tainted-kernels.rst161
-rw-r--r--Documentation/translations/zh_TW/admin-guide/unicode.rst174
-rw-r--r--Documentation/translations/zh_TW/arch/arm/Booting176
-rw-r--r--Documentation/translations/zh_TW/arch/arm/kernel_user_helpers.txt285
-rw-r--r--Documentation/translations/zh_TW/arch/arm64/amu.rst104
-rw-r--r--Documentation/translations/zh_TW/arch/arm64/booting.txt251
-rw-r--r--Documentation/translations/zh_TW/arch/arm64/elf_hwcaps.rst244
-rw-r--r--Documentation/translations/zh_TW/arch/arm64/hugetlbpage.rst49
-rw-r--r--Documentation/translations/zh_TW/arch/arm64/index.rst23
-rw-r--r--Documentation/translations/zh_TW/arch/arm64/legacy_instructions.txt77
-rw-r--r--Documentation/translations/zh_TW/arch/arm64/memory.txt119
-rw-r--r--Documentation/translations/zh_TW/arch/arm64/perf.rst88
-rw-r--r--Documentation/translations/zh_TW/arch/arm64/silicon-errata.txt79
-rw-r--r--Documentation/translations/zh_TW/arch/arm64/tagged-pointers.txt57
-rw-r--r--Documentation/translations/zh_TW/arch/index.rst29
-rw-r--r--Documentation/translations/zh_TW/arch/loongarch/booting.rst49
-rw-r--r--Documentation/translations/zh_TW/arch/loongarch/features.rst9
-rw-r--r--Documentation/translations/zh_TW/arch/loongarch/index.rst28
-rw-r--r--Documentation/translations/zh_TW/arch/loongarch/introduction.rst354
-rw-r--r--Documentation/translations/zh_TW/arch/loongarch/irq-chip-model.rst158
-rw-r--r--Documentation/translations/zh_TW/arch/mips/booting.rst35
-rw-r--r--Documentation/translations/zh_TW/arch/mips/features.rst14
-rw-r--r--Documentation/translations/zh_TW/arch/mips/index.rst30
-rw-r--r--Documentation/translations/zh_TW/arch/mips/ingenic-tcu.rst73
-rw-r--r--Documentation/translations/zh_TW/arch/openrisc/index.rst33
-rw-r--r--Documentation/translations/zh_TW/arch/openrisc/openrisc_port.rst128
-rw-r--r--Documentation/translations/zh_TW/arch/openrisc/todo.rst24
-rw-r--r--Documentation/translations/zh_TW/arch/parisc/debugging.rst46
-rw-r--r--Documentation/translations/zh_TW/arch/parisc/index.rst32
-rw-r--r--Documentation/translations/zh_TW/arch/parisc/registers.rst157
-rw-r--r--Documentation/translations/zh_TW/cpu-freq/core.rst110
-rw-r--r--Documentation/translations/zh_TW/cpu-freq/cpu-drivers.rst258
-rw-r--r--Documentation/translations/zh_TW/cpu-freq/cpufreq-stats.rst134
-rw-r--r--Documentation/translations/zh_TW/cpu-freq/index.rst48
-rw-r--r--Documentation/translations/zh_TW/dev-tools/gcov.rst265
-rw-r--r--Documentation/translations/zh_TW/dev-tools/gdb-kernel-debugging.rst168
-rw-r--r--Documentation/translations/zh_TW/dev-tools/index.rst43
-rw-r--r--Documentation/translations/zh_TW/dev-tools/kasan.rst463
-rw-r--r--Documentation/translations/zh_TW/dev-tools/sparse.rst91
-rw-r--r--Documentation/translations/zh_TW/dev-tools/testing-overview.rst162
-rw-r--r--Documentation/translations/zh_TW/disclaimer-zh_TW.rst11
-rw-r--r--Documentation/translations/zh_TW/filesystems/debugfs.rst223
-rw-r--r--Documentation/translations/zh_TW/filesystems/index.rst31
-rw-r--r--Documentation/translations/zh_TW/filesystems/sysfs.txt377
-rw-r--r--Documentation/translations/zh_TW/filesystems/tmpfs.rst147
-rw-r--r--Documentation/translations/zh_TW/filesystems/virtiofs.rst60
-rw-r--r--Documentation/translations/zh_TW/gpio.txt591
-rw-r--r--Documentation/translations/zh_TW/index.rst134
-rw-r--r--Documentation/translations/zh_TW/io_ordering.txt68
-rw-r--r--Documentation/translations/zh_TW/process/1.Intro.rst199
-rw-r--r--Documentation/translations/zh_TW/process/2.Process.rst369
-rw-r--r--Documentation/translations/zh_TW/process/3.Early-stage.rst172
-rw-r--r--Documentation/translations/zh_TW/process/4.Coding.rst297
-rw-r--r--Documentation/translations/zh_TW/process/5.Posting.rst250
-rw-r--r--Documentation/translations/zh_TW/process/6.Followthrough.rst156
-rw-r--r--Documentation/translations/zh_TW/process/7.AdvancedTopics.rst137
-rw-r--r--Documentation/translations/zh_TW/process/8.Conclusion.rst73
-rw-r--r--Documentation/translations/zh_TW/process/code-of-conduct-interpretation.rst112
-rw-r--r--Documentation/translations/zh_TW/process/code-of-conduct.rst76
-rw-r--r--Documentation/translations/zh_TW/process/coding-style.rst1087
-rw-r--r--Documentation/translations/zh_TW/process/development-process.rst30
-rw-r--r--Documentation/translations/zh_TW/process/email-clients.rst329
-rw-r--r--Documentation/translations/zh_TW/process/embargoed-hardware-issues.rst232
-rw-r--r--Documentation/translations/zh_TW/process/howto.rst499
-rw-r--r--Documentation/translations/zh_TW/process/index.rst67
-rw-r--r--Documentation/translations/zh_TW/process/kernel-driver-statement.rst203
-rw-r--r--Documentation/translations/zh_TW/process/kernel-enforcement-statement.rst155
-rw-r--r--Documentation/translations/zh_TW/process/license-rules.rst372
-rw-r--r--Documentation/translations/zh_TW/process/magic-number.rst76
-rw-r--r--Documentation/translations/zh_TW/process/management-style.rst211
-rw-r--r--Documentation/translations/zh_TW/process/programming-language.rst75
-rw-r--r--Documentation/translations/zh_TW/process/stable-api-nonsense.rst159
-rw-r--r--Documentation/translations/zh_TW/process/stable-kernel-rules.rst68
-rw-r--r--Documentation/translations/zh_TW/process/submit-checklist.rst114
-rw-r--r--Documentation/translations/zh_TW/process/submitting-patches.rst659
-rw-r--r--Documentation/translations/zh_TW/process/volatile-considered-harmful.rst110
433 files changed, 66666 insertions, 3688 deletions
diff --git a/Documentation/translations/index.rst b/Documentation/translations/index.rst
index e446e5ed00a6..b826c34791c0 100644
--- a/Documentation/translations/index.rst
+++ b/Documentation/translations/index.rst
@@ -8,9 +8,11 @@ Translations
:maxdepth: 1
zh_CN/index
+ zh_TW/index
it_IT/index
ko_KR/index
ja_JP/index
+ sp_SP/index
.. _translations_disclaimer:
@@ -18,6 +20,10 @@ Translations
Disclaimer
----------
+.. raw:: latex
+
+ \kerneldocCJKoff
+
Translation's purpose is to ease reading and understanding in languages other
than English. Its aim is to help people who do not understand English or have
doubts about its interpretation. Additionally, some people prefer to read
diff --git a/Documentation/translations/it_IT/admin-guide/README.rst b/Documentation/translations/it_IT/admin-guide/README.rst
index b37166817842..c874586a9af9 100644
--- a/Documentation/translations/it_IT/admin-guide/README.rst
+++ b/Documentation/translations/it_IT/admin-guide/README.rst
@@ -4,7 +4,7 @@
.. _it_readme:
-Rilascio del kernel Linux 5.x <http://kernel.org/>
+Rilascio del kernel Linux 6.x <http://kernel.org/>
===================================================
.. warning::
diff --git a/Documentation/translations/it_IT/admin-guide/security-bugs.rst b/Documentation/translations/it_IT/admin-guide/security-bugs.rst
index 18a5822c7d9a..20994f4bfa31 100644
--- a/Documentation/translations/it_IT/admin-guide/security-bugs.rst
+++ b/Documentation/translations/it_IT/admin-guide/security-bugs.rst
@@ -1,6 +1,6 @@
.. include:: ../disclaimer-ita.rst
-:Original: :ref:`Documentation/admin-guide/security-bugs.rst <securitybugs>`
+:Original: :ref:`Documentation/process/security-bugs.rst <securitybugs>`
.. _it_securitybugs:
diff --git a/Documentation/translations/it_IT/core-api/index.rst b/Documentation/translations/it_IT/core-api/index.rst
new file mode 100644
index 000000000000..cc4c4328ad03
--- /dev/null
+++ b/Documentation/translations/it_IT/core-api/index.rst
@@ -0,0 +1,18 @@
+===============================
+Documentazione dell'API di base
+===============================
+
+Utilità di base
+===============
+
+.. toctree::
+ :maxdepth: 1
+
+ symbol-namespaces
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
diff --git a/Documentation/translations/it_IT/core-api/symbol-namespaces.rst b/Documentation/translations/it_IT/core-api/symbol-namespaces.rst
new file mode 100644
index 000000000000..17abc25ee4c1
--- /dev/null
+++ b/Documentation/translations/it_IT/core-api/symbol-namespaces.rst
@@ -0,0 +1,165 @@
+.. include:: ../disclaimer-ita.rst
+
+:Original: Documentation/core-api/symbol-namespaces.rst
+
+===========================
+Spazio dei nomi dei simboli
+===========================
+
+Questo documento descrive come usare lo spazio dei nomi dei simboli
+per strutturare quello che viene esportato internamente al kernel
+grazie alle macro della famiglia EXPORT_SYMBOL().
+
+1. Introduzione
+===============
+
+Lo spazio dei nomi dei simboli è stato introdotto come mezzo per strutturare
+l'API esposta internamente al kernel. Permette ai manutentori di un
+sottosistema di organizzare i simboli esportati in diversi spazi di
+nomi. Questo meccanismo è utile per la documentazione (pensate ad
+esempio allo spazio dei nomi SUBSYSTEM_DEBUG) così come per limitare
+la disponibilità di un gruppo di simboli in altre parti del kernel. Ad
+oggi, i moduli che usano simboli esportati da uno spazio di nomi
+devono prima importare detto spazio. Altrimenti il kernel, a seconda
+della configurazione, potrebbe rifiutare di caricare il modulo o
+avvisare l'utente di un'importazione mancante.
+
+2. Come definire uno spazio dei nomi dei simboli
+================================================
+
+I simboli possono essere esportati in spazi dei nomi usando diversi
+meccanismi. Tutti questi meccanismi cambiano il modo in cui
+EXPORT_SYMBOL e simili vengono guidati verso la creazione di voci in ksymtab.
+
+2.1 Usare le macro EXPORT_SYMBOL
+================================
+
+In aggiunta alle macro EXPORT_SYMBOL() e EXPORT_SYMBOL_GPL(), che permettono
+di esportare simboli del kernel nella rispettiva tabella, ci sono
+varianti che permettono di esportare simboli all'interno di uno spazio dei
+nomi: EXPORT_SYMBOL_NS() ed EXPORT_SYMBOL_NS_GPL(). Queste macro richiedono un
+argomento aggiuntivo: lo spazio dei nomi.
+Tenete presente che per via dell'espansione delle macro questo argomento deve
+essere un simbolo di preprocessore. Per esempio per esportare il
+simbolo ``usb_stor_suspend`` nello spazio dei nomi ``USB_STORAGE`` usate::
+
+ EXPORT_SYMBOL_NS(usb_stor_suspend, USB_STORAGE);
+
+Di conseguenza, nella tabella dei simboli del kernel ci sarà una voce
+rappresentata dalla struttura ``kernel_symbol`` che avrà il campo
+``namespace`` (spazio dei nomi) impostato. Un simbolo esportato senza uno spazio
+dei nomi avrà questo campo impostato a ``NULL``. Non esiste uno spazio dei nomi
+di base. Il programma ``modpost`` e il codice in kernel/module/main.c usano lo
+spazio dei nomi, rispettivamente, durante la compilazione e durante il
+caricamento di un modulo.
+
+2.2 Usare il simbolo di preprocessore DEFAULT_SYMBOL_NAMESPACE
+==============================================================
+
+Definire lo spazio dei nomi per tutti i simboli di un sottosistema può essere
+logorante e di difficile manutenzione. Perciò è stato fornito un simbolo
+di preprocessore di base (DEFAULT_SYMBOL_NAMESPACE), che, se impostato,
+diventa lo spazio dei simboli di base per tutti gli usi di EXPORT_SYMBOL()
+ed EXPORT_SYMBOL_GPL() che non specificano esplicitamente uno spazio dei nomi.
+
+Ci sono molti modi per specificare questo simbolo di preprocessore e il loro
+uso dipende dalle preferenze del manutentore di un sottosistema. La prima
+possibilità è quella di definire il simbolo nel ``Makefile`` del sottosistema.
+Per esempio per esportare tutti i simboli definiti in usb-common nello spazio
+dei nomi USB_COMMON, si può aggiungere la seguente linea in
+drivers/usb/common/Makefile::
+
+ ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=USB_COMMON
+
+Questo cambierà tutte le macro EXPORT_SYMBOL() ed EXPORT_SYMBOL_GPL(). Invece,
+un simbolo esportato con EXPORT_SYMBOL_NS() non verrà cambiato e il simbolo
+verrà esportato nello spazio dei nomi indicato.
+
+Una seconda possibilità è quella di definire il simbolo di preprocessore
+direttamente nei file da compilare. L'esempio precedente diventerebbe::
+
+ #undef DEFAULT_SYMBOL_NAMESPACE
+ #define DEFAULT_SYMBOL_NAMESPACE USB_COMMON
+
+Questo va messo prima di un qualsiasi uso di EXPORT_SYMBOL.
+
+3. Come usare i simboli esportati attraverso uno spazio dei nomi
+================================================================
+
+Per usare i simboli esportati da uno spazio dei nomi, i moduli del
+kernel devono esplicitamente importare il relativo spazio dei nomi; altrimenti
+il kernel potrebbe rifiutarsi di caricare il modulo. Il codice del
+modulo deve usare la macro MODULE_IMPORT_NS per importare lo spazio
+dei nomi che contiene i simboli desiderati. Per esempio un modulo che
+usa il simbolo usb_stor_suspend deve importare lo spazio dei nomi
+USB_STORAGE usando la seguente dichiarazione::
+
+ MODULE_IMPORT_NS(USB_STORAGE);
+
+Questo creerà un'etichetta ``modinfo`` per ogni spazio dei nomi
+importato. Un risvolto di questo fatto è che gli spazi dei
+nomi importati da un modulo possono essere ispezionati tramite
+modinfo::
+
+ $ modinfo drivers/usb/storage/ums-karma.ko
+ [...]
+ import_ns: USB_STORAGE
+ [...]
+
+
+Si consiglia di posizionare la dichiarazione MODULE_IMPORT_NS() vicino
+ai metadati del modulo come MODULE_AUTHOR() o MODULE_LICENSE(). Fate
+riferimento alla sezione 5. per creare automaticamente le importazioni
+mancanti.
+
+4. Caricare moduli che usano simboli provenienti da spazi dei nomi
+==================================================================
+
+Quando un modulo viene caricato (per esempio usando ``insmod``), il kernel
+verificherà la disponibilità di ogni simbolo usato e se lo spazio dei nomi
+che potrebbe contenerli è stato importato. Il comportamento di base del kernel
+è di rifiutarsi di caricare quei moduli che non importano tutti gli spazi dei
+nomi necessari. L'errore verrà annotato e il caricamento fallirà con l'errore
+EINVAL. Per caricare i moduli che non soddisfano questo requisito esiste
+un'opzione di configurazione: impostare
+MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS=y caricherà i moduli comunque ma
+emetterà un avviso.
+
+5. Creare automaticamente la dichiarazione MODULE_IMPORT_NS
+===========================================================
+
+La mancanza di un'importazione può essere individuata facilmente al momento
+della compilazione. Infatti, modpost emetterà un avviso se il modulo usa
+un simbolo da uno spazio dei nomi che non è stato importato.
+La dichiarazione MODULE_IMPORT_NS() viene solitamente aggiunta in un posto
+ben definito (assieme agli altri metadati del modulo). Per facilitare
+la vita di chi scrive moduli (e i manutentori di sottosistemi), esistono uno
+script e un target make per correggere le importazioni mancanti. Questo può
+essere fatto con::
+
+ $ make nsdeps
+
+Lo scenario tipico di chi scrive un modulo potrebbe essere::
+
+ - scrivere codice che dipende da un simbolo appartenente ad uno spazio
+ dei nomi non importato
+ - eseguire ``make``
+ - aver notato un avviso da modpost che parla di un'importazione
+ mancante
+ - eseguire ``make nsdeps`` per aggiungere import nel posto giusto
+
+Per i manutentori di sottosistemi che vogliono aggiungere uno spazio dei nomi,
+l'approccio è simile. Di nuovo, eseguendo ``make nsdeps`` aggiungerà le
+importazioni mancanti nei moduli inclusi nel kernel::
+
+ - spostare o aggiungere simboli ad uno spazio dei nomi (per esempio
+ usando EXPORT_SYMBOL_NS())
+ - eseguire ``make`` (preferibilmente con allmodconfig per coprire tutti
+ i moduli del kernel)
+ - aver notato un avviso da modpost che parla di un'importazione
+ mancante
+ - eseguire ``make nsdeps`` per aggiungere import nel posto giusto
+
+Potete anche eseguire nsdeps per moduli esterni. Solitamente si usa così::
+
+ $ make -C <path_to_kernel_src> M=$PWD nsdeps
diff --git a/Documentation/translations/it_IT/devicetree/bindings/submitting-patches.rst b/Documentation/translations/it_IT/devicetree/bindings/submitting-patches.rst
new file mode 100644
index 000000000000..b473cd2190be
--- /dev/null
+++ b/Documentation/translations/it_IT/devicetree/bindings/submitting-patches.rst
@@ -0,0 +1,11 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-ita.rst
+
+:Original: Documentation/devicetree/bindings/submitting-patches.rst
+
+================================================
+Sottomettere patch per devicetree (DT) *binding*
+================================================
+
+.. note:: to be translated
diff --git a/Documentation/translations/it_IT/doc-guide/kernel-doc.rst b/Documentation/translations/it_IT/doc-guide/kernel-doc.rst
index a4ecd8f27631..5cece223b46b 100644
--- a/Documentation/translations/it_IT/doc-guide/kernel-doc.rst
+++ b/Documentation/translations/it_IT/doc-guide/kernel-doc.rst
@@ -3,8 +3,11 @@
.. note:: Per leggere la documentazione originale in inglese:
:ref:`Documentation/doc-guide/index.rst <doc_guide>`
+.. title:: Commenti in kernel-doc
+
.. _it_kernel_doc:
+=================================
Scrivere i commenti in kernel-doc
=================================
@@ -419,26 +422,24 @@ del `dominio Sphinx per il C`_.
Riferimenti usando reStructuredText
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Per fare riferimento a funzioni e tipi di dato definiti nei commenti kernel-doc
-all'interno dei documenti reStructuredText, utilizzate i riferimenti dal
-`dominio Sphinx per il C`_. Per esempio::
+Nei documenti reStructuredText non serve alcuna sintassi speciale per
+fare riferimento a funzioni e tipi definiti nei commenti
+kernel-doc. Sarà sufficiente terminare i nomi di funzione con ``()``,
+e scrivere ``struct``, ``union``, ``enum``, o ``typedef`` prima di un
+tipo. Per esempio::
- See function :c:func:`foo` and struct/union/enum/typedef :c:type:`bar`.
+ See foo()
+ See struct foo.
+ See union bar.
+ See enum baz.
+ See typedef meh.
-Nonostante il riferimento ai tipi di dato funzioni col solo nome,
-ovvero senza specificare struct/union/enum/typedef, potreste preferire il
-seguente::
+Tuttavia, la personalizzazione dei collegamenti è possibile solo con
+la seguente sintassi::
- See :c:type:`struct foo <foo>`.
- See :c:type:`union bar <bar>`.
- See :c:type:`enum baz <baz>`.
- See :c:type:`typedef meh <meh>`.
+ See :c:func:`my custom link text for function foo <foo>`.
+ See :c:type:`my custom link text for struct bar <bar>`.
-Questo produce dei collegamenti migliori, ed è in linea con il modo in cui
-kernel-doc gestisce i riferimenti.
-
-Per maggiori informazioni, siete pregati di consultare la documentazione
-del `dominio Sphinx per il C`_.
Commenti per una documentazione generale
----------------------------------------
@@ -471,6 +472,7 @@ Il titolo che segue ``DOC:`` funziona da intestazione all'interno del file
sorgente, ma anche come identificatore per l'estrazione di questi commenti di
documentazione. Quindi, il titolo dev'essere unico all'interno del file.
+=======================================
Includere i commenti di tipo kernel-doc
=======================================
@@ -515,6 +517,22 @@ internal: *[source-pattern ...]*
.. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
:internal:
+identifiers: *[ function/type ...]*
+ Include la documentazione per ogni *function* e *type* in *source*.
+ Se non vengono esplicitamente specificate le funzioni da includere, allora
+ verranno incluse tutte quelle disponibili in *source*.
+
+ Esempi::
+
+ .. kernel-doc:: lib/bitmap.c
+ :identifiers: bitmap_parselist bitmap_parselist_user
+
+ .. kernel-doc:: lib/idr.c
+ :identifiers:
+
+functions: *[ function ...]*
+ Questo è uno pseudonimo, deprecato, per la direttiva 'identifiers'.
+
doc: *title*
Include la documentazione del paragrafo ``DOC:`` identificato dal titolo
(*title*) all'interno del file sorgente (*source*). Gli spazi in *title* sono
@@ -528,15 +546,6 @@ doc: *title*
.. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
:doc: High Definition Audio over HDMI and Display Port
-functions: *function* *[...]*
- Dal file sorgente (*source*) include la documentazione per le funzioni
- elencate (*function*).
-
- Esempio::
-
- .. kernel-doc:: lib/bitmap.c
- :functions: bitmap_parselist bitmap_parselist_user
-
Senza alcuna opzione, la direttiva kernel-doc include tutti i commenti di
documentazione presenti nel file sorgente (*source*).
diff --git a/Documentation/translations/it_IT/doc-guide/parse-headers.rst b/Documentation/translations/it_IT/doc-guide/parse-headers.rst
index b38918ca637e..c7076a21667a 100644
--- a/Documentation/translations/it_IT/doc-guide/parse-headers.rst
+++ b/Documentation/translations/it_IT/doc-guide/parse-headers.rst
@@ -1,7 +1,6 @@
.. include:: ../disclaimer-ita.rst
-.. note:: Per leggere la documentazione originale in inglese:
- :ref:`Documentation/doc-guide/index.rst <doc_guide>`
+:Original: Documentation/doc-guide/index.rst
=========================================
Includere gli i file di intestazione uAPI
@@ -17,7 +16,7 @@ con le modifiche del kernel.
Il programma :ref:`parse_headers.pl <it_parse_headers>` genera questi riferimenti.
Esso dev'essere invocato attraverso un Makefile, mentre si genera la
documentazione. Per avere un esempio su come utilizzarlo all'interno del kernel
-consultate ``Documentation/media/Makefile``.
+consultate ``Documentation/userspace-api/media/Makefile``.
.. _it_parse_headers:
@@ -190,7 +189,7 @@ COPYRIGHT
Copyright (c) 2016 by Mauro Carvalho Chehab <mchehab@s-opensource.com>.
-Licenza GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>.
+Licenza GPLv2: GNU GPL version 2 <https://gnu.org/licenses/gpl.html>.
Questo è software libero: siete liberi di cambiarlo e ridistribuirlo.
Non c'è alcuna garanzia, nei limiti permessi dalla legge.
diff --git a/Documentation/translations/it_IT/doc-guide/sphinx.rst b/Documentation/translations/it_IT/doc-guide/sphinx.rst
index f1ad4504b734..1f513bc33618 100644
--- a/Documentation/translations/it_IT/doc-guide/sphinx.rst
+++ b/Documentation/translations/it_IT/doc-guide/sphinx.rst
@@ -5,8 +5,9 @@
.. _it_sphinxdoc:
-Introduzione
-============
+=============================================
+Usare Sphinx per la documentazione del kernel
+=============================================
Il kernel Linux usa `Sphinx`_ per la generazione della documentazione a partire
dai file `reStructuredText`_ che si trovano nella cartella ``Documentation``.
@@ -35,7 +36,7 @@ Installazione Sphinx
====================
I marcatori ReST utilizzati nei file in Documentation/ sono pensati per essere
-processati da ``Sphinx`` nella versione 1.3 o superiore.
+processati da ``Sphinx`` nella versione 1.7 o superiore.
Esiste uno script che verifica i requisiti Sphinx. Per ulteriori dettagli
consultate :ref:`it_sphinx-pre-install`.
@@ -53,11 +54,6 @@ pacchettizzato dalla vostra distribuzione.
.. note::
- #) Le versioni di Sphinx inferiori alla 1.5 non funzionano bene
- con il pacchetto Python docutils versione 0.13.1 o superiore.
- Se volete usare queste versioni, allora dovere eseguire
- ``pip install 'docutils==0.12'``.
-
#) Viene raccomandato l'uso del tema RTD per la documentazione in HTML.
A seconda della versione di Sphinx, potrebbe essere necessaria
l'installazione tramite il comando ``pip install sphinx_rtd_theme``.
@@ -67,13 +63,13 @@ pacchettizzato dalla vostra distribuzione.
utilizzando LaTeX. Per una corretta interpretazione, è necessario aver
installato texlive con i pacchetti amdfonts e amsmath.
-Riassumendo, se volete installare la versione 1.7.9 di Sphinx dovete eseguire::
+Riassumendo, se volete installare la versione 2.4.4 di Sphinx dovete eseguire::
- $ virtualenv sphinx_1.7.9
- $ . sphinx_1.7.9/bin/activate
- (sphinx_1.7.9) $ pip install -r Documentation/sphinx/requirements.txt
+ $ virtualenv sphinx_2.4.4
+ $ . sphinx_2.4.4/bin/activate
+ (sphinx_2.4.4) $ pip install -r Documentation/sphinx/requirements.txt
-Dopo aver eseguito ``. sphinx_1.7.9/bin/activate``, il prompt cambierà per
+Dopo aver eseguito ``. sphinx_2.4.4/bin/activate``, il prompt cambierà per
indicare che state usando il nuovo ambiente. Se aprite un nuova sessione,
prima di generare la documentazione, dovrete rieseguire questo comando per
rientrare nell'ambiente virtuale.
@@ -94,7 +90,7 @@ Generazione in PDF e LaTeX
--------------------------
Al momento, la generazione di questi documenti è supportata solo dalle
-versioni di Sphinx superiori alla 1.4.
+versioni di Sphinx superiori alla 2.4.
Per la generazione di PDF e LaTeX, avrete bisogno anche del pacchetto
``XeLaTeX`` nella versione 3.14159265
@@ -119,8 +115,8 @@ l'installazione::
You should run:
sudo dnf install -y texlive-luatex85
- /usr/bin/virtualenv sphinx_1.7.9
- . sphinx_1.7.9/bin/activate
+ /usr/bin/virtualenv sphinx_2.4.4
+ . sphinx_2.4.4/bin/activate
pip install -r Documentation/sphinx/requirements.txt
Can't build as 1 mandatory dependency is missing at ./scripts/sphinx-pre-install line 468.
@@ -155,7 +151,8 @@ Ovviamente, per generare la documentazione, Sphinx (``sphinx-build``)
dev'essere installato. Se disponibile, il tema *Read the Docs* per Sphinx
verrà utilizzato per ottenere una documentazione HTML più gradevole.
Per la documentazione in formato PDF, invece, avrete bisogno di ``XeLaTeX`
-e di ``convert(1)`` disponibile in ImageMagick (https://www.imagemagick.org).
+e di ``convert(1)`` disponibile in ImageMagick
+(https://www.imagemagick.org). \ [#ink]_
Tipicamente, tutti questi pacchetti sono disponibili e pacchettizzati nelle
distribuzioni Linux.
@@ -163,9 +160,23 @@ Per poter passare ulteriori opzioni a Sphinx potete utilizzare la variabile
make ``SPHINXOPTS``. Per esempio, se volete che Sphinx sia più verboso durante
la generazione potete usare il seguente comando ``make SPHINXOPTS=-v htmldocs``.
+Potete anche personalizzare l'ouptut html passando un livello aggiuntivo
+DOCS_CSS usando la rispettiva variabile d'ambiente ``DOCS_CSS``.
+
+La variable make ``SPHINXDIRS`` è utile quando si vuole generare solo una parte
+della documentazione. Per esempio, si possono generare solo di documenti in
+``Documentation/doc-guide`` eseguendo ``make SPHINXDIRS=doc-guide htmldocs``. La
+sezione dedicata alla documentazione di ``make help`` vi mostrerà quali sotto
+cartelle potete specificare.
+
Potete eliminare la documentazione generata tramite il comando
``make cleandocs``.
+.. [#ink] Avere installato anche ``inkscape(1)`` dal progetto Inkscape ()
+ potrebbe aumentare la qualità delle immagini che verranno integrate
+ nel documento PDF, specialmente per quando si usando rilasci del
+ kernel uguali o superiori a 5.18
+
Scrivere la documentazione
==========================
@@ -281,11 +292,11 @@ incrociato quando questa ha una voce nell'indice. Se trovate degli usi di
Tabelle a liste
---------------
-Raccomandiamo l'uso delle tabelle in formato lista (*list table*). Le tabelle
-in formato lista sono liste di liste. In confronto all'ASCII-art potrebbero
-non apparire di facile lettura nei file in formato testo. Il loro vantaggio è
-che sono facili da creare o modificare e che la differenza di una modifica è
-molto più significativa perché limitata alle modifiche del contenuto.
+Il formato ``list-table`` può essere utile per tutte quelle tabelle che non
+possono essere facilmente scritte usando il formato ASCII-art di Sphinx. Però,
+questo genere di tabelle sono illeggibili per chi legge direttamente i file di
+testo. Dunque, questo formato dovrebbe essere evitato senza forti argomenti che
+ne giustifichino l'uso.
La ``flat-table`` è anch'essa una lista di liste simile alle ``list-table``
ma con delle funzionalità aggiuntive:
@@ -330,17 +341,17 @@ la lista di celle che compongono la *riga* stessa. Fanno eccezione i *commenti*
- head col 3
- head col 4
- * - column 1
+ * - row 1
- field 1.1
- field 1.2 with autospan
- * - column 2
+ * - row 2
- field 2.1
- :rspan:`1` :cspan:`1` field 2.2 - 3.3
* .. _`it last row`:
- - column 3
+ - row 3
Che verrà rappresentata nel seguente modo:
@@ -352,17 +363,46 @@ Che verrà rappresentata nel seguente modo:
- head col 3
- head col 4
- * - column 1
+ * - row 1
- field 1.1
- field 1.2 with autospan
- * - column 2
+ * - row 2
- field 2.1
- :rspan:`1` :cspan:`1` field 2.2 - 3.3
* .. _`it last row`:
- - column 3
+ - row 3
+
+Riferimenti incrociati
+----------------------
+
+Aggiungere un riferimento incrociato da una pagina della
+documentazione ad un'altra può essere fatto scrivendo il percorso al
+file corrispondende, non serve alcuna sintassi speciale. Si possono
+usare sia percorsi assoluti che relativi. Quelli assoluti iniziano con
+"documentation/". Per esempio, potete fare riferimento a questo
+documento in uno dei seguenti modi (da notare che l'estensione
+``.rst`` è necessaria)::
+
+ Vedere Documentation/doc-guide/sphinx.rst. Questo funziona sempre
+ Guardate pshinx.rst, che si trova nella stessa cartella.
+ Leggete ../sphinx.rst, che si trova nella cartella precedente.
+
+Se volete che il collegamento abbia un testo diverso rispetto al
+titolo del documento, allora dovrete usare la direttiva Sphinx
+``doc``. Per esempio::
+
+ Vedere :doc:`il mio testo per il collegamento <sphinx>`.
+
+Nella maggioranza dei casi si consiglia il primo metodo perché è più
+pulito ed adatto a chi legge dai sorgenti. Se incontrare un ``:doc:``
+che non da alcun valore, sentitevi liberi di convertirlo in un
+percorso al documento.
+
+Per informazioni riguardo ai riferimenti incrociati ai commenti
+kernel-doc per funzioni o tipi, consultate
.. _it_sphinx_kfigure:
@@ -371,7 +411,7 @@ Figure ed immagini
Se volete aggiungere un'immagine, utilizzate le direttive ``kernel-figure``
e ``kernel-image``. Per esempio, per inserire una figura di un'immagine in
-formato SVG::
+formato SVG (:ref:`it_svg_image_example`)::
.. kernel-figure:: ../../../doc-guide/svg_image.svg
:alt: una semplice immagine SVG
diff --git a/Documentation/translations/it_IT/index.rst b/Documentation/translations/it_IT/index.rst
index 409eaac03e9f..b95dfa1ded04 100644
--- a/Documentation/translations/it_IT/index.rst
+++ b/Documentation/translations/it_IT/index.rst
@@ -1,11 +1,29 @@
+.. SPDX-License-Identifier: GPL-2.0
+
.. _it_linux_doc:
-===================
-Traduzione italiana
-===================
+==================================
+La documentazione del kernel Linux
+==================================
+
+.. raw:: latex
+
+ \kerneldocCJKoff
:manutentore: Federico Vaga <federico.vaga@vaga.pv.it>
+Questo è il livello principale della documentazione del kernel in
+lingua italiana. La traduzione è incompleta, noterete degli avvisi
+che vi segnaleranno la mancanza di una traduzione o di un gruppo di
+traduzioni.
+
+Più in generale, la documentazione, come il kernel stesso, sono in
+costante sviluppo; particolarmente vero in quanto stiamo lavorando
+alla riorganizzazione della documentazione in modo più coerente.
+I miglioramenti alla documentazione sono sempre i benvenuti; per cui,
+se vuoi aiutare, iscriviti alla lista di discussione linux-doc presso
+vger.kernel.org.
+
.. _it_disclaimer:
Avvertenze
@@ -48,89 +66,68 @@ Se avete bisogno d'aiuto per comunicare con la comunità Linux ma non vi sentite
a vostro agio nello scrivere in inglese, potete chiedere aiuto al manutentore
della traduzione.
-La documentazione del kernel Linux
-==================================
+Lavorare con la comunità di sviluppo
+====================================
-Questo è il livello principale della documentazione del kernel in
-lingua italiana. La traduzione è incompleta, noterete degli avvisi
-che vi segnaleranno la mancanza di una traduzione o di un gruppo di
-traduzioni.
-
-Più in generale, la documentazione, come il kernel stesso, sono in
-costante sviluppo; particolarmente vero in quanto stiamo lavorando
-alla riorganizzazione della documentazione in modo più coerente.
-I miglioramenti alla documentazione sono sempre i benvenuti; per cui,
-se vuoi aiutare, iscriviti alla lista di discussione linux-doc presso
-vger.kernel.org.
+Le guide fondamentali per l'interazione con la comunità di sviluppo del kernel e
+su come vedere il proprio lavoro integrato.
-Documentazione sulla licenza dei sorgenti
------------------------------------------
-
-I seguenti documenti descrivono la licenza usata nei sorgenti del kernel Linux
-(GPLv2), come licenziare i singoli file; inoltre troverete i riferimenti al
-testo integrale della licenza.
-
-* :ref:`it_kernel_licensing`
-
-Documentazione per gli utenti
------------------------------
-
-I seguenti manuali sono scritti per gli *utenti* del kernel - ovvero,
-coloro che cercano di farlo funzionare in modo ottimale su un dato sistema
-
-.. warning::
+.. toctree::
+ :maxdepth: 1
- TODO ancora da tradurre
+ process/development-process
+ process/submitting-patches
+ Code of conduct <process/code-of-conduct>
+ All development-process docs <process/index>
-Documentazione per gli sviluppatori di applicazioni
----------------------------------------------------
-Il manuale delle API verso lo spazio utente è una collezione di documenti
-che descrivono le interfacce del kernel viste dagli sviluppatori
-di applicazioni.
+Manuali sull'API interna
+========================
-.. warning::
+Di seguito una serie di manuali per gli sviluppatori che hanno bisogno di
+interfacciarsi con il resto del kernel.
- TODO ancora da tradurre
+.. toctree::
+ :maxdepth: 1
+ core-api/index
-Introduzione allo sviluppo del kernel
--------------------------------------
+Strumenti e processi per lo sviluppo
+====================================
-Questi manuali contengono informazioni su come contribuire allo sviluppo
-del kernel.
-Attorno al kernel Linux gira una comunità molto grande con migliaia di
-sviluppatori che contribuiscono ogni anno. Come in ogni grande comunità,
-sapere come le cose vengono fatte renderà il processo di integrazione delle
-vostre modifiche molto più semplice
+Di seguito una serie di manuali contenenti informazioni utili a tutti gli
+sviluppatori del kernel.
.. toctree::
- :maxdepth: 2
+ :maxdepth: 1
- process/index
+ process/license-rules
doc-guide/index
kernel-hacking/index
-Documentazione della API del kernel
------------------------------------
+Documentazione per gli utenti
+=============================
+
+Di seguito una serie di manuali per gli *utenti* del kernel - ovvero coloro che
+stanno cercando di farlo funzionare al meglio per un dato sistema, ma anche
+coloro che stanno sviluppando applicazioni che sfruttano l'API verso lo
+spazio-utente.
-Questi manuali forniscono dettagli su come funzionano i sottosistemi del
-kernel dal punto di vista degli sviluppatori del kernel. Molte delle
-informazioni contenute in questi manuali sono prese direttamente dai
-file sorgenti, informazioni aggiuntive vengono aggiunte solo se necessarie
-(o almeno ci proviamo — probabilmente *non* tutto quello che è davvero
-necessario).
+Consultate anche `Linux man pages <https://www.kernel.org/doc/man-pages/>`_, che
+vengono mantenuti separatamente dalla documentazione del kernel Linux
-.. warning::
+Documentazione relativa ai firmware
+===================================
+Di seguito informazioni sulle aspettative del kernel circa i firmware.
- TODO ancora da tradurre
Documentazione specifica per architettura
------------------------------------------
+=========================================
-Questi manuali forniscono dettagli di programmazione per le diverse
-implementazioni d'architettura.
-.. warning::
+Documentazione varia
+====================
- TODO ancora da tradurre
+Ci sono documenti che sono difficili da inserire nell'attuale organizzazione
+della documentazione; altri hanno bisogno di essere migliorati e/o convertiti
+nel formato *ReStructured Text*; altri sono semplicamente troppo vecchi.
diff --git a/Documentation/translations/it_IT/kernel-hacking/hacking.rst b/Documentation/translations/it_IT/kernel-hacking/hacking.rst
index 24c592852bf1..dd06bfc1a050 100644
--- a/Documentation/translations/it_IT/kernel-hacking/hacking.rst
+++ b/Documentation/translations/it_IT/kernel-hacking/hacking.rst
@@ -90,7 +90,7 @@ i gestori d'interruzioni devono essere veloci: spesso si limitano
esclusivamente a notificare la presa in carico dell'interruzione,
programmare una 'interruzione software' per l'esecuzione e quindi terminare.
-Potete dire d'essere in una interruzione hardware perché :c:func:`in_irq()`
+Potete dire d'essere in una interruzione hardware perché in_hardirq()
ritorna vero.
.. warning::
@@ -129,8 +129,7 @@ eseguiti simultaneamente.
.. warning::
Il nome 'tasklet' è ingannevole: non hanno niente a che fare
- con i 'processi' ('tasks'), e probabilmente hanno più a che vedere
- con qualche pessima vodka che Alexey Kuznetsov si fece a quel tempo.
+ con i 'processi' ('tasks').
Potete determinate se siete in un softirq (o tasklet) utilizzando la
macro :c:func:`in_softirq()` (``include/linux/preempt.h``).
@@ -138,7 +137,7 @@ macro :c:func:`in_softirq()` (``include/linux/preempt.h``).
.. warning::
State attenti che questa macro ritornerà un falso positivo
- se :ref:`botton half lock <it_local_bh_disable>` è bloccato.
+ se :ref:`bottom half lock <it_local_bh_disable>` è bloccato.
Alcune regole basilari
======================
@@ -308,7 +307,7 @@ esse copiano una quantità arbitraria di dati da e verso lo spazio utente.
Al contrario di:c:func:`put_user()` e :c:func:`get_user()`, queste
funzioni ritornano la quantità di dati copiati (0 è comunque un successo).
-[Sì, questa stupida interfaccia mi imbarazza. La battaglia torna in auge anno
+[Sì, questa interfaccia mi imbarazza. La battaglia torna in auge anno
dopo anno. --RR]
Le funzioni potrebbero dormire implicitamente. Queste non dovrebbero mai essere
@@ -369,7 +368,7 @@ all'inizio dell'avvio del sistema è attraverso la procedura
Prima di inventare la vostra cache per gli oggetti più usati, considerate
l'uso di una cache slab disponibile in ``include/linux/slab.h``.
-:c:func:`current()`
+:c:macro:`current`
-------------------
Definita in ``include/asm/current.h``
@@ -402,7 +401,7 @@ il valore convertito. Tutte le varianti supportano anche il processo inverso:
:c:func:`be32_to_cpu()`, eccetera.
Queste funzioni hanno principalmente due varianti: la variante per
-puntatori, come :c:func:`cpu_to_be32p(), che prende un puntatore
+puntatori, come :c:func:`cpu_to_be32p()`, che prende un puntatore
ad un tipo, e ritorna il valore convertito. L'altra variante per
la famiglia di conversioni "in-situ", come :c:func:`cpu_to_be32s()`,
che convertono il valore puntato da un puntatore, e ritornano void.
@@ -627,6 +626,24 @@ Alcuni manutentori e sviluppatori potrebbero comunque richiedere
:c:func:`EXPORT_SYMBOL_GPL()` quando si aggiungono nuove funzionalità o
interfacce.
+:c:func:`EXPORT_SYMBOL_NS()`
+----------------------------
+
+Definita in ``include/linux/export.h``
+
+Questa è una variate di `EXPORT_SYMBOL()` che permette di specificare uno
+spazio dei nomi. Lo spazio dei nomi è documentato in
+Documentation/translations/it_IT/core-api/symbol-namespaces.rst.
+
+:c:func:`EXPORT_SYMBOL_NS_GPL()`
+--------------------------------
+
+Definita in ``include/linux/export.h``
+
+Questa è una variate di `EXPORT_SYMBOL_GPL()` che permette di specificare uno
+spazio dei nomi. Lo spazio dei nomi è documentato in
+Documentation/translations/it_IT/core-api/symbol-namespaces.rst.
+
Procedure e convenzioni
=======================
@@ -661,9 +678,8 @@ tutti sulle spine: questo riflette cambiamenti fondamentati (eg. la funzione
non può più essere chiamata con le funzioni attive, o fa controlli aggiuntivi,
o non fa più controlli che venivano fatti in precedenza). Solitamente a questo
s'accompagna un'adeguata e completa nota sulla lista di discussone
-linux-kernel; cercate negli archivi.
-Solitamente eseguire una semplice sostituzione su tutto un file rendere
-le cose **peggiori**.
+più adatta; cercate negli archivi. Solitamente eseguire una semplice
+sostituzione su tutto un file rendere le cose **peggiori**.
Inizializzazione dei campi d'una struttura
------------------------------------------
@@ -741,14 +757,14 @@ Mettere le vostre cose nel kernel
Al fine d'avere le vostre cose in ordine per l'inclusione ufficiale, o
anche per avere patch pulite, c'è del lavoro amministrativo da fare:
-- Trovare di chi è lo stagno in cui state pisciando. Guardare in cima
+- Trovare chi è responsabile del codice che state modificando. Guardare in cima
ai file sorgenti, all'interno del file ``MAINTAINERS``, ed alla fine
di tutti nel file ``CREDITS``. Dovreste coordinarvi con queste persone
per evitare di duplicare gli sforzi, o provare qualcosa che è già stato
rigettato.
Assicuratevi di mettere il vostro nome ed indirizzo email in cima a
- tutti i file che create o che mangeggiate significativamente. Questo è
+ tutti i file che create o che maneggiate significativamente. Questo è
il primo posto dove le persone guarderanno quando troveranno un baco,
o quando **loro** vorranno fare una modifica.
@@ -769,16 +785,15 @@ anche per avere patch pulite, c'è del lavoro amministrativo da fare:
"obj-$(CONFIG_xxx) += xxx.o". La sintassi è documentata nel file
``Documentation/kbuild/makefiles.rst``.
-- Aggiungete voi stessi in ``CREDITS`` se avete fatto qualcosa di notevole,
- solitamente qualcosa che supera il singolo file (comunque il vostro nome
- dovrebbe essere all'inizio dei file sorgenti). ``MAINTAINERS`` significa
+- Aggiungete voi stessi in ``CREDITS`` se credete di aver fatto qualcosa di
+ notevole, solitamente qualcosa che supera il singolo file (comunque il vostro
+ nome dovrebbe essere all'inizio dei file sorgenti). ``MAINTAINERS`` significa
che volete essere consultati quando vengono fatte delle modifiche ad un
- sottosistema, e quando ci sono dei bachi; questo implica molto di più
- di un semplice impegno su una parte del codice.
+ sottosistema, e quando ci sono dei bachi; questo implica molto di più di un
+ semplice impegno su una parte del codice.
- Infine, non dimenticatevi di leggere
- ``Documentation/process/submitting-patches.rst`` e possibilmente anche
- ``Documentation/process/submitting-drivers.rst``.
+ ``Documentation/process/submitting-patches.rst``.
Trucchetti del kernel
=====================
diff --git a/Documentation/translations/it_IT/kernel-hacking/locking.rst b/Documentation/translations/it_IT/kernel-hacking/locking.rst
index b9a6be4b8499..4c21cf60f775 100644
--- a/Documentation/translations/it_IT/kernel-hacking/locking.rst
+++ b/Documentation/translations/it_IT/kernel-hacking/locking.rst
@@ -1,5 +1,7 @@
.. include:: ../disclaimer-ita.rst
+.. c:namespace:: it_IT
+
:Original: :ref:`Documentation/kernel-hacking/locking.rst <kernel_hacking_lock>`
:Translator: Federico Vaga <federico.vaga@vaga.pv.it>
@@ -100,16 +102,11 @@ che non esistano.
Sincronizzazione nel kernel Linux
=================================
-Se posso darvi un suggerimento: non dormite mai con qualcuno più pazzo di
-voi. Ma se dovessi darvi un suggerimento sulla sincronizzazione:
-**mantenetela semplice**.
+Se dovessi darvi un suggerimento sulla sincronizzazione: **mantenetela
+semplice**.
Siate riluttanti nell'introduzione di nuovi *lock*.
-Abbastanza strano, quest'ultimo è l'esatto opposto del mio suggerimento
-su quando **avete** dormito con qualcuno più pazzo di voi. E dovreste
-pensare a prendervi un cane bello grande.
-
I due principali tipi di *lock* nel kernel: spinlock e mutex
------------------------------------------------------------
@@ -125,11 +122,11 @@ il vostro processo si auto-sospenderà; verrà riattivato quando il mutex
verrà rilasciato. Questo significa che il processore potrà occuparsi d'altro
mentre il vostro processo è in attesa. Esistono molti casi in cui non potete
permettervi di sospendere un processo (vedere
-:ref:`Quali funzioni possono essere chiamate in modo sicuro dalle interruzioni? <it_sleeping-things>`)
+`Quali funzioni possono essere chiamate in modo sicuro dalle interruzioni?`_)
e quindi dovrete utilizzare gli spinlock.
Nessuno di questi *lock* è ricorsivo: vedere
-:ref:`Stallo: semplice ed avanzato <it_deadlock>`
+`Stallo: semplice ed avanzato`_
I *lock* e i kernel per sistemi monoprocessore
----------------------------------------------
@@ -159,17 +156,17 @@ Sincronizzazione in contesto utente
Se avete una struttura dati che verrà utilizzata solo dal contesto utente,
allora, per proteggerla, potete utilizzare un semplice mutex
(``include/linux/mutex.h``). Questo è il caso più semplice: inizializzate il
-mutex; invocate :c:func:`mutex_lock_interruptible()` per trattenerlo e
-:c:func:`mutex_unlock()` per rilasciarlo. C'è anche :c:func:`mutex_lock()`
+mutex; invocate mutex_lock_interruptible() per trattenerlo e
+mutex_unlock() per rilasciarlo. C'è anche mutex_lock()
ma questa dovrebbe essere evitata perché non ritorna in caso di segnali.
Per esempio: ``net/netfilter/nf_sockopt.c`` permette la registrazione
-di nuove chiamate per :c:func:`setsockopt()` e :c:func:`getsockopt()`
-usando la funzione :c:func:`nf_register_sockopt()`. La registrazione e
+di nuove chiamate per setsockopt() e getsockopt()
+usando la funzione nf_register_sockopt(). La registrazione e
la rimozione vengono eseguite solamente quando il modulo viene caricato
o scaricato (e durante l'avvio del sistema, qui non abbiamo concorrenza),
e la lista delle funzioni registrate viene consultata solamente quando
-:c:func:`setsockopt()` o :c:func:`getsockopt()` sono sconosciute al sistema.
+setsockopt() o getsockopt() sono sconosciute al sistema.
In questo caso ``nf_sockopt_mutex`` è perfetto allo scopo, in particolar modo
visto che setsockopt e getsockopt potrebbero dormire.
@@ -179,19 +176,19 @@ Sincronizzazione fra il contesto utente e i softirq
Se un softirq condivide dati col contesto utente, avete due problemi.
Primo, il contesto utente corrente potrebbe essere interroto da un softirq,
e secondo, la sezione critica potrebbe essere eseguita da un altro
-processore. Questo è quando :c:func:`spin_lock_bh()`
+processore. Questo è quando spin_lock_bh()
(``include/linux/spinlock.h``) viene utilizzato. Questo disabilita i softirq
-sul processore e trattiene il *lock*. Invece, :c:func:`spin_unlock_bh()` fa
+sul processore e trattiene il *lock*. Invece, spin_unlock_bh() fa
l'opposto. (Il suffisso '_bh' è un residuo storico che fa riferimento al
"Bottom Halves", il vecchio nome delle interruzioni software. In un mondo
perfetto questa funzione si chiamerebbe 'spin_lock_softirq()').
-Da notare che in questo caso potete utilizzare anche :c:func:`spin_lock_irq()`
-o :c:func:`spin_lock_irqsave()`, queste fermano anche le interruzioni hardware:
-vedere :ref:`Contesto di interruzione hardware <it_hardirq-context>`.
+Da notare che in questo caso potete utilizzare anche spin_lock_irq()
+o spin_lock_irqsave(), queste fermano anche le interruzioni hardware:
+vedere `Contesto di interruzione hardware`_.
Questo funziona alla perfezione anche sui sistemi monoprocessore: gli spinlock
-svaniscono e questa macro diventa semplicemente :c:func:`local_bh_disable()`
+svaniscono e questa macro diventa semplicemente local_bh_disable()
(``include/linux/interrupt.h``), la quale impedisce ai softirq d'essere
eseguiti.
@@ -224,8 +221,8 @@ Differenti tasklet/timer
~~~~~~~~~~~~~~~~~~~~~~~~
Se un altro tasklet/timer vuole condividere dati col vostro tasklet o timer,
-allora avrete bisogno entrambe di :c:func:`spin_lock()` e
-:c:func:`spin_unlock()`. Qui :c:func:`spin_lock_bh()` è inutile, siete già
+allora avrete bisogno entrambe di spin_lock() e
+spin_unlock(). Qui spin_lock_bh() è inutile, siete già
in un tasklet ed avete la garanzia che nessun altro verrà eseguito sullo
stesso processore.
@@ -239,17 +236,17 @@ Lo stesso softirq
Lo stesso softirq può essere eseguito su un diverso processore: allo scopo
di migliorare le prestazioni potete utilizzare dati riservati ad ogni
-processore (vedere :ref:`Dati per processore <it_per-cpu>`). Se siete arrivati
+processore (vedere `Dati per processore`_). Se siete arrivati
fino a questo punto nell'uso dei softirq, probabilmente tenete alla scalabilità
delle prestazioni abbastanza da giustificarne la complessità aggiuntiva.
-Dovete utilizzare :c:func:`spin_lock()` e :c:func:`spin_unlock()` per
+Dovete utilizzare spin_lock() e spin_unlock() per
proteggere i dati condivisi.
Diversi Softirqs
~~~~~~~~~~~~~~~~
-Dovete utilizzare :c:func:`spin_lock()` e :c:func:`spin_unlock()` per
+Dovete utilizzare spin_lock() e spin_unlock() per
proteggere i dati condivisi, che siano timer, tasklet, diversi softirq o
lo stesso o altri softirq: uno qualsiasi di essi potrebbe essere in esecuzione
su un diverso processore.
@@ -270,40 +267,40 @@ Se un gestore di interruzioni hardware condivide dati con un softirq, allora
avrete due preoccupazioni. Primo, il softirq può essere interrotto da
un'interruzione hardware, e secondo, la sezione critica potrebbe essere
eseguita da un'interruzione hardware su un processore diverso. Questo è il caso
-dove :c:func:`spin_lock_irq()` viene utilizzato. Disabilita le interruzioni
-sul processore che l'esegue, poi trattiene il lock. :c:func:`spin_unlock_irq()`
+dove spin_lock_irq() viene utilizzato. Disabilita le interruzioni
+sul processore che l'esegue, poi trattiene il lock. spin_unlock_irq()
fa l'opposto.
-Il gestore d'interruzione hardware non usa :c:func:`spin_lock_irq()` perché
-i softirq non possono essere eseguiti quando il gestore d'interruzione hardware
-è in esecuzione: per questo si può usare :c:func:`spin_lock()`, che è un po'
+Il gestore d'interruzione hardware non ha bisogno di usare spin_lock_irq()
+perché i softirq non possono essere eseguiti quando il gestore d'interruzione
+hardware è in esecuzione: per questo si può usare spin_lock(), che è un po'
più veloce. L'unica eccezione è quando un altro gestore d'interruzioni
-hardware utilizza lo stesso *lock*: :c:func:`spin_lock_irq()` impedirà a questo
+hardware utilizza lo stesso *lock*: spin_lock_irq() impedirà a questo
secondo gestore di interrompere quello in esecuzione.
Questo funziona alla perfezione anche sui sistemi monoprocessore: gli spinlock
-svaniscono e questa macro diventa semplicemente :c:func:`local_irq_disable()`
+svaniscono e questa macro diventa semplicemente local_irq_disable()
(``include/asm/smp.h``), la quale impedisce a softirq/tasklet/BH d'essere
eseguiti.
-:c:func:`spin_lock_irqsave()` (``include/linux/spinlock.h``) è una variante che
+spin_lock_irqsave() (``include/linux/spinlock.h``) è una variante che
salva lo stato delle interruzioni in una variabile, questa verrà poi passata
-a :c:func:`spin_unlock_irqrestore()`. Questo significa che lo stesso codice
+a spin_unlock_irqrestore(). Questo significa che lo stesso codice
potrà essere utilizzato in un'interruzione hardware (dove le interruzioni sono
già disabilitate) e in un softirq (dove la disabilitazione delle interruzioni
è richiesta).
Da notare che i softirq (e quindi tasklet e timer) sono eseguiti al ritorno
-da un'interruzione hardware, quindi :c:func:`spin_lock_irq()` interrompe
+da un'interruzione hardware, quindi spin_lock_irq() interrompe
anche questi. Tenuto conto di questo si può dire che
-:c:func:`spin_lock_irqsave()` è la funzione di sincronizzazione più generica
+spin_lock_irqsave() è la funzione di sincronizzazione più generica
e potente.
Sincronizzazione fra due gestori d'interruzioni hardware
--------------------------------------------------------
Condividere dati fra due gestori di interruzione hardware è molto raro, ma se
-succede, dovreste usare :c:func:`spin_lock_irqsave()`: è una specificità
+succede, dovreste usare spin_lock_irqsave(): è una specificità
dell'architettura il fatto che tutte le interruzioni vengano interrotte
quando si eseguono di gestori di interruzioni.
@@ -314,14 +311,14 @@ Pete Zaitcev ci offre il seguente riassunto:
- Se siete in un contesto utente (una qualsiasi chiamata di sistema)
e volete sincronizzarvi con altri processi, usate i mutex. Potete trattenere
- il mutex e dormire (``copy_from_user*(`` o ``kmalloc(x,GFP_KERNEL)``).
+ il mutex e dormire (``copy_from_user(`` o ``kmalloc(x,GFP_KERNEL)``).
- Altrimenti (== i dati possono essere manipolati da un'interruzione) usate
- :c:func:`spin_lock_irqsave()` e :c:func:`spin_unlock_irqrestore()`.
+ spin_lock_irqsave() e spin_unlock_irqrestore().
- Evitate di trattenere uno spinlock per più di 5 righe di codice incluse
le chiamate a funzione (ad eccezione di quell per l'accesso come
- :c:func:`readb()`).
+ readb()).
Tabella dei requisiti minimi
----------------------------
@@ -334,7 +331,7 @@ processore alla volta, ma se deve condividere dati con un altro thread, allora
la sincronizzazione è necessaria).
Ricordatevi il suggerimento qui sopra: potete sempre usare
-:c:func:`spin_lock_irqsave()`, che è un sovrainsieme di tutte le altre funzioni
+spin_lock_irqsave(), che è un sovrainsieme di tutte le altre funzioni
per spinlock.
============== ============= ============= ========= ========= ========= ========= ======= ======= ============== ==============
@@ -378,13 +375,13 @@ protetti dal *lock* quando qualche altro thread lo sta già facendo
trattenendo il *lock*. Potrete acquisire il *lock* più tardi se vi
serve accedere ai dati protetti da questo *lock*.
-La funzione :c:func:`spin_trylock()` non ritenta di acquisire il *lock*,
+La funzione spin_trylock() non ritenta di acquisire il *lock*,
se ci riesce al primo colpo ritorna un valore diverso da zero, altrimenti
se fallisce ritorna 0. Questa funzione può essere utilizzata in un qualunque
-contesto, ma come :c:func:`spin_lock()`: dovete disabilitare i contesti che
+contesto, ma come spin_lock(): dovete disabilitare i contesti che
potrebbero interrompervi e quindi trattenere lo spinlock.
-La funzione :c:func:`mutex_trylock()` invece di sospendere il vostro processo
+La funzione mutex_trylock() invece di sospendere il vostro processo
ritorna un valore diverso da zero se è possibile trattenere il lock al primo
colpo, altrimenti se fallisce ritorna 0. Nonostante non dorma, questa funzione
non può essere usata in modo sicuro in contesti di interruzione hardware o
@@ -506,7 +503,7 @@ della memoria che il suo contenuto sono protetti dal *lock*. Questo
caso è semplice dato che copiamo i dati dall'utente e non permettiamo
mai loro di accedere direttamente agli oggetti.
-C'è una piccola ottimizzazione qui: nella funzione :c:func:`cache_add()`
+C'è una piccola ottimizzazione qui: nella funzione cache_add()
impostiamo i campi dell'oggetto prima di acquisire il *lock*. Questo è
sicuro perché nessun altro potrà accedervi finché non lo inseriremo
nella memoria.
@@ -514,7 +511,7 @@ nella memoria.
Accesso dal contesto utente
---------------------------
-Ora consideriamo il caso in cui :c:func:`cache_find()` può essere invocata
+Ora consideriamo il caso in cui cache_find() può essere invocata
dal contesto d'interruzione: sia hardware che software. Un esempio potrebbe
essere un timer che elimina oggetti dalla memoria.
@@ -583,15 +580,15 @@ sono quelle rimosse, mentre quelle ``+`` sono quelle aggiunte.
return ret;
}
-Da notare che :c:func:`spin_lock_irqsave()` disabiliterà le interruzioni
+Da notare che spin_lock_irqsave() disabiliterà le interruzioni
se erano attive, altrimenti non farà niente (quando siamo già in un contesto
d'interruzione); dunque queste funzioni possono essere chiamante in
sicurezza da qualsiasi contesto.
-Sfortunatamente, :c:func:`cache_add()` invoca :c:func:`kmalloc()` con
+Sfortunatamente, cache_add() invoca kmalloc() con
l'opzione ``GFP_KERNEL`` che è permessa solo in contesto utente. Ho supposto
-che :c:func:`cache_add()` venga chiamata dal contesto utente, altrimenti
-questa opzione deve diventare un parametro di :c:func:`cache_add()`.
+che cache_add() venga chiamata dal contesto utente, altrimenti
+questa opzione deve diventare un parametro di cache_add().
Esporre gli oggetti al di fuori del file
----------------------------------------
@@ -610,7 +607,7 @@ Il secondo problema è il problema del ciclo di vita: se un'altra struttura
mantiene un puntatore ad un oggetto, presumibilmente si aspetta che questo
puntatore rimanga valido. Sfortunatamente, questo è garantito solo mentre
si trattiene il *lock*, altrimenti qualcuno potrebbe chiamare
-:c:func:`cache_delete()` o peggio, aggiungere un oggetto che riutilizza lo
+cache_delete() o peggio, aggiungere un oggetto che riutilizza lo
stesso indirizzo.
Dato che c'è un solo *lock*, non potete trattenerlo a vita: altrimenti
@@ -710,9 +707,9 @@ Ecco il codice::
}
Abbiamo incapsulato il contatore di riferimenti nelle tipiche funzioni
-di 'get' e 'put'. Ora possiamo ritornare l'oggetto da :c:func:`cache_find()`
+di 'get' e 'put'. Ora possiamo ritornare l'oggetto da cache_find()
col vantaggio che l'utente può dormire trattenendo l'oggetto (per esempio,
-:c:func:`copy_to_user()` per copiare il nome verso lo spazio utente).
+copy_to_user() per copiare il nome verso lo spazio utente).
Un altro punto da notare è che ho detto che il contatore dovrebbe incrementarsi
per ogni puntatore ad un oggetto: quindi il contatore di riferimenti è 1
@@ -727,8 +724,8 @@ Ci sono un certo numbero di operazioni atomiche definite
in ``include/asm/atomic.h``: queste sono garantite come atomiche su qualsiasi
processore del sistema, quindi non sono necessari i *lock*. In questo caso è
più semplice rispetto all'uso degli spinlock, benché l'uso degli spinlock
-sia più elegante per casi non banali. Le funzioni :c:func:`atomic_inc()` e
-:c:func:`atomic_dec_and_test()` vengono usate al posto dei tipici operatori di
+sia più elegante per casi non banali. Le funzioni atomic_inc() e
+atomic_dec_and_test() vengono usate al posto dei tipici operatori di
incremento e decremento, e i *lock* non sono più necessari per proteggere il
contatore stesso.
@@ -820,7 +817,7 @@ al nome di cambiare abbiamo tre possibilità:
- Si può togliere static da ``cache_lock`` e dire agli utenti che devono
trattenere il *lock* prima di modificare il nome di un oggetto.
-- Si può fornire una funzione :c:func:`cache_obj_rename()` che prende il
+- Si può fornire una funzione cache_obj_rename() che prende il
*lock* e cambia il nome per conto del chiamante; si dirà poi agli utenti
di usare questa funzione.
@@ -878,11 +875,11 @@ Da notare che ho deciso che il contatore di popolarità dovesse essere
protetto da ``cache_lock`` piuttosto che dal *lock* dell'oggetto; questo
perché è logicamente parte dell'infrastruttura (come
:c:type:`struct list_head <list_head>` nell'oggetto). In questo modo,
-in :c:func:`__cache_add()`, non ho bisogno di trattenere il *lock* di ogni
+in __cache_add(), non ho bisogno di trattenere il *lock* di ogni
oggetto mentre si cerca il meno popolare.
Ho anche deciso che il campo id è immutabile, quindi non ho bisogno di
-trattenere il lock dell'oggetto quando si usa :c:func:`__cache_find()`
+trattenere il lock dell'oggetto quando si usa __cache_find()
per leggere questo campo; il *lock* dell'oggetto è usato solo dal chiamante
che vuole leggere o scrivere il campo name.
@@ -894,8 +891,6 @@ leggendo solamente il codice. E come dice Alan Cox: “Lock data, not code”.
Problemi comuni
===============
-.. _`it_deadlock`:
-
Stallo: semplice ed avanzato
----------------------------
@@ -907,7 +902,7 @@ Questo è facile da diagnosticare: non è uno di quei problemi che ti tengono
sveglio 5 notti a parlare da solo.
Un caso un pochino più complesso; immaginate d'avere una spazio condiviso
-fra un softirq ed il contesto utente. Se usate :c:func:`spin_lock()` per
+fra un softirq ed il contesto utente. Se usate spin_lock() per
proteggerlo, il contesto utente potrebbe essere interrotto da un softirq
mentre trattiene il lock, da qui il softirq rimarrà in attesa attiva provando
ad acquisire il *lock* già trattenuto nel contesto utente.
@@ -979,9 +974,6 @@ fallisce nel trovare quello che vuole, quindi rilascia il *lock* di lettura,
trattiene un *lock* di scrittura ed inserisce un oggetto; questo genere di
codice presenta una corsa critica.
-Se non riuscite a capire il perché, per favore state alla larga dal mio
-codice.
-
corsa fra temporizzatori: un passatempo del kernel
--------------------------------------------------
@@ -998,7 +990,7 @@ potreste fare come segue::
while (list) {
struct foo *next = list->next;
- del_timer(&list->timer);
+ timer_delete(&list->timer);
kfree(list);
list = next;
}
@@ -1006,12 +998,12 @@ potreste fare come segue::
spin_unlock_bh(&list_lock);
Primo o poi, questo esploderà su un sistema multiprocessore perché un
-temporizzatore potrebbe essere già partiro prima di :c:func:`spin_lock_bh()`,
-e prenderà il *lock* solo dopo :c:func:`spin_unlock_bh()`, e cercherà
+temporizzatore potrebbe essere già partiro prima di spin_lock_bh(),
+e prenderà il *lock* solo dopo spin_unlock_bh(), e cercherà
di eliminare il suo oggetto (che però è già stato eliminato).
Questo può essere evitato controllando il valore di ritorno di
-:c:func:`del_timer()`: se ritorna 1, il temporizzatore è stato già
+timer_delete(): se ritorna 1, il temporizzatore è stato già
rimosso. Se 0, significa (in questo caso) che il temporizzatore è in
esecuzione, quindi possiamo fare come segue::
@@ -1020,7 +1012,7 @@ esecuzione, quindi possiamo fare come segue::
while (list) {
struct foo *next = list->next;
- if (!del_timer(&list->timer)) {
+ if (!timer_delete(&list->timer)) {
/* Give timer a chance to delete this */
spin_unlock_bh(&list_lock);
goto retry;
@@ -1032,12 +1024,15 @@ esecuzione, quindi possiamo fare come segue::
spin_unlock_bh(&list_lock);
Un altro problema è l'eliminazione dei temporizzatori che si riavviano
-da soli (chiamando :c:func:`add_timer()` alla fine della loro esecuzione).
+da soli (chiamando add_timer() alla fine della loro esecuzione).
Dato che questo è un problema abbastanza comune con una propensione
-alle corse critiche, dovreste usare :c:func:`del_timer_sync()`
-(``include/linux/timer.h``) per gestire questo caso. Questa ritorna il
-numero di volte che il temporizzatore è stato interrotto prima che
-fosse in grado di fermarlo senza che si riavviasse.
+alle corse critiche, dovreste usare timer_delete_sync()
+(``include/linux/timer.h``) per gestire questo caso.
+
+Prima di rilasciare un temporizzatore dovreste chiamare la funzione
+timer_shutdown() o timer_shutdown_sync() di modo che non venga più riarmato.
+Ogni successivo tentativo di riarmare il temporizzatore verrà silenziosamente
+ignorato.
Velocità della sincronizzazione
===============================
@@ -1116,7 +1111,7 @@ chiamata ``list``::
wmb();
list->next = new;
-La funzione :c:func:`wmb()` è una barriera di sincronizzazione delle
+La funzione wmb() è una barriera di sincronizzazione delle
scritture. Questa garantisce che la prima operazione (impostare l'elemento
``next`` del nuovo elemento) venga completata e vista da tutti i processori
prima che venga eseguita la seconda operazione (che sarebbe quella di mettere
@@ -1127,7 +1122,7 @@ completamente il nuovo elemento; oppure che lo vedano correttamente e quindi
il puntatore ``next`` deve puntare al resto della lista.
Fortunatamente, c'è una funzione che fa questa operazione sulle liste
-:c:type:`struct list_head <list_head>`: :c:func:`list_add_rcu()`
+:c:type:`struct list_head <list_head>`: list_add_rcu()
(``include/linux/list.h``).
Rimuovere un elemento dalla lista è anche più facile: sostituiamo il puntatore
@@ -1138,7 +1133,7 @@ l'elemento o lo salteranno.
list->next = old->next;
-La funzione :c:func:`list_del_rcu()` (``include/linux/list.h``) fa esattamente
+La funzione list_del_rcu() (``include/linux/list.h``) fa esattamente
questo (la versione normale corrompe il vecchio oggetto, e non vogliamo che
accada).
@@ -1146,9 +1141,9 @@ Anche i lettori devono stare attenti: alcuni processori potrebbero leggere
attraverso il puntatore ``next`` il contenuto dell'elemento successivo
troppo presto, ma non accorgersi che il contenuto caricato è sbagliato quando
il puntatore ``next`` viene modificato alla loro spalle. Ancora una volta
-c'è una funzione che viene in vostro aiuto :c:func:`list_for_each_entry_rcu()`
+c'è una funzione che viene in vostro aiuto list_for_each_entry_rcu()
(``include/linux/list.h``). Ovviamente, gli scrittori possono usare
-:c:func:`list_for_each_entry()` dato che non ci possono essere due scrittori
+list_for_each_entry() dato che non ci possono essere due scrittori
in contemporanea.
Il nostro ultimo dilemma è il seguente: quando possiamo realmente distruggere
@@ -1156,15 +1151,15 @@ l'elemento rimosso? Ricordate, un lettore potrebbe aver avuto accesso a questo
elemento proprio ora: se eliminiamo questo elemento ed il puntatore ``next``
cambia, il lettore salterà direttamente nella spazzatura e scoppierà. Dobbiamo
aspettare finché tutti i lettori che stanno attraversando la lista abbiano
-finito. Utilizziamo :c:func:`call_rcu()` per registrare una funzione di
+finito. Utilizziamo call_rcu() per registrare una funzione di
richiamo che distrugga l'oggetto quando tutti i lettori correnti hanno
terminato. In alternative, potrebbe essere usata la funzione
-:c:func:`synchronize_rcu()` che blocca l'esecuzione finché tutti i lettori
+synchronize_rcu() che blocca l'esecuzione finché tutti i lettori
non terminano di ispezionare la lista.
Ma come fa l'RCU a sapere quando i lettori sono finiti? Il meccanismo è
il seguente: innanzi tutto i lettori accedono alla lista solo fra la coppia
-:c:func:`rcu_read_lock()`/:c:func:`rcu_read_unlock()` che disabilita la
+rcu_read_lock()/rcu_read_unlock() che disabilita la
prelazione così che i lettori non vengano sospesi mentre stanno leggendo
la lista.
@@ -1253,12 +1248,12 @@ codice RCU è un po' più ottimizzato di così, ma questa è l'idea di fondo.
}
Da notare che i lettori modificano il campo popularity nella funzione
-:c:func:`__cache_find()`, e ora non trattiene alcun *lock*. Una soluzione
+__cache_find(), e ora non trattiene alcun *lock*. Una soluzione
potrebbe essere quella di rendere la variabile ``atomic_t``, ma per l'uso
che ne abbiamo fatto qui, non ci interessano queste corse critiche perché un
risultato approssimativo è comunque accettabile, quindi non l'ho cambiato.
-Il risultato è che la funzione :c:func:`cache_find()` non ha bisogno di alcuna
+Il risultato è che la funzione cache_find() non ha bisogno di alcuna
sincronizzazione con le altre funzioni, quindi è veloce su un sistema
multi-processore tanto quanto lo sarebbe su un sistema mono-processore.
@@ -1271,16 +1266,15 @@ riferimenti.
Ora, dato che il '*lock* di lettura' di un RCU non fa altro che disabilitare
la prelazione, un chiamante che ha sempre la prelazione disabilitata fra le
-chiamate :c:func:`cache_find()` e :c:func:`object_put()` non necessita
+chiamate cache_find() e object_put() non necessita
di incrementare e decrementare il contatore di riferimenti. Potremmo
-esporre la funzione :c:func:`__cache_find()` dichiarandola non-static,
+esporre la funzione __cache_find() dichiarandola non-static,
e quel chiamante potrebbe usare direttamente questa funzione.
Il beneficio qui sta nel fatto che il contatore di riferimenti no
viene scritto: l'oggetto non viene alterato in alcun modo e quindi diventa
molto più veloce su sistemi molti-processore grazie alla loro memoria cache.
-.. _`it_per-cpu`:
Dati per processore
-------------------
@@ -1293,10 +1287,10 @@ singolo contatore. Facile e pulito.
Se questo dovesse essere troppo lento (solitamente non lo è, ma se avete
dimostrato che lo è devvero), potreste usare un contatore per ogni processore
e quindi non sarebbe più necessaria la mutua esclusione. Vedere
-:c:func:`DEFINE_PER_CPU()`, :c:func:`get_cpu_var()` e :c:func:`put_cpu_var()`
+DEFINE_PER_CPU(), get_cpu_var() e put_cpu_var()
(``include/linux/percpu.h``).
-Il tipo di dato ``local_t``, la funzione :c:func:`cpu_local_inc()` e tutte
+Il tipo di dato ``local_t``, la funzione cpu_local_inc() e tutte
le altre funzioni associate, sono di particolare utilità per semplici contatori
per-processore; su alcune architetture sono anche più efficienti
(``include/asm/local.h``).
@@ -1318,25 +1312,24 @@ se i dati vengono occasionalmente utilizzati da un contesto utente o
da un'interruzione software. Il gestore d'interruzione non utilizza alcun
*lock*, e tutti gli altri accessi verranno fatti così::
- spin_lock(&lock);
+ mutex_lock(&lock);
disable_irq(irq);
...
enable_irq(irq);
- spin_unlock(&lock);
+ mutex_unlock(&lock);
-La funzione :c:func:`disable_irq()` impedisce al gestore d'interruzioni
+La funzione disable_irq() impedisce al gestore d'interruzioni
d'essere eseguito (e aspetta che finisca nel caso fosse in esecuzione su
un altro processore). Lo spinlock, invece, previene accessi simultanei.
Naturalmente, questo è più lento della semplice chiamata
-:c:func:`spin_lock_irq()`, quindi ha senso solo se questo genere di accesso
+spin_lock_irq(), quindi ha senso solo se questo genere di accesso
è estremamente raro.
-.. _`it_sleeping-things`:
Quali funzioni possono essere chiamate in modo sicuro dalle interruzioni?
=========================================================================
-Molte funzioni del kernel dormono (in sostanza, chiamano ``schedule()``)
+Molte funzioni del kernel dormono (in sostanza, chiamano schedule())
direttamente od indirettamente: non potete chiamarle se trattenere uno
spinlock o avete la prelazione disabilitata, mai. Questo significa che
dovete necessariamente essere nel contesto utente: chiamarle da un
@@ -1354,23 +1347,23 @@ dormire.
- Accessi allo spazio utente:
- - :c:func:`copy_from_user()`
+ - copy_from_user()
- - :c:func:`copy_to_user()`
+ - copy_to_user()
- - :c:func:`get_user()`
+ - get_user()
- - :c:func:`put_user()`
+ - put_user()
-- :c:func:`kmalloc(GFP_KERNEL) <kmalloc>`
+- kmalloc(GFP_KERNEL) <kmalloc>`
-- :c:func:`mutex_lock_interruptible()` and
- :c:func:`mutex_lock()`
+- mutex_lock_interruptible() and
+ mutex_lock()
- C'è anche :c:func:`mutex_trylock()` che però non dorme.
+ C'è anche mutex_trylock() che però non dorme.
Comunque, non deve essere usata in un contesto d'interruzione dato
che la sua implementazione non è sicura in quel contesto.
- Anche :c:func:`mutex_unlock()` non dorme mai. Non può comunque essere
+ Anche mutex_unlock() non dorme mai. Non può comunque essere
usata in un contesto d'interruzione perché un mutex deve essere rilasciato
dallo stesso processo che l'ha acquisito.
@@ -1380,11 +1373,11 @@ Alcune funzioni che non dormono
Alcune funzioni possono essere chiamate tranquillamente da qualsiasi
contesto, o trattenendo un qualsiasi *lock*.
-- :c:func:`printk()`
+- printk()
-- :c:func:`kfree()`
+- kfree()
-- :c:func:`add_timer()` e :c:func:`del_timer()`
+- add_timer() e timer_delete()
Riferimento per l'API dei Mutex
===============================
@@ -1398,7 +1391,19 @@ Riferimento per l'API dei Mutex
Riferimento per l'API dei Futex
===============================
-.. kernel-doc:: kernel/futex.c
+.. kernel-doc:: kernel/futex/core.c
+ :internal:
+
+.. kernel-doc:: kernel/futex/futex.h
+ :internal:
+
+.. kernel-doc:: kernel/futex/pi.c
+ :internal:
+
+.. kernel-doc:: kernel/futex/requeue.c
+ :internal:
+
+.. kernel-doc:: kernel/futex/waitwake.c
:internal:
Approfondimenti
@@ -1444,14 +1449,14 @@ prelazione
bh
Bottom Half: per ragioni storiche, le funzioni che contengono '_bh' nel
loro nome ora si riferiscono a qualsiasi interruzione software; per esempio,
- :c:func:`spin_lock_bh()` blocca qualsiasi interuzione software sul processore
+ spin_lock_bh() blocca qualsiasi interuzione software sul processore
corrente. I *Bottom Halves* sono deprecati, e probabilmente verranno
sostituiti dai tasklet. In un dato momento potrà esserci solo un
*bottom half* in esecuzione.
contesto d'interruzione
Non è il contesto utente: qui si processano le interruzioni hardware e
- software. La macro :c:func:`in_interrupt()` ritorna vero.
+ software. La macro in_interrupt() ritorna vero.
contesto utente
Il kernel che esegue qualcosa per conto di un particolare processo (per
@@ -1461,12 +1466,12 @@ contesto utente
che hardware.
interruzione hardware
- Richiesta di interruzione hardware. :c:func:`in_irq()` ritorna vero in un
+ Richiesta di interruzione hardware. in_hardirq() ritorna vero in un
gestore d'interruzioni hardware.
interruzione software / softirq
- Gestore di interruzioni software: :c:func:`in_irq()` ritorna falso;
- :c:func:`in_softirq()` ritorna vero. I tasklet e le softirq sono entrambi
+ Gestore di interruzioni software: in_hardirq() ritorna falso;
+ in_softirq() ritorna vero. I tasklet e le softirq sono entrambi
considerati 'interruzioni software'.
In soldoni, un softirq è uno delle 32 interruzioni software che possono
diff --git a/Documentation/translations/it_IT/maintainer/configure-git.rst b/Documentation/translations/it_IT/maintainer/configure-git.rst
new file mode 100644
index 000000000000..8316fa53946f
--- /dev/null
+++ b/Documentation/translations/it_IT/maintainer/configure-git.rst
@@ -0,0 +1,10 @@
+.. include:: ../disclaimer-ita.rst
+
+:Original: Documentation/process/botching-up-ioctls.rst
+
+.. _it_configuregit:
+
+Configurare Git
+===============
+
+.. note:: To be translated
diff --git a/Documentation/translations/it_IT/networking/netdev-FAQ.rst b/Documentation/translations/it_IT/networking/netdev-FAQ.rst
index 8489ead7cff1..8a1e049585c0 100644
--- a/Documentation/translations/it_IT/networking/netdev-FAQ.rst
+++ b/Documentation/translations/it_IT/networking/netdev-FAQ.rst
@@ -1,6 +1,6 @@
.. include:: ../disclaimer-ita.rst
-:Original: :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
+:Original: :ref:`Documentation/process/maintainer-netdev.rst <netdev-FAQ>`
.. _it_netdev-FAQ:
diff --git a/Documentation/translations/it_IT/process/2.Process.rst b/Documentation/translations/it_IT/process/2.Process.rst
index 9af4d01617c4..25cd00351c03 100644
--- a/Documentation/translations/it_IT/process/2.Process.rst
+++ b/Documentation/translations/it_IT/process/2.Process.rst
@@ -23,18 +23,18 @@ ogni due o tre mesi viene effettuata un rilascio importante del kernel.
I rilasci più recenti sono stati:
====== =================
- 4.11 Aprile 30, 2017
- 4.12 Luglio 2, 2017
- 4.13 Settembre 3, 2017
- 4.14 Novembre 12, 2017
- 4.15 Gennaio 28, 2018
- 4.16 Aprile 1, 2018
+ 5.0 3 marzo, 2019
+ 5.1 5 maggio, 2019
+ 5.2 7 luglio, 2019
+ 5.3 15 settembre, 2019
+ 5.4 24 novembre, 2019
+ 5.5 6 gennaio, 2020
====== =================
-Ciascun rilascio 4.x è un importante rilascio del kernel con nuove
+Ciascun rilascio 5.x è un importante rilascio del kernel con nuove
funzionalità, modifiche interne dell'API, e molto altro. Un tipico
-rilascio 4.x contiene quasi 13,000 gruppi di modifiche con ulteriori
-modifiche a parecchie migliaia di linee di codice. La 4.x. è pertanto la
+rilascio contiene quasi 13,000 gruppi di modifiche con ulteriori
+modifiche a parecchie migliaia di linee di codice. La 5.x. è pertanto la
linea di confine nello sviluppo del kernel Linux; il kernel utilizza un sistema
di sviluppo continuo che integra costantemente nuove importanti modifiche.
@@ -55,8 +55,8 @@ verrà descritto dettagliatamente più avanti).
La finestra di inclusione resta attiva approssimativamente per due settimane.
Al termine di questo periodo, Linus Torvald dichiarerà che la finestra è
chiusa e rilascerà il primo degli "rc" del kernel.
-Per il kernel che è destinato ad essere 2.6.40, per esempio, il rilascio
-che emerge al termine della finestra d'inclusione si chiamerà 2.6.40-rc1.
+Per il kernel che è destinato ad essere 5.6, per esempio, il rilascio
+che emerge al termine della finestra d'inclusione si chiamerà 5.6-rc1.
Questo rilascio indica che il momento di aggiungere nuovi componenti è
passato, e che è iniziato il periodo di stabilizzazione del prossimo kernel.
@@ -76,22 +76,23 @@ Mentre le correzioni si aprono la loro strada all'interno del ramo principale,
il ritmo delle modifiche rallenta col tempo. Linus rilascia un nuovo
kernel -rc circa una volta alla settimana; e ne usciranno circa 6 o 9 prima
che il kernel venga considerato sufficientemente stabile e che il rilascio
-finale 2.6.x venga fatto. A quel punto tutto il processo ricomincerà.
+finale venga fatto. A quel punto tutto il processo ricomincerà.
-Esempio: ecco com'è andato il ciclo di sviluppo della versione 4.16
+Esempio: ecco com'è andato il ciclo di sviluppo della versione 5.4
(tutte le date si collocano nel 2018)
============== =======================================
- Gennaio 28 4.15 rilascio stabile
- Febbraio 11 4.16-rc1, finestra di inclusione chiusa
- Febbraio 18 4.16-rc2
- Febbraio 25 4.16-rc3
- Marzo 4 4.16-rc4
- Marzo 11 4.16-rc5
- Marzo 18 4.16-rc6
- Marzo 25 4.16-rc7
- Aprile 1 4.17 rilascio stabile
+ 15 settembre 5.3 rilascio stabile
+ 30 settembre 5.4-rc1, finestra di inclusione chiusa
+ 6 ottobre 5.4-rc2
+ 13 ottobre 5.4-rc3
+ 20 ottobre 5.4-rc4
+ 27 ottobre 5.4-rc5
+ 3 novembre 5.4-rc6
+ 10 novembre 5.4-rc7
+ 17 novembre 5.4-rc8
+ 24 novembre 5.4 rilascio stabile
============== =======================================
In che modo gli sviluppatori decidono quando chiudere il ciclo di sviluppo e
@@ -108,44 +109,38 @@ tipo di perfezione difficilmente viene raggiunta; esistono troppe variabili
in un progetto di questa portata. Arriva un punto dove ritardare il rilascio
finale peggiora la situazione; la quantità di modifiche in attesa della
prossima finestra di inclusione crescerà enormemente, creando ancor più
-regressioni al giro successivo. Quindi molti kernel 4.x escono con una
+regressioni al giro successivo. Quindi molti kernel 5.x escono con una
manciata di regressioni delle quali, si spera, nessuna è grave.
Una volta che un rilascio stabile è fatto, il suo costante mantenimento è
affidato al "squadra stabilità", attualmente composta da Greg Kroah-Hartman.
Questa squadra rilascia occasionalmente degli aggiornamenti relativi al
-rilascio stabile usando la numerazione 4.x.y. Per essere presa in
+rilascio stabile usando la numerazione 5.x.y. Per essere presa in
considerazione per un rilascio d'aggiornamento, una modifica deve:
(1) correggere un baco importante (2) essere già inserita nel ramo principale
per il prossimo sviluppo del kernel. Solitamente, passato il loro rilascio
iniziale, i kernel ricevono aggiornamenti per più di un ciclo di sviluppo.
-Quindi, per esempio, la storia del kernel 4.13 appare così:
+Quindi, per esempio, la storia del kernel 5.2 appare così (anno 2019):
============== ===============================
- Settembre 3 4.13 rilascio stabile
- Settembre 13 4.13.1
- Settembre 20 4.13.2
- Settembre 27 4.13.3
- Ottobre 5 4.13.4
- Ottobre 12 4.13.5
+ 7 luglio 5.2 rilascio stabile
+ 14 luglio 5.2.1
+ 21 luglio 5.2.2
+ 26 luglio 5.2.3
+ 28 luglio 5.2.4
+ 31 luglio 5.2.5
... ...
- Novembre 24 4.13.16
+ 11 ottobre 5.2.21
============== ===============================
-La 4.13.16 fu l'aggiornamento finale per la versione 4.13.
+La 5.2.21 fu l'aggiornamento finale per la versione 5.2.
Alcuni kernel sono destinati ad essere kernel a "lungo termine"; questi
-riceveranno assistenza per un lungo periodo di tempo. Al momento in cui
-scriviamo, i manutentori dei kernel stabili a lungo termine sono:
-
- ====== ====================== ==========================================
- 3.16 Ben Hutchings (kernel stabile molto più a lungo termine)
- 4.1 Sasha Levin
- 4.4 Greg Kroah-Hartman (kernel stabile molto più a lungo termine)
- 4.9 Greg Kroah-Hartman
- 4.14 Greg Kroah-Hartman
- ====== ====================== ==========================================
+riceveranno assistenza per un lungo periodo di tempo. Consultate il seguente
+collegamento per avere la lista delle versioni attualmente supportate e i
+relativi manutentori:
+ https://www.kernel.org/category/releases.html
Questa selezione di kernel di lungo periodo sono puramente dovuti ai loro
manutentori, alla loro necessità e al tempo per tenere aggiornate proprio
@@ -229,12 +224,13 @@ Come le modifiche finiscono nel Kernel
--------------------------------------
Esiste una sola persona che può inserire le patch nel repositorio principale
-del kernel: Linus Torvalds. Ma, di tutte le 9500 patch che entrarono nella
-versione 2.6.38 del kernel, solo 112 (circa l'1,3%) furono scelte direttamente
-da Linus in persona. Il progetto del kernel è cresciuto fino a raggiungere
-una dimensione tale per cui un singolo sviluppatore non può controllare e
-selezionare indipendentemente ogni modifica senza essere supportato.
-La via scelta dagli sviluppatori per indirizzare tale crescita è stata quella
+del kernel: Linus Torvalds. Ma, per esempio, di tutte le 9500 patch
+che entrarono nella versione 2.6.38 del kernel, solo 112 (circa
+l'1,3%) furono scelte direttamente da Linus in persona. Il progetto
+del kernel è cresciuto fino a raggiungere una dimensione tale per cui
+un singolo sviluppatore non può controllare e selezionare
+indipendentemente ogni modifica senza essere supportato. La via
+scelta dagli sviluppatori per indirizzare tale crescita è stata quella
di utilizzare un sistema di "sottotenenti" basato sulla fiducia.
Il codice base del kernel è spezzato in una serie si sottosistemi: rete,
@@ -431,7 +427,7 @@ l'elenco principale lo si trova sul sito:
http://vger.kernel.org/vger-lists.html
Esistono liste gestite altrove; un certo numero di queste sono in
-lists.redhat.com.
+redhat.com/mailman/listinfo.
La lista di discussione principale per lo sviluppo del kernel è, ovviamente,
linux-kernel. Questa lista è un luogo ostile dove trovarsi; i volumi possono
diff --git a/Documentation/translations/it_IT/process/3.Early-stage.rst b/Documentation/translations/it_IT/process/3.Early-stage.rst
index 443ac1e5558f..0809de39108a 100644
--- a/Documentation/translations/it_IT/process/3.Early-stage.rst
+++ b/Documentation/translations/it_IT/process/3.Early-stage.rst
@@ -168,14 +168,15 @@ in questa ricerca:
.../scripts/get_maintainer.pl
-Se questo script viene eseguito con l'opzione "-f" ritornerà il
-manutentore(i) attuale per un dato file o cartella. Se viene passata una
-patch sulla linea di comando, lo script elencherà i manutentori che
-dovrebbero riceverne una copia. Ci sono svariate opzioni che regolano
-quanto a fondo get_maintainer.pl debba cercare i manutentori;
-siate quindi prudenti nell'utilizzare le opzioni più aggressive poiché
-potreste finire per includere sviluppatori che non hanno un vero interesse
-per il codice che state modificando.
+Se questo script viene eseguito con l'opzione "-f" ritornerà il manutentore(i)
+attuale per un dato file o cartella. Se viene passata una patch sulla linea di
+comando, lo script elencherà i manutentori che dovrebbero riceverne una copia.
+Questo è la maniera raccomandata (non quella con "-f") per ottenere la lista di
+persone da aggiungere a Cc per le vostre patch. Ci sono svariate opzioni che
+regolano quanto a fondo get_maintainer.pl debba cercare i manutentori; siate
+quindi prudenti nell'utilizzare le opzioni più aggressive poiché potreste finire
+per includere sviluppatori che non hanno un vero interesse per il codice che
+state modificando.
Se tutto ciò dovesse fallire, parlare con Andrew Morton potrebbe essere
un modo efficace per capire chi è il manutentore di un dato pezzo di codice.
diff --git a/Documentation/translations/it_IT/process/4.Coding.rst b/Documentation/translations/it_IT/process/4.Coding.rst
index a5e36aa60448..54fd255b77d0 100644
--- a/Documentation/translations/it_IT/process/4.Coding.rst
+++ b/Documentation/translations/it_IT/process/4.Coding.rst
@@ -256,7 +256,7 @@ e cercate di evitare le "riparazioni" che fan sparire l'avvertimento senza
però averne trovato la causa.
Tenete a mente che non tutti gli avvertimenti sono disabilitati di default.
-Costruite il kernel con "make EXTRA_CFLAGS=-W" per ottenerli tutti.
+Costruite il kernel con "make KCFLAGS=-W" per ottenerli tutti.
Il kernel fornisce differenti opzioni che abilitano funzionalità di debugging;
molti di queste sono trovano all'interno del sotto menu "kernel hacking".
@@ -264,11 +264,10 @@ La maggior parte di queste opzioni possono essere attivate per qualsiasi
kernel utilizzato per lo sviluppo o a scopo di test. In particolare dovreste
attivare:
- - ENABLE_MUST_CHECK e FRAME_WARN per ottenere degli
- avvertimenti dedicati a problemi come l'uso di interfacce deprecate o
- l'ignorare un importante valore di ritorno di una funzione. Il risultato
- generato da questi avvertimenti può risultare verboso, ma non bisogna
- preoccuparsi per gli avvertimenti provenienti da altre parti del kernel.
+ - FRAME_WARN per ottenere degli avvertimenti su stack frame più
+ grandi di un dato valore. Il risultato generato da questi
+ avvertimenti può risultare verboso, ma non bisogna preoccuparsi per
+ gli avvertimenti provenienti da altre parti del kernel.
- DEBUG_OBJECTS aggiungerà un codice per tracciare il ciclo di vita di
diversi oggetti creati dal kernel e avvisa quando qualcosa viene eseguito
diff --git a/Documentation/translations/it_IT/process/5.Posting.rst b/Documentation/translations/it_IT/process/5.Posting.rst
index 1476d51eb5e5..a7e2a3238415 100644
--- a/Documentation/translations/it_IT/process/5.Posting.rst
+++ b/Documentation/translations/it_IT/process/5.Posting.rst
@@ -16,9 +16,8 @@ e di procedure per la pubblicazione delle patch; seguirle renderà la vita
più facile a tutti quanti. Questo documento cercherà di coprire questi
argomenti con un ragionevole livello di dettaglio; più informazioni possono
essere trovare nella cartella 'Documentation', nei file
-:ref:`translations/it_IT/process/submitting-patches.rst <it_submittingpatches>`,
-:ref:`translations/it_IT/process/submitting-drivers.rst <it_submittingdrivers>`, e
-:ref:`translations/it_IT/process/submit-checklist.rst <it_submitchecklist>`.
+:ref:`translations/it_IT/process/submitting-patches.rst <it_submittingpatches>`
+e :ref:`translations/it_IT/process/submit-checklist.rst <it_submitchecklist>`.
Quando pubblicarle
@@ -214,13 +213,28 @@ irrilevanti (quelli generati dal processo di generazione, per esempio, o i file
di backup del vostro editor). Il file "dontdiff" nella cartella Documentation
potrà esservi d'aiuto su questo punto; passatelo a diff con l'opzione "-X".
-Le etichette sopra menzionante sono usate per descrivere come i vari
-sviluppatori sono stati associati allo sviluppo di una patch. Sono descritte
-in dettaglio nel documento :ref:`translations/it_IT/process/submitting-patches.rst <it_submittingpatches>`;
-quello che segue è un breve riassunto. Ognuna di queste righe ha il seguente
-formato:
+Le etichette sopracitate danno un'idea di come una patch prende vita e sono
+descritte nel dettaglio nel documento
+:ref:`Documentation/translations/it_IT/process/submitting-patches.rst <it_submittingpatches>`.
+Qui di seguito un breve riassunto.
-::
+Un'etichetta ci può dire quale commit ha introdotto il problema che viene corretto nella patch::
+
+ Fixes: 1f2e3d4c5b6a ("The first line of the commit specified by the first 12 characters of its SHA-1 ID")
+
+Un'altra etichetta viene usata per fornire collegamenti a pagine web contenenti
+maggiori informazioni, per esempio un rapporto circa il baco risolto dalla
+patch, oppure un documento con le specifiche implementate dalla patch::
+
+ Link: https://example.com/somewhere.html optional-other-stuff
+
+Alcuni manutentori aggiungono quest'etichetta alla patch per fare riferimento
+alla più recente discussione pubblica. A volte questo è fatto automaticamente da
+alcuni strumenti come b4 or un *hook* git come quello descritto qui
+'Documentation/translations/it_IT/maintainer/configure-git.rst'
+
+Un terzo tipo di etichetta viene usato per indicare chi ha contribuito allo
+sviluppo della patch. Tutte queste etichette seguono il formato::
tag: Full Name <email address> optional-other-stuff
@@ -251,15 +265,18 @@ Le etichette in uso più comuni sono:
:ref:`Documentation/translations/it_IT/process/submitting-patches.rst <it_submittingpatches>`
- Reported-by: menziona l'utente che ha riportato il problema corretto da
- questa patch; quest'etichetta viene usata per dare credito alle persone
- che hanno verificato il codice e ci hanno fatto sapere quando le cose non
- funzionavano correttamente.
+ questa patch; quest'etichetta viene usata per dare credito alle persone che
+ hanno verificato il codice e ci hanno fatto sapere quando le cose non
+ funzionavano correttamente. Se esiste un rapporto disponibile sul web, allora
+ L'etichetta dovrebbe essere seguita da un collegamento al suddetto rapporto.
- Cc: la persona menzionata ha ricevuto una copia della patch ed ha avuto
l'opportunità di commentarla.
-State attenti ad aggiungere queste etichette alla vostra patch: solo
-"Cc:" può essere aggiunta senza il permesso esplicito della persona menzionata.
+State attenti ad aggiungere queste etichette alla vostra patch: solo "Cc:" può
+essere aggiunta senza il permesso esplicito della persona menzionata. Il più
+delle volte anche Reported-by: va bene, ma è sempre meglio chiedere specialmente
+se il baco è stato riportato in una comunicazione privata.
Inviare la modifica
-------------------
diff --git a/Documentation/translations/it_IT/process/7.AdvancedTopics.rst b/Documentation/translations/it_IT/process/7.AdvancedTopics.rst
index cc1cff5d23ae..dffd813a0910 100644
--- a/Documentation/translations/it_IT/process/7.AdvancedTopics.rst
+++ b/Documentation/translations/it_IT/process/7.AdvancedTopics.rst
@@ -35,9 +35,9 @@ git è parte del processo di sviluppo del kernel. Gli sviluppatori che
desiderassero diventare agili con git troveranno più informazioni ai
seguenti indirizzi:
- http://git-scm.com/
+ https://git-scm.com/
- http://www.kernel.org/pub/software/scm/git/docs/user-manual.html
+ https://www.kernel.org/pub/software/scm/git/docs/user-manual.html
e su varie guide che potrete trovare su internet.
@@ -63,7 +63,7 @@ eseguire git-daemon è relativamente semplice . Altrimenti, iniziano a
svilupparsi piattaforme che offrono spazi pubblici, e gratuiti (Github,
per esempio). Gli sviluppatori permanenti possono ottenere un account
su kernel.org, ma non è proprio facile da ottenere; per maggiori informazioni
-consultate la pagina web http://kernel.org/faq/.
+consultate la pagina web https://kernel.org/faq/.
In git è normale avere a che fare con tanti rami. Ogni linea di sviluppo
può essere separata in "rami per argomenti" e gestiti indipendentemente.
@@ -137,7 +137,7 @@ vostri rami. Citando Linus
facendo, e ho bisogno di fidarmi *senza* dover passare tutte
le modifiche manualmente una per una.
-(http://lwn.net/Articles/224135/).
+(https://lwn.net/Articles/224135/).
Per evitare queste situazioni, assicuratevi che tutte le patch in un ramo
siano strettamente correlate al tema delle modifiche; un ramo "driver fixes"
diff --git a/Documentation/translations/it_IT/process/8.Conclusion.rst b/Documentation/translations/it_IT/process/8.Conclusion.rst
index 039bfc5a4108..32659ff467c0 100644
--- a/Documentation/translations/it_IT/process/8.Conclusion.rst
+++ b/Documentation/translations/it_IT/process/8.Conclusion.rst
@@ -13,9 +13,8 @@ e argomenti correlati. Primo tra questi sarà sempre la cartella Documentation
che si trova nei sorgenti kernel.
Il file :ref:`process/howto.rst <it_process_howto>` è un punto di partenza
-importante; :ref:`process/submitting-patches.rst <it_submittingpatches>` e
-:ref:`process/submitting-drivers.rst <it_submittingdrivers>` sono
-anch'essi qualcosa che tutti gli sviluppatori del kernel dovrebbero leggere.
+importante; :ref:`process/submitting-patches.rst <it_submittingpatches>` è
+anch'esso qualcosa che tutti gli sviluppatori del kernel dovrebbero leggere.
Molte API interne al kernel sono documentate utilizzando il meccanismo
kerneldoc; "make htmldocs" o "make pdfdocs" possono essere usati per generare
quei documenti in HTML o PDF (sebbene le versioni di TeX di alcune
diff --git a/Documentation/translations/it_IT/process/adding-syscalls.rst b/Documentation/translations/it_IT/process/adding-syscalls.rst
index c3a3439595a6..df8c652d004b 100644
--- a/Documentation/translations/it_IT/process/adding-syscalls.rst
+++ b/Documentation/translations/it_IT/process/adding-syscalls.rst
@@ -39,7 +39,7 @@ vostra interfaccia.
un qualche modo opaca.
- Se dovete esporre solo delle informazioni sul sistema, un nuovo nodo in
- sysfs (vedere ``Documentation/filesystems/sysfs.txt``) o
+ sysfs (vedere ``Documentation/filesystems/sysfs.rst``) o
in procfs potrebbe essere sufficiente. Tuttavia, l'accesso a questi
meccanismi richiede che il filesystem sia montato, il che potrebbe non
essere sempre vero (per esempio, in ambienti come namespace/sandbox/chroot).
@@ -562,7 +562,7 @@ kernel. Se la nuova funzionalità è utile all'interno del kernel, per esempio
dev'essere condivisa fra una vecchia e una nuova chiamata di sistema o
dev'essere utilizzata da una chiamata di sistema e la sua variante compatibile,
allora dev'essere implementata come una funzione di supporto
-(*helper function*) (per esempio ``kern_xyzzy()``). Questa funzione potrà
+(*helper function*) (per esempio ``ksys_xyzzy()``). Questa funzione potrà
essere chiamata dallo *stub* (``sys_xyzzy()``), dalla variante compatibile
(``compat_sys_xyzzy()``), e/o da altri parti del kernel.
@@ -611,21 +611,21 @@ Riferimenti e fonti
https://lwn.net/Articles/486306/
- Raccomandazioni da Andrew Morton circa il fatto che tutte le informazioni
su una nuova chiamata di sistema dovrebbero essere contenute nello stesso
- filone di discussione di email: https://lkml.org/lkml/2014/7/24/641
+ filone di discussione di email: https://lore.kernel.org/r/20140724144747.3041b208832bbdf9fbce5d96@linux-foundation.org
- Raccomandazioni da Michael Kerrisk circa il fatto che le nuove chiamate di
- sistema dovrebbero avere una pagina man: https://lkml.org/lkml/2014/6/13/309
+ sistema dovrebbero avere una pagina man: https://lore.kernel.org/r/CAKgNAkgMA39AfoSoA5Pe1r9N+ZzfYQNvNPvcRN7tOvRb8+v06Q@mail.gmail.com
- Consigli da Thomas Gleixner sul fatto che il collegamento all'architettura
x86 dovrebbe avvenire in un *commit* differente:
- https://lkml.org/lkml/2014/11/19/254
+ https://lore.kernel.org/r/alpine.DEB.2.11.1411191249560.3909@nanos
- Consigli da Greg Kroah-Hartman circa la bontà d'avere una pagina man e un
programma di auto-verifica per le nuove chiamate di sistema:
- https://lkml.org/lkml/2014/3/19/710
+ https://lore.kernel.org/r/20140320025530.GA25469@kroah.com
- Discussione di Michael Kerrisk sulle nuove chiamate di sistema contro
- le estensioni :manpage:`prctl(2)`: https://lkml.org/lkml/2014/6/3/411
+ le estensioni :manpage:`prctl(2)`: https://lore.kernel.org/r/CAHO5Pa3F2MjfTtfNxa8LbnkeeU8=YJ+9tDqxZpw7Gz59E-4AUg@mail.gmail.com
- Consigli da Ingo Molnar che le chiamate di sistema con più argomenti
dovrebbero incapsularli in una struttura che includa un argomento
*size* per garantire l'estensibilità futura:
- https://lkml.org/lkml/2015/7/30/117
+ https://lore.kernel.org/r/20150730083831.GA22182@gmail.com
- Un certo numero di casi strani emersi dall'uso (riuso) dei flag O_*:
- commit 75069f2b5bfb ("vfs: renumber FMODE_NONOTIFY and add to uniqueness
@@ -635,9 +635,9 @@ Riferimenti e fonti
- commit bb458c644a59 ("Safer ABI for O_TMPFILE")
- Discussion from Matthew Wilcox about restrictions on 64-bit arguments:
- https://lkml.org/lkml/2008/12/12/187
+ https://lore.kernel.org/r/20081212152929.GM26095@parisc-linux.org
- Raccomandazioni da Greg Kroah-Hartman sul fatto che i flag sconosciuti dovrebbero
- essere controllati: https://lkml.org/lkml/2014/7/17/577
+ essere controllati: https://lore.kernel.org/r/20140717193330.GB4703@kroah.com
- Raccomandazioni da Linus Torvalds che le chiamate di sistema x32 dovrebbero
favorire la compatibilità con le versioni a 64-bit piuttosto che quelle a 32-bit:
- https://lkml.org/lkml/2011/8/31/244
+ https://lore.kernel.org/r/CA+55aFxfmwfB7jbbrXxa=K7VBYPfAvmu3XOkGrLbB1UFjX1+Ew@mail.gmail.com
diff --git a/Documentation/translations/it_IT/process/botching-up-ioctls.rst b/Documentation/translations/it_IT/process/botching-up-ioctls.rst
new file mode 100644
index 000000000000..91732cdf808a
--- /dev/null
+++ b/Documentation/translations/it_IT/process/botching-up-ioctls.rst
@@ -0,0 +1,249 @@
+.. include:: ../disclaimer-ita.rst
+
+:Original: Documentation/process/botching-up-ioctls.rst
+
+==========================================
+(Come evitare di) Raffazzonare delle ioctl
+==========================================
+
+Preso da: https://blog.ffwll.ch/2013/11/botching-up-ioctls.html
+
+Scritto da : Daniel Vetter, Copyright © 2013 Intel Corporation
+
+Una cosa che gli sviluppatori del sottosistema grafico del kernel Linux hanno
+imparato negli ultimi anni è l'inutilità di cercare di creare un'interfaccia
+unificata per gestire la memoria e le unità esecutive di diverse GPU. Dunque,
+oggigiorno ogni driver ha il suo insieme di ioctl per allocare memoria ed
+inviare dei programmi alla GPU. Il che è va bene dato che non c'è più un insano
+sistema che finge di essere generico, ma al suo posto ci sono interfacce
+dedicate. Ma al tempo stesso è più facile incasinare le cose.
+
+Per evitare di ripetere gli stessi errori ho preso nota delle lezioni imparate
+mentre raffazzonavo il driver drm/i915. La maggior parte di queste lezioni si
+focalizzano sui tecnicismi e non sulla visione d'insieme, come le discussioni
+riguardo al modo migliore per implementare una ioctl per inviare compiti alla
+GPU. Probabilmente, ogni sviluppatore di driver per GPU dovrebbe imparare queste
+lezioni in autonomia.
+
+
+Prerequisiti
+------------
+
+Prima i prerequisiti. Seguite i seguenti suggerimenti se non volete fallire in
+partenza e ritrovarvi ad aggiungere un livello di compatibilità a 32-bit.
+
+* Usate solamente interi a lunghezza fissa. Per evitare i conflitti coi tipi
+ definiti nello spazio utente, il kernel definisce alcuni tipi speciali, come:
+ ``__u32``, ``__s64``. Usateli.
+
+* Allineate tutto alla lunghezza naturale delle piattaforma in uso e riempite
+ esplicitamente i vuoti. Non necessariamente le piattaforme a 32-bit allineano
+ i valori a 64-bit rispettandone l'allineamento, ma le piattaforme a 64-bit lo
+ fanno. Dunque, per farlo correttamente in entrambe i casi dobbiamo sempre
+ riempire i vuoti.
+
+* Se una struttura dati contiene valori a 64-bit, allora fate si che la sua
+ dimensione sia allineata a 64-bit, altrimenti la sua dimensione varierà su
+ sistemi a 32-bit e 64-bit. Avere una dimensione differente causa problemi
+ quando si passano vettori di strutture dati al kernel, o quando il kernel
+ effettua verifiche sulla dimensione (per esempio il sistema drm lo fa).
+
+* I puntatori sono di tipo ``__u64``, con un *cast* da/a ``uintptr_t`` da lato
+ spazio utente e da/a ``void __user *`` nello spazio kernel. Sforzatevi il più
+ possibile per non ritardare la conversione, o peggio maneggiare ``__u64`` nel
+ vostro codice perché questo riduce le verifiche che strumenti come sparse
+ possono effettuare. La macro u64_to_user_ptr() può essere usata nel kernel
+ per evitare avvisi riguardo interi e puntatori di dimensioni differenti.
+
+
+Le Basi
+-------
+
+Con la gioia d'aver evitato un livello di compatibilità, possiamo ora dare uno
+sguardo alle basi. Trascurare questi punti renderà difficile la gestione della
+compatibilità all'indietro ed in avanti. E dato che sbagliare al primo colpo è
+garantito, dovrete rivisitare il codice o estenderlo per ogni interfaccia.
+
+* Abbiate un modo chiaro per capire dallo spazio utente se una nuova ioctl, o
+ l'estensione di una esistente, sia supportata dal kernel in esecuzione. Se non
+ potete fidarvi del fatto che un vecchio kernel possa rifiutare correttamente
+ un nuovo *flag*, modalità, o ioctl, (probabilmente perché avevate raffazzonato
+ qualcosa nel passato) allora dovrete implementare nel driver un meccanismo per
+ notificare quali funzionalità sono supportate, o in alternativa un numero di
+ versione.
+
+* Abbiate un piano per estendere le ioctl con nuovi *flag* o campi alla fine di
+ una struttura dati. Il sistema drm verifica la dimensione di ogni ioctl in
+ arrivo, ed estende con zeri ogni incongruenza fra kernel e spazio utente.
+ Questo aiuta, ma non è una soluzione completa dato che uno spazio utente nuovo
+ su un kernel vecchio non noterebbe che i campi nuovi alla fine della struttura
+ vengono ignorati. Dunque, anche questo avrà bisogno di essere notificato dal
+ driver allo spazio utente.
+
+* Verificate tutti i campi e *flag* inutilizzati ed i riempimenti siano a 0,
+ altrimenti rifiutare la ioctl. Se non lo fate il vostro bel piano per
+ estendere le ioctl andrà a rotoli dato che qualcuno userà delle ioctl con
+ strutture dati con valori casuali dallo stack nei campi inutilizzati. Il che
+ si traduce nell'avere questi campi nell'ABI, e la cui unica utilità sarà
+ quella di contenere spazzatura. Per questo dovrete esplicitamente riempire i
+ vuoti di tutte le vostre strutture dati, anche se non le userete in un
+ vettore. Il riempimento fatto dal compilatore potrebbe contenere valori
+ casuali.
+
+* Abbiate un semplice codice di test per ognuno dei casi sopracitati.
+
+
+Divertirsi coi percorsi d'errore
+--------------------------------
+
+Oggigiorno non ci sono più scuse rimaste per permettere ai driver drm di essere
+sfruttati per diventare root. Questo significa che dobbiamo avere una completa
+validazione degli input e gestire in modo robusto i percorsi - tanto le GPU
+moriranno comunque nel più strano dei casi particolari:
+
+ * Le ioctl devono verificare l'overflow dei vettori. Inoltre, per i valori
+ interi si devono verificare *overflow*, *underflow*, e *clamping*. Il
+ classico esempio è l'inserimento direttamente nell'hardware di valori di
+ posizionamento di un'immagine *sprite* quando l'hardware supporta giusto 12
+ bit, o qualcosa del genere. Tutto funzionerà finché qualche strano *display
+ server* non decide di preoccuparsi lui stesso del *clamping* e il cursore
+ farà il giro dello schermo.
+
+ * Avere un test semplice per ogni possibile fallimento della vostra ioctl.
+ Verificate che il codice di errore rispetti le aspettative. Ed infine,
+ assicuratevi che verifichiate un solo percorso sbagliato per ogni sotto-test
+ inviando comunque dati corretti. Senza questo, verifiche precedenti
+ potrebbero rigettare la ioctl troppo presto, impedendo l'esecuzione del
+ codice che si voleva effettivamente verificare, rischiando quindi di
+ mascherare bachi e regressioni.
+
+ * Fate si che tutte le vostre ioctl siano rieseguibili. Prima di tutto X adora
+ i segnali; secondo questo vi permetterà di verificare il 90% dei percorsi
+ d'errore interrompendo i vostri test con dei segnali. Grazie all'amore di X
+ per i segnali, otterrete gratuitamente un eccellente copertura di base per
+ tutti i vostri percorsi d'errore. Inoltre, siate consistenti sul modo di
+ gestire la riesecuzione delle ioctl - per esempio, drm ha una piccola
+ funzione di supporto `drmIoctl` nella sua librerie in spazio utente. Il
+ driver i915 l'abbozza con l'ioctl `set_tiling`, ed ora siamo inchiodati per
+ sempre con una semantica arcana sia nel kernel che nello spazio utente.
+
+
+ * Se non potete rendere un pezzo di codice rieseguibile, almeno rendete
+ possibile la sua interruzione. Le GPU moriranno e i vostri utenti non vi
+ apprezzeranno affatto se tenete in ostaggio il loro scatolotto (mediante un
+ processo X insopprimibile). Se anche recuperare lo stato è troppo complicato,
+ allora implementate una scadenza oppure come ultima spiaggia una rete di
+ sicurezza per rilevare situazioni di stallo quando l'hardware da di matto.
+
+ * Preparate dei test riguardo ai casi particolarmente estremi nel codice di
+ recupero del sistema - è troppo facile create uno stallo fra il vostro codice
+ anti-stallo e un processo scrittore.
+
+
+Tempi, attese e mancate scadenze
+--------------------------------
+
+Le GPU fanno quasi tutto in modo asincrono, dunque dobbiamo regolare le
+operazioni ed attendere quelle in sospeso. Questo è davvero difficile; al
+momento nessuna delle ioctl supportante dal driver drm/i915 riesce a farlo
+perfettamente, il che significa che qui ci sono ancora una valanga di lezioni da
+apprendere.
+
+ * Per fare riferimento al tempo usate sempre ``CLOCK_MONOTONIC``. Oggigiorno
+ questo è quello che viene usato di base da alsa, drm, e v4l. Tuttavia,
+ lasciate allo spazio utente la possibilità di capire quali *timestamp*
+ derivano da domini temporali diversi come il vostro orologio di sistema
+ (fornito dal kernel) oppure un contatore hardware indipendente da qualche
+ parte. Gli orologi divergeranno, ma con questa informazione gli strumenti di
+ analisi delle prestazioni possono compensare il problema. Se il vostro spazio
+ utente può ottenere i valori grezzi degli orologi, allora considerate di
+ esporre anch'essi.
+
+ * Per descrivere il tempo, usate ``__s64`` per i secondi e ``__u64`` per i
+ nanosecondi. Non è il modo migliore per specificare il tempo, ma è
+ praticamente uno standard.
+
+ * Verificate che gli input di valori temporali siano normalizzati, e se non lo
+ sono scartateli. Fate attenzione perché la struttura dati ``struct ktime``
+ del kernel usa interi con segni sia per i secondi che per i nanosecondi.
+
+ * Per le scadenze (*timeout*) usate valori temporali assoluti. Se siete dei
+ bravi ragazzi e avete reso la vostra ioctl rieseguibile, allora i tempi
+ relativi tendono ad essere troppo grossolani e a causa degli arrotondamenti
+ potrebbero estendere in modo indefinito i tempi di attesa ad ogni
+ riesecuzione. Particolarmente vero se il vostro orologio di riferimento è
+ qualcosa di molto lento come il contatore di *frame*. Con la giacca da
+ avvocato delle specifiche diremmo che questo non è un baco perché tutte le
+ scadenze potrebbero essere estese - ma sicuramente gli utenti vi odieranno
+ quando le animazioni singhiozzano.
+
+ * Considerate l'idea di eliminare tutte le ioctl sincrone con scadenze, e di
+ sostituirle con una versione asincrona il cui stato può essere consultato
+ attraverso il descrittore di file mediante ``poll``. Questo approccio si
+ sposa meglio in un applicazione guidata dagli eventi.
+
+ * Sviluppate dei test per i casi estremi, specialmente verificate che i valori
+ di ritorno per gli eventi già completati, le attese terminate con successo, e
+ le attese scadute abbiano senso e servano ai vostri scopi.
+
+
+Non perdere risorse
+-------------------
+Nel suo piccolo il driver drm implementa un sistema operativo specializzato per
+certe GPU. Questo significa che il driver deve esporre verso lo spazio
+utente tonnellate di agganci per accedere ad oggetti e altre risorse. Farlo
+correttamente porterà con se alcune insidie:
+
+ * Collegate sempre la vita di una risorsa creata dinamicamente, a quella del
+ descrittore di file. Considerate una mappatura 1:1 se la vostra risorsa
+ dev'essere condivisa fra processi - passarsi descrittori di file sul socket
+ unix semplifica la gestione anche per lo spazio utente.
+
+ * Dev'esserci sempre Il supporto ``O_CLOEXEC``.
+
+ * Assicuratevi di avere abbastanza isolamento fra utenti diversi. Di base
+ impostate uno spazio dei nomi riservato per ogni descrittore di file, il che
+ forzerà ogni condivisione ad essere esplicita. Usate uno spazio più globale
+ per dispositivo solo se gli oggetti sono effettivamente unici per quel
+ dispositivo. Un controesempio viene dall'interfaccia drm modeset, dove
+ oggetti specifici di dispositivo, come i connettori, condividono uno spazio
+ dei nomi con oggetti per il *framebuffer*, ma questi non sono per niente
+ condivisi. Uno spazio separato, privato di base, per i *framebuffer* sarebbe
+ stato meglio.
+
+ * Pensate all'identificazione univoca degli agganci verso lo spazio utente. Per
+ esempio, per la maggior parte dei driver drm, si considera fallace la doppia
+ sottomissione di un oggetto allo stesso comando ioctl. Ma per evitarlo, se
+ gli oggetti sono condivisibili, lo spazio utente ha bisogno di sapere se il
+ driver ha importato un oggetto da un altro processo. Non l'ho ancora provato,
+ ma considerate l'idea di usare il numero di inode come identificatore per i
+ descrittori di file condivisi - che poi è come si distinguono i veri file.
+ Sfortunatamente, questo richiederebbe lo sviluppo di un vero e proprio
+ filesystem virtuale nel kernel.
+
+
+Ultimo, ma non meno importante
+------------------------------
+
+Non tutti i problemi si risolvono con una nuova ioctl:
+
+* Pensateci su due o tre volte prima di implementare un'interfaccia privata per
+ un driver. Ovviamente è molto più veloce seguire questa via piuttosto che
+ buttarsi in lunghe discussioni alla ricerca di una soluzione più generica. Ed
+ a volte un'interfaccia privata è quello che serve per sviluppare un nuovo
+ concetto. Ma alla fine, una volta che c'è un'interfaccia generica a
+ disposizione finirete per mantenere due interfacce. Per sempre.
+
+* Considerate interfacce alternative alle ioctl. Gli attributi sysfs sono molto
+ meglio per impostazioni che sono specifiche di un dispositivo, o per
+ sotto-oggetti con una vita piuttosto statica (come le uscite dei connettori in
+ drm con tutti gli attributi per la sovrascrittura delle rilevazioni). O magari
+ solo il vostro sistema di test ha bisogno di una certa interfaccia, e allora
+ debugfs (che non ha un'interfaccia stabile) sarà la soluzione migliore.
+
+Per concludere. Questo gioco consiste nel fare le cose giuste fin da subito,
+dato che se il vostro driver diventa popolare e la piattaforma hardware longeva
+finirete per mantenere le vostre ioctl per sempre. Potrete tentare di deprecare
+alcune orribili ioctl, ma ci vorranno anni per riuscirci effettivamente. E
+ancora, altri anni prima che sparisca l'ultimo utente capace di lamentarsi per
+una regressione.
diff --git a/Documentation/translations/it_IT/process/changes.rst b/Documentation/translations/it_IT/process/changes.rst
index 94a6499742ac..f37c53f8b524 100644
--- a/Documentation/translations/it_IT/process/changes.rst
+++ b/Documentation/translations/it_IT/process/changes.rst
@@ -11,8 +11,8 @@ Requisiti minimi per compilare il kernel
Introduzione
============
-Questo documento fornisce una lista dei software necessari per eseguire i
-kernel 4.x.
+Questo documento fornisce una lista dei software necessari per eseguire questa
+versione del kernel.
Questo documento è basato sul file "Changes" del kernel 2.0.x e quindi le
persone che lo scrissero meritano credito (Jared Mauch, Axel Boldt,
@@ -32,11 +32,14 @@ PC Card, per esempio, probabilmente non dovreste preoccuparvi di pcmciautils.
====================== ================= ========================================
Programma Versione minima Comando per verificare la versione
====================== ================= ========================================
-GNU C 4.6 gcc --version
+GNU C 5.1 gcc --version
+Clang/LLVM (optional) 11.0.0 clang --version
GNU make 3.81 make --version
-binutils 2.21 ld -v
+bash 4.2 bash --version
+binutils 2.25 ld -v
flex 2.5.35 flex --version
bison 2.0 bison --version
+pahole 1.16 pahole --version
util-linux 2.10o fdformat --version
kmod 13 depmod -V
e2fsprogs 1.41.4 e2fsck -V
@@ -50,14 +53,14 @@ quota-tools 3.09 quota -V
PPP 2.4.0 pppd --version
nfs-utils 1.0.5 showmount --version
procps 3.2.0 ps --version
-oprofile 0.9 oprofiled --version
udev 081 udevd --version
grub 0.93 grub --version || grub-install --version
mcelog 0.6 mcelog --version
iptables 1.4.2 iptables -V
openssl & libcrypto 1.0.0 openssl version
bc 1.06.95 bc --version
-Sphinx\ [#f1]_ 1.3 sphinx-build --version
+Sphinx\ [#f1]_ 1.7 sphinx-build --version
+cpio any cpio --version
====================== ================= ========================================
.. [#f1] Sphinx è necessario solo per produrre la documentazione del Kernel
@@ -71,15 +74,30 @@ GCC
La versione necessaria di gcc potrebbe variare a seconda del tipo di CPU nel
vostro calcolatore.
+Clang/LLVM (opzionale)
+----------------------
+
+L'ultima versione di clang e *LLVM utils* (secondo `releases.llvm.org
+<https://releases.llvm.org>`_) sono supportati per la generazione del
+kernel. Non garantiamo che anche i rilasci più vecchi funzionino, inoltre
+potremmo rimuovere gli espedienti che abbiamo implementato per farli
+funzionare. Per maggiori informazioni
+:ref:`Building Linux with Clang/LLVM <kbuild_llvm>`.
+
Make
----
Per compilare il kernel vi servirà GNU make 3.81 o successivo.
+Bash
+----
+Per generare il kernel vengono usati alcuni script per bash.
+Questo richiede bash 4.2 o successivo.
+
Binutils
--------
-Per generare il kernel è necessario avere Binutils 2.21 o superiore.
+Per generare il kernel è necessario avere Binutils 2.25 o superiore.
pkg-config
----------
@@ -101,6 +119,16 @@ Bison
Dalla versione 4.16, il sistema di compilazione, durante l'esecuzione, genera
un parsificatore. Questo richiede bison 2.0 o successivo.
+pahole
+------
+
+Dalla versione 5.2, quando viene impostato CONFIG_DEBUG_INFO_BTF, il sistema di
+compilazione genera BTF (BPF Type Format) a partire da DWARF per vmlinux. Più
+tardi anche per i moduli. Questo richiede pahole v1.16 o successivo.
+
+A seconda della distribuzione, lo si può trovare nei pacchetti 'dwarves' o
+'pahole'. Oppure lo si può trovare qui: https://fedorapeople.org/~acme/dwarves/.
+
Perl
----
@@ -338,11 +366,21 @@ gcc
- <ftp://ftp.gnu.org/gnu/gcc/>
+Clang/LLVM
+----------
+
+- :ref:`Getting LLVM <getting_llvm>`.
+
Make
----
- <ftp://ftp.gnu.org/gnu/make/>
+Bash
+----
+
+- <ftp://ftp.gnu.org/gnu/bash/>
+
Binutils
--------
@@ -390,7 +428,8 @@ Mkinitrd
E2fsprogs
---------
-- <http://prdownloads.sourceforge.net/e2fsprogs/e2fsprogs-1.29.tar.gz>
+- <https://www.kernel.org/pub/linux/kernel/people/tytso/e2fsprogs/>
+- <https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/>
JFSutils
--------
@@ -400,12 +439,13 @@ JFSutils
Reiserfsprogs
-------------
-- <http://www.kernel.org/pub/linux/utils/fs/reiserfs/>
+- <https://git.kernel.org/pub/scm/linux/kernel/git/jeffm/reiserfsprogs.git/>
Xfsprogs
--------
-- <ftp://oss.sgi.com/projects/xfs/>
+- <https://git.kernel.org/pub/scm/fs/xfs/xfsprogs-dev.git>
+- <https://www.kernel.org/pub/linux/utils/fs/xfs/xfsprogs/>
Pcmciautils
-----------
@@ -438,13 +478,20 @@ mcelog
- <http://www.mcelog.org/>
+cpio
+----
+
+- <https://www.gnu.org/software/cpio/>
+
Rete
****
PPP
---
-- <ftp://ftp.samba.org/pub/ppp/>
+- <https://download.samba.org/pub/ppp/>
+- <https://git.ozlabs.org/?p=ppp.git>
+- <https://github.com/paulusmack/ppp/>
NFS-utils
@@ -455,7 +502,7 @@ NFS-utils
Iptables
--------
-- <http://www.iptables.org/downloads.html>
+- <https://netfilter.org/projects/iptables/index.html>
Ip-route2
---------
diff --git a/Documentation/translations/it_IT/process/clang-format.rst b/Documentation/translations/it_IT/process/clang-format.rst
index 77eac809a639..29f83c198025 100644
--- a/Documentation/translations/it_IT/process/clang-format.rst
+++ b/Documentation/translations/it_IT/process/clang-format.rst
@@ -40,7 +40,7 @@ Linux più popolari. Cercate ``clang-format`` nel vostro repositorio.
Altrimenti, potete scaricare una versione pre-generata dei binari di LLVM/clang
oppure generarlo dai codici sorgenti:
- http://releases.llvm.org/download.html
+ https://releases.llvm.org/download.html
Troverete più informazioni ai seguenti indirizzi:
diff --git a/Documentation/translations/it_IT/process/coding-style.rst b/Documentation/translations/it_IT/process/coding-style.rst
index 8995d2d19f20..5f244e16f511 100644
--- a/Documentation/translations/it_IT/process/coding-style.rst
+++ b/Documentation/translations/it_IT/process/coding-style.rst
@@ -62,7 +62,7 @@ i ``case``. Un esempio.:
case 'K':
case 'k':
mem <<= 10;
- /* fall through */
+ fallthrough;
default:
break;
}
@@ -75,9 +75,26 @@ stessa riga:
if (condition) do_this;
do_something_everytime;
-né mettete più assegnamenti sulla stessa riga. Lo stile del kernel
+Non usate le virgole per evitare le parentesi:
+
+.. code-block:: c
+
+ if (condition)
+ do_this(), do_that();
+
+Invece, usate sempre le parentesi per racchiudere più istruzioni.
+
+.. code-block:: c
+
+ if (condition) {
+ do_this();
+ do_that();
+ }
+
+Non mettete nemmeno più assegnamenti sulla stessa riga. Lo stile del kernel
è ultrasemplice. Evitate espressioni intricate.
+
Al di fuori dei commenti, della documentazione ed escludendo i Kconfig, gli
spazi non vengono mai usati per l'indentazione, e l'esempio qui sopra è
volutamente errato.
@@ -92,16 +109,22 @@ delle righe.
Lo stile del codice riguarda la leggibilità e la manutenibilità utilizzando
strumenti comuni.
-Il limite delle righe è di 80 colonne e questo e un limite fortemente
-desiderato.
+Come limite di riga si preferiscono le 80 colonne.
+
+Espressioni più lunghe di 80 colonne dovrebbero essere spezzettate in
+pezzi più piccoli, a meno che eccedere le 80 colonne non aiuti ad
+aumentare la leggibilità senza nascondere informazioni.
-Espressioni più lunghe di 80 colonne saranno spezzettate in pezzi più piccoli,
-a meno che eccedere le 80 colonne non aiuti ad aumentare la leggibilità senza
-nascondere informazioni. I pezzi derivati sono sostanzialmente più corti degli
-originali e vengono posizionati più a destra. Lo stesso si applica, nei file
-d'intestazione, alle funzioni con una lista di argomenti molto lunga. Tuttavia,
-non spezzettate mai le stringhe visibili agli utenti come i messaggi di
-printk, questo perché inibireste la possibilità d'utilizzare grep per cercarle.
+I nuovi pezzi derivati sono sostanzialmente più corti degli originali
+e vengono posizionati più a destra. Uno stile molto comune è quello di
+allineare i nuovi pezzi alla parentesi aperta di una funzione.
+
+Lo stesso si applica, nei file d'intestazione, alle funzioni con una
+lista di argomenti molto lunga.
+
+Tuttavia, non spezzettate mai le stringhe visibili agli utenti come i
+messaggi di printk, questo perché inibireste la possibilità
+d'utilizzare grep per cercarle.
3) Posizionamento di parentesi graffe e spazi
---------------------------------------------
@@ -313,9 +336,8 @@ che conta gli utenti attivi, dovreste chiamarla ``count_active_users()`` o
qualcosa di simile, **non** dovreste chiamarla ``cntusr()``.
Codificare il tipo di funzione nel suo nome (quella cosa chiamata notazione
-ungherese) fa male al cervello - il compilatore conosce comunque il tipo e
-può verificarli, e inoltre confonde i programmatori. Non c'è da
-sorprendersi che MicroSoft faccia programmi bacati.
+ungherese) è stupido - il compilatore conosce comunque il tipo e
+può verificarli, e inoltre confonde i programmatori.
Le variabili LOCALI dovrebbero avere nomi corti, e significativi. Se avete
un qualsiasi contatore di ciclo, probabilmente sarà chiamato ``i``.
@@ -444,14 +466,52 @@ la riga della parentesi graffa di chiusura. Ad esempio:
}
EXPORT_SYMBOL(system_is_up);
+6.1) Prototipi di funzione
+**************************
+
Nei prototipi di funzione, includete i nomi dei parametri e i loro tipi.
Nonostante questo non sia richiesto dal linguaggio C, in Linux viene preferito
perché è un modo semplice per aggiungere informazioni importanti per il
lettore.
-Non usate la parola chiave ``extern`` coi prototipi di funzione perché
+Non usate la parola chiave ``extern`` con le dichiarazioni di funzione perché
rende le righe più lunghe e non è strettamente necessario.
+Quando scrivete i prototipi di funzione mantenete `l'ordine degli elementi <https://lore.kernel.org/mm-commits/CAHk-=wiOCLRny5aifWNhr621kYrJwhfURsa0vFPeUEm8mF0ufg@mail.gmail.com/>`_.
+
+Prendiamo questa dichiarazione di funzione come esempio::
+
+ __init void * __must_check action(enum magic value, size_t size, u8 count,
+ char *fmt, ...) __printf(4, 5) __malloc;
+
+L'ordine suggerito per gli elementi di un prototipo di funzione è il seguente:
+
+- classe d'archiviazione (in questo caso ``static __always_inline``. Da notare
+ che ``__always_inline`` è tecnicamente un attributo ma che viene trattato come
+ ``inline``)
+- attributi della classe di archiviazione (in questo caso ``__init``, in altre
+ parole la sezione, ma anche cose tipo ``__cold``)
+- il tipo di ritorno (in questo caso, ``void *``)
+- attributi per il valore di ritorno (in questo caso, ``__must_check``)
+- il nome della funzione (in questo caso, ``action``)
+- i parametri della funzione(in questo caso,
+ ``(enum magic value, size_t size, u8 count, char *fmt, ...)``,
+ da notare che va messo anche il nome del parametro)
+- attributi dei parametri (in questo caso, ``__printf(4, 5)``)
+- attributi per il comportamento della funzione (in questo caso, ``__malloc_``)
+
+Notate che per la **definizione** di una funzione (il altre parole il corpo
+della funzione), il compilatore non permette di usare gli attributi per i
+parametri dopo i parametri. In questi casi, devono essere messi dopo gli
+attributi della classe d'archiviazione (notate che la posizione di
+``__printf(4,5)`` cambia rispetto alla **dichiarazione**)::
+
+ static __always_inline __init __printf(4, 5) void * __must_check action(enum magic value,
+ size_t size, u8 count, char *fmt, ...) __malloc
+ {
+ ...
+ }*)**``)**``)``)``*)``)``)``)``*``)``)``)*)
+
7) Centralizzare il ritorno delle funzioni
------------------------------------------
@@ -825,15 +885,15 @@ linguaggio assembler.
Agli sviluppatori del kernel piace essere visti come dotti. Tenete un occhio
di riguardo per l'ortografia e farete una belle figura. In inglese, evitate
-l'uso di parole mozzate come ``dont``: usate ``do not`` oppure ``don't``.
-Scrivete messaggi concisi, chiari, e inequivocabili.
+l'uso incorretto di abbreviazioni come ``dont``: usate ``do not`` oppure
+``don't``. Scrivete messaggi concisi, chiari, e inequivocabili.
I messaggi del kernel non devono terminare con un punto fermo.
Scrivere i numeri fra parentesi (%d) non migliora alcunché e per questo
dovrebbero essere evitati.
-Ci sono alcune macro per la diagnostica in <linux/device.h> che dovreste
+Ci sono alcune macro per la diagnostica in <linux/dev_printk.h> che dovreste
usare per assicurarvi che i messaggi vengano associati correttamente ai
dispositivi e ai driver, e che siano etichettati correttamente: dev_err(),
dev_warn(), dev_info(), e così via. Per messaggi che non sono associati ad
@@ -1005,7 +1065,7 @@ struttura, usate
.. code-block:: c
- #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
+ #define sizeof_field(t, f) (sizeof(((t*)0)->f))
Ci sono anche le macro min() e max() che, se vi serve, effettuano un controllo
rigido sui tipi. Sentitevi liberi di leggere attentamente questo file
@@ -1097,7 +1157,7 @@ la direttiva condizionale su di esse.
Se avete una variabile o funzione che potrebbe non essere usata in alcune
configurazioni, e quindi il compilatore potrebbe avvisarvi circa la definizione
-inutilizzata, marcate questa definizione come __maybe_used piuttosto che
+inutilizzata, marcate questa definizione come __maybe_unused piuttosto che
racchiuderla in una direttiva condizionale del preprocessore. (Comunque,
se una variabile o funzione è *sempre* inutilizzata, rimuovetela).
@@ -1144,10 +1204,10 @@ ISBN 0-201-61586-X.
Manuali GNU - nei casi in cui sono compatibili con K&R e questo documento -
per indent, cpp, gcc e i suoi dettagli interni, tutto disponibile qui
-http://www.gnu.org/manual/
+https://www.gnu.org/manual/
WG14 è il gruppo internazionale di standardizzazione per il linguaggio C,
-URL: http://www.open-std.org/JTC1/SC22/WG14/
+URL: https://www.open-std.org/JTC1/SC22/WG14/
-Kernel process/coding-style.rst, by greg@kroah.com at OLS 2002:
+Kernel CodingStyle, by greg@kroah.com at OLS 2002:
http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
diff --git a/Documentation/translations/it_IT/process/deprecated.rst b/Documentation/translations/it_IT/process/deprecated.rst
index 776f26732a94..ba0ed7dc154c 100644
--- a/Documentation/translations/it_IT/process/deprecated.rst
+++ b/Documentation/translations/it_IT/process/deprecated.rst
@@ -34,6 +34,33 @@ interfaccia come 'vecchia', questa non è una soluzione completa. L'interfaccia
deve essere rimossa dal kernel, o aggiunta a questo documento per scoraggiarne
l'uso.
+BUG() e BUG_ON()
+----------------
+Al loro posto usate WARN() e WARN_ON() per gestire le
+condizioni "impossibili" e gestitele come se fosse possibile farlo.
+Nonostante le funzioni della famiglia BUG() siano state progettate
+per asserire "situazioni impossibili" e interrompere in sicurezza un
+thread del kernel, queste si sono rivelate essere troppo rischiose
+(per esempio, in quale ordine rilasciare i *lock*? Ci sono stati che
+sono stati ripristinati?). Molto spesso l'uso di BUG()
+destabilizza il sistema o lo corrompe del tutto, il che rende
+impossibile un'attività di debug o anche solo leggere un rapporto
+circa l'errore. Linus ha un'opinione molto critica al riguardo:
+`email 1
+<https://lore.kernel.org/lkml/CA+55aFy6jNLsywVYdGp83AMrXBo_P-pkjkphPGrO=82SPKCpLQ@mail.gmail.com/>`_,
+`email 2
+<https://lore.kernel.org/lkml/CAHk-=whDHsbK3HTOpTF=ue_o04onRwTEaK_ZoJp_fjbqq4+=Jw@mail.gmail.com/>`_
+
+Tenete presente che la famiglia di funzioni WARN() dovrebbe essere
+usato solo per situazioni che si suppone siano "impossibili". Se
+volete avvisare gli utenti riguardo a qualcosa di possibile anche se
+indesiderato, usare le funzioni della famiglia pr_warn(). Chi
+amministra il sistema potrebbe aver attivato l'opzione sysctl
+*panic_on_warn* per essere sicuri che il sistema smetta di funzionare
+in caso si verifichino delle condizioni "inaspettate". (per esempio,
+date un'occhiata al questo `commit
+<https://git.kernel.org/linus/d4689846881d160a4d12a514e991a740bcb5d65a>`_)
+
Calcoli codificati negli argomenti di un allocatore
----------------------------------------------------
Il calcolo dinamico delle dimensioni (specialmente le moltiplicazioni) non
@@ -42,8 +69,8 @@ dovrebbero essere fatto negli argomenti di funzioni di allocazione di memoria
piccoli di quelli che il chiamante si aspettava. L'uso di questo modo di
allocare può portare ad un overflow della memoria di heap e altri
malfunzionamenti. (Si fa eccezione per valori numerici per i quali il
-compilatore può generare avvisi circa un potenziale overflow. Tuttavia usare
-i valori numerici come suggerito di seguito è innocuo).
+compilatore può generare avvisi circa un potenziale overflow. Tuttavia, anche in
+questi casi è preferibile riscrivere il codice come suggerito di seguito).
Per esempio, non usate ``count * size`` come argomento::
@@ -53,6 +80,9 @@ Al suo posto, si dovrebbe usare l'allocatore a due argomenti::
foo = kmalloc_array(count, size, GFP_KERNEL);
+Nello specifico, kmalloc() può essere sostituta da kmalloc_array(), e kzalloc()
+da kcalloc().
+
Se questo tipo di allocatore non è disponibile, allora dovrebbero essere usate
le funzioni del tipo *saturate-on-overflow*::
@@ -68,52 +98,110 @@ Invece, usate la seguente funzione::
header = kzalloc(struct_size(header, item, count), GFP_KERNEL);
-Per maggiori dettagli fate riferimento a :c:func:`array_size`,
-:c:func:`array3_size`, e :c:func:`struct_size`, così come la famiglia di
-funzioni :c:func:`check_add_overflow` e :c:func:`check_mul_overflow`.
+.. note:: Se per caso state usando struct_size() su una struttura dati che
+ in coda contiene un array di lunghezza zero o uno, allora siete
+ invitati a riorganizzare il vostro codice usando il
+ `flexible array member <#zero-length-and-one-element-arrays>`_.
+
+Per altri calcoli, usate le funzioni size_mul(), size_add(), e size_sub(). Per
+esempio, al posto di::
+
+ foo = krealloc(current_size + chunk_size * (count - 3), GFP_KERNEL);
+
+dovreste scrivere:
+
+ foo = krealloc(size_add(current_size,
+ size_mul(chunk_size,
+ size_sub(count, 3))), GFP_KERNEL);
+
+Per maggiori dettagli fate riferimento a array3_size() e flex_array_size(), ma
+anche le funzioni della famiglia check_mul_overflow(), check_add_overflow(),
+check_sub_overflow(), e check_shl_overflow().
simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull()
----------------------------------------------------------------------
-Le funzioni :c:func:`simple_strtol`, :c:func:`simple_strtoll`,
-:c:func:`simple_strtoul`, e :c:func:`simple_strtoull` ignorano volutamente
+Le funzioni simple_strtol(), simple_strtoll(),
+simple_strtoul(), e simple_strtoull() ignorano volutamente
i possibili overflow, e questo può portare il chiamante a generare risultati
-inaspettati. Le rispettive funzioni :c:func:`kstrtol`, :c:func:`kstrtoll`,
-:c:func:`kstrtoul`, e :c:func:`kstrtoull` sono da considerarsi le corrette
+inaspettati. Le rispettive funzioni kstrtol(), kstrtoll(),
+kstrtoul(), e kstrtoull() sono da considerarsi le corrette
sostitute; tuttavia va notato che queste richiedono che la stringa sia
terminata con il carattere NUL o quello di nuova riga.
strcpy()
--------
-La funzione :c:func:`strcpy` non fa controlli agli estremi del buffer
+La funzione strcpy() non fa controlli agli estremi del buffer
di destinazione. Questo può portare ad un overflow oltre i limiti del
buffer e generare svariati tipi di malfunzionamenti. Nonostante l'opzione
`CONFIG_FORTIFY_SOURCE=y` e svariate opzioni del compilatore aiutano
a ridurne il rischio, non c'è alcuna buona ragione per continuare ad usare
-questa funzione. La versione sicura da usare è :c:func:`strscpy`.
+questa funzione. La versione sicura da usare è strscpy(), tuttavia va
+prestata attenzione a tutti quei casi dove viene usato il valore di
+ritorno di strcpy(). La funzione strscpy() non ritorna un puntatore
+alla destinazione, ma un contatore dei byte non NUL copiati (oppure
+un errno negativo se la stringa è stata troncata).
strncpy() su stringe terminate con NUL
--------------------------------------
-L'utilizzo di :c:func:`strncpy` non fornisce alcuna garanzia sul fatto che
+L'utilizzo di strncpy() non fornisce alcuna garanzia sul fatto che
il buffer di destinazione verrà terminato con il carattere NUL. Questo
potrebbe portare a diversi overflow di lettura o altri malfunzionamenti
causati, appunto, dalla mancanza del terminatore. Questa estende la
terminazione nel buffer di destinazione quando la stringa d'origine è più
corta; questo potrebbe portare ad una penalizzazione delle prestazioni per
chi usa solo stringe terminate. La versione sicura da usare è
-:c:func:`strscpy`. (chi usa :c:func:`strscpy` e necessita di estendere la
-terminazione con NUL deve aggiungere una chiamata a :c:func:`memset`)
+strscpy(), tuttavia va prestata attenzione a tutti quei casi dove
+viene usato il valore di ritorno di strncpy(). La funzione strscpy()
+non ritorna un puntatore alla destinazione, ma un contatore dei byte
+non NUL copiati (oppure un errno negativo se la stringa è stata
+troncata). Tutti i casi che necessitano di estendere la
+terminazione con NUL dovrebbero usare strscpy_pad().
-Se il chiamate no usa stringhe terminate con NUL, allore :c:func:`strncpy()`
+Se il chiamate no usa stringhe terminate con NUL, allore strncpy()
può continuare ad essere usata, ma i buffer di destinazione devono essere
marchiati con l'attributo `__nonstring <https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html>`_
per evitare avvisi durante la compilazione.
strlcpy()
---------
-La funzione :c:func:`strlcpy`, per prima cosa, legge interamente il buffer di
+La funzione strlcpy(), per prima cosa, legge interamente il buffer di
origine, magari leggendo più di quanto verrà effettivamente copiato. Questo
è inefficiente e può portare a overflow di lettura quando la stringa non è
-terminata con NUL. La versione sicura da usare è :c:func:`strscpy`.
+terminata con NUL. La versione sicura da usare è strscpy(), tuttavia
+va prestata attenzione a tutti quei casi dove viene usato il valore di
+ritorno di strlcpy(), dato che strscpy() ritorna un valore di errno
+negativo quanto la stringa viene troncata.
+
+Segnaposto %p nella stringa di formato
+--------------------------------------
+
+Tradizionalmente, l'uso del segnaposto "%p" nella stringa di formato
+esponne un indirizzo di memoria in dmesg, proc, sysfs, eccetera. Per
+evitare che questi indirizzi vengano sfruttati da malintenzionati,
+tutto gli usi di "%p" nel kernel rappresentano l'hash dell'indirizzo,
+rendendolo di fatto inutilizzabile. Nuovi usi di "%p" non dovrebbero
+essere aggiunti al kernel. Per una rappresentazione testuale di un
+indirizzo usate "%pS", l'output è migliore perché mostrerà il nome del
+simbolo. Per tutto il resto, semplicemente non usate "%p".
+
+Parafrasando la `guida
+<https://lore.kernel.org/lkml/CA+55aFwQEd_d40g4mUCSsVRZzrFPUJt74vc6PPpb675hYNXcKw@mail.gmail.com/>`_
+di Linus:
+
+- Se il valore hash di "%p" è inutile, chiediti se il puntatore stesso
+ è importante. Forse dovrebbe essere rimosso del tutto?
+- Se credi davvero che il vero valore del puntatore sia importante,
+ perché alcuni stati del sistema o i livelli di privilegi di un
+ utente sono considerati "special"? Se pensi di poterlo giustificare
+ (in un commento e nel messaggio del commit) abbastanza bene da
+ affrontare il giudizio di Linus, allora forse potrai usare "%px",
+ assicurandosi anche di averne il permesso.
+
+Potete disabilitare temporaneamente l'hashing di "%p" nel caso in cui questa
+funzionalità vi sia d'ostacolo durante una sessione di debug. Per farlo
+aggiungete l'opzione di debug "`no_hash_pointers
+<https://git.kernel.org/linus/5ead723a20e0447bc7db33dc3070b420e5f80aa6>`_" alla
+riga di comando del kernel.
Vettori a dimensione variabile (VLA)
------------------------------------
@@ -127,3 +215,195 @@ Questo può portare a dei malfunzionamenti, potrebbe sovrascrivere
dati importanti alla fine dello stack (quando il kernel è compilato senza
`CONFIG_THREAD_INFO_IN_TASK=y`), o sovrascrivere un pezzo di memoria adiacente
allo stack (quando il kernel è compilato senza `CONFIG_VMAP_STACK=y`).
+
+Salto implicito nell'istruzione switch-case
+-------------------------------------------
+
+Il linguaggio C permette ai casi di un'istruzione `switch` di saltare al
+prossimo caso quando l'istruzione "break" viene omessa alla fine del caso
+corrente. Tuttavia questo rende il codice ambiguo perché non è sempre ovvio se
+l'istruzione "break" viene omessa intenzionalmente o è un baco. Per esempio,
+osservando il seguente pezzo di codice non è chiaro se lo stato
+`STATE_ONE` è stato progettato apposta per eseguire anche `STATE_TWO`::
+
+ switch (value) {
+ case STATE_ONE:
+ do_something();
+ case STATE_TWO:
+ do_other();
+ break;
+ default:
+ WARN("unknown state");
+ }
+
+Dato che c'è stata una lunga lista di problemi `dovuti alla mancanza dell'istruzione
+"break" <https://cwe.mitre.org/data/definitions/484.html>`_, oggigiorno non
+permettiamo più che vi sia un "salto implicito" (*fall-through*). Per
+identificare un salto implicito intenzionale abbiamo adottato la pseudo
+parola chiave 'fallthrough' che viene espansa nell'estensione di gcc
+`__attribute__((fallthrough))` `Statement Attributes
+<https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html>`_.
+(Quando la sintassi C17/C18 `[[fallthrough]]` sarà più comunemente
+supportata dai compilatori C, analizzatori statici, e dagli IDE,
+allora potremo usare quella sintassi per la pseudo parola chiave)
+
+Quando la sintassi [[fallthrough]] sarà più comunemente supportata dai
+compilatori, analizzatori statici, e ambienti di sviluppo IDE,
+allora potremo usarla anche noi.
+
+Ne consegue che tutti i blocchi switch/case devono finire in uno dei seguenti
+modi:
+
+* ``break;``
+* `fallthrough;``
+* ``continue;``
+* ``goto <label>;``
+* ``return [expression];``
+
+Array di lunghezza zero o con un solo elemento
+----------------------------------------------
+All'interno del kernel ricorre spesso la necessita di avere membri
+di dimensione variabile all'interno di una struttura dati. In questi
+casi il codice del kernel dovrebbe usare sempre i `"flexible array
+member" <https://en.wikipedia.org/wiki/Flexible_array_member>`_. La
+tecnica degli array a lunghezza nulla o di un solo elemento non
+dovrebbe essere più usata.
+
+Nel codice C più vecchio, la dichiarazione di un membro di dimensione
+variabile in coda ad una struttura dati veniva fatto dichiarando un
+array di un solo elemento posizionato alla fine della struttura dati::
+
+ struct something {
+ size_t count;
+ struct foo items[1];
+ };
+
+Questo ha portato ad un calcolo di sizeof() traballante (dovrebbe
+rimuovere la dimensione del singolo elemento in coda per calcolare la
+dimensione esatta dell' "intestazione"). Per evitare questi problemi è
+stata introdotta un' `estensione a GNU C
+<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_ che
+permettesse la dichiarazione di array a lungezza zero::
+
+ struct something {
+ size_t count;
+ struct foo items[0];
+ };
+
+Ma questo ha portato nuovi problemi, e non ha risolto alcuni dei
+problemi che affliggono entrambe le tecniche: per esempio
+l'impossibilità di riconoscere se un array di quel tipo viene usato
+nel mezzo di una struttura dati e _non_ alla fine (potrebbe accadere
+sia direttamente, sia indirettamente quando si usano le unioni o le
+strutture di strutture).
+
+Lo standard C99 introduce i "flexible array members". Questi array non
+hanno una dimensione nella loro dichiarazione::
+
+ struct something {
+ size_t count;
+ struct foo items[];
+ };
+
+Questo è il modo con cui ci si aspetta che vengano dichiarati gli
+elementi di lunghezza variabile in coda alle strutture dati. Permette
+al compilatore di produrre errori quando gli array flessibili non si
+trovano alla fine della struttura dati, il che permette di prevenire
+alcuni tipi di bachi dovuti a `comportamenti inaspettati
+<https://git.kernel.org/linus/76497732932f15e7323dc805e8ea8dc11bb587cf>`_.
+Inoltre, permette al compilatore di analizzare correttamente le
+dimensioni degli array (attraverso sizeof(), `CONFIG_FORTIFY_SOURCE`,
+e `CONFIG_UBSAN_BOUNDS`). Per esempio, non esiste alcun meccanismo in
+grado di avvisarci che il seguente uso di sizeof() dia sempre come
+zero come risultato::
+
+ struct something {
+ size_t count;
+ struct foo items[0];
+ };
+
+ struct something *instance;
+
+ instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL);
+ instance->count = count;
+
+ size = sizeof(instance->items) * instance->count;
+ memcpy(instance->items, source, size);
+
+Il valore di ``size`` nell'ultima riga sarà ``zero``, quando uno
+invece si aspetterebbe che il suo valore sia la dimensione totale in
+byte dell'allocazione dinamica che abbiamo appena fatto per l'array
+``items``. Qui un paio di esempi reali del problema: `collegamento 1
+<https://git.kernel.org/linus/f2cd32a443da694ac4e28fbf4ac6f9d5cc63a539>`_,
+`collegamento 2
+<https://git.kernel.org/linus/ab91c2a89f86be2898cee208d492816ec238b2cf>`_.
+Invece, `i flexible array members hanno un tipo incompleto, e quindi
+sizeof() non può essere applicato
+<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_; dunque ogni
+uso scorretto di questo operatore verrà identificato immediatamente
+durante la compilazione.
+
+Per quanto riguarda gli array di un solo elemento, bisogna essere
+consapevoli che `questi array occupano almeno quanto lo spazio di un
+singolo oggetti dello stesso tipo
+<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_, e quindi
+contribuiscono al calcolo della dimensione della struttura che li
+contiene. In questo caso è facile commettere errori quando si vuole
+calcolare la dimensione totale della memoria totale da allocare per
+una struttura dati::
+
+ struct something {
+ size_t count;
+ struct foo items[1];
+ };
+
+ struct something *instance;
+
+ instance = kmalloc(struct_size(instance, items, count - 1), GFP_KERNEL);
+ instance->count = count;
+
+ size = sizeof(instance->items) * instance->count;
+ memcpy(instance->items, source, size);
+
+In questo esempio ci siamo dovuti ricordare di usare ``count - 1`` in
+struct_size(), altrimenti avremmo --inavvertitamente-- allocato
+memoria per un oggetti ``items`` in più. Il modo più pulito e meno
+propenso agli errori è quello di usare i `flexible array member`, in
+combinazione con struct_size() e flex_array_size()::
+
+ struct something {
+ size_t count;
+ struct foo items[];
+ };
+
+ struct something *instance;
+
+ instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL);
+ instance->count = count;
+
+ memcpy(instance->items, source, flex_array_size(instance, items, instance->count));
+
+Ci sono due casi speciali dove è necessario usare la macro DECLARE_FLEX_ARRAY()
+(da notare che la stessa macro è chiamata __DECLARE_FLEX_ARRAY() nei file di
+intestazione UAPI). Uno è quando l'array flessibile è l'unico elemento di una
+struttura, e l'altro quando è parte di un unione. Per motivi non tecnici, entrambi
+i casi d'uso non sono permessi dalla specifica C99. Per esempio, per
+convertire il seguente codice::
+
+ struct something {
+ ...
+ union {
+ struct type1 one[0];
+ struct type2 two[0];
+ };
+ };
+
+La macro di supporto dev'essere usata::
+
+ struct something {
+ ...
+ union {
+ DECLARE_FLEX_ARRAY(struct type1, one);
+ DECLARE_FLEX_ARRAY(struct type2, two);
+ };
+ };
diff --git a/Documentation/translations/it_IT/process/development-process.rst b/Documentation/translations/it_IT/process/development-process.rst
index f1a6eca30824..20e77c9816a1 100644
--- a/Documentation/translations/it_IT/process/development-process.rst
+++ b/Documentation/translations/it_IT/process/development-process.rst
@@ -8,9 +8,17 @@
Una guida al processo di sviluppo del Kernel
============================================
-Contenuti:
+Lo scopo di questo documento è quello di aiutare gli sviluppatori (ed i loro
+supervisori) a lavorare con la communità di sviluppo con il minimo sforzo. È
+un tentativo di documentare il funzionamento di questa communità in modo che
+sia accessibile anche a coloro che non hanno famigliarità con lo sviluppo del
+Kernel Linux (o, anzi, con lo sviluppo di software libero in generale). Benchè
+qui sia presente del materiale tecnico, questa è una discussione rivolta in
+particolare al procedimento, e quindi per essere compreso non richiede una
+conoscenza approfondità sullo sviluppo del kernel.
.. toctree::
+ :caption: Contenuti
:numbered:
:maxdepth: 2
@@ -22,12 +30,3 @@ Contenuti:
6.Followthrough
7.AdvancedTopics
8.Conclusion
-
-Lo scopo di questo documento è quello di aiutare gli sviluppatori (ed i loro
-supervisori) a lavorare con la communità di sviluppo con il minimo sforzo. È
-un tentativo di documentare il funzionamento di questa communità in modo che
-sia accessibile anche a coloro che non hanno famigliarità con lo sviluppo del
-Kernel Linux (o, anzi, con lo sviluppo di software libero in generale). Benchè
-qui sia presente del materiale tecnico, questa è una discussione rivolta in
-particolare al procedimento, e quindi per essere compreso non richiede una
-conoscenza approfondità sullo sviluppo del kernel.
diff --git a/Documentation/translations/it_IT/process/email-clients.rst b/Documentation/translations/it_IT/process/email-clients.rst
index 224ab031ffd3..76ca3226c8cd 100644
--- a/Documentation/translations/it_IT/process/email-clients.rst
+++ b/Documentation/translations/it_IT/process/email-clients.rst
@@ -1,12 +1,391 @@
.. include:: ../disclaimer-ita.rst
-:Original: :ref:`Documentation/process/email-clients.rst <email_clients>`
+:Original: :doc:`../../../process/email-clients`
+:Translator: Alessia Mantegazza <amantegazza@vaga.pv.it>
.. _it_email_clients:
Informazioni sui programmi di posta elettronica per Linux
=========================================================
-.. warning::
+Git
+---
- TODO ancora da tradurre
+Oggigiorno, la maggior parte degli sviluppatori utilizza ``git send-email``
+al posto dei classici programmi di posta elettronica. Le pagine man sono
+abbastanza buone. Dal lato del ricevente, i manutentori utilizzano ``git am``
+per applicare le patch.
+
+Se siete dei novelli utilizzatori di ``git`` allora inviate la patch a voi
+stessi. Salvatela come testo includendo tutte le intestazioni. Poi eseguite
+il comando ``git am messaggio-formato-testo.txt`` e revisionatene il risultato
+con ``git log``. Quando tutto funziona correttamente, allora potete inviare
+la patch alla lista di discussione più appropriata.
+
+Panoramica delle opzioni
+------------------------
+
+Le patch per il kernel vengono inviate per posta elettronica, preferibilmente
+come testo integrante del messaggio. Alcuni manutentori accettano gli
+allegati, ma in questo caso gli allegati devono avere il *content-type*
+impostato come ``text/plain``. Tuttavia, generalmente gli allegati non sono
+ben apprezzati perché rende più difficile citare porzioni di patch durante il
+processo di revisione.
+
+Inoltre, è vivamente raccomandato l'uso di puro testo nel corpo del
+messaggio, sia per la patch che per qualsiasi altro messaggio. Il sito
+https://useplaintext.email/ può esservi d'aiuto per configurare il
+vostro programma di posta elettronica.
+
+I programmi di posta elettronica che vengono usati per inviare le patch per il
+kernel Linux dovrebbero inviarle senza alterazioni. Per esempio, non
+dovrebbero modificare o rimuovere tabulazioni o spazi, nemmeno all'inizio o
+alla fine delle righe.
+
+Non inviate patch con ``format=flowed``. Questo potrebbe introdurre
+interruzioni di riga inaspettate e indesiderate.
+
+Non lasciate che il vostro programma di posta vada a capo automaticamente.
+Questo può corrompere le patch.
+
+I programmi di posta non dovrebbero modificare la codifica dei caratteri nel
+testo. Le patch inviate per posta elettronica dovrebbero essere codificate in
+ASCII o UTF-8.
+Se configurate il vostro programma per inviare messaggi codificati con UTF-8
+eviterete possibili problemi di codifica.
+
+I programmi di posta dovrebbero generare e mantenere le intestazioni
+"References" o "In-Reply-To:" cosicché la discussione non venga interrotta.
+
+Di solito, il copia-e-incolla (o taglia-e-incolla) non funziona con le patch
+perché le tabulazioni vengono convertite in spazi. Usando xclipboard, xclip
+e/o xcutsel potrebbe funzionare, ma è meglio che lo verifichiate o meglio
+ancora: non usate il copia-e-incolla.
+
+Non usate firme PGP/GPG nei messaggi che contengono delle patch. Questo
+impedisce il corretto funzionamento di alcuni script per leggere o applicare
+patch (questo si dovrebbe poter correggere).
+
+Prima di inviare le patch sulle liste di discussione Linux, può essere una
+buona idea quella di inviare la patch a voi stessi, salvare il messaggio
+ricevuto, e applicarlo ai sorgenti con successo.
+
+
+Alcuni suggerimenti per i programmi di posta elettronica (MUA)
+--------------------------------------------------------------
+
+Qui troverete alcuni suggerimenti per configurare i vostri MUA allo scopo
+di modificare ed inviare patch per il kernel Linux. Tuttavia, questi
+suggerimenti non sono da considerarsi come un riassunto di una configurazione
+completa.
+
+Legenda:
+
+- TUI = interfaccia utente testuale (*text-based user interface*)
+- GUI = interfaccia utente grafica (*graphical user interface*)
+
+Alpine (TUI)
+************
+
+Opzioni per la configurazione:
+
+Nella sezione :menuselection:`Sending Preferences`:
+
+- :menuselection:`Do Not Send Flowed Text` deve essere ``enabled``
+- :menuselection:`Strip Whitespace Before Sending` deve essere ``disabled``
+
+Quando state scrivendo un messaggio, il cursore dev'essere posizionato
+dove volete che la patch inizi, poi premendo :kbd:`CTRL-R` vi verrà chiesto
+di selezionare il file patch da inserire nel messaggio.
+
+Claws Mail (GUI)
+****************
+
+Funziona. Alcune persone riescono ad usarlo con successo per inviare le patch.
+
+Per inserire una patch usate :menuselection:`Messaggio-->Inserisci file`
+(:kbd:`CTRL-I`) oppure un editor esterno.
+
+Se la patch che avete inserito dev'essere modificata usando la finestra di
+scrittura di Claws, allora assicuratevi che l'"auto-interruzione" sia
+disabilitata :menuselection:`Configurazione-->Preferenze-->Composizione-->Interruzione riga`.
+
+Evolution (GUI)
+***************
+
+Alcune persone riescono ad usarlo con successo per inviare le patch.
+
+Quando state scrivendo una lettera selezionate: Preformattato
+ da :menuselection:`Formato-->Stile del paragrafo-->Preformattato`
+ (:kbd:`CTRL-7`) o dalla barra degli strumenti
+
+Poi per inserire la patch usate:
+:menuselection:`Inserisci--> File di testo...` (:kbd:`ALT-N x`)
+
+Potete anche eseguire ``diff -Nru old.c new.c | xclip``, selezionare
+:menuselection:`Preformattato`, e poi usare il tasto centrale del mouse.
+
+Kmail (GUI)
+***********
+
+Alcune persone riescono ad usarlo con successo per inviare le patch.
+
+La configurazione base che disabilita la composizione di messaggi HTML è
+corretta; non abilitatela.
+
+Quando state scrivendo un messaggio, nel menu opzioni, togliete la selezione a
+"A capo automatico". L'unico svantaggio sarà che qualsiasi altra cosa scriviate
+nel messaggio non verrà mandata a capo in automatico ma dovrete farlo voi.
+Il modo più semplice per ovviare a questo problema è quello di scrivere il
+messaggio con l'opzione abilitata e poi di salvarlo nelle bozze. Riaprendo ora
+il messaggio dalle bozze le andate a capo saranno parte integrante del
+messaggio, per cui togliendo l'opzione "A capo automatico" non perderete nulla.
+
+Alla fine del vostro messaggio, appena prima di inserire la vostra patch,
+aggiungete il delimitatore di patch: tre trattini (``---``).
+
+Ora, dal menu :menuselection:`Messaggio`, selezionate :menuselection:`Inserisci file di testo...`
+quindi scegliete la vostra patch.
+Come soluzione aggiuntiva potreste personalizzare la vostra barra degli
+strumenti aggiungendo un'icona per :menuselection:`Inserisci file di testo...`.
+
+Allargate la finestra di scrittura abbastanza da evitare andate a capo.
+Questo perché in Kmail 1.13.5 (KDE 4.5.4), Kmail aggiunge andate a capo
+automaticamente al momento dell'invio per tutte quelle righe che graficamente,
+nella vostra finestra di composizione, si sono estete su una riga successiva.
+Disabilitare l'andata a capo automatica non è sufficiente. Dunque, se la vostra
+patch contiene delle righe molto lunghe, allora dovrete allargare la finestra
+di composizione per evitare che quelle righe vadano a capo. Vedere:
+https://bugs.kde.org/show_bug.cgi?id=174034
+
+Potete firmare gli allegati con GPG, ma per le patch si preferisce aggiungerle
+al testo del messaggio per cui non usate la firma GPG. Firmare le patch
+inserite come testo del messaggio le rende più difficili da estrarre dalla loro
+codifica a 7-bit.
+
+Se dovete assolutamente inviare delle patch come allegati invece di integrarle
+nel testo del messaggio, allora premete il tasto destro sull'allegato e
+selezionate :menuselection:`Proprietà`, e poi attivate
+:menuselection:`Suggerisci visualizzazione automatica` per far si che
+l'allegato sia più leggibile venendo visualizzato come parte del messaggio.
+
+Per salvare le patch inviate come parte di un messaggio, selezionate il
+messaggio che la contiene, premete il tasto destro e selezionate
+:menuselection:`Salva come`. Se il messaggio fu ben preparato, allora potrete
+usarlo interamente senza alcuna modifica.
+I messaggi vengono salvati con permessi di lettura-scrittura solo per l'utente,
+nel caso in cui vogliate copiarli altrove per renderli disponibili ad altri
+gruppi o al mondo, ricordatevi di usare ``chmod`` per cambiare i permessi.
+
+Lotus Notes (GUI)
+*****************
+
+Scappate finché potete.
+
+IBM Verse (Web GUI)
+*******************
+
+Vedi il commento per Lotus Notes.
+
+Mutt (TUI)
+**********
+
+Un sacco di sviluppatori Linux usano ``mutt``, per cui deve funzionare
+abbastanza bene.
+
+Mutt non ha un proprio editor, quindi qualunque sia il vostro editor dovrete
+configurarlo per non aggiungere automaticamente le andate a capo. Molti
+editor hanno un'opzione :menuselection:`Inserisci file` che inserisce il
+contenuto di un file senza alterarlo.
+
+Per usare ``vim`` come editor per mutt::
+
+ set editor="vi"
+
+Se per inserire la patch nel messaggio usate xclip, scrivete il comando::
+
+ :set paste
+
+prima di premere il tasto centrale o shift-insert. Oppure usate il
+comando::
+
+ :r filename
+
+(a)llega funziona bene senza ``set paste``
+
+Potete generare le patch con ``git format-patch`` e usare Mutt per inviarle::
+
+ $ mutt -H 0001-some-bug-fix.patch
+
+Opzioni per la configurazione:
+
+Tutto dovrebbe funzionare già nella configurazione base.
+Tuttavia, è una buona idea quella di impostare ``send_charset``::
+
+ set send_charset="us-ascii:utf-8"
+
+Mutt è molto personalizzabile. Qui di seguito trovate la configurazione minima
+per iniziare ad usare Mutt per inviare patch usando Gmail::
+
+ # .muttrc
+ # ================ IMAP ====================
+ set imap_user = 'yourusername@gmail.com'
+ set imap_pass = 'yourpassword'
+ set spoolfile = imaps://imap.gmail.com/INBOX
+ set folder = imaps://imap.gmail.com/
+ set record="imaps://imap.gmail.com/[Gmail]/Sent Mail"
+ set postponed="imaps://imap.gmail.com/[Gmail]/Drafts"
+ set mbox="imaps://imap.gmail.com/[Gmail]/All Mail"
+
+ # ================ SMTP ====================
+ set smtp_url = "smtp://username@smtp.gmail.com:587/"
+ set smtp_pass = $imap_pass
+ set ssl_force_tls = yes # Require encrypted connection
+
+ # ================ Composition ====================
+ set editor = `echo \$EDITOR`
+ set edit_headers = yes # See the headers when editing
+ set charset = UTF-8 # value of $LANG; also fallback for send_charset
+ # Sender, email address, and sign-off line must match
+ unset use_domain # because joe@localhost is just embarrassing
+ set realname = "YOUR NAME"
+ set from = "username@gmail.com"
+ set use_from = yes
+
+La documentazione di Mutt contiene molte più informazioni:
+
+ https://gitlab.com/muttmua/mutt/-/wikis/UseCases/Gmail
+
+ http://www.mutt.org/doc/manual/
+
+Pine (TUI)
+**********
+
+Pine aveva alcuni problemi con gli spazi vuoti, ma questi dovrebbero essere
+stati risolti.
+
+Se potete usate alpine (il successore di pine).
+
+Opzioni di configurazione:
+
+- Nelle versioni più recenti è necessario avere ``quell-flowed-text``
+- l'opzione ``no-strip-whitespace-before-send`` è necessaria
+
+Sylpheed (GUI)
+**************
+
+- funziona bene per aggiungere testo in linea (o usando allegati)
+- permette di utilizzare editor esterni
+- è lento su cartelle grandi
+- non farà l'autenticazione TSL SMTP su una connessione non SSL
+- ha un utile righello nella finestra di scrittura
+- la rubrica non comprende correttamente il nome da visualizzare e
+ l'indirizzo associato
+
+Thunderbird (GUI)
+*****************
+
+Thunderbird è un clone di Outlook a cui piace maciullare il testo, ma esistono
+modi per impedirglielo.
+
+Dopo la configurazione, inclusa l'installazione delle estenzioni, dovrete
+riavviare Thunderbird.
+
+- permettere l'uso di editor esterni:
+
+ La cosa più semplice da fare con Thunderbird e le patch è quello di usare
+ estensioni che permettano di aprire il vostro editor preferito.
+
+ Di seguito alcune estensioni che possono essere utili al caso.
+
+ - "External Editor Revived"
+
+ https://github.com/Frederick888/external-editor-revived
+
+ https://addons.thunderbird.net/en-GB/thunderbird/addon/external-editor-revived/
+
+ L'estensione richiede l'installazione di "native messaging host". Date
+ un'occhiata alla seguente wiki:
+ https://github.com/Frederick888/external-editor-revived/wiki
+
+ - "External Editor"
+
+ https://github.com/exteditor/exteditor
+
+ Per usarlo, scaricate ed installate l'applicazione. Poi aprite la finestra
+ :menuselection:`Scrivi` e a seguire aggiungete un bottone per eseguirlo
+ `Visualizza-->Barra degli strumenti-->Personalizza...`. Infine, premente
+ questo nuovo bottone tutte le volte che volete usare l'editor esterno.
+
+ Tenete presente che "external editor" richiede che il vostro editor non
+ faccia alcun fork, in altre parole, l'editor non deve ritornare prima di
+ essere stato chiuso. Potreste dover passare dei parametri aggiuntivi al
+ vostro editor oppure cambiargli la configurazione. Per esempio, usando
+ gvim dovrete aggiungere l'opzione -f ``/usr/bin/gvim -f`` (Se il binario
+ si trova in ``/usr/bin``) nell'apposito campo nell'interfaccia di
+ configurazione di :menuselection:`external editor`. Se usate altri editor
+ consultate il loro manuale per sapere come configurarli.``)``
+
+Per rendere l'editor interno un po' più sensato, fate così:
+
+- Modificate le impostazioni di Thunderbird per far si che non usi ``format=flowed``!
+ Andate sulla finestra principale e cercate il bottone per il menu a tendina principale.
+ Poi :menuselection:`Modifica-->Preferenze-->Avanzate-->Editor di configurazione`
+ per invocare il registro delle impostazioni.
+
+ - impostate ``mailnews.send_plaintext_flowed`` a ``false``
+
+ - impostate ``mailnews.wraplength`` da ``72`` a ``0``
+
+- Non scrivete messaggi HTML! Andate sulla finestra principale ed aprite la
+ schermata :menuselection:`Menu principale-->Impostazioni account-->nome@unserver.ovunque-->Composizioni e indirizzi`.
+ Qui potrete disabilitare l'opzione "Componi i messaggi in HTML"
+
+- Aprite i messaggi solo in formato testo! Andate sulla finestra principale e
+ selezionate
+ :menuselection:`Menu principale-->Visualizza-->Copro del messaggio come-->Testo semplice`
+
+
+TkRat (GUI)
+***********
+
+Funziona. Usare "Inserisci file..." o un editor esterno.
+
+Gmail (Web GUI)
+***************
+
+Non funziona per inviare le patch.
+
+Il programma web Gmail converte automaticamente i tab in spazi.
+
+Allo stesso tempo aggiunge andata a capo ogni 78 caratteri. Comunque
+il problema della conversione fra spazi e tab può essere risolto usando
+un editor esterno.
+
+Un altro problema è che Gmail usa la codifica base64 per tutti quei messaggi
+che contengono caratteri non ASCII. Questo include cose tipo i nomi europei.
+
+Proton Mail
+***********
+
+Il servizio Proton Mail ha una funzionalità che cripta tutti i messaggi verso
+ogni destinatario per cui è possibile trovare una chiave usando il *Web Key
+Directory* (WKD). Il servizio kernel.org pubblica il WKD per ogni sviluppatore
+in possesso di un conto kernel.org. Di conseguenza, tutti i messaggi inviati
+usando Proton Mail verso indirizzi kernel.org verranno criptati.
+
+Proton Mail non fornisce alcun meccanismo per disabilitare questa funzionalità
+perché verrebbe considerato un problema per la riservatezza. Questa funzionalità
+è attiva anche quando si inviano messaggi usando il Proton Mail Bridge. Dunque
+tutta la posta in uscita verrà criptata, incluse le patch inviate con ``git
+send-email``.
+
+I messaggi criptati sono una fonte di problemi; altri sviluppatori potrebbero
+non aver configurato i loro programmi, o strumenti, per gestire messaggi
+criptati; inoltre, alcuni programmi di posta elettronica potrebbero criptare le
+risposte a messaggi criptati per tutti i partecipanti alla discussione, inclusa
+la lista di discussione stessa.
+
+A meno che non venga introdotta una maniera per disabilitare questa
+funzionalità, non è consigliato usare Proton Mail per contribuire allo sviluppo
+del kernel.
diff --git a/Documentation/translations/it_IT/process/howto.rst b/Documentation/translations/it_IT/process/howto.rst
index 1db5a1082389..052f1b3610cb 100644
--- a/Documentation/translations/it_IT/process/howto.rst
+++ b/Documentation/translations/it_IT/process/howto.rst
@@ -44,7 +44,7 @@ altro, utili riferimenti:
- "C: A Reference Manual" di Harbison and Steele [Prentice Hall]
Il kernel è stato scritto usando GNU C e la toolchain GNU.
-Sebbene si attenga allo standard ISO C89, esso utilizza una serie di
+Sebbene si attenga allo standard ISO C11, esso utilizza una serie di
estensioni che non sono previste in questo standard. Il kernel è un
ambiente C indipendente, che non ha alcuna dipendenza dalle librerie
C standard, così alcune parti del C standard non sono supportate.
@@ -109,8 +109,7 @@ Di seguito una lista di file che sono presenti nei sorgente del kernel e che
accetteranno patch solo se queste osserveranno tali regole, e molte
persone revisioneranno il codice solo se scritto nello stile appropriato.
- :ref:`Documentation/translations/it_IT/process/submitting-patches.rst <it_submittingpatches>` e
- :ref:`Documentation/translations/it_IT/process/submitting-drivers.rst <it_submittingdrivers>`
+ :ref:`Documentation/translations/it_IT/process/submitting-patches.rst <it_submittingpatches>`
Questo file descrive dettagliatamente come creare ed inviare una patch
con successo, includendo (ma non solo questo):
@@ -357,17 +356,10 @@ benvenuti.
Riportare Bug
-------------
-https://bugzilla.kernel.org è dove gli sviluppatori del kernel Linux tracciano
-i bachi del kernel. Gli utenti sono incoraggiati nel riportare tutti i bachi
-che trovano utilizzando questo strumento.
-Per maggiori dettagli su come usare il bugzilla del kernel, guardare:
-
- https://bugzilla.kernel.org/page.cgi?id=faq.html
-
-Il file admin-guide/reporting-bugs.rst nella cartella principale del kernel
-fornisce un buon modello sul come segnalare un baco nel kernel, e spiega quali
-informazioni sono necessarie agli sviluppatori per poter aiutare il
-rintracciamento del problema.
+Il file 'Documentation/admin-guide/reporting-issues.rst' nella
+cartella principale del kernel spiega come segnalare un baco nel
+kernel, e fornisce dettagli su quali informazioni sono necessarie agli
+sviluppatori del kernel per poter studiare il problema.
Gestire i rapporti sui bug
--------------------------
@@ -380,8 +372,14 @@ al corrente della vostra presenza. Riparare bachi è una delle migliori vie per
acquisire meriti tra gli altri sviluppatori, perchè non a molte persone piace
perdere tempo a sistemare i bachi di altri.
-Per lavorare sui rapporti di bachi già riportati, andate su
-https://bugzilla.kernel.org.
+Per lavorare sui bachi già segnalati, per prima cosa cercate il
+sottosistema che vi interessa. Poi, verificate nel file MAINTAINERS
+dove vengono collezionati solitamente i bachi per quel sottosistema;
+spesso sarà una lista di discussione, raramente un bugtracker. Cercate
+bachi nell'archivio e aiutate dove credete di poterlo fare. Potete
+anche consultare https://bugzilla.kernel.org; però, solo una manciata di
+sottosistemi lo usano attivamente, ciò nonostante i bachi che
+coinvolgono l'intero kernel sono sempre riportati lì.
Liste di discussione
--------------------
@@ -396,7 +394,7 @@ trovati al sito:
Ci sono diversi archivi della lista di discussione. Usate un qualsiasi motore
di ricerca per trovarli. Per esempio:
- http://dir.gmane.org/gmane.linux.kernel
+ https://lore.kernel.org/lkml/
É caldamente consigliata una ricerca in questi archivi sul tema che volete
sollevare, prima di pubblicarlo sulla lista. Molte cose sono già state
diff --git a/Documentation/translations/it_IT/process/index.rst b/Documentation/translations/it_IT/process/index.rst
index 012de0f3154a..cd7977905fb8 100644
--- a/Documentation/translations/it_IT/process/index.rst
+++ b/Documentation/translations/it_IT/process/index.rst
@@ -10,6 +10,7 @@
.. _it_process_index:
+===============================================
Lavorare con la comunità di sviluppo del kernel
===============================================
@@ -41,12 +42,12 @@ degli sviluppatori:
:maxdepth: 1
changes
- submitting-drivers
stable-api-nonsense
management-style
stable-kernel-rules
submit-checklist
kernel-docs
+ maintainers
Ed infine, qui ci sono alcune guide più tecniche che son state messe qua solo
perché non si è trovato un posto migliore.
@@ -58,7 +59,9 @@ perché non si è trovato un posto migliore.
adding-syscalls
magic-number
volatile-considered-harmful
+ botching-up-ioctls
clang-format
+ ../riscv/patch-acceptance
.. only:: subproject and html
diff --git a/Documentation/translations/it_IT/process/kernel-docs.rst b/Documentation/translations/it_IT/process/kernel-docs.rst
index 38e0a955121a..eadcbf50a1b5 100644
--- a/Documentation/translations/it_IT/process/kernel-docs.rst
+++ b/Documentation/translations/it_IT/process/kernel-docs.rst
@@ -6,8 +6,8 @@
.. _it_kernel_docs:
-Indice di documenti per le persone interessate a capire e/o scrivere per il kernel Linux
-========================================================================================
+Ulteriore Documentazione Del Kernel Linux
+=========================================
.. note::
Questo documento contiene riferimenti a documenti in lingua inglese; inoltre
diff --git a/Documentation/translations/it_IT/process/magic-number.rst b/Documentation/translations/it_IT/process/magic-number.rst
index 783e0de314a0..ae92ab633c16 100644
--- a/Documentation/translations/it_IT/process/magic-number.rst
+++ b/Documentation/translations/it_IT/process/magic-number.rst
@@ -75,95 +75,16 @@ Registro dei cambiamenti::
Nome magico Numero Struttura File
===================== ================ ======================== ==========================================
PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/pg.h``
-CMAGIC 0x0111 user ``include/linux/a.out.h``
-MKISS_DRIVER_MAGIC 0x04bf mkiss_channel ``drivers/net/mkiss.h``
-HDLC_MAGIC 0x239e n_hdlc ``drivers/char/n_hdlc.c``
APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
-CYCLADES_MAGIC 0x4359 cyclades_port ``include/linux/cyclades.h``
-DB_MAGIC 0x4442 fc_info ``drivers/net/iph5526_novram.c``
-DL_MAGIC 0x444d fc_info ``drivers/net/iph5526_novram.c``
FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
-FF_MAGIC 0x4646 fc_info ``drivers/net/iph5526_novram.c``
-ISICOM_MAGIC 0x4d54 isi_port ``include/linux/isicom.h``
-PTY_MAGIC 0x5001 ``drivers/char/pty.c``
-PPP_MAGIC 0x5002 ppp ``include/linux/if_pppvar.h``
-SSTATE_MAGIC 0x5302 serial_state ``include/linux/serial.h``
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
-STRIP_MAGIC 0x5303 strip ``drivers/net/strip.c``
-X25_ASY_MAGIC 0x5303 x25_asy ``drivers/net/x25_asy.h``
-SIXPACK_MAGIC 0x5304 sixpack ``drivers/net/hamradio/6pack.h``
-AX25_MAGIC 0x5316 ax_disp ``drivers/net/mkiss.h``
-TTY_MAGIC 0x5401 tty_struct ``include/linux/tty.h``
-MGSL_MAGIC 0x5401 mgsl_info ``drivers/char/synclink.c``
-TTY_DRIVER_MAGIC 0x5402 tty_driver ``include/linux/tty_driver.h``
-MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c``
-TTY_LDISC_MAGIC 0x5403 tty_ldisc ``include/linux/tty_ldisc.h``
-USB_SERIAL_MAGIC 0x6702 usb_serial ``drivers/usb/serial/usb-serial.h``
-FULL_DUPLEX_MAGIC 0x6969 ``drivers/net/ethernet/dec/tulip/de2104x.c``
-USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/class/bluetty.c``
-RFCOMM_TTY_MAGIC 0x6d02 ``net/bluetooth/rfcomm/tty.c``
-USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port ``drivers/usb/serial/usb-serial.h``
-CG_MAGIC 0x00090255 ufs_cylinder_group ``include/linux/ufs_fs.h``
-RPORT_MAGIC 0x00525001 r_port ``drivers/char/rocket_int.h``
-LSEMAGIC 0x05091998 lse ``drivers/fc4/fc.c``
-GDTIOCTL_MAGIC 0x06030f07 gdth_iowr_str ``drivers/scsi/gdth_ioctl.h``
-RIEBL_MAGIC 0x09051990 ``drivers/net/atarilance.c``
-NBD_REQUEST_MAGIC 0x12560953 nbd_request ``include/linux/nbd.h``
-RED_MAGIC2 0x170fc2a5 (any) ``mm/slab.c``
BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c``
-ISDN_X25IFACE_MAGIC 0x1e75a2b9 isdn_x25iface_proto_data ``drivers/isdn/isdn_x25iface.h``
-ECP_MAGIC 0x21504345 cdkecpsig ``include/linux/cdk.h``
-LSOMAGIC 0x27091997 lso ``drivers/fc4/fc.c``
-LSMAGIC 0x2a3b4d2a ls ``drivers/fc4/fc.c``
-WANPIPE_MAGIC 0x414C4453 sdla_{dump,exec} ``include/linux/wanpipe.h``
-CS_CARD_MAGIC 0x43525553 cs_card ``sound/oss/cs46xx.c``
-LABELCL_MAGIC 0x4857434c labelcl_info_s ``include/asm/ia64/sn/labelcl.h``
-ISDN_ASYNC_MAGIC 0x49344C01 modem_info ``include/linux/isdn.h``
-CTC_ASYNC_MAGIC 0x49344C01 ctc_tty_info ``drivers/s390/net/ctctty.c``
-ISDN_NET_MAGIC 0x49344C02 isdn_net_local_s ``drivers/isdn/i4l/isdn_net_lib.h``
-SAVEKMSG_MAGIC2 0x4B4D5347 savekmsg ``arch/*/amiga/config.c``
-CS_STATE_MAGIC 0x4c4f4749 cs_state ``sound/oss/cs46xx.c``
-SLAB_C_MAGIC 0x4f17a36d kmem_cache ``mm/slab.c``
-COW_MAGIC 0x4f4f4f4d cow_header_v1 ``arch/um/drivers/ubd_user.c``
-I810_CARD_MAGIC 0x5072696E i810_card ``sound/oss/i810_audio.c``
-TRIDENT_CARD_MAGIC 0x5072696E trident_card ``sound/oss/trident.c``
-ROUTER_MAGIC 0x524d4157 wan_device [in ``wanrouter.h`` pre 3.9]
-SAVEKMSG_MAGIC1 0x53415645 savekmsg ``arch/*/amiga/config.c``
-GDA_MAGIC 0x58464552 gda ``arch/mips/include/asm/sn/gda.h``
-RED_MAGIC1 0x5a2cf071 (any) ``mm/slab.c``
-EEPROM_MAGIC_VALUE 0x5ab478d2 lanai_dev ``drivers/atm/lanai.c``
HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
-PCXX_MAGIC 0x5c6df104 channel ``drivers/char/pcxx.h``
KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``
-I810_STATE_MAGIC 0x63657373 i810_state ``sound/oss/i810_audio.c``
-TRIDENT_STATE_MAGIC 0x63657373 trient_state ``sound/oss/trident.c``
-M3_CARD_MAGIC 0x646e6f50 m3_card ``sound/oss/maestro3.c``
-FW_HEADER_MAGIC 0x65726F66 fw_header ``drivers/atm/fore200e.h``
-SLOT_MAGIC 0x67267321 slot ``drivers/hotplug/cpqphp.h``
-SLOT_MAGIC 0x67267322 slot ``drivers/hotplug/acpiphp.h``
-LO_MAGIC 0x68797548 nbd_device ``include/linux/nbd.h``
-OPROFILE_MAGIC 0x6f70726f super_block ``drivers/oprofile/oprofilefs.h``
-M3_STATE_MAGIC 0x734d724d m3_state ``sound/oss/maestro3.c``
-VMALLOC_MAGIC 0x87654320 snd_alloc_track ``sound/core/memory.c``
-KMALLOC_MAGIC 0x87654321 snd_alloc_track ``sound/core/memory.c``
-PWC_MAGIC 0x89DC10AB pwc_device ``drivers/usb/media/pwc.h``
-NBD_REPLY_MAGIC 0x96744668 nbd_reply ``include/linux/nbd.h``
-ENI155_MAGIC 0xa54b872d midway_eprom ``drivers/atm/eni.h``
CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h``
-DPMEM_MAGIC 0xc0ffee11 gdt_pci_sram ``drivers/scsi/gdth.h``
YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c``
CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c``
QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c``
QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c``
-HTB_CMAGIC 0xFEFAFEF1 htb_class ``net/sched/sch_htb.c``
NMI_MAGIC 0x48414d4d455201 nmi_s ``arch/mips/include/asm/sn/nmi.h``
===================== ================ ======================== ==========================================
-
-Da notare che ci sono anche dei numeri magici specifici per driver nel
-*sound memory management*. Consultate ``include/sound/sndmagic.h`` per una
-lista completa. Molti driver audio OSS hanno i loro numeri magici costruiti a
-partire dall'identificativo PCI della scheda audio - nemmeno questi sono
-elencati in questo file.
-
-Il file-system HFS è un altro grande utilizzatore di numeri magici - potete
-trovarli qui ``fs/hfs/hfs.h``.
diff --git a/Documentation/translations/it_IT/process/maintainer-handbooks.rst b/Documentation/translations/it_IT/process/maintainer-handbooks.rst
new file mode 100644
index 000000000000..d840145bcceb
--- /dev/null
+++ b/Documentation/translations/it_IT/process/maintainer-handbooks.rst
@@ -0,0 +1,24 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-ita.rst
+
+:Original: Documentation/process/maintainer-handbooks.rst
+:Translator: Federico Vaga <federico.vaga@vaga.pv.it>
+
+.. _it_maintainer_handbooks_main:
+
+Note sul processo di sviluppo dei sottosistemi e dei sorgenti dei manutentori
+=============================================================================
+
+Lo scopo di questo documento è quello di fornire informazioni sul processo di
+sviluppo dedicate ai sottosistemi che vanno ad integrare quelle più generali
+descritte in :ref:`Documentation/translations/it_IT/process
+<it_development_process_main>`.
+
+Indice:
+
+.. toctree::
+ :numbered:
+ :maxdepth: 2
+
+ maintainer-tip
diff --git a/Documentation/translations/it_IT/process/maintainer-pgp-guide.rst b/Documentation/translations/it_IT/process/maintainer-pgp-guide.rst
index f3c8e8d377ee..cdc43c4a9b0b 100644
--- a/Documentation/translations/it_IT/process/maintainer-pgp-guide.rst
+++ b/Documentation/translations/it_IT/process/maintainer-pgp-guide.rst
@@ -68,42 +68,24 @@ stesso.
Strumenti PGP
=============
-Usare GnuPG v2
---------------
+Usare GnuPG 2.2 o successivo
+----------------------------
La vostra distribuzione potrebbe avere già installato GnuPG, dovete solo
-verificare che stia utilizzando la versione 2.x e non la serie 1.4 --
-molte distribuzioni forniscono entrambe, di base il comando ''gpg''
-invoca GnuPG v.1. Per controllate usate::
+verificare che stia utilizzando la versione abbastanza recente. Per controllate
+usate::
$ gpg --version | head -n1
-Se visualizzate ``gpg (GnuPG) 1.4.x``, allora state usando GnuPG v.1.
-Provate il comando ``gpg2`` (se non lo avete, potreste aver bisogno
-di installare il pacchetto gnupg2)::
-
- $ gpg2 --version | head -n1
-
-Se visualizzate ``gpg (GnuPG) 2.x.x``, allora siete pronti a partire.
-Questa guida assume che abbiate la versione 2.2.(o successiva) di GnuPG.
-Se state usando la versione 2.0, alcuni dei comandi indicati qui non
-funzioneranno, in questo caso considerate un aggiornamento all'ultima versione,
-la 2.2. Versioni di gnupg-2.1.11 e successive dovrebbero essere compatibili
-per gli obiettivi di questa guida.
-
-Se avete entrambi i comandi: ``gpg`` e ``gpg2``, assicuratevi di utilizzare
-sempre la versione V2, e non quella vecchia. Per evitare errori potreste creare
-un alias::
-
- $ alias gpg=gpg2
-
-Potete mettere questa opzione nel vostro ``.bashrc`` in modo da essere sicuri.
+Se state utilizzando la version 2.2 o successiva, allora siete pronti a partire.
+Se invece state usando una versione precedente, allora alcuni comandi elencati
+in questa guida potrebbero non funzionare.
Configurare le opzioni di gpg-agent
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
L'agente GnuPG è uno strumento di aiuto che partirà automaticamente ogni volta
-che userete il comando ``gpg`` e funzionerà in background con l'obiettivo di
+che userete il comando ``gpg`` e funzionerà in *background* con l'obiettivo di
individuare la passphrase. Ci sono due opzioni che dovreste conoscere
per personalizzare la scadenza della passphrase nella cache:
@@ -131,19 +113,7 @@ valori::
riguarda vecchie le versioni di GnuPG, poiché potrebbero non svolgere più
bene il loro compito.
-Impostare un *refresh* con cronjob
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Potreste aver bisogno di rinfrescare regolarmente il vostro portachiavi in
-modo aggiornare le chiavi pubbliche di altre persone, lavoro che è svolto
-al meglio con un cronjob giornaliero::
-
- @daily /usr/bin/gpg2 --refresh >/dev/null 2>&1
-
-Controllate il percorso assoluto del vostro comando ``gpg`` o ``gpg2`` e usate
-il comando ``gpg2`` se per voi ``gpg`` corrisponde alla versione GnuPG v.1.
-
-.. _it_master_key:
+.. _it_protect_your_key:
Proteggere la vostra chiave PGP primaria
========================================
@@ -155,55 +125,62 @@ al documento "`Protecting Code Integrity`_" che abbiamo menzionato prima.
Dovreste inoltre creare una nuova chiave se quella attuale è inferiore a 2048
bit (RSA).
-Chiave principale o sottochiavi
--------------------------------
-
-Le sottochiavi sono chiavi PGP totalmente indipendenti, e sono collegate alla
-chiave principale attraverso firme certificate. È quindi importante
-comprendere i seguenti punti:
-
-1. Non ci sono differenze tecniche tra la chiave principale e la sottochiave.
-2. In fesa di creazione, assegniamo limitazioni funzionali ad ogni chiave
- assegnando capacità specifiche.
-3. Una chiave PGP può avere 4 capacità:
+Le sottochiavi PGP
+------------------
- - **[S]** può essere usata per firmare
- - **[E]** può essere usata per criptare
- - **[A]** può essere usata per autenticare
- - **[C]** può essere usata per certificare altre chiavi
+Raramente le chiavi PGP sono composte da una singola coppia -- solitamente, sono
+una collezione di sottochiavi indipendenti usate per diversi scopi in funzione
+delle capacità assegnate al momento della creazione. Una chiave PGP può avere
+quattro capacità:
+
+- **[S]** può essere usata per firmare
+- **[E]** può essere usata per criptare
+- **[A]** può essere usata per autenticare
+- **[C]** può essere usata per certificare altre chiavi
+
+La chiave con la capacità **[C]** viene spesso chiamata chiave "passepartout"
+(*master key*), ma è una terminologia fuorviante perché lascia intendere che la
+chiave di certificato possa essere usate in sostituzione delle altre (proprio
+come le vere chiavi passpartout in grado di aprire diverse serrature). Dato che
+questo non è il caso, per evitare fraintendimenti, in questa guida ci riferiremo
+a questa chiave chiamandola "La chiave di certificazione".
+
+I seguenti punti sono molto importanti:
+
+1. Tutte le sottochiavi sono indipendenti. Se perdete una sottochiave privata
+ non potrete recuperarla usando le altre.
+2. Ad eccezione della chiave di certificazione, ci possono essere più
+ sottochiavi con le stesse capacità (per esempio, potete avere 2 sottochiavi
+ per criptare, 3 per firmare, ma solo una per una sola per certificare). Tutte
+ le sottochiavi sono indipendenti -- un messaggio criptato usando una chiave
+ **[E]** non può essere decriptato usano altre sottochiavi **[E]**.
+3. Una sottochiave può avere più capacità (per esempio, la chiave **[C]** può
+ anche essere una chiave **[S]**).
+
+La chiave con capacità **[C]** (certificazione) è la sola che può essere usata
+per indicare relazioni fra chiavi. Solo la chiave **[C]** può essere usata per:
+
+- aggiungere o revocare altre chiavi (sottochiavi) che hanno capacità S/E/A;
+- aggiungere, modificare o eliminare le identità (unids) associate alla chiave;
+- aggiungere o modificare la propria data di scadenza o delle sottochiavi;
+- firmare le chiavi di altre persone a scopo di creare una rete di fiducia.
-4. Una singola chiave può avere più capacità
-5. Una sottochiave è completamente indipendente dalla chiave principale.
- Un messaggio criptato con la sottochiave non può essere decrittato con
- quella principale. Se perdete la vostra sottochiave privata, non può
- essere rigenerata in nessun modo da quella principale.
+Di base, alla creazione di nuove chiavi, GnuPG genera quanto segue:
-La chiave con capacità **[C]** (certify) è identificata come la chiave
-principale perché è l'unica che può essere usata per indicare la relazione
-con altre chiavi. Solo la chiave **[C]** può essere usata per:
+- Una chiave la capacità di certificazione che quella di firma (**[SC]**)
+- Una sottochiave separata con capacità di criptare (**[E]**)
-- Aggiungere o revocare altre chiavi (sottochiavi) che hanno capacità S/E/A
-- Aggiungere, modificare o eliminare le identità (unids) associate alla chiave
-- Aggiungere o modificare la data di termine di sé stessa o di ogni sottochiave
-- Firmare le chiavi di altre persone a scopo di creare una rete di fiducia
-Di base, alla creazione di nuove chiavi, GnuPG genera quanto segue:
-- Una chiave madre che porta sia la capacità di certificazione che quella
- di firma (**[SC]**)
-- Una sottochiave separata con capacità di criptaggio (**[E]**)
-Se avete usato i parametri di base per generare la vostra chiave, quello
+Se avete usato i parametri predefiniti per generare la vostra chiave, quello
sarà il risultato. Potete verificarlo utilizzando ``gpg --list-secret-keys``,
per esempio::
- sec rsa2048 2018-01-23 [SC] [expires: 2020-01-23]
+ sec ed25519 2022-12-20 [SC] [expires: 2024-12-19]
000000000000000000000000AAAABBBBCCCCDDDD
uid [ultimate] Alice Dev <adev@kernel.org>
- ssb rsa2048 2018-01-23 [E] [expires: 2020-01-23]
-
-Qualsiasi chiave che abbia la capacità **[C]** è la vostra chiave madre,
-indipendentemente da quali altre capacità potreste averle assegnato.
+ ssb cv25519 2022-12-20 [E] [expires: 2024-12-19]
La lunga riga sotto la voce ``sec`` è la vostra impronta digitale --
negli esempi che seguono, quando vedere ``[fpr]`` ci si riferisce a questa
@@ -238,20 +215,10 @@ possano ricevere la vostra nuova sottochiave::
$ gpg --send-key [fpr]
.. note:: Supporto ECC in GnuPG
- GnuPG 2.1 e successivi supportano pienamente *Elliptic Curve Cryptography*,
- con la possibilità di combinare sottochiavi ECC con le tradizionali chiavi
- primarie RSA. Il principale vantaggio della crittografia ECC è che è molto
- più veloce da calcolare e crea firme più piccole se confrontate byte per
- byte con le chiavi RSA a più di 2048 bit. A meno che non pensiate di
- utilizzare un dispositivo smartcard che non supporta le operazioni ECC, vi
- raccomandiamo ti creare sottochiavi di firma ECC per il vostro lavoro col
- kernel.
-
- Se per qualche ragione preferite rimanere con sottochiavi RSA, nel comando
- precedente, sostituite "ed25519" con "rsa2048". In aggiunta, se avete
- intenzione di usare un dispositivo hardware che non supporta le chiavi
- ED25519 ECC, come la Nitrokey Pro o la Yubikey, allora dovreste usare
- "nistp256" al posto di "ed25519".
+
+ Tenete presente che se avete intenzione di usare un dispositivo che non
+ supporta chiavi ED25519 ECC, allora dovreste usare "nistp256" al posto di
+ "ed25519". Più avanti ci sono alcune raccomandazioni per i dispositivi.
Copia di riserva della chiave primaria per gestire il recupero da disastro
--------------------------------------------------------------------------
@@ -286,9 +253,7 @@ magari in una cassetta di sicurezza in banca.
Probabilmente la vostra stampante non è più quello stupido dispositivo
connesso alla porta parallela, ma dato che il suo output è comunque
criptato con la passphrase, eseguire la stampa in un sistema "cloud"
- moderno dovrebbe essere comunque relativamente sicuro. Un'opzione potrebbe
- essere quella di cambiare la passphrase della vostra chiave primaria
- subito dopo aver finito con paperkey.
+ moderno dovrebbe essere comunque relativamente sicuro.
Copia di riserva di tutta la cartella GnuPG
-------------------------------------------
@@ -362,13 +327,13 @@ Per prima cosa, identificate il keygrip della vostra chiave primaria::
L'output assomiglierà a questo::
- pub rsa2048 2018-01-24 [SC] [expires: 2020-01-24]
+ pub ed25519 2022-12-20 [SC] [expires: 2022-12-19]
000000000000000000000000AAAABBBBCCCCDDDD
Keygrip = 1111000000000000000000000000000000000000
uid [ultimate] Alice Dev <adev@kernel.org>
- sub rsa2048 2018-01-24 [E] [expires: 2020-01-24]
+ sub cv25519 2022-12-20 [E] [expires: 2022-12-19]
Keygrip = 2222000000000000000000000000000000000000
- sub ed25519 2018-01-24 [S]
+ sub ed25519 2022-12-20 [S]
Keygrip = 3333000000000000000000000000000000000000
Trovate la voce keygrid che si trova sotto alla riga ``pub`` (appena sotto
@@ -391,11 +356,11 @@ Ora, se eseguite il comando ``--list-secret-keys``, vedrete che la chiave
primaria non compare più (il simbolo ``#`` indica che non è disponibile)::
$ gpg --list-secret-keys
- sec# rsa2048 2018-01-24 [SC] [expires: 2020-01-24]
+ sec# ed25519 2022-12-20 [SC] [expires: 2024-12-19]
000000000000000000000000AAAABBBBCCCCDDDD
uid [ultimate] Alice Dev <adev@kernel.org>
- ssb rsa2048 2018-01-24 [E] [expires: 2020-01-24]
- ssb ed25519 2018-01-24 [S]
+ ssb cv25519 2022-12-20 [E] [expires: 2024-12-19]
+ ssb ed25519 2022-12-20 [S]
Dovreste rimuovere anche i file ``secring.gpg`` che si trovano nella cartella
``~/.gnupg``, in quanto rimasugli delle versioni precedenti di GnuPG.
@@ -463,18 +428,20 @@ soluzioni disponibili:
computer portatili più recenti. In aggiunta, offre altre funzionalità di
sicurezza come FIDO, U2F, e ora supporta anche le chiavi ECC (NISTP)
-`Su LWN c'è una buona recensione`_ dei modelli elencati qui sopra e altri.
-La scelta dipenderà dal costo, dalla disponibilità nella vostra area
-geografica e vostre considerazioni sull'hardware aperto/proprietario.
+La vostra scelta dipenderà dal costo, la disponibilità nella vostra regione, e
+sulla scelta fra dispositivi aperti e proprietari.
-Se volete usare chiavi ECC, la vostra migliore scelta sul mercato è la
-Nitrokey Start.
+.. note::
+
+ Se siete nella lista MAINTAINERS o avete un profilo su kernel.org, allora
+ `potrete avere gratuitamente una Nitrokey Start`_ grazie alla fondazione
+ Linux.
.. _`Nitrokey Start`: https://shop.nitrokey.com/shop/product/nitrokey-start-6
.. _`Nitrokey Pro 2`: https://shop.nitrokey.com/shop/product/nitrokey-pro-2-3
.. _`Yubikey 5`: https://www.yubico.com/product/yubikey-5-overview/
-.. _Gnuk: http://www.fsij.org/doc-gnuk/
-.. _`Su LWN c'è una buona recensione`: https://lwn.net/Articles/736231/
+.. _Gnuk: https://www.fsij.org/doc-gnuk/
+.. _`potrete avere gratuitamente una Nitrokey Start`: https://www.kernel.org/nitrokey-digital-tokens-for-kernel-developers.html
Configurare il vostro dispositivo smartcard
-------------------------------------------
@@ -515,6 +482,12 @@ altre informazioni sulla carta che potrebbero trapelare in caso di smarrimento.
A dispetto del nome "PIN", né il PIN utente né quello dell'amministratore
devono essere esclusivamente numerici.
+.. warning::
+
+ Alcuni dispositivi richiedono la presenza delle sottochiavi nel dispositivo
+ stesso prima che possiate cambiare la passphare. Verificate la
+ documentazione del produttore.
+
Spostare le sottochiavi sulla smartcard
---------------------------------------
@@ -527,11 +500,11 @@ dell'amministratore::
Secret subkeys are available.
- pub rsa2048/AAAABBBBCCCCDDDD
- created: 2018-01-23 expires: 2020-01-23 usage: SC
+ pub ed25519/AAAABBBBCCCCDDDD
+ created: 2022-12-20 expires: 2024-12-19 usage: SC
trust: ultimate validity: ultimate
- ssb rsa2048/1111222233334444
- created: 2018-01-23 expires: never usage: E
+ ssb cv25519/1111222233334444
+ created: 2022-12-20 expires: never usage: E
ssb ed25519/5555666677778888
created: 2017-12-07 expires: never usage: S
[ultimate] (1). Alice Dev <adev@kernel.org>
@@ -596,11 +569,11 @@ Ora, se doveste usare l'opzione ``--list-secret-keys``, vedrete una
sottile differenza nell'output::
$ gpg --list-secret-keys
- sec# rsa2048 2018-01-24 [SC] [expires: 2020-01-24]
+ sec# ed25519 2022-12-20 [SC] [expires: 2024-12-19]
000000000000000000000000AAAABBBBCCCCDDDD
uid [ultimate] Alice Dev <adev@kernel.org>
- ssb> rsa2048 2018-01-24 [E] [expires: 2020-01-24]
- ssb> ed25519 2018-01-24 [S]
+ ssb> cv25519 2022-12-20 [E] [expires: 2024-12-19]
+ ssb> ed25519 2022-12-20 [S]
Il simbolo ``>`` in ``ssb>`` indica che la sottochiave è disponibile solo
nella smartcard. Se tornate nella vostra cartella delle chiavi segrete e
@@ -663,7 +636,7 @@ eseguite::
Se per voi è più facile da memorizzare, potete anche utilizzare una data
specifica (per esempio, il vostro compleanno o capodanno)::
- $ gpg --quick-set-expire [fpr] 2020-07-01
+ $ gpg --quick-set-expire [fpr] 2025-07-01
Ricordatevi di inviare l'aggiornamento ai keyserver::
@@ -678,6 +651,21 @@ dovreste importarle nella vostra cartella di lavoro abituale::
$ gpg --export | gpg --homedir ~/.gnupg --import
$ unset GNUPGHOME
+Usare gpg-agent con ssh
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Se dovete firmare tag o commit su un sistema remoto, potete ridirezionare il
+vostro gpg-agent attraverso ssh. Consultate le istruzioni disponibili nella wiki
+GnuPG:
+
+- `Agent Forwarding over SSH`_
+
+Funziona senza troppi intoppi se avete la possibilità di modificare le
+impostazioni di sshd sul sistema remoto.
+
+.. _`Agent Forwarding over SSH`: https://wiki.gnupg.org/AgentForwarding
+
+.. _it_pgp_with_git:
Usare PGP con Git
=================
@@ -711,11 +699,6 @@ avere più chiavi segrete, potete dire a git quale dovrebbe usare (``[fpg]``
$ git config --global user.signingKey [fpr]
-**IMPORTANTE**: se avete una comando dedicato per ``gpg2``, allora dovreste
-dire a git di usare sempre quello piuttosto che il vecchio comando ``gpg``::
-
- $ git config --global gpg.program gpg2
-
Come firmare i tag
------------------
@@ -814,6 +797,61 @@ Potete dire a git di firmare sempre i commit::
.. _it_verify_identities:
+Come lavorare con patch firmate
+-------------------------------
+
+Esiste la possibilità di usare la vostra chiave PGP per firmare le patch che
+invierete alla liste di discussione del kernel. I meccanismi esistenti per la
+firma delle email (PGP-Mime o PGP-inline) tendono a causare problemi
+nell'attività di revisione del codice. Si suggerisce, invece, di utilizare lo
+strumento sviluppato da kernel.org che mette nell'intestazione del messaggio
+un'attestazione delle firme crittografiche (tipo DKIM):
+
+- `Patatt Patch Attestation`_
+
+.. _`Patatt Patch Attestation`: https://pypi.org/project/patatt/
+
+Installare e configurate patatt
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Lo strumento patatt è disponibile per diverse distribuzioni, dunque cercatelo
+prima lì. Oppure potete installarlo usano pypi "``pip install patatt``"
+
+Se avete già configurato git con la vostra chiave PGP (usando
+``user.signingKey``), allora patatt non ha bisogno di alcuna configurazione
+aggiuntiva. Potete iniziare a firmare le vostre patch aggiungendo un aggancio a
+git-send-email nel vostro repositorio::
+
+ patatt install-hook
+
+Ora, qualsiasi patch che invierete con ``git send-email`` verrà automaticamente
+firmata usando la vostra firma crittografica.
+
+Verificare le firme di patatt
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Se usate ``b4`` per verificare ed applicare le patch, allora tenterà
+automaticamente di verificare tutte le firme DKIM e patatt disponibili. Per
+esempio::
+
+ $ b4 am 20220720205013.890942-1-broonie@kernel.org
+ [...]
+ Checking attestation on all messages, may take a moment...
+ ---
+ ✓ [PATCH v1 1/3] kselftest/arm64: Correct buffer allocation for SVE Z registers
+ ✓ [PATCH v1 2/3] arm64/sve: Document our actual ABI for clearing registers on syscall
+ ✓ [PATCH v1 3/3] kselftest/arm64: Enforce actual ABI for SVE syscalls
+ ---
+ ✓ Signed: openpgp/broonie@kernel.org
+ ✓ Signed: DKIM/kernel.org
+
+.. note::
+
+ Lo sviluppo di patatt e b4 è piuttosto attivo. Si consiglia di verificare la
+ documentazione più recente.
+
+.. _it_kernel_identities:
+
Come verificare l'identità degli sviluppatori del kernel
========================================================
@@ -886,68 +924,18 @@ di base di GnuPG v2). Per farlo, aggiungete (o modificate) l'impostazione
trust-model tofu+pgp
-Come usare i keyserver in sicurezza
------------------------------------
-Se ottenete l'errore "No public key" quando cercate di validate il tag di
-qualcuno, allora dovreste cercare quella chiave usando un keyserver. È
-importante tenere bene a mente che non c'è alcuna garanzia che la chiave
-che avete recuperato da un keyserver PGP appartenga davvero alla persona
-reale -- è progettato così. Dovreste usare il Web of Trust per assicurarvi
-che la chiave sia valida.
-
-Come mantenere il Web of Trust va oltre gli scopi di questo documento,
-semplicemente perché farlo come si deve richiede sia sforzi che perseveranza
-che tendono ad andare oltre al livello di interesse della maggior parte degli
-esseri umani. Qui di seguito alcuni rapidi suggerimenti per aiutarvi a ridurre
-il rischio di importare chiavi maligne.
-
-Primo, diciamo che avete provato ad eseguire ``git verify-tag`` ma restituisce
-un errore dicendo che la chiave non è stata trovata::
-
- $ git verify-tag sunxi-fixes-for-4.15-2
- gpg: Signature made Sun 07 Jan 2018 10:51:55 PM EST
- gpg: using RSA key DA73759BF8619E484E5A3B47389A54219C0F2430
- gpg: issuer "wens@...org"
- gpg: Can't check signature: No public key
-
-Cerchiamo nel keyserver per maggiori informazioni sull'impronta digitale
-della chiave (l'impronta digitale, probabilmente, appartiene ad una
-sottochiave, dunque non possiamo usarla direttamente senza trovare prima
-l'ID della chiave primaria associata ad essa)::
-
- $ gpg --search DA73759BF8619E484E5A3B47389A54219C0F2430
- gpg: data source: hkp://keys.gnupg.net
- (1) Chen-Yu Tsai <wens@...org>
- 4096 bit RSA key C94035C21B4F2AEB, created: 2017-03-14, expires: 2019-03-15
- Keys 1-1 of 1 for "DA73759BF8619E484E5A3B47389A54219C0F2430". Enter number(s), N)ext, or Q)uit > q
-
-Localizzate l'ID della chiave primaria, nel nostro esempio
-``C94035C21B4F2AEB``. Ora visualizzate le chiavi di Linus Torvalds
-che avete nel vostro portachiavi::
-
- $ gpg --list-key torvalds@kernel.org
- pub rsa2048 2011-09-20 [SC]
- ABAF11C65A2970B130ABE3C479BE3E4300411886
- uid [ unknown] Linus Torvalds <torvalds@kernel.org>
- sub rsa2048 2011-09-20 [E]
-
-Poi, aprite il `PGP pathfinder`_. Nel campo "From", incollate l'impronta
-digitale della chiave di Linus Torvalds che si vede nell'output qui sopra.
-Nel campo "to", incollate il key-id della chiave sconosciuta che avete
-trovato con ``gpg --search``, e poi verificare il risultato:
-
-- `Finding paths to Linus`_
-
-Se trovate un paio di percorsi affidabili è un buon segno circa la validità
-della chiave. Ora, potete aggiungerla al vostro portachiavi dal keyserver::
-
- $ gpg --recv-key C94035C21B4F2AEB
-
-Questa procedura non è perfetta, e ovviamente state riponendo la vostra
-fiducia nell'amministratore del servizio *PGP Pathfinder* sperando che non
-sia malintenzionato (infatti, questo va contro :ref:`it_devs_not_infra`).
-Tuttavia, se mantenete con cura la vostra rete di fiducia sarà un deciso
-miglioramento rispetto alla cieca fiducia nei keyserver.
-
-.. _`PGP pathfinder`: https://pgp.cs.uu.nl/
-.. _`Finding paths to Linus`: https://pgp.cs.uu.nl/paths/79BE3E4300411886/to/C94035C21B4F2AEB.html
+Usare il repositorio kernel.org per il web of trust
+---------------------------------------------------
+
+Il progetto kernel.org mantiene un repositorio git con le chiavi pubbliche degli sviluppatori in alternativa alla replica dei server di chiavi che negli ultimi anni sono spariti. La documentazione completa su come impostare il repositorio come vostra sorgente di chiavi pubbliche può essere trovato qui:
+
+- `Kernel developer PGP Keyring`_
+
+Se siete uno sviluppatore del kernel, per favore valutate l'idea di inviare la
+vostra chiave per l'inclusione in quel portachiavi.
+
+
+If you are a kernel developer, please consider submitting your key for
+inclusion into that keyring.
+
+.. _`Kernel developer PGP Keyring`: https://korg.docs.kernel.org/pgpkeys.html
diff --git a/Documentation/translations/it_IT/process/maintainer-tip.rst b/Documentation/translations/it_IT/process/maintainer-tip.rst
new file mode 100644
index 000000000000..126f17ee541e
--- /dev/null
+++ b/Documentation/translations/it_IT/process/maintainer-tip.rst
@@ -0,0 +1,10 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-ita.rst
+
+:Original: Documentation/process/maintainer-tip.rst
+
+Il tascabile dei sorgenti tip
+=============================
+
+.. note:: To be translated
diff --git a/Documentation/translations/it_IT/process/maintainers.rst b/Documentation/translations/it_IT/process/maintainers.rst
new file mode 100644
index 000000000000..3225f7c89fda
--- /dev/null
+++ b/Documentation/translations/it_IT/process/maintainers.rst
@@ -0,0 +1,13 @@
+:Original: Documentation/process/maintainers.rst
+
+Lista dei manutentori e come inviare modifiche al kernel
+========================================================
+
+Questa pagina non verrà tradotta. Fate riferimento alla versione originale in
+inglese.
+
+.. note:: La pagina originale usa una direttiva speciale per integrare il file
+ `MAINTAINERS` in sphinx. La parte di quel documento che si potrebbe
+ tradurre contiene comunque informazioni già presenti in
+ :ref:`Documentation/translations/it_IT/process/submitting-patches.rst
+ <it_submittingpatches>`.
diff --git a/Documentation/translations/it_IT/process/management-style.rst b/Documentation/translations/it_IT/process/management-style.rst
index 07e68bfb8402..76ed074082ea 100644
--- a/Documentation/translations/it_IT/process/management-style.rst
+++ b/Documentation/translations/it_IT/process/management-style.rst
@@ -1,12 +1,295 @@
.. include:: ../disclaimer-ita.rst
-:Original: :ref:`Documentation/process/management-style.rst <managementstyle>`
+:Original: :doc:`../../../process/management-style`
+:Translator: Alessia Mantegazza <amantegazza@vaga.pv.it>
.. _it_managementstyle:
-Tipo di gestione del kernel Linux
-=================================
+Il modello di gestione del kernel Linux
+=======================================
-.. warning::
+Questo breve documento descrive il modello di gestione del kernel Linux.
+Per certi versi, esso rispecchia il documento
+:ref:`translations/it_IT/process/coding-style.rst <it_codingstyle>`,
+ed è principalmente scritto per evitare di rispondere [#f1]_ in continuazione
+alle stesse identiche (o quasi) domande.
- TODO ancora da tradurre
+Il modello di gestione è qualcosa di molto personale e molto più difficile da
+qualificare rispetto a delle semplici regole di codifica, quindi questo
+documento potrebbe avere più o meno a che fare con la realtà. È cominciato
+come un gioco, ma ciò non significa che non possa essere vero.
+Lo dovrete decidere voi stessi.
+
+In ogni caso, quando si parla del "dirigente del kernel", ci si riferisce
+sempre alla persona che dirige tecnicamente, e non a coloro che
+tradizionalmente hanno un ruolo direttivo all'interno delle aziende. Se vi
+occupate di convalidare acquisti o avete una qualche idea sul budget del vostro
+gruppo, probabilmente non siete un dirigente del kernel. Quindi i suggerimenti
+qui indicati potrebbero fare al caso vostro, oppure no.
+
+Prima di tutto, suggerirei di acquistare "Le sette regole per avere successo",
+e di non leggerlo. Bruciatelo, è un grande gesto simbolico.
+
+.. [#f1] Questo documento non fa molto per risponde alla domanda, ma rende
+ così dannatamente ovvio a chi la pone che non abbiamo la minima idea
+ di come rispondere.
+
+Comunque, partiamo:
+
+.. _it_decisions:
+
+1) Le decisioni
+---------------
+
+Tutti pensano che i dirigenti decidano, e che questo prendere decisioni
+sia importante. Più grande e dolorosa è la decisione, più importante deve
+essere il dirigente che la prende. Questo è molto profondo ed ovvio, ma non è
+del tutto vero.
+
+Il gioco consiste nell'"evitare" di dover prendere decisioni. In particolare
+se qualcuno vi chiede di "Decidere" tra (a) o (b), e vi dice che ha
+davvero bisogno di voi per questo, come dirigenti siete nei guai.
+Le persone che gestite devono conoscere i dettagli più di quanto li conosciate
+voi, quindi se vengono da voi per una decisione tecnica, siete fottuti.
+Non sarete chiaramente competente per prendere quella decisione per loro.
+
+(Corollario: se le persone che gestite non conoscono i dettagli meglio di voi,
+anche in questo caso sarete fregati, tuttavia per altre ragioni. Ossia state
+facendo il lavoro sbagliato, e che invece dovrebbero essere "loro" a gestirvi)
+
+Quindi il gioco si chiama "evitare" decisioni, almeno le più grandi e
+difficili. Prendere decisioni piccoli e senza conseguenze va bene, e vi fa
+sembrare competenti in quello che state facendo, quindi quello che un dirigente
+del kernel ha bisogno di fare è trasformare le decisioni grandi e difficili
+in minuzie delle quali nessuno importa.
+
+Ciò aiuta a capire che la differenza chiave tra una grande decisione ed una
+piccola sta nella possibilità di modificare tale decisione in seguito.
+Qualsiasi decisione importante può essere ridotta in decisioni meno importanti,
+ma dovete assicurarvi che possano essere reversibili in caso di errori
+(presenti o futuri). Improvvisamente, dovrete essere doppiamente dirigenti
+per **due** decisioni non sequenziali - quella sbagliata **e** quella giusta.
+
+E le persone vedranno tutto ciò come prova di vera capacità di comando
+(*cough* cavolata *cough*)
+
+Così la chiave per evitare le decisioni difficili diviene l'evitare
+di fare cose che non possono essere disfatte. Non infilatevi in un angolo
+dal quale non potrete sfuggire. Un topo messo all'angolo può rivelarsi
+pericoloso - un dirigente messo all'angolo è solo pietoso.
+
+**In ogni caso** dato che nessuno è stupido al punto da lasciare veramente ad
+un dirigente del kernel un enorme responsabilità, solitamente è facile fare
+marcia indietro. Annullare una decisione è molto facile: semplicemente dite a
+tutti che siete stati degli scemi incompetenti, dite che siete dispiaciuti, ed
+annullate tutto l'inutile lavoro sul quale gli altri hanno lavorato nell'ultimo
+anno. Improvvisamente la decisione che avevate preso un anno fa non era poi
+così grossa, dato che può essere facilmente annullata.
+
+È emerso che alcune persone hanno dei problemi con questo tipo di approccio,
+questo per due ragioni:
+
+ - ammettere di essere degli idioti è più difficile di quanto sembri. A tutti
+ noi piace mantenere le apparenze, ed uscire allo scoperto in pubblico per
+ ammettere che ci si è sbagliati è qualcosa di davvero impegnativo.
+ - avere qualcuno che ti dice che ciò su cui hai lavorato nell'ultimo anno
+ non era del tutto valido, può rivelarsi difficile anche per un povero ed
+ umile ingegnere, e mentre il **lavoro** vero era abbastanza facile da
+ cancellare, dall'altro canto potreste aver irrimediabilmente perso la
+ fiducia di quell'ingegnere. E ricordate che l'"irrevocabile" era quello
+ che avevamo cercato di evitare fin dall'inizio, e la vostra decisione
+ ha finito per esserlo.
+
+Fortunatamente, entrambe queste ragioni posso essere mitigate semplicemente
+ammettendo fin dal principio che non avete una cavolo di idea, dicendo
+agli altri in anticipo che la vostra decisione è puramente ipotetica, e che
+potrebbe essere sbagliata. Dovreste sempre riservarvi il diritto di cambiare
+la vostra opinione, e rendere gli altri ben **consapevoli** di ciò.
+Ed è molto più facile ammettere di essere stupidi quando non avete **ancora**
+fatto quella cosa stupida.
+
+Poi, quando è realmente emersa la vostra stupidità, le persone semplicemente
+roteeranno gli occhi e diranno "Uffa, no, ancora".
+
+Questa ammissione preventiva di incompetenza potrebbe anche portare le persone
+che stanno facendo il vero lavoro, a pensarci due volte. Dopo tutto, se
+**loro** non sono certi se sia una buona idea, voi, sicuro come la morte,
+non dovreste incoraggiarli promettendogli che ciò su cui stanno lavorando
+verrà incluso. Fate si che ci pensino due volte prima che si imbarchino in un
+grosso lavoro.
+
+Ricordate: loro devono sapere più cose sui dettagli rispetto a voi, e
+solitamente pensano di avere già la risposta a tutto. La miglior cosa che
+potete fare in qualità di dirigente è di non instillare troppa fiducia, ma
+invece fornire una salutare dose di pensiero critico su quanto stanno facendo.
+
+Comunque, un altro modo di evitare una decisione è quello di lamentarsi
+malinconicamente dicendo : "non possiamo farli entrambi e basta?" e con uno
+sguardo pietoso. Fidatevi, funziona. Se non è chiaro quale sia il miglior
+approccio, lo scopriranno. La risposta potrebbe essere data dal fatto che
+entrambe i gruppi di lavoro diventano frustati al punto di rinunciarvi.
+
+Questo può suonare come un fallimento, ma di solito questo è un segno che
+c'era qualcosa che non andava in entrambe i progetti, e il motivo per
+il quale le persone coinvolte non abbiano potuto decidere era che entrambe
+sbagliavano. Voi ne uscirete freschi come una rosa, e avrete evitato un'altra
+decisione con la quale avreste potuto fregarvi.
+
+
+2) Le persone
+-------------
+
+Ci sono molte persone stupide, ed essere un dirigente significa che dovrete
+scendere a patti con questo, e molto più importate, che **loro** devono avere
+a che fare con **voi**.
+
+Ne emerge che mentre è facile annullare degli errori tecnici, non è invece
+così facile rimuovere i disordini della personalità. Dovrete semplicemente
+convivere con i loro, ed i vostri, problemi.
+
+Comunque, al fine di preparavi in qualità di dirigenti del kernel, è meglio
+ricordare di non abbattere alcun ponte, bombardare alcun paesano innocente,
+o escludere troppi sviluppatori kernel. Ne emerge che escludere le persone
+è piuttosto facile, mentre includerle nuovamente è difficile. Così
+"l'esclusione" immediatamente cade sotto il titolo di "non reversibile", e
+diviene un no-no secondo la sezione :ref:`it_decisions`.
+
+Esistono alcune semplici regole qui:
+
+ (1) non chiamate le persone teste di c*** (al meno, non in pubblico)
+ (2) imparate a scusarvi quando dimenticate la regola (1)
+
+Il problema del punto numero 1 è che è molto facile da rispettare, dato che
+è possibile dire "sei una testa di c***" in milioni di modi differenti [#f2]_,
+a volte senza nemmeno pensarci, e praticamente sempre con la calda convinzione
+di essere nel giusto.
+
+E più convinti sarete che avete ragione (e diciamolo, potete chiamare
+praticamente **tutti** testa di c**, e spesso **sarete** nel giusto), più
+difficile sarà scusarvi successivamente.
+
+Per risolvere questo problema, avete due possibilità:
+
+ - diventare davvero bravi nello scusarsi
+ - essere amabili così che nessuno finirà col sentirsi preso di mira. Siate
+ creativi abbastanza, e potrebbero esserne divertiti.
+
+L'opzione dell'essere immancabilmente educati non esiste proprio. Nessuno
+si fiderà di qualcuno che chiaramente sta nascondendo il suo vero carattere.
+
+.. [#f2] Paul Simon cantava: "50 modi per lasciare il vostro amante", perché,
+ molto francamente, "Un milione di modi per dire ad uno sviluppatore
+ Testa di c***" non avrebbe funzionato. Ma sono sicuro che ci abbia
+ pensato.
+
+
+3) Le persone II - quelle buone
+-------------------------------
+
+Mentre emerge che la maggior parte delle persone sono stupide, il corollario
+a questo è il triste fatto che anche voi siete fra queste, e che mentre
+possiamo tutti crogiolarci nella sicurezza di essere migliori della media
+delle persone (diciamocelo, nessuno crede di essere nelle media o sotto di
+essa), dovremmo anche ammettere che non siamo il "coltello più affilato" del
+circondario, e che ci saranno altre persone che sono meno stupide di quanto
+lo siete voi.
+
+Molti reagiscono male davanti alle persone intelligenti. Altri le usano a
+proprio vantaggio.
+
+Assicuratevi che voi, in qualità di manutentori del kernel, siate nel secondo
+gruppo. Inchinatevi dinanzi a loro perché saranno le persone che vi renderanno
+il lavoro più facile. In particolare, prenderanno le decisioni per voi, che è
+l'oggetto di questo gioco.
+
+Quindi quando trovate qualcuno più sveglio di voi, prendetevela comoda.
+Le vostre responsabilità dirigenziali si ridurranno in gran parte nel dire
+"Sembra una buona idea - Vai", oppure "Sembra buono, ma invece circa questo e
+quello?". La seconda versione in particolare è una gran modo per imparare
+qualcosa di nuovo circa "questo e quello" o di sembrare **extra** dirigenziali
+sottolineando qualcosa alla quale i più svegli non avevano pensato. In
+entrambe i casi, vincete.
+
+Una cosa alla quale dovete fare attenzione è che l'essere grandi in qualcosa
+non si traduce automaticamente nell'essere grandi anche in altre cose. Quindi
+dovreste dare una spintarella alle persone in una specifica direzione, ma
+diciamocelo, potrebbero essere bravi in ciò che fanno e far schifo in tutto
+il resto. La buona notizia è che le persone tendono a gravitare attorno a ciò
+in cui sono bravi, quindi non state facendo nulla di irreversibile quando li
+spingete verso una certa direzione, solo non spingete troppo.
+
+
+4) Addossare le colpe
+---------------------
+
+Le cose andranno male, e le persone vogliono qualcuno da incolpare. Sarete voi.
+
+Non è poi così difficile accettare la colpa, specialmente se le persone
+riescono a capire che non era **tutta** colpa vostra. Il che ci porta
+sulla miglior strada per assumersi la colpa: fatelo per qualcun'altro.
+Vi sentirete bene nel assumervi la responsabilità, e loro si sentiranno
+bene nel non essere incolpati, e coloro che hanno perso i loro 36GB di
+pornografia a causa della vostra incompetenza ammetteranno a malincuore che
+almeno non avete cercato di fare il furbetto.
+
+Successivamente fate in modo che gli sviluppatori che in realtà hanno fallito
+(se riuscite a trovarli) sappiano **in privato** che sono "fottuti".
+Questo non per fargli sapere che la prossima volta possono evitarselo ma per
+fargli capire che sono in debito. E, forse cosa più importante, sono loro che
+devono sistemare la cosa. Perché, ammettiamolo, è sicuro non sarete voi a
+farlo.
+
+Assumersi la colpa è anche ciò che vi rendere dirigenti in prima battuta.
+È parte di ciò che spinge gli altri a fidarsi di voi, e vi garantisce
+la gloria potenziale, perché siete gli unici a dire "Ho fatto una cavolata".
+E se avete seguito le regole precedenti, sarete decisamente bravi nel dirlo.
+
+
+5) Le cose da evitare
+---------------------
+
+Esiste una cosa che le persone odiano più che essere chiamate "teste di c****",
+ed è essere chiamate "teste di c****" con fare da bigotto. Se per il primo
+caso potrete comunque scusarvi, per il secondo non ve ne verrà data nemmeno
+l'opportunità. Probabilmente smetteranno di ascoltarvi anche se tutto sommato
+state svolgendo un buon lavoro.
+
+Tutti crediamo di essere migliori degli altri, il che significa che quando
+qualcuno inizia a darsi delle arie, ci da **davvero** fastidio. Potreste anche
+essere moralmente ed intellettualmente superiore a tutti quelli attorno a voi,
+ma non cercate di renderlo ovvio per gli altri a meno che non **vogliate**
+veramente far arrabbiare qualcuno [#f3]_.
+
+Allo stesso modo evitate di essere troppo gentili e pacati. Le buone maniere
+facilmente finiscono per strabordare e nascondere i problemi, e come si usa
+dire, "su internet nessuno può sentire la vostra pacatezza". Usate argomenti
+diretti per farvi capire, non potete sperare che la gente capisca in altro
+modo.
+
+Un po' di umorismo può aiutare a smorzare sia la franchezza che la moralità.
+Andare oltre i limiti al punto d'essere ridicolo può portare dei punti a casa
+senza renderlo spiacevole per i riceventi, i quali penseranno che stavate
+facendo gli scemi. Può anche aiutare a lasciare andare quei blocchi mentali
+che abbiamo nei confronti delle critiche.
+
+.. [#f3] Suggerimento: i forum di discussione su internet, che non sono
+ collegati col vostro lavoro, sono ottimi modi per sfogare la frustrazione
+ verso altre persone. Di tanto in tanto scrivete messaggi offensivi col ghigno
+ in faccia per infiammare qualche discussione: vi sentirete purificati. Solo
+ cercate di non cagare troppo vicino a casa.
+
+6) Perché io?
+-------------
+
+Dato che la vostra responsabilità principale è quella di prendervi le colpe
+d'altri, e rendere dolorosamente ovvio a tutti che siete degli incompetenti,
+la domanda naturale che ne segue sarà : perché dovrei fare tutto ciò?
+
+Innanzitutto, potreste diventare o no popolari al punto da avere la fila di
+ragazzine (o ragazzini, evitiamo pregiudizi o sessismo) che gridano e bussano
+alla porta del vostro camerino, ma comunque **proverete** un immenso senso di
+realizzazione personale dall'essere "in carica". Dimenticate il fatto che voi
+state discutendo con tutti e che cercate di inseguirli il più velocemente che
+potete. Tutti continueranno a pensare che voi siete la persona in carica.
+
+È un bel lavoro se riuscite ad adattarlo a voi.
diff --git a/Documentation/translations/it_IT/process/programming-language.rst b/Documentation/translations/it_IT/process/programming-language.rst
index f4b006395849..5bc5b9d42f31 100644
--- a/Documentation/translations/it_IT/process/programming-language.rst
+++ b/Documentation/translations/it_IT/process/programming-language.rst
@@ -8,26 +8,24 @@
Linguaggio di programmazione
============================
-Il kernel è scritto nel linguaggio di programmazione C [c-language]_.
-Più precisamente, il kernel viene compilato con ``gcc`` [gcc]_ usando
-l'opzione ``-std=gnu89`` [gcc-c-dialect-options]_: il dialetto GNU
-dello standard ISO C90 (con l'aggiunta di alcune funzionalità da C99)
+Il kernel è scritto nel linguaggio di programmazione C [it-c-language]_.
+Più precisamente, il kernel viene compilato con ``gcc`` [it-gcc]_ usando
+l'opzione ``-std=gnu11`` [it-gcc-c-dialect-options]_: il dialetto GNU
+dello standard ISO C11.
+Linux supporta anche ``clang`` [it-clang]_, leggete la documentazione
+:ref:`Building Linux with Clang/LLVM <kbuild_llvm>`.
-Questo dialetto contiene diverse estensioni al linguaggio [gnu-extensions]_,
+Questo dialetto contiene diverse estensioni al linguaggio [it-gnu-extensions]_,
e molte di queste vengono usate sistematicamente dal kernel.
-Il kernel offre un certo livello di supporto per la compilazione con ``clang``
-[clang]_ e ``icc`` [icc]_ su diverse architetture, tuttavia in questo momento
-il supporto non è completo e richiede delle patch aggiuntive.
-
Attributi
---------
Una delle estensioni più comuni e usate nel kernel sono gli attributi
-[gcc-attribute-syntax]_. Gli attributi permettono di aggiungere una semantica,
+[it-gcc-attribute-syntax]_. Gli attributi permettono di aggiungere una semantica,
definita dell'implementazione, alle entità del linguaggio (come le variabili,
le funzioni o i tipi) senza dover fare importanti modifiche sintattiche al
-linguaggio stesso (come l'aggiunta di nuove parole chiave) [n2049]_.
+linguaggio stesso (come l'aggiunta di nuove parole chiave) [it-n2049]_.
In alcuni casi, gli attributi sono opzionali (ovvero un compilatore che non
dovesse supportarli dovrebbe produrre comunque codice corretto, anche se
@@ -41,11 +39,30 @@ possono usare e/o per accorciare il codice.
Per maggiori informazioni consultate il file d'intestazione
``include/linux/compiler_attributes.h``.
-.. [c-language] http://www.open-std.org/jtc1/sc22/wg14/www/standards
-.. [gcc] https://gcc.gnu.org
-.. [clang] https://clang.llvm.org
-.. [icc] https://software.intel.com/en-us/c-compilers
-.. [gcc-c-dialect-options] https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html
-.. [gnu-extensions] https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html
-.. [gcc-attribute-syntax] https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html
-.. [n2049] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2049.pdf
+Rust
+----
+
+Il kernel supporta sperimentalmente il linguaggio di programmazione Rust
+[it-rust-language]_ abilitando l'opzione di configurazione ``CONFIG_RUST``. Il
+codice verrà compilato usando ``rustc`` [it-rustc]_ con l'opzione
+``--edition=2021`` [it-rust-editions]_. Le edizioni Rust sono un modo per
+introdurre piccole modifiche senza compatibilità all'indietro._
+
+In aggiunta, nel kernel vengono utilizzate alcune funzionalità considerate
+instabili [it-rust-unstable-features]_. Queste funzionalità potrebbero cambiare
+in futuro, dunque è un'obiettivo importante è quello di far uso solo di
+funzionalità stabili.
+
+Per maggiori informazioni fate riferimento a Documentation/rust/index.rst .
+
+.. [it-c-language] http://www.open-std.org/jtc1/sc22/wg14/www/standards
+.. [it-gcc] https://gcc.gnu.org
+.. [it-clang] https://clang.llvm.org
+.. [it-gcc-c-dialect-options] https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html
+.. [it-gnu-extensions] https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html
+.. [it-gcc-attribute-syntax] https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html
+.. [it-n2049] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2049.pdf
+.. [it-rust-language] https://www.rust-lang.org
+.. [it-rustc] https://doc.rust-lang.org/rustc/
+.. [it-rust-editions] https://doc.rust-lang.org/edition-guide/editions/
+.. [it-rust-unstable-features] https://github.com/Rust-for-Linux/linux/issues/2
diff --git a/Documentation/translations/it_IT/process/stable-kernel-rules.rst b/Documentation/translations/it_IT/process/stable-kernel-rules.rst
index 4f206cee31a7..248bf1e4b171 100644
--- a/Documentation/translations/it_IT/process/stable-kernel-rules.rst
+++ b/Documentation/translations/it_IT/process/stable-kernel-rules.rst
@@ -41,16 +41,10 @@ Regole sul tipo di patch che vengono o non vengono accettate nei sorgenti
Procedura per sottomettere patch per i sorgenti -stable
-------------------------------------------------------
- - Se la patch contiene modifiche a dei file nelle cartelle net/ o drivers/net,
- allora seguite le linee guida descritte in
- :ref:`Documentation/translations/it_IT/networking/netdev-FAQ.rst <it_netdev-FAQ>`;
- ma solo dopo aver verificato al seguente indirizzo che la patch non sia
- già in coda:
- https://patchwork.ozlabs.org/bundle/davem/stable/?series=&submitter=&state=*&q=&archive=
- - Una patch di sicurezza non dovrebbero essere gestite (solamente) dal processo
- di revisione -stable, ma dovrebbe seguire le procedure descritte in
- :ref:`Documentation/translations/it_IT/admin-guide/security-bugs.rst <it_securitybugs>`.
-
+.. note::
+ Una patch di sicurezza non dovrebbe essere gestita (solamente) dal processo
+ di revisione -stable, ma dovrebbe seguire le procedure descritte in
+ :ref:`Documentation/translations/it_IT/admin-guide/security-bugs.rst <it_securitybugs>`.
Per tutte le altre sottomissioni, scegliere una delle seguenti procedure
------------------------------------------------------------------------
@@ -96,9 +90,9 @@ L':ref:`it_option_2` e l':ref:`it_option_3` sono più utili quando, al momento
dell'inclusione dei sorgenti principali, si ritiene che non debbano essere
incluse anche in quelli stabili (per esempio, perché si crede che si dovrebbero
fare più verifiche per eventuali regressioni). L':ref:`it_option_3` è
-particolarmente utile se la patch ha bisogno di qualche modifica per essere
-applicata ad un kernel più vecchio (per esempio, perché nel frattempo l'API è
-cambiata).
+particolarmente utile se una patch dev'essere riportata su una versione
+precedente (per esempio la patch richiede modifiche a causa di cambiamenti di
+API).
Notate che per l':ref:`it_option_3`, se la patch è diversa da quella nei
sorgenti principali (per esempio perché è stato necessario un lavoro di
@@ -112,6 +106,12 @@ al messaggio della patch, così:
commit <sha1> upstream.
+o in alternativa:
+
+.. code-block:: none
+
+ [ Upstream commit <sha1> ]
+
In aggiunta, alcune patch inviate attraverso l':ref:`it_option_1` potrebbero
dipendere da altre che devo essere incluse. Questa situazione può essere
indicata nel seguente modo nell'area dedicata alle firme:
@@ -173,9 +173,18 @@ Ciclo di una revisione
della lista linux-kernel obietta la bontà della patch, sollevando problemi
che i manutentori ed i membri non avevano compreso, allora la patch verrà
rimossa dalla coda.
- - Alla fine del ciclo di revisione tutte le patch che hanno ricevuto l'ACK
- verranno aggiunte per il prossimo rilascio -stable, e successivamente
- questo nuovo rilascio verrà fatto.
+ - Le patch che hanno ricevuto un ACK verranno inviate nuovamente come parte di
+ un rilascio candidato (-rc) al fine di essere verificate dagli sviluppatori e
+ dai testatori.
+ - Solitamente si pubblica solo una -rc, tuttavia se si riscontrano problemi
+ importanti, alcune patch potrebbero essere modificate o essere scartate,
+ oppure nuove patch potrebbero essere messe in coda. Dunque, verranno pubblicate
+ nuove -rc e così via finché non si ritiene che non vi siano più problemi.
+ - Si può rispondere ad una -rc scrivendo sulla lista di discussione un'email
+ con l'etichetta "Tested-by:". Questa etichetta verrà raccolta ed aggiunta al
+ commit rilascio.
+ - Alla fine del ciclo di revisione il nuovo rilascio -stable conterrà tutte le
+ patch che erano in coda e sono state verificate.
- Le patch di sicurezza verranno accettate nei sorgenti -stable direttamente
dalla squadra per la sicurezza del kernel, e non passerà per il normale
ciclo di revisione. Contattate la suddetta squadra per maggiori dettagli
@@ -192,8 +201,19 @@ Sorgenti
- Il rilascio definitivo, e marchiato, di tutti i kernel stabili può essere
trovato in rami distinti per versione al seguente indirizzo:
- https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
+ https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
+
+ - I rilasci candidati di tutti i kernel stabili possono essere trovati al
+ seguente indirizzo:
+
+ https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git/
+
+ .. warning::
+ I sorgenti -stable-rc sono un'istantanea dei sorgenti stable-queue e
+ subirà frequenti modifiche, dunque verrà anche trapiantato spesso.
+ Dovrebbe essere usato solo allo scopo di verifica (per esempio in un
+ sistema di CI)
Comitato per la revisione
-------------------------
diff --git a/Documentation/translations/it_IT/process/submit-checklist.rst b/Documentation/translations/it_IT/process/submit-checklist.rst
index 995ee69fab11..2fc09cc1f0be 100644
--- a/Documentation/translations/it_IT/process/submit-checklist.rst
+++ b/Documentation/translations/it_IT/process/submit-checklist.rst
@@ -28,6 +28,10 @@ sottomissione delle patch, in particolare
c) quando si usa ``O=builddir``
+ d) Qualsiasi modifica in Documentation/ deve compilare con successo senza
+ avvisi o errori. Usare ``make htmldocs`` o ``make pdfdocs`` per verificare
+ e correggere i problemi
+
3) Compilare per diverse architetture di processore usando strumenti per
la cross-compilazione o altri.
@@ -54,8 +58,7 @@ sottomissione delle patch, in particolare
9) Verificare con sparse.
-10) Usare ``make checkstack`` e ``make namespacecheck`` e correggere tutti i
- problemi rilevati.
+10) Usare ``make checkstack`` e correggere tutti i problemi rilevati.
.. note::
@@ -95,31 +98,29 @@ sottomissione delle patch, in particolare
informazioni. Le patch che modificano le interfacce utente dovrebbero
essere inviate in copia anche a linux-api@vger.kernel.org.
-20) Verifica che il kernel passi con successo ``make headers_check``
-
-21) La patch è stata verificata con l'iniezione di fallimenti in slab e
+20) La patch è stata verificata con l'iniezione di fallimenti in slab e
nell'allocazione di pagine. Vedere ``Documentation/fault-injection/``.
Se il nuovo codice è corposo, potrebbe essere opportuno aggiungere
l'iniezione di fallimenti specifici per il sottosistema.
-22) Il nuovo codice è stato compilato con ``gcc -W`` (usate
- ``make EXTRA_CFLAGS=-W``). Questo genererà molti avvisi, ma è ottimo
+21) Il nuovo codice è stato compilato con ``gcc -W`` (usate
+ ``make KCFLAGS=-W``). Questo genererà molti avvisi, ma è ottimo
per scovare bachi come "warning: comparison between signed and unsigned".
-23) La patch è stata verificata dopo essere stata inclusa nella serie di patch
+22) La patch è stata verificata dopo essere stata inclusa nella serie di patch
-mm; questo al fine di assicurarsi che continui a funzionare assieme a
tutte le altre patch in coda e i vari cambiamenti nei sottosistemi VM, VFS
e altri.
-24) Tutte le barriere di sincronizzazione {per esempio, ``barrier()``,
+23) Tutte le barriere di sincronizzazione {per esempio, ``barrier()``,
``rmb()``, ``wmb()``} devono essere accompagnate da un commento nei
sorgenti che ne spieghi la logica: cosa fanno e perché.
-25) Se la patch aggiunge nuove chiamate ioctl, allora aggiornate
- ``Documentation/ioctl/ioctl-number.rst``.
+24) Se la patch aggiunge nuove chiamate ioctl, allora aggiornate
+ ``Documentation/userspace-api/ioctl/ioctl-number.rst``.
-26) Se il codice che avete modificato dipende o usa una qualsiasi interfaccia o
+25) Se il codice che avete modificato dipende o usa una qualsiasi interfaccia o
funzionalità del kernel che è associata a uno dei seguenti simboli
``Kconfig``, allora verificate che il kernel compili con diverse
configurazioni dove i simboli sono disabilitati e/o ``=m`` (se c'è la
diff --git a/Documentation/translations/it_IT/process/submitting-drivers.rst b/Documentation/translations/it_IT/process/submitting-drivers.rst
deleted file mode 100644
index dadd77e47613..000000000000
--- a/Documentation/translations/it_IT/process/submitting-drivers.rst
+++ /dev/null
@@ -1,16 +0,0 @@
-.. include:: ../disclaimer-ita.rst
-
-:Original: :ref:`Documentation/process/submitting-drivers.rst <submittingdrivers>`
-:Translator: Federico Vaga <federico.vaga@vaga.pv.it>
-
-.. _it_submittingdrivers:
-
-Sottomettere driver per il kernel Linux
-=======================================
-
-.. note::
-
- Questo documento è vecchio e negli ultimi anni non è stato più aggiornato;
- dovrebbe essere aggiornato, o forse meglio, rimosso. La maggior parte di
- quello che viene detto qui può essere trovato anche negli altri documenti
- dedicati allo sviluppo. Per questo motivo il documento non verrà tradotto.
diff --git a/Documentation/translations/it_IT/process/submitting-patches.rst b/Documentation/translations/it_IT/process/submitting-patches.rst
index cba1f8cb61ed..f91c8092844f 100644
--- a/Documentation/translations/it_IT/process/submitting-patches.rst
+++ b/Documentation/translations/it_IT/process/submitting-patches.rst
@@ -14,23 +14,24 @@ una certa familiarità col "sistema". Questo testo è una raccolta di
suggerimenti che aumenteranno significativamente le probabilità di vedere le
vostre patch accettate.
-Questo documento contiene un vasto numero di suggerimenti concisi. Per
-maggiori dettagli su come funziona il processo di sviluppo del kernel leggete
-:ref:`Documentation/translations/it_IT/process <it_development_process_main>`.
-Leggete anche :ref:`Documentation/translations/it_IT/process/submit-checklist.rst <it_submitchecklist>`
-per una lista di punti da verificare prima di inviare del codice. Se state
-inviando un driver, allora leggete anche :ref:`Documentation/translations/it_IT/process/submitting-drivers.rst <it_submittingdrivers>`;
-per delle patch relative alle associazioni per Device Tree leggete
-Documentation/devicetree/bindings/submitting-patches.txt.
-
-Molti di questi passi descrivono il comportamento di base del sistema di
-controllo di versione ``git``; se utilizzate ``git`` per preparare le vostre
-patch molto del lavoro più ripetitivo lo troverete già fatto per voi, tuttavia
-dovete preparare e documentare un certo numero di patch. Generalmente, l'uso
-di ``git`` renderà la vostra vita di sviluppatore del kernel più facile.
-
-0) Ottenere i sorgenti attuali
-------------------------------
+Questo documento contiene un vasto numero di suggerimenti concisi. Per maggiori
+dettagli su come funziona il processo di sviluppo del kernel leggete
+Documentation/translations/it_IT/process/development-process.rst. Leggete anche
+Documentation/translations/it_IT/process/submit-checklist.rst per una lista di
+punti da verificare prima di inviare del codice.
+Per delle patch relative alle associazioni per Device Tree leggete
+Documentation/translations/it_IT/process/submitting-patches.rst.
+
+Questa documentazione assume che sappiate usare ``git`` per preparare le patch.
+Se non siete pratici di ``git``, allora è bene che lo impariate;
+renderà la vostra vita di sviluppatore del kernel molto più semplice.
+
+I sorgenti di alcuni sottosistemi e manutentori contengono più informazioni
+riguardo al loro modo di lavorare ed aspettative. Consultate
+:ref:`Documentation/translations/it_IT/process/maintainer-handbooks.rst <it_maintainer_handbooks_main>`
+
+Ottenere i sorgenti attuali
+---------------------------
Se non avete un repositorio coi sorgenti del kernel più recenti, allora usate
``git`` per ottenerli. Vorrete iniziare col repositorio principale che può
@@ -45,69 +46,10 @@ Guardate l'elemento **T:** per un determinato sottosistema nel file MAINTANERS
che troverete nei sorgenti, o semplicemente chiedete al manutentore nel caso
in cui i sorgenti da usare non siano elencati il quel file.
-Esiste ancora la possibilità di scaricare un rilascio del kernel come archivio
-tar (come descritto in una delle prossime sezioni), ma questa è la via più
-complicata per sviluppare per il kernel.
-
-1) ``diff -up``
----------------
-
-Se dovete produrre le vostre patch a mano, usate ``diff -up`` o ``diff -uprN``
-per crearle. Git produce di base le patch in questo formato; se state
-usando ``git``, potete saltare interamente questa sezione.
-
-Tutte le modifiche al kernel Linux avvengono mediate patch, come descritte
-in :manpage:`diff(1)`. Quando create la vostra patch, assicuratevi di
-crearla nel formato "unified diff", come l'argomento ``-u`` di
-:manpage:`diff(1)`.
-Inoltre, per favore usate l'argomento ``-p`` per mostrare la funzione C
-alla quale si riferiscono le diverse modifiche - questo rende il risultato
-di ``diff`` molto più facile da leggere. Le patch dovrebbero essere basate
-sulla radice dei sorgenti del kernel, e non sulle sue sottocartelle.
-
-Per creare una patch per un singolo file, spesso è sufficiente fare::
-
- SRCTREE=linux
- MYFILE=drivers/net/mydriver.c
-
- cd $SRCTREE
- cp $MYFILE $MYFILE.orig
- vi $MYFILE # make your change
- cd ..
- diff -up $SRCTREE/$MYFILE{.orig,} > /tmp/patch
-
-Per creare una patch per molteplici file, dovreste spacchettare i sorgenti
-"vergini", o comunque non modificati, e fare un ``diff`` coi vostri.
-Per esempio::
-
- MYSRC=/devel/linux
-
- tar xvfz linux-3.19.tar.gz
- mv linux-3.19 linux-3.19-vanilla
- diff -uprN -X linux-3.19-vanilla/Documentation/dontdiff \
- linux-3.19-vanilla $MYSRC > /tmp/patch
-
-``dontdiff`` è una lista di file che sono generati durante il processo di
-compilazione del kernel; questi dovrebbero essere ignorati in qualsiasi
-patch generata con :manpage:`diff(1)`.
-
-Assicuratevi che la vostra patch non includa file che non ne fanno veramente
-parte. Al fine di verificarne la correttezza, assicuratevi anche di
-revisionare la vostra patch -dopo- averla generata con :manpage:`diff(1)`.
-
-Se le vostre modifiche producono molte differenze, allora dovrete dividerle
-in patch indipendenti che modificano le cose in passi logici; leggete
-:ref:`split_changes`. Questo faciliterà la revisione da parte degli altri
-sviluppatori, il che è molto importante se volete che la patch venga accettata.
-
-Se state utilizzando ``git``, ``git rebase -i`` può aiutarvi nel procedimento.
-Se non usate ``git``, un'alternativa popolare è ``quilt``
-<http://savannah.nongnu.org/projects/quilt>.
-
.. _it_describe_changes:
-2) Descrivete le vostre modifiche
----------------------------------
+Descrivete le vostre modifiche
+------------------------------
Descrivete il vostro problema. Esiste sempre un problema che via ha spinto
ha fare il vostro lavoro, che sia la correzione di un baco da una riga o una
@@ -144,11 +86,11 @@ comporti come descritto.
I manutentori vi saranno grati se scrivete la descrizione della patch in un
formato che sia compatibile con il gestore dei sorgenti usato dal kernel,
-``git``, come un "commit log". Leggete :ref:`it_explicit_in_reply_to`.
+``git``, come un "commit log". Leggete :ref:`it_the_canonical_patch_format`.
Risolvete solo un problema per patch. Se la vostra descrizione inizia ad
essere lunga, potrebbe essere un segno che la vostra patch necessita d'essere
-divisa. Leggete :ref:`split_changes`.
+divisa. Leggete :ref:`it_split_changes`.
Quando inviate o rinviate una patch o una serie, includete la descrizione
completa delle modifiche e la loro giustificazione. Non limitatevi a dire che
@@ -164,17 +106,28 @@ do frotz" piuttosto che "[This patch] makes xyzzy do frotz" or "[I] changed
xyzzy to do frotz", come se steste dando ordini al codice di cambiare il suo
comportamento.
-Se la patch corregge un baco conosciuto, fare riferimento a quel baco inserendo
-il suo numero o il suo URL. Se la patch è la conseguenza di una discussione
-su una lista di discussione, allora fornite l'URL all'archivio di quella
-discussione; usate i collegamenti a https://lkml.kernel.org/ con il
-``Message-Id``, in questo modo vi assicurerete che il collegamento non diventi
-invalido nel tempo.
+Se ci sono delle discussioni, o altre informazioni d'interesse, che fanno
+riferimento alla patch, allora aggiungete l'etichetta 'Link:' per farvi
+riferimento. Per esempio, se la vostra patch corregge un baco potete aggiungere
+quest'etichetta per fare riferimento ad un rapporto su una lista di discussione
+o un *bug tracker*. Un altro esempio; potete usare quest'etichetta per far
+riferimento ad una discussione precedentemente avvenuta su una lista di
+discussione, o qualcosa di documentato sul web, da cui poi è nata la patch in
+questione.
-Tuttavia, cercate di rendere la vostra spiegazione comprensibile anche senza
-far riferimento a fonti esterne. In aggiunta ai collegamenti a bachi e liste
-di discussione, riassumente i punti più importanti della discussione che hanno
-portato alla creazione della patch.
+Quando volete fare riferimento ad una lista di discussione, preferite il
+servizio d'archiviazione lore.kernel.org. Per create un collegamento URL è
+sufficiente usare il campo ``Message-Id``, presente nell'intestazione del
+messaggio, senza parentesi angolari. Per esempio::
+
+ Link: https://lore.kernel.org/r/30th.anniversary.repost@klaava.Helsinki.FI/
+
+Prima d'inviare il messaggio ricordatevi di verificare che il collegamento così
+creato funzioni e che indirizzi verso il messaggio desiderato.
+
+Tuttavia, provate comunque a dare una spiegazione comprensibile anche senza
+accedere alle fonti esterne. Inoltre, riassumente i punti più salienti che hanno
+condotto all'invio della patch.
Se volete far riferimento a uno specifico commit, non usate solo
l'identificativo SHA-1. Per cortesia, aggiungete anche la breve riga
@@ -208,10 +161,15 @@ precedente::
[pretty]
fixes = Fixes: %h (\"%s\")
+Un esempio::
+
+ $ git log -1 --pretty=fixes 54a4f0239f2e
+ Fixes: 54a4f0239f2e ("KVM: MMU: make kvm_mmu_zap_page() return the number of pages it actually freed")
+
.. _it_split_changes:
-3) Separate le vostre modifiche
--------------------------------
+Separate le vostre modifiche
+----------------------------
Separate ogni **cambiamento logico** in patch distinte.
@@ -249,7 +207,7 @@ ed integrate.
---------------------------------------------
Controllate che la vostra patch non violi lo stile del codice, maggiori
-dettagli sono disponibili in :ref:`Documentation/translations/it_IT/process/coding-style.rst <it_codingstyle>`.
+dettagli sono disponibili in Documentation/translations/it_IT/process/coding-style.rst.
Non farlo porta semplicemente a una perdita di tempo da parte dei revisori e
voi vedrete la vostra patch rifiutata, probabilmente senza nemmeno essere stata
letta.
@@ -281,18 +239,19 @@ nella vostra patch.
Dovreste sempre inviare una copia della patch ai manutentori dei sottosistemi
interessati dalle modifiche; date un'occhiata al file MAINTAINERS e alla storia
-delle revisioni per scoprire chi si occupa del codice. Lo script
-scripts/get_maintainer.pl può esservi d'aiuto. Se non riuscite a trovare un
-manutentore per il sottosistema su cui state lavorando, allora Andrew Morton
-(akpm@linux-foundation.org) sarà la vostra ultima possibilità.
-
-Normalmente, dovreste anche scegliere una lista di discussione a cui inviare
-la vostra serie di patch. La lista di discussione linux-kernel@vger.kernel.org
-è proprio l'ultima spiaggia, il volume di email su questa lista fa si che
-diversi sviluppatori non la seguano. Guardate nel file MAINTAINERS per trovare
-la lista di discussione dedicata ad un sottosistema; probabilmente lì la vostra
-patch riceverà molta più attenzione. Tuttavia, per favore, non spammate le
-liste di discussione che non sono interessate al vostro lavoro.
+delle revisioni per scoprire chi si occupa del codice. Lo script
+scripts/get_maintainer.pl può esservi d'aiuto (passategli il percorso alle
+vostre patch). Se non riuscite a trovare un manutentore per il sottosistema su
+cui state lavorando, allora Andrew Morton (akpm@linux-foundation.org) sarà la
+vostra ultima possibilità.
+
+Normalmente, dovreste anche scegliere una lista di discussione a cui inviare la
+vostra serie di patch. La lista di discussione linux-kernel@vger.kernel.org
+dovrebbe essere usata per inviare tutte le patch, ma il traffico è tale per cui
+diversi sviluppatori la trascurano. Guardate nel file MAINTAINERS per trovare la
+lista di discussione dedicata ad un sottosistema; probabilmente lì la vostra
+patch riceverà molta più attenzione. Tuttavia, per favore, non spammate le liste
+di discussione che non sono interessate al vostro lavoro.
Molte delle liste di discussione relative al kernel vengono ospitate su
vger.kernel.org; potete trovare un loro elenco alla pagina
@@ -312,7 +271,8 @@ sfruttato, inviatela a security@kernel.org. Per bachi importanti, un breve
embargo potrebbe essere preso in considerazione per dare il tempo alle
distribuzioni di prendere la patch e renderla disponibile ai loro utenti;
in questo caso, ovviamente, la patch non dovrebbe essere inviata su alcuna
-lista di discussione pubblica.
+lista di discussione pubblica. Leggete anche
+Documentation/process/security-bugs.rst.
Patch che correggono bachi importanti su un kernel già rilasciato, dovrebbero
essere inviate ai manutentori dei kernel stabili aggiungendo la seguente riga::
@@ -321,12 +281,7 @@ essere inviate ai manutentori dei kernel stabili aggiungendo la seguente riga::
nella vostra patch, nell'area dedicata alle firme (notate, NON come destinatario
delle e-mail). In aggiunta a questo file, dovreste leggere anche
-:ref:`Documentation/translations/it_IT/process/stable-kernel-rules.rst <it_stable_kernel_rules>`
-
-Tuttavia, notate, che alcuni manutentori di sottosistema preferiscono avere
-l'ultima parola su quali patch dovrebbero essere aggiunte ai kernel stabili.
-La rete di manutentori, in particolare, non vorrebbe vedere i singoli
-sviluppatori aggiungere alle loro patch delle righe come quella sopracitata.
+Documentation/translations/it_IT/process/stable-kernel-rules.rst.
Se le modifiche hanno effetti sull'interfaccia con lo spazio utente, per favore
inviate una patch per le pagine man ai manutentori di suddette pagine (elencati
@@ -335,27 +290,8 @@ cosicché l'informazione possa trovare la sua strada nel manuale. Le modifiche
all'API dello spazio utente dovrebbero essere inviate in copia anche a
linux-api@vger.kernel.org.
-Per le piccole patch potreste aggiungere in CC l'indirizzo
-*Trivial Patch Monkey trivial@kernel.org* che ha lo scopo di raccogliere
-le patch "banali". Date uno sguardo al file MAINTAINERS per vedere chi
-è l'attuale amministratore.
-
-Le patch banali devono rientrare in una delle seguenti categorie:
-
-- errori grammaticali nella documentazione
-- errori grammaticali negli errori che potrebbero rompere :manpage:`grep(1)`
-- correzione di avvisi di compilazione (riempirsi di avvisi inutili è negativo)
-- correzione di errori di compilazione (solo se correggono qualcosa sul serio)
-- rimozione di funzioni/macro deprecate
-- sostituzione di codice non potabile con uno portabile (anche in codice
- specifico per un'architettura, dato che le persone copiano, fintanto che
- la modifica sia banale)
-- qualsiasi modifica dell'autore/manutentore di un file (in pratica
- "patch monkey" in modalità ritrasmissione)
-
-
-6) Niente: MIME, links, compressione, allegati. Solo puro testo
-----------------------------------------------------------------
+Niente: MIME, links, compressione, allegati. Solo puro testo
+-------------------------------------------------------------
Linus e gli altri sviluppatori del kernel devono poter commentare
le modifiche che sottomettete. Per uno sviluppatore è importante
@@ -364,7 +300,11 @@ programmi di posta elettronica, cosicché sia possibile commentare
una porzione specifica del vostro codice.
Per questa ragione tutte le patch devono essere inviate via e-mail
-come testo.
+come testo. Il modo più facile, e quello raccomandato, è con ``git
+send-email``. Al sito https://git-send-email.io è disponibile una
+guida interattiva sull'uso di ``git send-email``.
+
+Se decidete di non usare ``git send-email``:
.. warning::
@@ -381,37 +321,38 @@ così la possibilità che il vostro allegato-MIME venga accettato.
Eccezione: se il vostro servizio di posta storpia le patch, allora qualcuno
potrebbe chiedervi di rinviarle come allegato MIME.
-Leggete :ref:`Documentation/translations/it_IT/process/email-clients.rst <it_email_clients>`
+Leggete Documentation/translations/it_IT/process/email-clients.rst
per dei suggerimenti sulla configurazione del programmi di posta elettronica
per l'invio di patch intatte.
-7) Dimensione delle e-mail
---------------------------
-
-Le grosse modifiche non sono adatte ad una lista di discussione, e nemmeno
-per alcuni manutentori. Se la vostra patch, non compressa, eccede i 300 kB
-di spazio, allora caricatela in una spazio accessibile su internet fornendo
-l'URL (collegamento) ad essa. Ma notate che se la vostra patch eccede i 300 kB
-è quasi certo che necessiti comunque di essere spezzettata.
-
-8) Rispondere ai commenti di revisione
---------------------------------------
+Rispondere ai commenti di revisione
+-----------------------------------
-Quasi certamente i revisori vi invieranno dei commenti su come migliorare
-la vostra patch. Dovete rispondere a questi commenti; ignorare i revisori
-è un ottimo modo per essere ignorati. Riscontri o domande che non conducono
-ad una modifica del codice quasi certamente dovrebbero portare ad un commento
-nel changelog cosicché il prossimo revisore potrà meglio comprendere cosa stia
-accadendo.
+In risposta alla vostra email, quasi certamente i revisori vi
+invieranno dei commenti su come migliorare la vostra patch. Dovete
+rispondere a questi commenti; ignorare i revisori è un ottimo modo per
+essere ignorati. Riscontri o domande che non conducono ad una
+modifica del codice quasi certamente dovrebbero portare ad un commento
+nel changelog cosicché il prossimo revisore potrà meglio comprendere
+cosa stia accadendo.
Assicuratevi di dire ai revisori quali cambiamenti state facendo e di
ringraziarli per il loro tempo. Revisionare codice è un lavoro faticoso e che
-richiede molto tempo, e a volte i revisori diventano burberi. Tuttavia, anche
-in questo caso, rispondete con educazione e concentratevi sul problema che
-hanno evidenziato.
+richiede molto tempo, e a volte i revisori diventano burberi. Tuttavia, anche in
+questo caso, rispondete con educazione e concentratevi sul problema che hanno
+evidenziato. Quando inviate una versione successiva ricordatevi di aggiungere un
+``patch changelog`` alla email di intestazione o ad ogni singola patch spiegando
+le differenze rispetto a sottomissioni precedenti (vedere
+:ref:`it_the_canonical_patch_format`).
-9) Non scoraggiatevi - o impazientitevi
----------------------------------------
+Leggete Documentation/translations/it_IT/process/email-clients.rst per
+le raccomandazioni sui programmi di posta elettronica e l'etichetta da usare
+sulle liste di discussione.
+
+.. _it_resend_reminders:
+
+Non scoraggiatevi - o impazientitevi
+------------------------------------
Dopo che avete inviato le vostre modifiche, siate pazienti e aspettate.
I revisori sono persone occupate e potrebbero non ricevere la vostra patch
@@ -424,17 +365,29 @@ aver inviato le patch correttamente. Aspettate almeno una settimana prima di
rinviare le modifiche o sollecitare i revisori - probabilmente anche di più
durante la finestra d'integrazione.
-10) Aggiungete PATCH nell'oggetto
----------------------------------
+Potete anche rinviare la patch, o la serie di patch, dopo un paio di settimane
+aggiungendo la parola "RESEND" nel titolo::
+
+ [PATCH Vx RESEND] sub/sys: Condensed patch summary
+
+Ma non aggiungete "RESEND" quando state sottomettendo una versione modificata
+della vostra patch, o serie di patch - "RESEND" si applica solo alla
+sottomissione di patch, o serie di patch, che non hanno subito modifiche
+dall'ultima volta che sono state inviate.
+
+Aggiungete PATCH nell'oggetto
+-----------------------------
Dato l'alto volume di e-mail per Linus, e la lista linux-kernel, è prassi
prefiggere il vostro oggetto con [PATCH]. Questo permette a Linus e agli
altri sviluppatori del kernel di distinguere facilmente le patch dalle altre
discussioni.
+``git send-email`` lo fa automaticamente.
-11) Firmate il vostro lavoro - Il certificato d'origine dello sviluppatore
---------------------------------------------------------------------------
+
+Firmate il vostro lavoro - Il certificato d'origine dello sviluppatore
+----------------------------------------------------------------------
Per migliorare la tracciabilità su "chi ha fatto cosa", specialmente per
quelle patch che per raggiungere lo stadio finale passano attraverso
@@ -476,66 +429,26 @@ poi dovete solo aggiungere una riga che dice::
Signed-off-by: Random J Developer <random@developer.example.org>
-usando il vostro vero nome (spiacenti, non si accettano pseudonimi o
-contributi anonimi).
+usando il vostro vero nome (spiacenti, non si accettano
+contributi anonimi). Questo verrà fatto automaticamente se usate
+``git commit -s``. Anche il ripristino di uno stato precedente dovrebbe
+includere "Signed-off-by", se usate ``git revert -s`` questo verrà
+fatto automaticamente.
Alcune persone aggiungono delle etichette alla fine. Per ora queste verranno
ignorate, ma potete farlo per meglio identificare procedure aziendali interne o
per aggiungere dettagli circa la firma.
-Se siete un manutentore di un sottosistema o di un ramo, qualche volta dovrete
-modificare leggermente le patch che avete ricevuto al fine di poterle
-integrare; questo perché il codice non è esattamente lo stesso nei vostri
-sorgenti e in quelli dei vostri contributori. Se rispettate rigidamente la
-regola (c), dovreste chiedere al mittente di rifare la patch, ma questo è
-controproducente e una totale perdita di tempo ed energia. La regola (b)
-vi permette di correggere il codice, ma poi diventa davvero maleducato cambiare
-la patch di qualcuno e addossargli la responsabilità per i vostri bachi.
-Per risolvere questo problema dovreste aggiungere una riga, fra l'ultimo
-Signed-off-by e il vostro, che spiega la vostra modifica. Nonostante non ci
-sia nulla di obbligatorio, un modo efficace è quello di indicare il vostro
-nome o indirizzo email fra parentesi quadre, seguito da una breve descrizione;
-questo renderà abbastanza visibile chi è responsabile per le modifiche
-dell'ultimo minuto. Per esempio::
-
- Signed-off-by: Random J Developer <random@developer.example.org>
- [lucky@maintainer.example.org: struct foo moved from foo.c to foo.h]
- Signed-off-by: Lucky K Maintainer <lucky@maintainer.example.org>
-
-Questa pratica è particolarmente utile se siete i manutentori di un ramo
-stabile ma al contempo volete dare credito agli autori, tracciare e integrare
-le modifiche, e proteggere i mittenti dalle lamentele. Notate che in nessuna
-circostanza è permessa la modifica dell'identità dell'autore (l'intestazione
-From), dato che è quella che appare nei changelog.
-
-Un appunto speciale per chi porta il codice su vecchie versioni. Sembra che
-sia comune l'utile pratica di inserire un'indicazione circa l'origine della
-patch all'inizio del messaggio di commit (appena dopo la riga dell'oggetto)
-al fine di migliorare la tracciabilità. Per esempio, questo è quello che si
-vede nel rilascio stabile 3.x-stable::
-
- Date: Tue Oct 7 07:26:38 2014 -0400
-
- libata: Un-break ATA blacklist
-
- commit 1c40279960bcd7d52dbdf1d466b20d24b99176c8 upstream.
-
-E qui quello che potrebbe vedersi su un kernel più vecchio dove la patch è
-stata applicata::
-
- Date: Tue May 13 22:12:27 2008 +0200
+In seguito al SoB (Signed-off-by:) dell'autore ve ne sono altri da
+parte di tutte quelle persone che si sono occupate della gestione e
+del trasporto della patch. Queste però non sono state coinvolte nello
+sviluppo, ma la loro sequenza d'apparizione ci racconta il percorso
+**reale** che una patch a intrapreso dallo sviluppatore, fino al
+manutentore, per poi giungere a Linus.
- wireless, airo: waitbusy() won't delay
- [backport of 2.6 commit b7acbdfbd1f277c1eb23f344f899cfa4cd0bf36a]
-
-Qualunque sia il formato, questa informazione fornisce un importante aiuto
-alle persone che vogliono seguire i vostri sorgenti, e quelle che cercano
-dei bachi.
-
-
-12) Quando utilizzare Acked-by:, Cc:, e Co-developed-by:
---------------------------------------------------------
+Quando utilizzare Acked-by:, Cc:, e Co-developed-by:
+----------------------------------------------------
L'etichetta Signed-off-by: indica che il firmatario è stato coinvolto nello
sviluppo della patch, o che era nel suo percorso di consegna.
@@ -604,13 +517,14 @@ Esempio di una patch sottomessa dall'autore Co-developed-by:::
Co-developed-by: Submitting Co-Author <sub@coauthor.example.org>
Signed-off-by: Submitting Co-Author <sub@coauthor.example.org>
-13) Utilizzare Reported-by:, Tested-by:, Reviewed-by:, Suggested-by: e Fixes:
------------------------------------------------------------------------------
+Utilizzare Reported-by:, Tested-by:, Reviewed-by:, Suggested-by: e Fixes:
+-------------------------------------------------------------------------
L'etichetta Reported-by da credito alle persone che trovano e riportano i bachi
e si spera che questo possa ispirarli ad aiutarci nuovamente in futuro.
Rammentate che se il baco è stato riportato in privato, dovrete chiedere il
-permesso prima di poter utilizzare l'etichetta Reported-by.
+permesso prima di poter utilizzare l'etichetta Reported-by. Questa etichetta va
+usata per i bachi, dunque non usatela per richieste di nuove funzionalità.
L'etichetta Tested-by: indica che la patch è stata verificata con successo
(su un qualche sistema) dalla persona citata. Questa etichetta informa i
@@ -618,7 +532,7 @@ manutentori che qualche verifica è stata fatta, fornisce un mezzo per trovare
persone che possano verificare il codice in futuro, e garantisce che queste
stesse persone ricevano credito per il loro lavoro.
-Reviewd-by:, invece, indica che la patch è stata revisionata ed è stata
+Reviewed-by:, invece, indica che la patch è stata revisionata ed è stata
considerata accettabile in accordo con la dichiarazione dei revisori:
Dichiarazione di svista dei revisori
@@ -649,11 +563,18 @@ una modifica che si ritiene appropriata e senza alcun problema tecnico
importante. Qualsiasi revisore interessato (quelli che lo hanno fatto)
possono offrire il proprio Reviewed-by per la patch. Questa etichetta serve
a dare credito ai revisori e a informare i manutentori sul livello di revisione
-che è stato fatto sulla patch. L'etichetta Reviewd-by, quando fornita da
+che è stato fatto sulla patch. L'etichetta Reviewed-by, quando fornita da
revisori conosciuti per la loro conoscenza sulla materia in oggetto e per la
loro serietà nella revisione, accrescerà le probabilità che la vostra patch
venga integrate nel kernel.
+Quando si riceve una email sulla lista di discussione da un tester o
+un revisore, le etichette Tested-by o Reviewed-by devono essere
+aggiunte dall'autore quando invierà nuovamente la patch. Tuttavia, se
+la patch è cambiata in modo significativo, queste etichette potrebbero
+non avere più senso e quindi andrebbero rimosse. Solitamente si tiene traccia
+della rimozione nel changelog della patch (subito dopo il separatore '---').
+
L'etichetta Suggested-by: indica che l'idea della patch è stata suggerita
dalla persona nominata e le da credito. Tenete a mente che questa etichetta
non dovrebbe essere aggiunta senza un permesso esplicito, specialmente se
@@ -668,9 +589,15 @@ kernel stabili al fine di capire quale kernel deve ricevere la correzione.
Questo è il modo suggerito per indicare che un baco è stato corretto nella
patch. Per maggiori dettagli leggete :ref:`it_describe_changes`
+Da notare che aggiungere un tag "Fixes:" non esime dalle regole
+previste per i kernel stabili, e nemmeno dalla necessità di aggiungere
+in copia conoscenza stable@vger.kernel.org su tutte le patch per
+suddetti kernel.
-14) Il formato canonico delle patch
------------------------------------
+.. _it_the_canonical_patch_format:
+
+Il formato canonico delle patch
+-------------------------------
Questa sezione descrive il formato che dovrebbe essere usato per le patch.
Notate che se state usando un repositorio ``git`` per salvare le vostre patch
@@ -736,16 +663,20 @@ Le etichette non verranno considerate come parte della frase riassuntiva, ma
indicano come la patch dovrebbe essere trattata. Fra le etichette più comuni
ci sono quelle di versione che vengono usate quando una patch è stata inviata
più volte (per esempio, "v1, v2, v3"); oppure "RFC" per indicare che si
-attendono dei commenti (*Request For Comments*). Se ci sono quattro patch
-nella serie, queste dovrebbero essere enumerate così: 1/4, 2/4, 3/4, 4/4.
-Questo assicura che gli sviluppatori capiranno l'ordine in cui le patch
-dovrebbero essere applicate, e per tracciare quelle che hanno revisionate o
-che hanno applicato.
+attendono dei commenti (*Request For Comments*).
+
+Se ci sono quattro patch nella serie, queste dovrebbero essere
+enumerate così: 1/4, 2/4, 3/4, 4/4. Questo assicura che gli
+sviluppatori capiranno l'ordine in cui le patch dovrebbero essere
+applicate, e per tracciare quelle che hanno revisionate o che hanno
+applicato.
Un paio di esempi di oggetti::
Subject: [PATCH 2/5] ext2: improve scalability of bitmap searching
Subject: [PATCH v2 01/27] x86: fix eflags tracking
+ Subject: [PATCH v2] sub/sys: Condensed patch summary
+ Subject: [PATCH v2 M/N] sub/sys: Condensed patch summary
La riga ``from`` dev'essere la prima nel corpo del messaggio ed è nel
formato:
@@ -762,34 +693,82 @@ deve aver senso per un lettore esperto che è ha dimenticato i dettagli della
discussione che hanno portato alla patch. L'inclusione di informazioni
sui problemi oggetto dalla patch (messaggi del kernel, messaggi di oops,
eccetera) è particolarmente utile per le persone che potrebbero cercare fra
-i messaggi di log per la patch che li tratta. Se la patch corregge un errore
-di compilazione, non sarà necessario includere proprio _tutto_ quello che
-è uscito dal compilatore; aggiungete solo quello che è necessario per far si
-che la vostra patch venga trovata. Come nella ``summary phrase``, è importante
-essere sia brevi che descrittivi.
+i messaggi di log per la patch che li tratta. Il testo dovrebbe essere scritto
+con abbastanza dettagli da far capire al lettore **perché** quella
+patch fu creata, e questo a distanza di settimane, mesi, o addirittura
+anni.
+
+Se la patch corregge un errore di compilazione, non sarà necessario
+includere proprio _tutto_ quello che è uscito dal compilatore;
+aggiungete solo quello che è necessario per far si che la vostra patch
+venga trovata. Come nella ``summary phrase``, è importante essere sia
+brevi che descrittivi.
La linea di demarcazione ``---`` serve essenzialmente a segnare dove finisce
il messaggio di changelog.
Aggiungere il ``diffstat`` dopo ``---`` è un buon uso di questo spazio, per
mostrare i file che sono cambiati, e il numero di file aggiunto o rimossi.
-Un ``diffstat`` è particolarmente utile per le patch grandi. Altri commenti
-che sono importanti solo per i manutentori, quindi inadatti al changelog
-permanente, dovrebbero essere messi qui. Un buon esempio per questo tipo
-di commenti potrebbe essere quello di descrivere le differenze fra le versioni
+Un ``diffstat`` è particolarmente utile per le patch grandi. Se
+includete un ``diffstat`` dopo ``---``, usate le opzioni ``-p 1 -w70``
+cosicché i nomi dei file elencati non occupino troppo spazio
+(facilmente rientreranno negli 80 caratteri, magari con qualche
+indentazione). (``git`` genera di base dei diffstat adatti).
+
+I commenti che sono importanti solo per i manutentori, quindi
+inadatti al changelog permanente, dovrebbero essere messi qui. Un
+buon esempio per questo tipo di commenti potrebbe essere il cosiddetto
+``patch changelogs`` che descrivere le differenze fra le versioni
della patch.
-Se includete un ``diffstat`` dopo ``---``, usate le opzioni ``-p 1 -w70``
-cosicché i nomi dei file elencati non occupino troppo spazio (facilmente
-rientreranno negli 80 caratteri, magari con qualche indentazione).
-(``git`` genera di base dei diffstat adatti).
+Queste informazioni devono andare **dopo** la linea ``---`` che separa
+il *changelog* dal resto della patch. Le informazioni riguardanti la
+versione di una patch non sono parte del *chagelog* che viene incluso
+in git. Queste sono informazioni utili solo ai revisori. Se venissero
+messe sopra la riga, qualcuno dovrà fare del lavoro manuale per
+rimuoverle; cosa che invece viene fatta automaticamente quando vengono
+messe correttamente oltre la riga.::
+
+ <commit message>
+ ...
+ Signed-off-by: Author <author@mail>
+ ---
+ V2 -> V3: Removed redundant helper function
+ V1 -> V2: Cleaned up coding style and addressed review comments
+
+ path/to/file | 5+++--
+ ...
Maggiori dettagli sul formato delle patch nei riferimenti qui di seguito.
+.. _it_backtraces:
+
+Aggiungere i *backtrace* nei messaggi di commit
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+I *backtrace* aiutano a documentare la sequenza di chiamate a funzione
+che portano ad un problema. Tuttavia, non tutti i *backtrace* sono
+davvero utili. Per esempio, le sequenze iniziali di avvio sono uniche
+e ovvie. Copiare integralmente l'output di ``dmesg`` aggiunge tante
+informazioni che distraggono dal vero problema (per esempio, i
+marcatori temporali, la lista dei moduli, la lista dei registri, lo
+stato dello stack).
+
+Quindi, per rendere utile un *backtrace* dovreste eliminare le
+informazioni inutili, cosicché ci si possa focalizzare sul
+problema. Ecco un esempio di un *backtrace* essenziale::
+
+ unchecked MSR access error: WRMSR to 0xd51 (tried to write 0x0000000000000064)
+ at rIP: 0xffffffffae059994 (native_write_msr+0x4/0x20)
+ Call Trace:
+ mba_wrmsr
+ update_domains
+ rdtgroup_mkdir
+
.. _it_explicit_in_reply_to:
-15) Usare esplicitamente In-Reply-To nell'intestazione
-------------------------------------------------------
+Usare esplicitamente In-Reply-To nell'intestazione
+--------------------------------------------------
Aggiungere manualmente In-Reply-To: nell'intestazione dell'e-mail
potrebbe essere d'aiuto per associare una patch ad una discussione
@@ -798,74 +777,15 @@ che lo riportava. Tuttavia, per serie di patch multiple è generalmente
sconsigliato l'uso di In-Reply-To: per collegare precedenti versioni.
In questo modo versioni multiple di una patch non diventeranno un'ingestibile
giungla di riferimenti all'interno dei programmi di posta. Se un collegamento
-è utile, potete usare https://lkml.kernel.org/ per ottenere i collegamenti
+è utile, potete usare https://lore.kernel.org/ per ottenere i collegamenti
ad una versione precedente di una serie di patch (per esempio, potete usarlo
per l'email introduttiva alla serie).
-16) Inviare richieste ``git pull``
-----------------------------------
-
-Se avete una serie di patch, potrebbe essere più conveniente per un manutentore
-tirarle dentro al repositorio del sottosistema attraverso l'operazione
-``git pull``. Comunque, tenete presente che prendere patch da uno sviluppatore
-in questo modo richiede un livello di fiducia più alto rispetto a prenderle da
-una lista di discussione. Di conseguenza, molti manutentori sono riluttanti
-ad accettare richieste di *pull*, specialmente dagli sviluppatori nuovi e
-quindi sconosciuti. Se siete in dubbio, potete fare una richiesta di *pull*
-come messaggio introduttivo ad una normale pubblicazione di patch, così
-il manutentore avrà la possibilità di scegliere come integrarle.
-
-Una richiesta di *pull* dovrebbe avere nell'oggetto [GIT] o [PULL].
-La richiesta stessa dovrebbe includere il nome del repositorio e quello del
-ramo su una singola riga; dovrebbe essere più o meno così::
-
- Please pull from
-
- git://jdelvare.pck.nerim.net/jdelvare-2.6 i2c-for-linus
-
- to get these changes:
-
-Una richiesta di *pull* dovrebbe includere anche un messaggio generico
-che dica cos'è incluso, una lista delle patch usando ``git shortlog``, e una
-panoramica sugli effetti della serie di patch con ``diffstat``. Il modo più
-semplice per ottenere tutte queste informazioni è, ovviamente, quello di
-lasciar fare tutto a ``git`` con il comando ``git request-pull``.
-
-Alcuni manutentori (incluso Linus) vogliono vedere le richieste di *pull*
-da commit firmati con GPG; questo fornisce una maggiore garanzia sul fatto
-che siate stati proprio voi a fare la richiesta. In assenza di tale etichetta
-firmata Linus, in particolare, non prenderà alcuna patch da siti pubblici come
-GitHub.
-
-Il primo passo verso la creazione di questa etichetta firmata è quello di
-creare una chiave GNUPG ed averla fatta firmare da uno o più sviluppatori
-principali del kernel. Questo potrebbe essere difficile per i nuovi
-sviluppatori, ma non ci sono altre vie. Andare alle conferenze potrebbe
-essere un buon modo per trovare sviluppatori che possano firmare la vostra
-chiave.
-
-Una volta che avete preparato la vostra serie di patch in ``git``, e volete che
-qualcuno le prenda, create una etichetta firmata col comando ``git tag -s``.
-Questo creerà una nuova etichetta che identifica l'ultimo commit della serie
-contenente una firma creata con la vostra chiave privata. Avrete anche
-l'opportunità di aggiungere un messaggio di changelog all'etichetta; questo è
-il posto ideale per descrivere gli effetti della richiesta di *pull*.
-
-Se i sorgenti da cui il manutentore prenderà le patch non sono gli stessi del
-repositorio su cui state lavorando, allora non dimenticatevi di caricare
-l'etichetta firmata anche sui sorgenti pubblici.
-
-Quando generate una richiesta di *pull*, usate l'etichetta firmata come
-obiettivo. Un comando come il seguente farà il suo dovere::
-
- git request-pull master git://my.public.tree/linux.git my-signed-tag
-
-
Riferimenti
-----------
Andrew Morton, "La patch perfetta" (tpp).
- <http://www.ozlabs.org/~akpm/stuff/tpp.txt>
+ <https://www.ozlabs.org/~akpm/stuff/tpp.txt>
Jeff Garzik, "Formato per la sottomissione di patch per il kernel Linux"
<https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html>
@@ -884,13 +804,12 @@ Greg Kroah-Hartman, "Come scocciare un manutentore di un sottosistema"
<http://www.kroah.com/log/linux/maintainer-06.html>
No!!!! Basta gigantesche bombe patch alle persone sulla lista linux-kernel@vger.kernel.org!
- <https://lkml.org/lkml/2005/7/11/336>
+ <https://lore.kernel.org/r/20050711.125305.08322243.davem@davemloft.net>
-Kernel Documentation/translations/it_IT/process/coding-style.rst:
- :ref:`Documentation/translations/it_IT/process/coding-style.rst <it_codingstyle>`
+Kernel Documentation/translations/it_IT/process/coding-style.rst.
E-mail di Linus Torvalds sul formato canonico di una patch:
- <http://lkml.org/lkml/2005/4/7/183>
+ <https://lore.kernel.org/r/Pine.LNX.4.58.0504071023190.28951@ppc970.osdl.org>
Andi Kleen, "Su come sottomettere patch del kernel"
Alcune strategie su come sottomettere modifiche toste o controverse.
diff --git a/Documentation/translations/it_IT/process/volatile-considered-harmful.rst b/Documentation/translations/it_IT/process/volatile-considered-harmful.rst
index efc640cac596..4fff9a59b548 100644
--- a/Documentation/translations/it_IT/process/volatile-considered-harmful.rst
+++ b/Documentation/translations/it_IT/process/volatile-considered-harmful.rst
@@ -119,9 +119,9 @@ concorrenza siano stati opportunamente considerati.
Riferimenti
===========
-[1] http://lwn.net/Articles/233481/
+[1] https://lwn.net/Articles/233481/
-[2] http://lwn.net/Articles/233482/
+[2] https://lwn.net/Articles/233482/
Crediti
=======
diff --git a/Documentation/translations/it_IT/riscv/patch-acceptance.rst b/Documentation/translations/it_IT/riscv/patch-acceptance.rst
new file mode 100644
index 000000000000..2d7afb1f6959
--- /dev/null
+++ b/Documentation/translations/it_IT/riscv/patch-acceptance.rst
@@ -0,0 +1,40 @@
+.. include:: ../disclaimer-ita.rst
+
+:Original: :doc:`../../../arch/riscv/patch-acceptance`
+:Translator: Federico Vaga <federico.vaga@vaga.pv.it>
+
+arch/riscv linee guida alla manutenzione per gli sviluppatori
+=============================================================
+
+Introduzione
+------------
+
+L'insieme di istruzioni RISC-V sono sviluppate in modo aperto: le
+bozze in fase di sviluppo sono disponibili a tutti per essere
+revisionate e per essere sperimentare nelle implementazioni. Le bozze
+dei nuovi moduli o estensioni possono cambiare in fase di sviluppo - a
+volte in modo incompatibile rispetto a bozze precedenti. Questa
+flessibilità può portare a dei problemi di manutenzioni per il
+supporto RISC-V nel kernel Linux. I manutentori Linux non amano
+l'abbandono del codice, e il processo di sviluppo del kernel
+preferisce codice ben revisionato e testato rispetto a quello
+sperimentale. Desideriamo estendere questi stessi principi al codice
+relativo all'architettura RISC-V che verrà accettato per l'inclusione
+nel kernel.
+
+In aggiunta alla lista delle verifiche da fare prima di inviare una patch
+-------------------------------------------------------------------------
+
+Accetteremo le patch per un nuovo modulo o estensione se la fondazione
+RISC-V li classifica come "Frozen" o "Retified". (Ovviamente, gli
+sviluppatori sono liberi di mantenere una copia del kernel Linux
+contenente il codice per una bozza di estensione).
+
+In aggiunta, la specifica RISC-V permette agli implementatori di
+creare le proprie estensioni. Queste estensioni non passano
+attraverso il processo di revisione della fondazione RISC-V. Per
+questo motivo, al fine di evitare complicazioni o problemi di
+prestazioni, accetteremo patch solo per quelle estensioni che sono
+state ufficialmente accettate dalla fondazione RISC-V. (Ovviamente,
+gli implementatori sono liberi di mantenere una copia del kernel Linux
+contenente il codice per queste specifiche estensioni).
diff --git a/Documentation/translations/ja_JP/SubmitChecklist b/Documentation/translations/ja_JP/SubmitChecklist
index b42220d3d46c..1759c6b452d6 100644
--- a/Documentation/translations/ja_JP/SubmitChecklist
+++ b/Documentation/translations/ja_JP/SubmitChecklist
@@ -56,8 +56,8 @@ Linux カーネルパッチ投稿者向けチェックリスト
9: sparseを利用してちゃんとしたコードチェックをしてください。
-10: 'make checkstack' と 'make namespacecheck' を利用し、問題が発見されたら
- 修正してください。'make checkstack' は明示的に問題を示しませんが、どれか
+10: 'make checkstack' を利用し、問題が発見されたら修正してください。
+ 'make checkstack' は明示的に問題を示しませんが、どれか
1つの関数が512バイトより大きいスタックを使っていれば、修正すべき候補と
なります。
@@ -88,20 +88,18 @@ Linux カーネルパッチ投稿者向けチェックリスト
18: 新しいuserspaceインタフェースを作成した場合には、Documentation/ABI/ に
Documentation/ABI/README を参考にして必ずドキュメントを追加してください。
-19: 'make headers_check'を実行して全く問題がないことを確認してください。
-
-20: 少なくともslabアロケーションとpageアロケーションに失敗した場合の
+19: 少なくともslabアロケーションとpageアロケーションに失敗した場合の
挙動について、fault-injectionを利用して確認してください。
Documentation/fault-injection/ を参照してください。
追加したコードがかなりの量であったならば、サブシステム特有の
fault-injectionを追加したほうが良いかもしれません。
-21: 新たに追加したコードは、`gcc -W'でコンパイルしてください。
+20: 新たに追加したコードは、`gcc -W'でコンパイルしてください。
このオプションは大量の不要なメッセージを出力しますが、
"warning: comparison between signed and unsigned" のようなメッセージは、
バグを見つけるのに役に立ちます。
-22: 投稿したパッチが -mm パッチセットにマージされた後、全ての既存のパッチや
+21: 投稿したパッチが -mm パッチセットにマージされた後、全ての既存のパッチや
VM, VFS およびその他のサブシステムに関する様々な変更と、現時点でも共存
できることを確認するテストを行ってください。
diff --git a/Documentation/translations/ja_JP/SubmittingPatches b/Documentation/translations/ja_JP/SubmittingPatches
index dd0c3280ba5a..5334db471744 100644
--- a/Documentation/translations/ja_JP/SubmittingPatches
+++ b/Documentation/translations/ja_JP/SubmittingPatches
@@ -35,8 +35,7 @@ Linux カーネルに変更を加えたいと思っている個人又は会社
てもらえやすくする提案を集めたものです。
コードを投稿する前に、Documentation/process/submit-checklist.rst の項目リストに目
-を通してチェックしてください。もしあなたがドライバーを投稿しようとし
-ているなら、Documentation/process/submitting-drivers.rst にも目を通してください。
+を通してチェックしてください。
--------------------------------------------
セクション1 パッチの作り方と送り方
@@ -81,9 +80,7 @@ Linux カーネルに対する全ての変更は diff(1) コマンドによる
dontdiff ファイルには Linux カーネルのビルドプロセスの過程で生成された
ファイルの一覧がのっています。そして、それらはパッチを生成する diff(1)
コマンドで無視されるべきです。dontdiff ファイルは 2.6.12 以後のバージョ
-ンの Linux カーネルソースツリーに含まれています。それより前のバージョン
-の Linux カーネルソースツリーに対する dontdiff ファイルは、
-<http://www.xenotime.net/linux/doc/dontdiff>から取得することができます。
+ンの Linux カーネルソースツリーに含まれています。
投稿するパッチの中に関係のない余分なファイルが含まれていないことを確
認してください。diff(1) コマンドで生成したパッチがあなたの意図したとお
@@ -125,6 +122,17 @@ http://savannah.nongnu.org/projects/quilt
登録済みのバグエントリを修正するパッチであれば、そのバグエントリを示すバグ ID
や URL を明記してください。
+特定のコミットを参照したい場合は、その SHA-1 ID だけでなく、一行サマリ
+も含めてください。それにより、それが何に関するコミットなのかがレビューする
+人にわかりやすくなります。
+例 (英文のママ):
+
+ Commit e21d2170f36602ae2708 ("video: remove unnecessary
+ platform_set_drvdata()") removed the unnecessary
+ platform_set_drvdata(), but left the variable "dev" unused,
+ delete it.
+
+
3) パッチの分割
意味のあるひとまとまりごとに変更を個々のパッチファイルに分けてください。
@@ -162,7 +170,8 @@ http://savannah.nongnu.org/projects/quilt
MAINTAINERS ファイルとソースコードに目を通してください。そして、その変
更がメンテナのいる特定のサブシステムに加えられるものであることが分か
-れば、その人に電子メールを送ってください。
+れば、その人に電子メールを送ってください。その際
+./scripts/get_maintainers.pl のスクリプトが有用です。
もし、メンテナが載っていなかったり、メンテナからの応答がないなら、
LKML ( linux-kernel@vger.kernel.org )へパッチを送ってください。ほとんど
@@ -208,21 +217,6 @@ VGER.KERNEL.ORG でホスティングされているメーリングリストの
たとえ、メンテナが #5 で反応がなかったとしても、メンテナのコードに変更を
加えたときには、いつもメンテナに CC するのを忘れないようにしてください。
-小さなパッチであれば、Trivial Patch Monkey(ちょっとしたパッチを集めている)
-<trivial@kernel.org>に CC してもいいです。その現管理者については MAINTAINERS
-ファイルを見てください。ちょっとしたパッチとは以下のルールのどれか1つを満たして
-いなければなりません。
- ・ドキュメントのスペルミスの修正
- ・grep(1) コマンドによる検索を困難にしているスペルの修正
- ・コンパイル時の警告の修正(無駄な警告が散乱することは好ましくないた
- めです)
- ・コンパイル問題の修正(それらの修正が本当に正しい場合に限る)
- ・実行時の問題の修正(それらの修正が本当に問題を修正している場合に限る)
- ・廃止予定の関数やマクロを使用しているコードの除去(例 check_region )
- ・問い合わせ先やドキュメントの修正
- ・移植性のないコードから移植性のあるコードへの置き換え(小さい範囲で
- あればアーキテクチャ特有のことでも他の人がコピーできます)
- ・作者やメンテナによる修正(すなわち patch monkey の再転送モード)
7) MIME やリンクや圧縮ファイルや添付ファイルではなくプレインテキストのみ
@@ -415,7 +409,7 @@ Acked-by: が必ずしもパッチ全体の承認を示しているわけでは
このタグはパッチに関心があると思われる人達がそのパッチの議論に含まれていたこと
を明文化します。
-14) Reported-by と Tested-by: と Reviewed-by: の利用
+14) Reported-by:, Tested-by:, Reviewed-by: および Suggested-by: の利用
他の誰かによって報告された問題を修正するパッチであれば、問題報告者という寄与を
クレジットするために、Reported-by: タグを追加することを検討してください。
@@ -456,7 +450,7 @@ Reviewed-by: タグは、それとは異なり、下記のレビューア宣言
状況においてその宣言した目的や機能が正しく実現することに関して、
いかなる保証もしない(特にどこかで明示しない限り)。
-Reviewd-by タグはそのパッチがカーネルに対して適切な修正であって、深刻な技術的
+Reviewed-by タグはそのパッチがカーネルに対して適切な修正であって、深刻な技術的
問題を残していないという意見の宣言です。興味のあるレビューアは誰でも(レビュー
作業を終えたら)パッチに対して Reviewed-by タグを提示できます。このタグは
レビューアの寄与をクレジットする働き、レビューの進捗の度合いをメンテナに
@@ -464,6 +458,13 @@ Reviewd-by タグはそのパッチがカーネルに対して適切な修正で
レビューを実施したレビューアによって提供される時、Reviewed-by: タグがあなたの
パッチをカーネルにマージする可能性を高めるでしょう。
+Suggested-by: タグは、パッチのアイデアがその人からの提案に基づくものである
+ことを示し、アイデアの提供をクレジットするものです。提案者の明示的な許可が
+ない場合、特にそのアイデアが公開のフォーラムで示されていない場合には、この
+タグをつけないように注意してください。とはいえ、アイデアの提供者をこつこつ
+クレジットしていけば、望むらくはその人たちが将来別の機会に再度力を貸す気に
+なってくれるかもしれません。
+
15) 標準的なパッチのフォーマット
標準的なパッチのサブジェクトは以下のとおりです。
@@ -696,19 +697,20 @@ Jeff Garzik, "Linux kernel patch submission format".
<https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html>
Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer".
- <http://www.kroah.com/log/2005/03/31/>
- <http://www.kroah.com/log/2005/07/08/>
- <http://www.kroah.com/log/2005/10/19/>
- <http://www.kroah.com/log/2006/01/11/>
+ <http://www.kroah.com/log/linux/maintainer.html>
+ <http://www.kroah.com/log/linux/maintainer-02.html>
+ <http://www.kroah.com/log/linux/maintainer-03.html>
+ <http://www.kroah.com/log/linux/maintainer-04.html>
+ <http://www.kroah.com/log/linux/maintainer-05.html>
NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people!
- <https://lkml.org/lkml/2005/7/11/336>
+ <https://lore.kernel.org/r/20050711.125305.08322243.davem@davemloft.net>
Kernel Documentation/process/coding-style.rst:
<http://users.sosdg.org/~qiyong/lxr/source/Documentation/process/coding-style.rst>
Linus Torvalds's mail on the canonical patch format:
- <http://lkml.org/lkml/2005/4/7/183>
+ <https://lore.kernel.org/r/Pine.LNX.4.58.0504071023190.28951@ppc970.osdl.org>
Andi Kleen, "On submitting kernel patches"
Some strategies to get difficult or controversial changes in.
diff --git a/Documentation/translations/ja_JP/howto.rst b/Documentation/translations/ja_JP/howto.rst
index 73ebdab4ced7..8d856ebe873c 100644
--- a/Documentation/translations/ja_JP/howto.rst
+++ b/Documentation/translations/ja_JP/howto.rst
@@ -1,3 +1,7 @@
+.. raw:: latex
+
+ \kerneldocCJKoff
+
NOTE:
This is a version of Documentation/process/howto.rst translated into Japanese.
This document is maintained by Tsugikazu Shibata <tshibata@ab.jp.nec.com>
@@ -11,6 +15,10 @@ try to update the original English file first.
----------------------------------
+.. raw:: latex
+
+ \kerneldocCJKon
+
この文書は、
Documentation/process/howto.rst
の和訳です。
@@ -57,7 +65,7 @@ Linux カーネル開発のやり方
- 『新・詳説 C 言語 H&S リファレンス』 (サミュエル P ハービソン/ガイ L スティール共著 斉藤 信男監訳)[ソフトバンク]
カーネルは GNU C と GNU ツールチェインを使って書かれています。カーネル
-は ISO C89 仕様に準拠して書く一方で、標準には無い言語拡張を多く使って
+は ISO C11 仕様に準拠して書く一方で、標準には無い言語拡張を多く使って
います。カーネルは標準 C ライブラリに依存しない、C 言語非依存環境です。
そのため、C の標準の中で使えないものもあります。特に任意の long long
の除算や浮動小数点は使えません。カーネルがツールチェインや C 言語拡張
@@ -78,9 +86,14 @@ info ページ( info gcc )を見てください。
--------
Linux カーネルのソースコードは GPL ライセンスの下でリリースされていま
-す。ライセンスの詳細については、ソースツリーのメインディレクトリに存在
-する、COPYING のファイルを見てください。もしライセンスについてさらに質
-問があれば、Linux Kernel メーリングリストに質問するのではなく、どうぞ
+す。ソースツリーのメインディレクトリにある COPYING のファイルを見てく
+ださい。Linux カーネルのライセンスルールとソースコード内の
+`SPDX <https://spdx.org/>`_ 識別子の使い方は
+:ref:`Documentation/process/license-rules.rst <kernel_licensing>`
+に説明されています。
+
+もしライセンスについてさらに質問があれば、
+Linux Kernel メーリングリストに質問するのではなく、どうぞ
法律家に相談してください。メーリングリストの人達は法律家ではなく、法的
問題については彼らの声明はあてにするべきではありません。
@@ -103,7 +116,7 @@ linux-api@vger.kernel.org に送ることを勧めます。
以下はカーネルソースツリーに含まれている読んでおくべきファイルの一覧で
す-
- README
+ :ref:`Documentation/admin-guide/README.rst <readme>`
このファイルは Linuxカーネルの簡単な背景とカーネルを設定(訳注
configure )し、生成(訳注 build )するために必要なことは何かが書かれ
ています。 カーネルに関して初めての人はここからスタートすると良い
@@ -121,8 +134,8 @@ linux-api@vger.kernel.org に送ることを勧めます。
ルに従っているものだけを受け付け、多くの人は正しいスタイルのコード
だけをレビューします。
- :ref:`Documentation/process/submitting-patches.rst <codingstyle>` と :ref:`Documentation/process/submitting-drivers.rst <submittingdrivers>`
- これらのファイルには、どうやってうまくパッチを作って投稿するかにつ
+ :ref:`Documentation/process/submitting-patches.rst <codingstyle>`
+ このファイルには、どうやってうまくパッチを作って投稿するかにつ
いて非常に詳しく書かれており、以下を含みます (これだけに限らない
けれども)
@@ -137,7 +150,8 @@ linux-api@vger.kernel.org に送ることを勧めます。
この他にパッチを作る方法についてのよくできた記述は-
"The Perfect Patch"
- http://www.ozlabs.org/~akpm/stuff/tpp.txt
+ https://www.ozlabs.org/~akpm/stuff/tpp.txt
+
"Linux kernel patch submission format"
https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html
@@ -153,7 +167,7 @@ linux-api@vger.kernel.org に送ることを勧めます。
このドキュメントは Linux 開発の思想を理解するのに非常に重要です。
そして、他のOSでの開発者が Linux に移る時にとても重要です。
- :ref:`Documentation/admin-guide/security-bugs.rst <securitybugs>`
+ :ref:`Documentation/process/security-bugs.rst <securitybugs>`
もし Linux カーネルでセキュリティ問題を発見したように思ったら、こ
のドキュメントのステップに従ってカーネル開発者に連絡し、問題解決を
支援してください。
@@ -229,13 +243,6 @@ Linux カーネルソースツリーの中に含まれる、きれいにし、
れるための基礎を学ぶことができ、そしてもしあなたがまだアイディアを持っ
ていない場合には、次にやる仕事の方向性が見えてくるかもしれません。
-もしあなたが、すでにひとまとまりコードを書いていて、カーネルツリーに入
-れたいと思っていたり、それに関する適切な支援を求めたい場合、カーネルメ
-ンターズプロジェクトはそのような皆さんを助けるためにできました。ここに
-はメーリングリストがあり、以下から参照できます -
-
- https://selenic.com/mailman/listinfo/kernel-mentors
-
実際に Linux カーネルのコードについて修正を加える前に、どうやってその
コードが動作するのかを理解することが必要です。そのためには、特別なツー
ルの助けを借りてでも、それを直接よく読むことが最良の方法です(ほとんど
@@ -254,27 +261,29 @@ Linux カーネルの開発プロセスは現在幾つかの異なるメイン
チ」と多数のサブシステム毎のカーネルブランチから構成されます。これらの
ブランチとは -
- - メインの 4.x カーネルツリー
- - 4.x.y -stable カーネルツリー
- - サブシステム毎のカーネルツリーとパッチ
- - 統合テストのための 4.x -next カーネルツリー
+ - Linus のメインラインツリー
+ - メジャー番号をまたぐ数本の安定版ツリー
+ - サブシステム毎のカーネルツリー
+ - 統合テストのための linux-next カーネルツリー
-4.x カーネルツリー
+メインラインツリー
~~~~~~~~~~~~~~~~~~
-4.x カーネルは Linus Torvalds によってメンテナンスされ、
-https://kernel.org の pub/linux/kernel/v4.x/ ディレクトリに存在します。
+メインラインツリーは Linus Torvalds によってメンテナンスされ、
+https://kernel.org のリポジトリに存在します。
この開発プロセスは以下のとおり -
- 新しいカーネルがリリースされた直後に、2週間の特別期間が設けられ、
この期間中に、メンテナ達は Linus に大きな差分を送ることができます。
- このような差分は通常 -next カーネルに数週間含まれてきたパッチです。
+ このような差分は通常 linux-next カーネルに数週間含まれてきたパッチです。
大きな変更は git(カーネルのソース管理ツール、詳細は
http://git-scm.com/ 参照) を使って送るのが好ましいやり方ですが、パッ
チファイルの形式のまま送るのでも十分です。
- - 2週間後、-rc1 カーネルがリリースされ、この後にはカーネル全体の安定
- 性に影響をあたえるような新機能は含まない類のパッチしか取り込むこと
- はできません。新しいドライバ(もしくはファイルシステム)のパッチは
+ - 2週間後 -rc1 カーネルがリリースされ、新しいカーネルを可能な限り堅牢に
+ することに焦点が移ります。この期間のパッチのほとんどは退行を修正する
+ ものとなります。以前から存在していたバグは退行には当たらないため、
+ 送るのは重要な修正だけにしてください。
+ 新しいドライバ (もしくはファイルシステム) のパッチは
-rc1 の後で受け付けられることもあることを覚えておいてください。な
ぜなら、変更が独立していて、追加されたコードの外の領域に影響を与え
ない限り、退行のリスクは無いからです。-rc1 がリリースされた後、
@@ -295,20 +304,21 @@ Andrew Morton が Linux-kernel メーリングリストにカーネルリリー
前もって決められた計画によってリリースされるものではないから
です。」*
-4.x.y -stable カーネルツリー
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+メジャー番号をまたぐ数本の安定版ツリー
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
バージョン番号が3つの数字に分かれているカーネルは -stable カーネルです。
-これには、4.x カーネルで見つかったセキュリティ問題や重大な後戻りに対す
-る比較的小さい重要な修正が含まれます。
+これには最初の2つのバージョン番号の数字に対応した、
+メジャーメインラインリリースで見つかったセキュリティ問題や
+重大な後戻りに対する比較的小さい重要な修正が含まれます。
+
+メジャー安定版シリーズのそれぞれのリリースは
+バージョン番号の3番目を増加させ、最初の2つの番号は同じ値を保ちます。
これは、開発/実験的バージョンのテストに協力することに興味が無く、最新
の安定したカーネルを使いたいユーザに推奨するブランチです。
-もし、4.x.y カーネルが存在しない場合には、番号が一番大きい 4.x が最新
-の安定版カーネルです。
-
-4.x.y は "stable" チーム <stable@vger.kernel.org> でメンテされており、
+安定版ツリーは"stable" チーム <stable@vger.kernel.org> でメンテされており、
必要に応じてリリースされます。通常のリリース期間は 2週間毎ですが、差
し迫った問題がなければもう少し長くなることもあります。セキュリティ関
連の問題の場合はこれに対してだいたいの場合、すぐにリリースがされます。
@@ -318,7 +328,7 @@ Documentation/process/stable-kernel-rules.rst ファイルにはどのような
類の変更が -stable ツリーに受け入れ可能か、またリリースプロセスがどう
動くかが記述されています。
-サブシステム毎のカーネルツリーとパッチ
+サブシステム毎のカーネルツリー
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
それぞれのカーネルサブシステムのメンテナ達は --- そして多くのカーネル
@@ -343,33 +353,27 @@ quilt シリーズとして公開されているパッチキューも使われ
けることができます。大部分のこれらの patchwork のサイトは
https://patchwork.kernel.org/ でリストされています。
-統合テストのための 4.x -next カーネルツリー
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+統合テストのための linux-next カーネルツリー
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-サブシステムツリーの更新内容がメインラインの 4.x ツリーにマージされる
+サブシステムツリーの更新内容がメインラインツリーにマージされる
前に、それらは統合テストされる必要があります。この目的のため、実質的に
全サブシステムツリーからほぼ毎日プルされてできる特別なテスト用のリポジ
トリが存在します-
https://git.kernel.org/?p=linux/kernel/git/next/linux-next.git
-このやり方によって、-next カーネルは次のマージ機会でどんなものがメイン
-ラインカーネルにマージされるか、おおまかなの展望を提供します。-next カー
-ネルの実行テストを行う冒険好きなテスターは大いに歓迎されます。
+このやり方によって、linux-next は次のマージ機会でどんなものがメイン
+ラインにマージされるか、おおまかな展望を提供します。
+linux-next の実行テストを行う冒険好きなテスターは大いに歓迎されます。
バグレポート
-------------
-https://bugzilla.kernel.org は Linux カーネル開発者がカーネルのバグを追跡する
-場所です。ユーザは見つけたバグの全てをこのツールで報告すべきです。どう
-kernel bugzilla を使うかの詳細は、以下を参照してください -
-
- https://bugzilla.kernel.org/page.cgi?id=faq.html
-
メインカーネルソースディレクトリにあるファイル
-admin-guide/reporting-bugs.rstはカーネルバグらしいものについてどうレポー
-トするかの良いテンプレートであり、問題の追跡を助けるためにカーネル開発
-者にとってどんな情報が必要なのかの詳細が書かれています。
+'Documentation/admin-guide/reporting-issues.rst'
+は、カーネルバグらしきものの報告の仕方、および、カーネル開発者が問題を
+追跡する際の手がかりとなる情報についての詳細を説明しています。
バグレポートの管理
-------------------
@@ -382,15 +386,13 @@ admin-guide/reporting-bugs.rstはカーネルバグらしいものについて
道です、なぜなら多くの人は他人のバグの修正に時間を浪費することを好まな
いからです。
-すでにレポートされたバグのために仕事をするためには、
-https://bugzilla.kernel.org に行ってください。もし今後のバグレポートに
-ついてアドバイスを受けたいのであれば、bugme-new メーリングリスト(新し
-いバグレポートだけがここにメールされる) または bugme-janitor メーリン
-グリスト(bugzilla の変更毎にここにメールされる)を購読できます。
-
- https://lists.linux-foundation.org/mailman/listinfo/bugme-new
-
- https://lists.linux-foundation.org/mailman/listinfo/bugme-janitors
+すでにレポートされたバグの作業をするためには、興味のあるサブシステムを
+見つけ、そのサブシステムのバグの報告先 (多くの場合メーリングリスト、
+稀にバグトラッカー) を MAINTAINERS ファイルで調べてください。
+そのアーカイブで最近の報告を検索し、できそうなものに力を貸してください。
+https://bugzilla.kernel.org でバグ報告を調べようとする人もいるでしょう。
+これは限られた一部のサブシステムのバグ報告と追跡に利用されるとともに、
+とりわけ、カーネル全体に対するバグの登録先となっています。
メーリングリスト
----------------
@@ -404,7 +406,7 @@ https://bugzilla.kernel.org に行ってください。もし今後のバグレ
このメーリングリストのアーカイブは web 上の多数の場所に存在します。こ
れらのアーカイブを探すにはサーチエンジンを使いましょう。例えば-
- http://dir.gmane.org/gmane.linux.kernel
+ https://lore.kernel.org/lkml/
リストに投稿する前にすでにその話題がアーカイブに存在するかどうかを検索
することを是非やってください。多数の事がすでに詳細に渡って議論されてお
@@ -615,7 +617,7 @@ Linux カーネルコミュニティは、一度に大量のコードの塊を
ントの ChangeLog セクションを見てください -
"The Perfect Patch"
- http://www.ozlabs.org/~akpm/stuff/tpp.txt
+ https://www.ozlabs.org/~akpm/stuff/tpp.txt
これらはどれも、実行することが時にはとても困難です。これらの例を完璧に
実施するには数年かかるかもしれません。これは継続的な改善のプロセスであ
diff --git a/Documentation/translations/ja_JP/index.rst b/Documentation/translations/ja_JP/index.rst
index 2f91b895e3c2..43b9fb7246d3 100644
--- a/Documentation/translations/ja_JP/index.rst
+++ b/Documentation/translations/ja_JP/index.rst
@@ -1,12 +1,18 @@
.. raw:: latex
- \renewcommand\thesection*
- \renewcommand\thesubsection*
+ \renewcommand\thesection*
+ \renewcommand\thesubsection*
+ \kerneldocCJKon
+ \kerneldocBeginJP{
-Japanese translations
+日本語訳
=====================
.. toctree::
:maxdepth: 1
howto
+
+.. raw:: latex
+
+ }\kerneldocEndJP
diff --git a/Documentation/translations/ko_KR/howto.rst b/Documentation/translations/ko_KR/howto.rst
index ae3ad897d2ae..34f14899c155 100644
--- a/Documentation/translations/ko_KR/howto.rst
+++ b/Documentation/translations/ko_KR/howto.rst
@@ -1,3 +1,7 @@
+.. raw:: latex
+
+ \kerneldocCJKoff
+
NOTE:
This is a version of Documentation/process/howto.rst translated into korean
This document is maintained by Minchan Kim <minchan@kernel.org>
@@ -11,6 +15,10 @@ try to update the original English file first.
----------------------------------
+.. raw:: latex
+
+ \kerneldocCJKon
+
이 문서는
Documentation/process/howto.rst
의 한글 번역입니다.
@@ -54,7 +62,7 @@ Documentation/process/howto.rst
- "Practical C Programming" by Steve Oualline [O'Reilly]
- "C: A Reference Manual" by Harbison and Steele [Prentice Hall]
-커널은 GNU C와 GNU 툴체인을 사용하여 작성되었다. 이 툴들은 ISO C89 표준을
+커널은 GNU C와 GNU 툴체인을 사용하여 작성되었다. 이 툴들은 ISO C11 표준을
따르는 반면 표준에 있지 않은 많은 확장기능도 가지고 있다. 커널은 표준 C
라이브러리와는 관계없이 freestanding C 환경이어서 C 표준의 일부는
지원되지 않는다. 임의의 long long 나누기나 floating point는 지원되지 않는다.
@@ -116,7 +124,7 @@ mtk.manpages@gmail.com의 메인테이너에게 보낼 것을 권장한다.
메인테이너들은 이 규칙을 따르는 패치들만을 받아들일 것이고 많은 사람들이
그 패치가 올바른 스타일일 경우만 코드를 검토할 것이다.
- :ref:`Documentation/process/submitting-patches.rst <submittingpatches>` 와 :ref:`Documentation/process/submitting-drivers.rst <submittingdrivers>`
+ :ref:`Documentation/process/submitting-patches.rst <submittingpatches>`
이 파일들은 성공적으로 패치를 만들고 보내는 법을 다음의 내용들로
굉장히 상세히 설명하고 있다(그러나 다음으로 한정되진 않는다).
@@ -149,7 +157,7 @@ mtk.manpages@gmail.com의 메인테이너에게 보낼 것을 권장한다.
리눅스로 전향하는 사람들에게는 매우 중요하다.
- :ref:`Documentation/admin-guide/security-bugs.rst <securitybugs>`
+ :ref:`Documentation/process/security-bugs.rst <securitybugs>`
여러분들이 리눅스 커널의 보안 문제를 발견했다고 생각한다면 이 문서에
나온 단계에 따라서 커널 개발자들에게 알리고 그 문제를 해결할 수 있도록
도와 달라.
@@ -284,9 +292,10 @@ Andrew Morton의 글이 있다.
여러 메이저 넘버를 갖는 다양한 안정된 커널 트리들
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-3 자리 숫자로 이루어진 버젼의 커널들은 -stable 커널들이다. 그것들은 해당 메이저
-메인라인 릴리즈에서 발견된 큰 회귀들이나 보안 문제들 중 비교적 작고 중요한
-수정들을 포함하며, 앞의 두 버전 넘버는 같은 기반 버전을 의미한다.
+세개의 버젼 넘버로 이루어진 버젼의 커널들은 -stable 커널들이다. 그것들은 해당
+메이저 메인라인 릴리즈에서 발견된 큰 회귀들이나 보안 문제들 중 비교적 작고
+중요한 수정들을 포함한다. 주요 stable 시리즈 릴리즈는 세번째 버젼 넘버를
+증가시키며 앞의 두 버젼 넘버는 그대로 유지한다.
이것은 가장 최근의 안정적인 커널을 원하는 사용자에게 추천되는 브랜치이며,
개발/실험적 버젼을 테스트하는 것을 돕고자 하는 사용자들과는 별로 관련이 없다.
@@ -316,10 +325,10 @@ Andrew Morton의 글이 있다.
제안된 패치는 서브시스템 트리에 커밋되기 전에 메일링 리스트를 통해
리뷰된다(아래의 관련 섹션을 참고하기 바란다). 일부 커널 서브시스템의 경우, 이
리뷰 프로세스는 patchwork라는 도구를 통해 추적된다. patchwork은 등록된 패치와
-패치에 대한 코멘트, 패치의 버전을 볼 수 있는 웹 인터페이스를 제공하고,
+패치에 대한 코멘트, 패치의 버젼을 볼 수 있는 웹 인터페이스를 제공하고,
메인테이너는 패치를 리뷰 중, 리뷰 통과, 또는 반려됨으로 표시할 수 있다.
-대부분의 이러한 patchwork 사이트는 https://patchwork.kernel.org/ 또는
-http://patchwork.ozlabs.org/ 에 나열되어 있다.
+대부분의 이러한 patchwork 사이트는 https://patchwork.kernel.org/ 에 나열되어
+있다.
통합 테스트를 위한 linux-next 커널 트리
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -328,7 +337,7 @@ http://patchwork.ozlabs.org/ 에 나열되어 있다.
거쳐야 한다. 이런 목적으로, 모든 서브시스템 트리의 변경사항을 거의 매일
받아가는 특수한 테스트 저장소가 존재한다:
- https://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git
+ https://git.kernel.org/?p=linux/kernel/git/next/linux-next.git
이런 식으로, linux-next 커널을 통해 다음 머지 기간에 메인라인 커널에 어떤
변경이 가해질 것인지 간략히 알 수 있다. 모험심 강한 테스터라면 linux-next
@@ -338,14 +347,8 @@ http://patchwork.ozlabs.org/ 에 나열되어 있다.
버그 보고
---------
-https://bugzilla.kernel.org 는 리눅스 커널 개발자들이 커널의 버그를 추적하는
-곳이다. 사용자들은 발견한 모든 버그들을 보고하기 위하여 이 툴을 사용할 것을
-권장한다. kernel bugzilla를 사용하는 자세한 방법은 다음을 참조하라.
-
- https://bugzilla.kernel.org/page.cgi?id=faq.html
-
-메인 커널 소스 디렉토리에 있는 :ref:`admin-guide/reporting-bugs.rst <reportingbugs>`
-파일은 커널 버그라고 생각되는 것을 보고하는 방법에 관한 좋은 템플릿이며 문제를
+메인 커널 소스 디렉토리에 있는 'Documentation/admin-guide/reporting-issues.rst'
+파일은 커널 버그라고 생각되는 것을 어떻게 보고하면 되는지, 그리고 문제를
추적하기 위해서 커널 개발자들이 필요로 하는 정보가 무엇들인지를 상세히 설명하고
있다.
@@ -361,8 +364,14 @@ https://bugzilla.kernel.org 는 리눅스 커널 개발자들이 커널의 버
점수를 얻을 수 있는 가장 좋은 방법중의 하나이다. 왜냐하면 많은 사람들은
다른 사람들의 버그들을 수정하기 위하여 시간을 낭비하지 않기 때문이다.
-이미 보고된 버그 리포트들을 가지고 작업하기 위해서 https://bugzilla.kernel.org
-를 참조하라.
+이미 보고된 버그 리포트들을 가지고 작업하기 위해서는 여러분이 관심있는
+서브시스템을 찾아라. 해당 서브시스템의 버그들이 어디로 리포트 되는지
+MAINTAINERS 파일을 체크하라; 그건 대부분 메일링 리스트이고, 가끔은 버그 추적
+시스템이다. 그 장소에 있는 최근 버그 리포트 기록들을 검색하고 여러분이 보기에
+적합하다 싶은 것을 도와라. 여러분은 버그 리포트를 위해
+https://bugzilla.kernel.org 를 체크하고자 할 수도 있다; 소수의 커널
+서브시스템들만이 버그 신고와 추적을 위해 해당 시스템을 실제로 사용하고 있지만,
+전체 커널의 버그들이 그곳에 정리된다.
메일링 리스트들
@@ -377,7 +386,7 @@ https://bugzilla.kernel.org 는 리눅스 커널 개발자들이 커널의 버
웹상의 많은 다른 곳에도 메일링 리스트의 아카이브들이 있다.
이러한 아카이브들을 찾으려면 검색 엔진을 사용하라. 예를 들어:
- http://dir.gmane.org/gmane.linux.kernel
+ https://lore.kernel.org/lkml/
여러분이 새로운 문제에 관해 리스트에 올리기 전에 말하고 싶은 주제에 관한
것을 아카이브에서 먼저 찾아보기를 강력히 권장한다. 이미 상세하게 토론된 많은
@@ -582,7 +591,7 @@ Pat이라는 이름을 가진 여자가 있을 수도 있는 것이다. 리눅
"The Perfect Patch"
- http://www.ozlabs.org/~akpm/stuff/tpp.txt
+ https://www.ozlabs.org/~akpm/stuff/tpp.txt
이 모든 것을 하는 것은 매우 어려운 일이다. 완벽히 소화하는 데는 적어도 몇년이
diff --git a/Documentation/translations/ko_KR/index.rst b/Documentation/translations/ko_KR/index.rst
index 27995c4233de..4add6b2fe1f2 100644
--- a/Documentation/translations/ko_KR/index.rst
+++ b/Documentation/translations/ko_KR/index.rst
@@ -1,7 +1,9 @@
.. raw:: latex
- \renewcommand\thesection*
- \renewcommand\thesubsection*
+ \renewcommand\thesection*
+ \renewcommand\thesubsection*
+ \kerneldocCJKon
+ \kerneldocBeginKR{
한국어 번역
===========
@@ -10,3 +12,18 @@
:maxdepth: 1
howto
+
+
+리눅스 커널 메모리 배리어
+-------------------------
+
+.. raw:: latex
+
+ \footnotesize
+
+.. include:: ./memory-barriers.txt
+ :literal:
+
+.. raw:: latex
+
+ }\kerneldocEndKR
diff --git a/Documentation/translations/ko_KR/memory-barriers.txt b/Documentation/translations/ko_KR/memory-barriers.txt
index f07c40a068b5..7165927a708e 100644
--- a/Documentation/translations/ko_KR/memory-barriers.txt
+++ b/Documentation/translations/ko_KR/memory-barriers.txt
@@ -1,6 +1,6 @@
NOTE:
This is a version of Documentation/memory-barriers.txt translated into Korean.
-This document is maintained by SeongJae Park <sj38.park@gmail.com>.
+This document is maintained by SeongJae Park <sj@kernel.org>.
If you find any difference between this document and the original file or
a problem with the translation, please contact the maintainer of this file.
@@ -10,13 +10,13 @@ a fork. So if you have any comments or updates for this file please
update the original English file first. The English version is
definitive, and readers should look there if they have any doubt.
-===================================
+=================================
이 문서는
Documentation/memory-barriers.txt
의 한글 번역입니다.
-역자: 박성재 <sj38.park@gmail.com>
-===================================
+역자: 박성재 <sj@kernel.org>
+=================================
=========================
@@ -80,7 +80,7 @@ Documentation/memory-barriers.txt
- 메모리 배리어의 종류.
- 메모리 배리어에 대해 가정해선 안될 것.
- - 데이터 의존성 배리어 (역사적).
+ - 주소 데이터 의존성 배리어 (역사적).
- 컨트롤 의존성.
- SMP 배리어 짝맞추기.
- 메모리 배리어 시퀀스의 예.
@@ -91,7 +91,6 @@ Documentation/memory-barriers.txt
- 컴파일러 배리어.
- CPU 메모리 배리어.
- - MMIO 쓰기 배리어.
(*) 암묵적 커널 메모리 배리어.
@@ -103,7 +102,6 @@ Documentation/memory-barriers.txt
(*) CPU 간 ACQUIRING 배리어의 효과.
- Acquire vs 메모리 액세스.
- - Acquire vs I/O 액세스.
(*) 메모리 배리어가 필요한 곳
@@ -219,7 +217,7 @@ Documentation/memory-barriers.txt
P = &B D = *Q;
D 로 읽혀지는 값은 CPU 2 에서 P 로부터 읽혀진 주소값에 의존적이기 때문에 여기엔
-분명한 데이터 의존성이 있습니다. 하지만 이 이벤트들의 실행 결과로는 아래의
+분명한 주소 의존성이 있습니다. 하지만 이 이벤트들의 실행 결과로는 아래의
결과들이 모두 나타날 수 있습니다:
(Q == &A) and (D == 1)
@@ -418,19 +416,19 @@ CPU 에게 기대할 수 있는 최소한의 보장사항 몇가지가 있습니
하나씩 요청해 집어넣습니다. 쓰기 배리어 앞의 모든 스토어 오퍼레이션들은
쓰기 배리어 뒤의 모든 스토어 오퍼레이션들보다 _앞서_ 수행될 겁니다.
- [!] 쓰기 배리어들은 읽기 또는 데이터 의존성 배리어와 함께 짝을 맞춰
+ [!] 쓰기 배리어들은 읽기 또는 주소 의존성 배리어와 함께 짝을 맞춰
사용되어야만 함을 알아두세요; "SMP 배리어 짝맞추기" 서브섹션을 참고하세요.
- (2) 데이터 의존성 배리어.
+ (2) 주소 의존성 배리어 (역사적).
- 데이터 의존성 배리어는 읽기 배리어의 보다 완화된 형태입니다. 두개의 로드
+ 주소 의존성 배리어는 읽기 배리어의 보다 완화된 형태입니다. 두개의 로드
오퍼레이션이 있고 두번째 것이 첫번째 것의 결과에 의존하고 있을 때(예:
두번째 로드가 참조할 주소를 첫번째 로드가 읽는 경우), 두번째 로드가 읽어올
데이터는 첫번째 로드에 의해 그 주소가 얻어진 뒤에 업데이트 됨을 보장하기
- 위해서 데이터 의존성 배리어가 필요할 수 있습니다.
+ 위해서 주소 의존성 배리어가 필요할 수 있습니다.
- 데이터 의존성 배리어는 상호 의존적인 로드 오퍼레이션들 사이의 부분적 순서
+ 주소 의존성 배리어는 상호 의존적인 로드 오퍼레이션들 사이의 부분적 순서
세우기입니다; 스토어 오퍼레이션들이나 독립적인 로드들, 또는 중복되는
로드들에 대해서는 어떤 영향도 끼치지 않습니다.
@@ -438,37 +436,41 @@ CPU 에게 기대할 수 있는 최소한의 보장사항 몇가지가 있습니
오퍼레이션들을 던져 넣고 있으며, 거기에 관심이 있는 다른 CPU 는 그
오퍼레이션들을 메모리 시스템이 실행한 결과를 인지할 수 있습니다. 이처럼
다른 CPU 의 스토어 오퍼레이션의 결과에 관심을 두고 있는 CPU 가 수행 요청한
- 데이터 의존성 배리어는, 배리어 앞의 어떤 로드 오퍼레이션이 다른 CPU 에서
+ 주소 의존성 배리어는, 배리어 앞의 어떤 로드 오퍼레이션이 다른 CPU 에서
던져 넣은 스토어 오퍼레이션과 같은 영역을 향했다면, 그런 스토어
- 오퍼레이션들이 만들어내는 결과가 데이터 의존성 배리어 뒤의 로드
+ 오퍼레이션들이 만들어내는 결과가 주소 의존성 배리어 뒤의 로드
오퍼레이션들에게는 보일 것을 보장합니다.
이 순서 세우기 제약에 대한 그림을 보기 위해선 "메모리 배리어 시퀀스의 예"
서브섹션을 참고하시기 바랍니다.
- [!] 첫번째 로드는 반드시 _데이터_ 의존성을 가져야지 컨트롤 의존성을 가져야
+ [!] 첫번째 로드는 반드시 _주소_ 의존성을 가져야지 컨트롤 의존성을 가져야
하는게 아님을 알아두십시오. 만약 두번째 로드를 위한 주소가 첫번째 로드에
의존적이지만 그 의존성은 조건적이지 그 주소 자체를 가져오는게 아니라면,
그것은 _컨트롤_ 의존성이고, 이 경우에는 읽기 배리어나 그보다 강력한
무언가가 필요합니다. 더 자세한 내용을 위해서는 "컨트롤 의존성" 서브섹션을
참고하시기 바랍니다.
- [!] 데이터 의존성 배리어는 보통 쓰기 배리어들과 함께 짝을 맞춰 사용되어야
+ [!] 주소 의존성 배리어는 보통 쓰기 배리어들과 함께 짝을 맞춰 사용되어야
합니다; "SMP 배리어 짝맞추기" 서브섹션을 참고하세요.
+ [!] 커널 v5.9 릴리즈에서 명시적 주소 의존성 배리어를 위한 커널 API 들이
+ 삭제되었습니다. 오늘날에는 공유된 변수들의 로드를 표시하는 READ_ONCE() 나
+ rcu_dereference() 와 같은 API 들은 묵시적으로 주소 의존성 배리어를 제공합니다.
+
(3) 읽기 (또는 로드) 메모리 배리어.
- 읽기 배리어는 데이터 의존성 배리어 기능의 보장사항에 더해서 배리어보다
- 앞서 명시된 모든 LOAD 오퍼레이션들이 배리어 뒤에 명시되는 모든 LOAD
+ 읽기 배리어는 주소 의존성 배리어 기능의 보장사항에 더해서 배리어보다 앞서
+ 명시된 모든 LOAD 오퍼레이션들이 배리어 뒤에 명시되는 모든 LOAD
오퍼레이션들보다 먼저 행해진 것으로 시스템의 다른 컴포넌트들에 보여질 것을
보장합니다.
읽기 배리어는 로드 오퍼레이션에 행해지는 부분적 순서 세우기입니다; 스토어
오퍼레이션에 대해서는 어떤 영향도 끼치지 않습니다.
- 읽기 메모리 배리어는 데이터 의존성 배리어를 내장하므로 데이터 의존성
- 배리어를 대신할 수 있습니다.
+ 읽기 메모리 배리어는 주소 의존성 배리어를 내장하므로 주소 의존성 배리어를
+ 대신할 수 있습니다.
[!] 읽기 배리어는 일반적으로 쓰기 배리어들과 함께 짝을 맞춰 사용되어야
합니다; "SMP 배리어 짝맞추기" 서브섹션을 참고하세요.
@@ -515,14 +517,13 @@ CPU 에게 기대할 수 있는 최소한의 보장사항 몇가지가 있습니
완료되기 전에 행해진 것처럼 보일 수 있습니다.
ACQUIRE 와 RELEASE 오퍼레이션의 사용은 일반적으로 다른 메모리 배리어의
- 필요성을 없앱니다 (하지만 "MMIO 쓰기 배리어" 서브섹션에서 설명되는 예외를
- 알아두세요). 또한, RELEASE+ACQUIRE 조합은 범용 메모리 배리어처럼 동작할
- 것을 보장하지 -않습니다-. 하지만, 어떤 변수에 대한 RELEASE 오퍼레이션을
- 앞서는 메모리 액세스들의 수행 결과는 이 RELEASE 오퍼레이션을 뒤이어 같은
- 변수에 대해 수행된 ACQUIRE 오퍼레이션을 뒤따르는 메모리 액세스에는 보여질
- 것이 보장됩니다. 다르게 말하자면, 주어진 변수의 크리티컬 섹션에서는, 해당
- 변수에 대한 앞의 크리티컬 섹션에서의 모든 액세스들이 완료되었을 것을
- 보장합니다.
+ 필요성을 없앱니다. 또한, RELEASE+ACQUIRE 조합은 범용 메모리 배리어처럼
+ 동작할 것을 보장하지 -않습니다-. 하지만, 어떤 변수에 대한 RELEASE
+ 오퍼레이션을 앞서는 메모리 액세스들의 수행 결과는 이 RELEASE 오퍼레이션을
+ 뒤이어 같은 변수에 대해 수행된 ACQUIRE 오퍼레이션을 뒤따르는 메모리
+ 액세스에는 보여질 것이 보장됩니다. 다르게 말하자면, 주어진 변수의
+ 크리티컬 섹션에서는, 해당 변수에 대한 앞의 크리티컬 섹션에서의 모든
+ 액세스들이 완료되었을 것을 보장합니다.
즉, ACQUIRE 는 최소한의 "취득" 동작처럼, 그리고 RELEASE 는 최소한의 "공개"
처럼 동작한다는 의미입니다.
@@ -570,20 +571,24 @@ ACQUIRE 는 해당 오퍼레이션의 로드 부분에만 적용되고 RELEASE
[*] 버스 마스터링 DMA 와 일관성에 대해서는 다음을 참고하시기 바랍니다:
Documentation/driver-api/pci/pci.rst
- Documentation/DMA-API-HOWTO.txt
- Documentation/DMA-API.txt
+ Documentation/core-api/dma-api-howto.rst
+ Documentation/core-api/dma-api.rst
-데이터 의존성 배리어 (역사적)
------------------------------
+주소 의존성 배리어 (역사적)
+---------------------------
-리눅스 커널 v4.15 기준으로, smp_read_barrier_depends() 가 READ_ONCE() 에
+리눅스 커널 v4.15 기준으로, smp_mb() 가 DEC Alpha 용 READ_ONCE() 코드에
추가되었는데, 이는 이 섹션에 주의를 기울여야 하는 사람들은 DEC Alpha 아키텍쳐
전용 코드를 만드는 사람들과 READ_ONCE() 자체를 만드는 사람들 뿐임을 의미합니다.
-그런 분들을 위해, 그리고 역사에 관심 있는 분들을 위해, 여기 데이터 의존성
+그런 분들을 위해, 그리고 역사에 관심 있는 분들을 위해, 여기 주소 의존성
배리어에 대한 이야기를 적습니다.
-데이터 의존성 배리어의 사용에 있어 지켜야 하는 사항들은 약간 미묘하고, 데이터
+[!] 주소 의존성은 로드에서 로드로와 로드에서 스토어로의 관계들 모두에서
+나타나지만, 주소 의존성 배리어는 로드에서 스토어로의 상황에서는 필요하지
+않습니다.
+
+주소 의존성 배리어의 사용에 있어 지켜야 하는 사항들은 약간 미묘하고, 데이터
의존성 배리어가 사용되어야 하는 상황도 항상 명백하지는 않습니다. 설명을 위해
다음의 이벤트 시퀀스를 생각해 봅시다:
@@ -593,10 +598,13 @@ ACQUIRE 는 해당 오퍼레이션의 로드 부분에만 적용되고 RELEASE
B = 4;
<쓰기 배리어>
WRITE_ONCE(P, &B)
- Q = READ_ONCE(P);
+ Q = READ_ONCE_OLD(P);
D = *Q;
-여기엔 분명한 데이터 의존성이 존재하므로, 이 시퀀스가 끝났을 때 Q 는 &A 또는 &B
+[!] READ_ONCE_OLD() 는 4.15 커널 전의 버전에서의, 주소 의존성 배리어를 내포하지
+않는 READ_ONCE() 에 해당합니다.
+
+여기엔 분명한 주소 의존성이 존재하므로, 이 시퀀스가 끝났을 때 Q 는 &A 또는 &B
일 것이고, 따라서:
(Q == &A) 는 (D == 1) 를,
@@ -611,8 +619,8 @@ ACQUIRE 는 해당 오퍼레이션의 로드 부분에만 적용되고 RELEASE
그렇지 않습니다, 그리고 이 현상은 (DEC Alpha 와 같은) 여러 CPU 에서 실제로
발견될 수 있습니다.
-이 문제 상황을 제대로 해결하기 위해, 데이터 의존성 배리어나 그보다 강화된
-무언가가 주소를 읽어올 때와 데이터를 읽어올 때 사이에 추가되어야만 합니다:
+이 문제 상황을 제대로 해결하기 위해, READ_ONCE() 는 커널 v4.15 릴리즈 부터
+묵시적 주소 의존성 배리어를 제공합니다:
CPU 1 CPU 2
=============== ===============
@@ -621,7 +629,7 @@ ACQUIRE 는 해당 오퍼레이션의 로드 부분에만 적용되고 RELEASE
<쓰기 배리어>
WRITE_ONCE(P, &B);
Q = READ_ONCE(P);
- <데이터 의존성 배리어>
+ <묵시적 주소 의존성 배리어>
D = *Q;
이 변경은 앞의 처음 두가지 결과 중 하나만이 발생할 수 있고, 세번째의 결과는
@@ -637,11 +645,11 @@ P 는 짝수 번호 캐시 라인에 저장되어 있고, 변수 B 는 홀수
중이라면 포인터 P (&B) 의 새로운 값과 변수 B 의 기존 값 (2) 를 볼 수 있습니다.
-의존적 쓰기들의 순서를 맞추는데에는 데이터 의존성 배리어가 필요치 않은데, 이는
+의존적 쓰기들의 순서를 맞추는데에는 주소 의존성 배리어가 필요치 않은데, 이는
리눅스 커널이 지원하는 CPU 들은 (1) 쓰기가 정말로 일어날지, (2) 쓰기가 어디에
이루어질지, 그리고 (3) 쓰여질 값을 확실히 알기 전까지는 쓰기를 수행하지 않기
때문입니다. 하지만 "컨트롤 의존성" 섹션과
-Documentation/RCU/rcu_dereference.txt 파일을 주의 깊게 읽어 주시기 바랍니다:
+Documentation/RCU/rcu_dereference.rst 파일을 주의 깊게 읽어 주시기 바랍니다:
컴파일러는 매우 창의적인 많은 방법으로 종속성을 깰 수 있습니다.
CPU 1 CPU 2
@@ -650,12 +658,12 @@ Documentation/RCU/rcu_dereference.txt 파일을 주의 깊게 읽어 주시기
B = 4;
<쓰기 배리어>
WRITE_ONCE(P, &B);
- Q = READ_ONCE(P);
+ Q = READ_ONCE_OLD(P);
WRITE_ONCE(*Q, 5);
-따라서, Q 로의 읽기와 *Q 로의 쓰기 사이에는 데이터 종속성 배리어가 필요치
-않습니다. 달리 말하면, 데이터 종속성 배리어가 없더라도 다음 결과는 생기지
-않습니다:
+따라서, Q 로의 읽기와 *Q 로의 쓰기 사이에는 주소 의존성 배리어가 필요치
+않습니다. 달리 말하면, 오늘날의 READ_ONCE() 의 묵시적 주소 의존성 배리어가
+없더라도 다음 결과는 생기지 않습니다:
(Q == &B) && (B == 4)
@@ -666,16 +674,16 @@ Documentation/RCU/rcu_dereference.txt 파일을 주의 깊게 읽어 주시기
해줍니다.
-데이터 의존성에 의해 제공되는 이 순서규칙은 이를 포함하고 있는 CPU 에
+주소 의존성에 의해 제공되는 이 순서규칙은 이를 포함하고 있는 CPU 에
지역적임을 알아두시기 바랍니다. 더 많은 정보를 위해선 "Multicopy 원자성"
섹션을 참고하세요.
-데이터 의존성 배리어는 매우 중요한데, 예를 들어 RCU 시스템에서 그렇습니다.
+주소 의존성 배리어는 매우 중요한데, 예를 들어 RCU 시스템에서 그렇습니다.
include/linux/rcupdate.h 의 rcu_assign_pointer() 와 rcu_dereference() 를
-참고하세요. 여기서 데이터 의존성 배리어는 RCU 로 관리되는 포인터의 타겟을 현재
-타겟에서 수정된 새로운 타겟으로 바꾸는 작업에서 새로 수정된 타겟이 초기화가
-완료되지 않은 채로 보여지는 일이 일어나지 않게 해줍니다.
+참고하세요. 이것들은 RCU 로 관리되는 포인터의 타겟을 현재 타겟에서 수정된
+새로운 타겟으로 바꾸는 작업에서 새로 수정된 타겟이 초기화가 완료되지 않은 채로
+보여지는 일이 일어나지 않게 해줍니다.
더 많은 예를 위해선 "캐시 일관성" 서브섹션을 참고하세요.
@@ -687,16 +695,17 @@ include/linux/rcupdate.h 의 rcu_assign_pointer() 와 rcu_dereference() 를
약간 다루기 어려울 수 있습니다. 이 섹션의 목적은 여러분이 컴파일러의 무시로
인해 여러분의 코드가 망가지는 걸 막을 수 있도록 돕는겁니다.
-로드-로드 컨트롤 의존성은 데이터 의존성 배리어만으로는 정확히 동작할 수가
-없어서 읽기 메모리 배리어를 필요로 합니다. 아래의 코드를 봅시다:
+로드-로드 컨트롤 의존성은 (묵시적인) 주소 의존성 배리어만으로는 정확히 동작할
+수가 없어서 읽기 메모리 배리어를 필요로 합니다. 아래의 코드를 봅시다:
q = READ_ONCE(a);
+ <묵시적 주소 의존성 배리어>
if (q) {
- <데이터 의존성 배리어> /* BUG: No data dependency!!! */
+ /* BUG: No address dependency!!! */
p = READ_ONCE(b);
}
-이 코드는 원하는 대로의 효과를 내지 못할 수 있는데, 이 코드에는 데이터 의존성이
+이 코드는 원하는 대로의 효과를 내지 못할 수 있는데, 이 코드에는 주소 의존성이
아니라 컨트롤 의존성이 존재하기 때문으로, 이런 상황에서 CPU 는 실행 속도를 더
빠르게 하기 위해 분기 조건의 결과를 예측하고 코드를 재배치 할 수 있어서 다른
CPU 는 b 로부터의 로드 오퍼레이션이 a 로부터의 로드 오퍼레이션보다 먼저 발생한
@@ -933,9 +942,9 @@ CPU 간 상호작용을 다룰 때에 일부 타입의 메모리 배리어는
범용 배리어들은 범용 배리어끼리도 짝을 맞추지만 multicopy 원자성이 없는
대부분의 다른 타입의 배리어들과도 짝을 맞춥니다. ACQUIRE 배리어는 RELEASE
배리어와 짝을 맞춥니다만, 둘 다 범용 배리어를 포함해 다른 배리어들과도 짝을
-맞출 수 있습니다. 쓰기 배리어는 데이터 의존성 배리어나 컨트롤 의존성, ACQUIRE
+맞출 수 있습니다. 쓰기 배리어는 주소 의존성 배리어나 컨트롤 의존성, ACQUIRE
배리어, RELEASE 배리어, 읽기 배리어, 또는 범용 배리어와 짝을 맞춥니다.
-비슷하게 읽기 배리어나 컨트롤 의존성, 또는 데이터 의존성 배리어는 쓰기 배리어나
+비슷하게 읽기 배리어나 컨트롤 의존성, 또는 주소 의존성 배리어는 쓰기 배리어나
ACQUIRE 배리어, RELEASE 배리어, 또는 범용 배리어와 짝을 맞추는데, 다음과
같습니다:
@@ -954,7 +963,7 @@ ACQUIRE 배리어, RELEASE 배리어, 또는 범용 배리어와 짝을 맞추
a = 1;
<쓰기 배리어>
WRITE_ONCE(b, &a); x = READ_ONCE(b);
- <데이터 의존성 배리어>
+ <묵시적 주소 의존성 배리어>
y = *x;
또는:
@@ -973,8 +982,8 @@ ACQUIRE 배리어, RELEASE 배리어, 또는 범용 배리어와 짝을 맞추
기본적으로, 여기서의 읽기 배리어는 "더 완화된" 타입일 순 있어도 항상 존재해야
합니다.
-[!] 쓰기 배리어 앞의 스토어 오퍼레이션은 일반적으로 읽기 배리어나 데이터
-의존성 배리어 뒤의 로드 오퍼레이션과 매치될 것이고, 반대도 마찬가지입니다:
+[!] 쓰기 배리어 앞의 스토어 오퍼레이션은 일반적으로 읽기 배리어나 주소 의존성
+배리어 뒤의 로드 오퍼레이션과 매치될 것이고, 반대도 마찬가지입니다:
CPU 1 CPU 2
=================== ===================
@@ -1026,7 +1035,7 @@ ACQUIRE 배리어, RELEASE 배리어, 또는 범용 배리어와 짝을 맞추
V
-둘째, 데이터 의존성 배리어는 데이터 의존적 로드 오퍼레이션들의 부분적 순서
+둘째, 주소 의존성 배리어는 데이터 의존적 로드 오퍼레이션들의 부분적 순서
세우기로 동작합니다. 다음 일련의 이벤트들을 보세요:
CPU 1 CPU 2
@@ -1072,7 +1081,7 @@ ACQUIRE 배리어, RELEASE 배리어, 또는 범용 배리어와 짝을 맞추
앞의 예에서, CPU 2 는 (B 의 값이 될) *C 의 값 읽기가 C 의 LOAD 뒤에 이어짐에도
B 가 7 이라는 결과를 얻습니다.
-하지만, 만약 데이터 의존성 배리어가 C 의 로드와 *C (즉, B) 의 로드 사이에
+하지만, 만약 주소 의존성 배리어가 C 의 로드와 *C (즉, B) 의 로드 사이에
있었다면:
CPU 1 CPU 2
@@ -1083,7 +1092,7 @@ B 가 7 이라는 결과를 얻습니다.
<쓰기 배리어>
STORE C = &B LOAD X
STORE D = 4 LOAD C (gets &B)
- <데이터 의존성 배리어>
+ <주소 의존성 배리어>
LOAD *C (reads B)
다음과 같이 됩니다:
@@ -1106,7 +1115,7 @@ B 가 7 이라는 결과를 얻습니다.
| +-------+ | |
| | X->9 |------>| |
| +-------+ | |
- C 로의 스토어 앞의 ---> \ ddddddddddddddddd | |
+ C 로의 스토어 앞의 ---> \ aaaaaaaaaaaaaaaaa | |
모든 이벤트 결과가 \ +-------+ | |
뒤의 로드에게 ----->| B->2 |------>| |
보이게 강제한다 +-------+ | |
@@ -1294,7 +1303,7 @@ A 의 로드 두개가 모두 B 의 로드 뒤에 있지만, 서로 다른 값
즉각 완료한다 : : +-------+
-읽기 배리어나 데이터 의존성 배리어를 두번째 로드 직전에 놓는다면:
+읽기 배리어나 주소 의존성 배리어를 두번째 로드 직전에 놓는다면:
CPU 1 CPU 2
======================= =======================
@@ -1501,8 +1510,6 @@ u 로의 스토어를 cpu1() 의 v 로부터의 로드 뒤에 일어난 것으
(*) CPU 메모리 배리어.
- (*) MMIO 쓰기 배리어.
-
컴파일러 배리어
---------------
@@ -1790,21 +1797,20 @@ READ_ONCE(jiffies) 라고 할 필요가 없습니다. READ_ONCE() 와 WRITE_ONC
CPU 메모리 배리어
-----------------
-리눅스 커널은 다음의 여덟개 기본 CPU 메모리 배리어를 가지고 있습니다:
+리눅스 커널은 다음의 일곱개 기본 CPU 메모리 배리어를 가지고 있습니다:
TYPE MANDATORY SMP CONDITIONAL
- =============== ======================= ===========================
+ =============== ======================= ===============
범용 mb() smp_mb()
쓰기 wmb() smp_wmb()
읽기 rmb() smp_rmb()
- 데이터 의존성 READ_ONCE()
+ 주소 의존성 READ_ONCE()
-데이터 의존성 배리어를 제외한 모든 메모리 배리어는 컴파일러 배리어를
-포함합니다. 데이터 의존성은 컴파일러에의 추가적인 순서 보장을 포함하지
-않습니다.
+주소 의존성 배리어를 제외한 모든 메모리 배리어는 컴파일러 배리어를 포함합니다.
+주소 의존성은 컴파일러에의 추가적인 순서 보장을 포함하지 않습니다.
-방백: 데이터 의존성이 있는 경우, 컴파일러는 해당 로드를 올바른 순서로 일으킬
+방백: 주소 의존성이 있는 경우, 컴파일러는 해당 로드를 올바른 순서로 일으킬
것으로 (예: `a[b]` 는 a[b] 를 로드 하기 전에 b 의 값을 먼저 로드한다)
기대되지만, C 언어 사양에는 컴파일러가 b 의 값을 추측 (예: 1 과 같음) 해서
b 로드 전에 a 로드를 하는 코드 (예: tmp = a[1]; if (b != 1) tmp = a[b]; ) 를
@@ -1842,12 +1848,15 @@ Mandatory 배리어들은 SMP 시스템에서도 UP 시스템에서도 SMP 효
(*) smp_mb__before_atomic();
(*) smp_mb__after_atomic();
- 이것들은 값을 리턴하지 않는 (더하기, 빼기, 증가, 감소와 같은) 어토믹
- 함수들을 위한, 특히 그것들이 레퍼런스 카운팅에 사용될 때를 위한
- 함수들입니다. 이 함수들은 메모리 배리어를 내포하고 있지는 않습니다.
+ 이것들은 메모리 배리어를 내포하지 않는 어토믹 RMW 함수를 사용하지만 코드에
+ 메모리 배리어가 필요한 경우를 위한 것들입니다. 메모리 배리어를 내포하지
+ 않는 어토믹 RMW 함수들의 예로는 더하기, 빼기, (실패한) 조건적
+ 오퍼레이션들, _relaxed 함수들이 있으며, atomic_read 나 atomic_set 은 이에
+ 해당되지 않습니다. 메모리 배리어가 필요해지는 흔한 예로는 어토믹
+ 오퍼레이션을 사용해 레퍼런스 카운트를 수정하는 경우를 들 수 있습니다.
- 이것들은 값을 리턴하지 않으며 어토믹한 (set_bit 과 clear_bit 같은) 비트
- 연산에도 사용될 수 있습니다.
+ 이것들은 또한 (set_bit 과 clear_bit 같은) 메모리 배리어를 내포하지 않는
+ 어토믹 RMW bitop 함수들을 위해서도 사용될 수 있습니다.
한 예로, 객체 하나를 무효한 것으로 표시하고 그 객체의 레퍼런스 카운트를
감소시키는 다음 코드를 보세요:
@@ -1865,6 +1874,7 @@ Mandatory 배리어들은 SMP 시스템에서도 UP 시스템에서도 SMP 효
(*) dma_wmb();
(*) dma_rmb();
+ (*) dma_mb();
이것들은 CPU 와 DMA 가능한 디바이스에서 모두 액세스 가능한 공유 메모리의
읽기, 쓰기 작업들의 순서를 보장하기 위해 consistent memory 에서 사용하기
@@ -1895,17 +1905,39 @@ Mandatory 배리어들은 SMP 시스템에서도 UP 시스템에서도 SMP 효
dma_rmb() 는 디스크립터로부터 데이터를 읽어오기 전에 디바이스가 소유권을
내려놓았을 것을 보장하고, dma_wmb() 는 디바이스가 자신이 소유권을 다시
- 가졌음을 보기 전에 디스크립터에 데이터가 쓰였을 것을 보장합니다. 참고로,
- writel() 을 사용하면 캐시 일관성이 있는 메모리 (cache coherent memory)
- 쓰기가 MMIO 영역에의 쓰기 전에 완료되었을 것을 보장하므로 writel() 앞에
- wmb() 를 실행할 필요가 없음을 알아두시기 바랍니다. writel() 보다 비용이
- 저렴한 writel_relaxed() 는 이런 보장을 제공하지 않으므로 여기선 사용되지
- 않아야 합니다.
+ 가졌음을 보기 전에 디스크립터에 데이터가 쓰였을 것을 보장합니다. dma_mb()
+ 는 dma_rmb() 와 dma_wmb() 를 모두 내포합니다. 참고로, writel() 을
+ 사용하면 캐시 일관성이 있는 메모리 (cache coherent memory) 쓰기가 MMIO
+ 영역에의 쓰기 전에 완료되었을 것을 보장하므로 writel() 앞에 wmb() 를
+ 실행할 필요가 없음을 알아두시기 바랍니다. writel() 보다 비용이 저렴한
+ writel_relaxed() 는 이런 보장을 제공하지 않으므로 여기선 사용되지 않아야
+ 합니다.
writel_relaxed() 와 같은 완화된 I/O 접근자들에 대한 자세한 내용을 위해서는
"커널 I/O 배리어의 효과" 섹션을, consistent memory 에 대한 자세한 내용을
- 위해선 Documentation/DMA-API.txt 문서를 참고하세요.
+ 위해선 Documentation/core-api/dma-api.rst 문서를 참고하세요.
+
+ (*) pmem_wmb();
+
+ 이것은 persistent memory 를 위한 것으로, persistent 저장소에 가해진 변경
+ 사항이 플랫폼 연속성 도메인에 도달했을 것을 보장하기 위한 것입니다.
+
+ 예를 들어, 임시적이지 않은 pmem 영역으로의 쓰기 후, 우리는 쓰기가 플랫폼
+ 연속성 도메인에 도달했을 것을 보장하기 위해 pmem_wmb() 를 사용합니다.
+ 이는 쓰기가 뒤따르는 instruction 들이 유발하는 어떠한 데이터 액세스나
+ 데이터 전송의 시작 전에 persistent 저장소를 업데이트 했을 것을 보장합니다.
+ 이는 wmb() 에 의해 이뤄지는 순서 규칙을 포함합니다.
+ Persistent memory 에서의 로드를 위해선 현재의 읽기 메모리 배리어로도 읽기
+ 순서를 보장하는데 충분합니다.
+
+ (*) io_stop_wc();
+
+ 쓰기와 결합된 특성을 갖는 메모리 액세스의 경우 (예: ioremap_wc() 에 의해
+ 리턴되는 것들), CPU 는 앞의 액세스들이 뒤따르는 것들과 병합되게끔 기다릴
+ 수 있습니다. io_stop_wc() 는 그런 기다림이 성능에 영향을 끼칠 수 있을 때,
+ 이 매크로 앞의 쓰기-결합된 메모리 액세스들이 매크로 뒤의 것들과 병합되는
+ 것을 방지하기 위해 사용될 수 있습니다.
=========================
암묵적 커널 메모리 배리어
@@ -2413,7 +2445,7 @@ _않습니다_.
알고 있는, - inb() 나 writel() 과 같은 - 적절한 액세스 루틴을 통해 이루어져야만
합니다. 이것들은 대부분의 경우에는 명시적 메모리 배리어 와 함께 사용될 필요가
없습니다만, 완화된 메모리 액세스 속성으로 I/O 메모리 윈도우로의 참조를 위해
-액세스 함수가 사용된다면 순서를 강제하기 위해 _madatory_ 메모리 배리어가
+액세스 함수가 사용된다면 순서를 강제하기 위해 _mandatory_ 메모리 배리어가
필요합니다.
더 많은 정보를 위해선 Documentation/driver-api/device-io.rst 를 참고하십시오.
@@ -2528,7 +2560,7 @@ I/O 액세스를 통한 주변장치와의 통신은 아키텍쳐와 기기에
이것들은 readX() 와 writeX() 랑 비슷하지만, 더 완화된 메모리 순서
보장을 제공합니다. 구체적으로, 이것들은 일반적 메모리 액세스나 delay()
루프 (예:앞의 2-5 항목) 에 대해 순서를 보장하지 않습니다만 디폴트 I/O
- 기능으로 매핑된 __iomem 포인터에 대해 동작할 때, 같은 CPU 쓰레드에 의해
+ 기능으로 매핑된 __iomem 포인터에 대해 동작할 때, 같은 CPU 쓰레드에 의한
같은 주변장치로의 액세스에는 순서가 맞춰질 것이 보장됩니다.
(*) readsX(), writesX():
@@ -2661,144 +2693,6 @@ CPU 코어는 프로그램의 인과성이 유지된다고만 여겨진다면
수도 있습니다.
-캐시 일관성
------------
-
-하지만 삶은 앞에서 이야기한 것처럼 단순하지 않습니다: 캐시들은 일관적일 것으로
-기대되지만, 그 일관성이 순서에도 적용될 거라는 보장은 없습니다. 한 CPU 에서
-만들어진 변경 사항은 최종적으로는 시스템의 모든 CPU 에게 보여지게 되지만, 다른
-CPU 들에게도 같은 순서로 보이게 될 거라는 보장은 없다는 뜻입니다.
-
-
-두개의 CPU (1 & 2) 가 달려 있고, 각 CPU 에 두개의 데이터 캐시(CPU 1 은 A/B 를,
-CPU 2 는 C/D 를 갖습니다)가 병렬로 연결되어 있는 시스템을 다룬다고 생각해
-봅시다:
-
- :
- : +--------+
- : +---------+ | |
- +--------+ : +--->| Cache A |<------->| |
- | | : | +---------+ | |
- | CPU 1 |<---+ | |
- | | : | +---------+ | |
- +--------+ : +--->| Cache B |<------->| |
- : +---------+ | |
- : | Memory |
- : +---------+ | System |
- +--------+ : +--->| Cache C |<------->| |
- | | : | +---------+ | |
- | CPU 2 |<---+ | |
- | | : | +---------+ | |
- +--------+ : +--->| Cache D |<------->| |
- : +---------+ | |
- : +--------+
- :
-
-이 시스템이 다음과 같은 특성을 갖는다 생각해 봅시다:
-
- (*) 홀수번 캐시라인은 캐시 A, 캐시 C 또는 메모리에 위치할 수 있음;
-
- (*) 짝수번 캐시라인은 캐시 B, 캐시 D 또는 메모리에 위치할 수 있음;
-
- (*) CPU 코어가 한개의 캐시에 접근하는 동안, 다른 캐시는 - 더티 캐시라인을
- 메모리에 내리거나 추측성 로드를 하거나 하기 위해 - 시스템의 다른 부분에
- 액세스 하기 위해 버스를 사용할 수 있음;
-
- (*) 각 캐시는 시스템의 나머지 부분들과 일관성을 맞추기 위해 해당 캐시에
- 적용되어야 할 오퍼레이션들의 큐를 가짐;
-
- (*) 이 일관성 큐는 캐시에 이미 존재하는 라인에 가해지는 평범한 로드에 의해서는
- 비워지지 않는데, 큐의 오퍼레이션들이 이 로드의 결과에 영향을 끼칠 수 있다
- 할지라도 그러함.
-
-이제, 첫번째 CPU 에서 두개의 쓰기 오퍼레이션을 만드는데, 해당 CPU 의 캐시에
-요청된 순서로 오퍼레이션이 도달됨을 보장하기 위해 두 오퍼레이션 사이에 쓰기
-배리어를 사용하는 상황을 상상해 봅시다:
-
- CPU 1 CPU 2 COMMENT
- =============== =============== =======================================
- u == 0, v == 1 and p == &u, q == &u
- v = 2;
- smp_wmb(); v 의 변경이 p 의 변경 전에 보일 것을
- 분명히 함
- <A:modify v=2> v 는 이제 캐시 A 에 독점적으로 존재함
- p = &v;
- <B:modify p=&v> p 는 이제 캐시 B 에 독점적으로 존재함
-
-여기서의 쓰기 메모리 배리어는 CPU 1 의 캐시가 올바른 순서로 업데이트 된 것으로
-시스템의 다른 CPU 들이 인지하게 만듭니다. 하지만, 이제 두번째 CPU 가 그 값들을
-읽으려 하는 상황을 생각해 봅시다:
-
- CPU 1 CPU 2 COMMENT
- =============== =============== =======================================
- ...
- q = p;
- x = *q;
-
-위의 두개의 읽기 오퍼레이션은 예상된 순서로 일어나지 못할 수 있는데, 두번째 CPU
-의 한 캐시에 다른 캐시 이벤트가 발생해 v 를 담고 있는 캐시라인의 해당 캐시에의
-업데이트가 지연되는 사이, p 를 담고 있는 캐시라인은 두번째 CPU 의 다른 캐시에
-업데이트 되어버렸을 수 있기 때문입니다.
-
- CPU 1 CPU 2 COMMENT
- =============== =============== =======================================
- u == 0, v == 1 and p == &u, q == &u
- v = 2;
- smp_wmb();
- <A:modify v=2> <C:busy>
- <C:queue v=2>
- p = &v; q = p;
- <D:request p>
- <B:modify p=&v> <D:commit p=&v>
- <D:read p>
- x = *q;
- <C:read *q> 캐시에 업데이트 되기 전의 v 를 읽음
- <C:unbusy>
- <C:commit v=2>
-
-기본적으로, 두개의 캐시라인 모두 CPU 2 에 최종적으로는 업데이트 될 것이지만,
-별도의 개입 없이는, 업데이트의 순서가 CPU 1 에서 만들어진 순서와 동일할
-것이라는 보장이 없습니다.
-
-
-여기에 개입하기 위해선, 데이터 의존성 배리어나 읽기 배리어를 로드 오퍼레이션들
-사이에 넣어야 합니다 (v4.15 부터는 READ_ONCE() 매크로에 의해 무조건적으로
-그렇게 됩니다). 이렇게 함으로써 캐시가 다음 요청을 처리하기 전에 일관성 큐를
-처리하도록 강제하게 됩니다.
-
- CPU 1 CPU 2 COMMENT
- =============== =============== =======================================
- u == 0, v == 1 and p == &u, q == &u
- v = 2;
- smp_wmb();
- <A:modify v=2> <C:busy>
- <C:queue v=2>
- p = &v; q = p;
- <D:request p>
- <B:modify p=&v> <D:commit p=&v>
- <D:read p>
- smp_read_barrier_depends()
- <C:unbusy>
- <C:commit v=2>
- x = *q;
- <C:read *q> 캐시에 업데이트 된 v 를 읽음
-
-
-이런 부류의 문제는 DEC Alpha 계열 프로세서들에서 발견될 수 있는데, 이들은
-데이터 버스를 좀 더 잘 사용해 성능을 개선할 수 있는, 분할된 캐시를 가지고 있기
-때문입니다. 대부분의 CPU 는 하나의 읽기 오퍼레이션의 메모리 액세스가 다른 읽기
-오퍼레이션에 의존적이라면 데이터 의존성 배리어를 내포시킵니다만, 모두가 그런건
-아니기 때문에 이점에 의존해선 안됩니다.
-
-다른 CPU 들도 분할된 캐시를 가지고 있을 수 있지만, 그런 CPU 들은 평범한 메모리
-액세스를 위해서도 이 분할된 캐시들 사이의 조정을 해야만 합니다. Alpha 는 가장
-약한 메모리 순서 시맨틱 (semantic) 을 선택함으로써 메모리 배리어가 명시적으로
-사용되지 않았을 때에는 그런 조정이 필요하지 않게 했으며, 이는 Alpha 가 당시에
-더 높은 CPU 클락 속도를 가질 수 있게 했습니다. 하지만, (다시 말하건대, v4.15
-이후부터는) Alpha 아키텍쳐 전용 코드와 READ_ONCE() 매크로 내부에서를 제외하고는
-smp_read_barrier_depends() 가 사용되지 않아야 함을 알아두시기 바랍니다.
-
-
캐시 일관성 VS DMA
------------------
@@ -2954,15 +2848,13 @@ ld.acq 와 stl.rel 인스트럭션을 각각 만들어 내도록 합니다.
DEC Alpha CPU 는 가장 완화된 메모리 순서의 CPU 중 하나입니다. 뿐만 아니라,
Alpha CPU 의 일부 버전은 분할된 데이터 캐시를 가지고 있어서, 의미적으로
관계되어 있는 두개의 캐시 라인이 서로 다른 시간에 업데이트 되는게 가능합니다.
-이게 데이터 의존성 배리어가 정말 필요해지는 부분인데, 데이터 의존성 배리어는
-메모리 일관성 시스템과 함께 두개의 캐시를 동기화 시켜서, 포인터 변경과 새로운
-데이터의 발견을 올바른 순서로 일어나게 하기 때문입니다.
+이게 주소 의존성 배리어가 정말 필요해지는 부분인데, 주소 의존성 배리어는 메모리
+일관성 시스템과 함께 두개의 캐시를 동기화 시켜서, 포인터 변경과 새로운 데이터의
+발견을 올바른 순서로 일어나게 하기 때문입니다.
리눅스 커널의 메모리 배리어 모델은 Alpha 에 기초해서 정의되었습니다만, v4.15
-부터는 리눅스 커널이 READ_ONCE() 내에 smp_read_barrier_depends() 를 추가해서
-Alpha 의 메모리 모델로의 영향력이 크게 줄어들긴 했습니다.
-
-위의 "캐시 일관성" 서브섹션을 참고하세요.
+부터는 Alpha 용 READ_ONCE() 코드 내에 smp_mb() 가 추가되어서 메모리 모델로의
+Alpha 의 영향력이 크게 줄어들었습니다.
가상 머신 게스트
diff --git a/Documentation/translations/sp_SP/disclaimer-sp.rst b/Documentation/translations/sp_SP/disclaimer-sp.rst
new file mode 100644
index 000000000000..841c2523e3dd
--- /dev/null
+++ b/Documentation/translations/sp_SP/disclaimer-sp.rst
@@ -0,0 +1,9 @@
+:orphan:
+
+.. warning::
+ Si tiene alguna duda sobre la exactitud del contenido de esta
+ traducción, la única referencia válida es la documentación oficial en
+ inglés.
+ Además, por defecto, los enlaces a documentos redirigen a la
+ documentación en inglés, incluso si existe una versión traducida.
+ Consulte el índice para más información.
diff --git a/Documentation/translations/sp_SP/index.rst b/Documentation/translations/sp_SP/index.rst
new file mode 100644
index 000000000000..c543b495c042
--- /dev/null
+++ b/Documentation/translations/sp_SP/index.rst
@@ -0,0 +1,80 @@
+
+=====================
+Traducción al español
+=====================
+
+.. raw:: latex
+
+ \kerneldocCJKoff
+
+:maintainer: Carlos Bilbao <carlos.bilbao@amd.com>
+
+.. _sp_disclaimer:
+
+Advertencia
+===========
+
+El objetivo de esta traducción es facilitar la lectura y comprensión para
+aquellos que no entiendan inglés o duden de sus interpretaciones, o
+simplemente para aquellos que prefieran leer en el idioma español. Sin
+embargo, tenga en cuenta que la *única* documentación oficial es la que
+está en inglés: :ref:`linux_doc`
+
+La propagación simultánea de la traducción de una modificación en
+:ref:`linux_doc` es altamente improbable. Los maintainers y colaboradores
+de la traducción intentan mantener sus traducciones al día, en tanto les
+es posible. Por tanto, no existe ninguna garantía de que una traducción
+esté actualizada con las últimas modificaciones. Si lo que lee en una
+traducción no se corresponde con lo que ve en el código fuente, informe
+al maintainer de la traducción y, si puede, consulte la documentación en
+inglés.
+
+Una traducción no es una * bifurcación * de la documentación oficial, por
+lo que los usuarios no encontrarán aquí ninguna información que no sea la
+versión oficial. Cualquier adición, supresión o modificación de los
+contenidos deberá ser realizada anteriormente en los documentos en inglés.
+Posteriormente, y cuando sea posible, dicho cambio debería aplicarse
+también a las traducciones. Los maintainers de las traducciones aceptan
+contribuciones que son puramente de interés relativo a la traducción (por
+ejemplo, nuevas traducciones, actualizaciones, correcciones, etc.).
+
+Las traducciones tratan de ser lo más precisas posible pero no es posible
+convertir directamente un idioma a otro. Cada idioma tiene su propia
+gramática, y una cultura tras ella, por lo tanto, la traducción de una
+oración al inglés se podría modificar para adaptarla al español. Por esta
+razón, cuando lea esta traducción, puede encontrar algunas diferencias en
+la forma, pero todavía transmiten el mensaje original. A pesar de la gran
+difusión del inglés en el idioma hablado, cuando sea posible, expresiones
+en inglés serán reemplazadas por las palabras correspondientes en español.
+
+Si necesita ayuda para comunicarse con la comunidad de Linux pero no se
+siente cómodo escribiendo en inglés, puede pedir ayuda al maintainer para
+obtener una traducción.
+
+Muchos países hablan español, cada uno con su propia cultura, expresiones,
+y diferencias gramaticales en ocasiones significativas. Las traducciones de
+los maintainers pueden utilizar el español con el que dichos maintainers se
+sientan más cómodos. En principio, estas pequeñas diferencias no deberían
+suponer una gran barrera para hablantes de distintas versiones del español,
+pero en caso de duda se puede consultar a los maintainers.
+
+La documentación del kernel Linux
+=================================
+
+Este es el nivel superior de la documentación del kernel en idioma español.
+La traducción es incompleta, y podría encontrar advertencias que indiquen
+la falta de una traducción o de un grupo de traducciones.
+
+En términos más generales, la documentación, como el kernel mismo, están en
+constante desarrollo. Las mejoras en la documentación siempre son
+bienvenidas; de modo que, si desea ayudar, únase a la lista de correo
+linux-doc en vger.kernel.org.
+
+Traducciones al español
+=======================
+
+.. toctree::
+ :maxdepth: 1
+
+ process/index
+ wrappers/memory-barriers
diff --git a/Documentation/translations/sp_SP/memory-barriers.txt b/Documentation/translations/sp_SP/memory-barriers.txt
new file mode 100644
index 000000000000..27097a808c88
--- /dev/null
+++ b/Documentation/translations/sp_SP/memory-barriers.txt
@@ -0,0 +1,3134 @@
+NOTE:
+This is a version of Documentation/memory-barriers.txt translated into
+Spanish by Carlos Bilbao <carlos.bilbao@amd.com>. If you find any
+difference between this document and the original file or a problem with
+the translation, please contact the maintainer of this file. Please also
+note that the purpose of this file is to be easier to read for non English
+(read: Spanish) speakers and is not intended as a fork. So if you have any
+comments or updates for this file please update the original English file
+first. The English version is definitive, and readers should look there if
+they have any doubt.
+
+ ======================================
+ BARRERAS DE MEMORIA EN EL KERNEL LINUX
+ ======================================
+
+Documento original: David Howells <dhowells@redhat.com>
+ Paul E. McKenney <paulmck@linux.ibm.com>
+ Will Deacon <will.deacon@arm.com>
+ Peter Zijlstra <peterz@infradead.org>
+
+Traducido por: Carlos Bilbao <carlos.bilbao@amd.com>
+Nota: Si tiene alguna duda sobre la exactitud del contenido de esta
+traducción, la única referencia válida es la documentación oficial en
+inglés.
+
+===========
+ADVERTENCIA
+===========
+
+Este documento no es una especificación; es intencionalmente (por motivos
+de brevedad) y sin querer (por ser humanos) incompleta. Este documento
+pretende ser una guía para usar las diversas barreras de memoria
+proporcionadas por Linux, pero ante cualquier duda (y hay muchas) por favor
+pregunte. Algunas dudas pueden ser resueltas refiriéndose al modelo de
+consistencia de memoria formal y documentación en tools/memory-model/. Sin
+embargo, incluso este modelo debe ser visto como la opinión colectiva de
+sus maintainers en lugar de que como un oráculo infalible.
+
+De nuevo, este documento no es una especificación de lo que Linux espera
+del hardware.
+
+El propósito de este documento es doble:
+
+ (1) especificar la funcionalidad mínima en la que se puede confiar para
+ cualquier barrera en concreto, y
+
+ (2) proporcionar una guía sobre cómo utilizar las barreras disponibles.
+
+Tenga en cuenta que una arquitectura puede proporcionar más que el
+requisito mínimo para cualquier barrera en particular, pero si la
+arquitectura proporciona menos de eso, dicha arquitectura es incorrecta.
+
+Tenga en cuenta también que es posible que una barrera no valga (sea no-op)
+para alguna arquitectura porque por la forma en que funcione dicha
+arquitectura, la barrera explícita resulte innecesaria en ese caso.
+
+==========
+CONTENIDOS
+==========
+
+ (*) Modelo abstracto de acceso a memoria.
+
+ - Operaciones del dispositivo.
+ - Garantías.
+
+ (*) ¿Qué son las barreras de memoria?
+
+ - Variedades de barrera de memoria.
+ - ¿Qué no se puede asumir sobre las barreras de memoria?
+ - Barreras de dirección-dependencia (históricas).
+ - Dependencias de control.
+ - Emparejamiento de barreras smp.
+ - Ejemplos de secuencias de barrera de memoria.
+ - Barreras de memoria de lectura frente a especulación de carga.
+ - Atomicidad multicopia.
+
+ (*) Barreras explícitas del kernel.
+
+ - Barrera del compilador.
+ - Barreras de memoria de la CPU.
+
+ (*) Barreras de memoria implícitas del kernel.
+
+ - Funciones de adquisición de cerrojo.
+ - Funciones de desactivación de interrupciones.
+ - Funciones de dormir y despertar.
+ - Funciones varias.
+
+ (*) Efectos de barrera adquiriendo intra-CPU.
+
+ - Adquisición vs accesos a memoria.
+
+ (*) ¿Dónde se necesitan barreras de memoria?
+
+ - Interacción entre procesadores.
+ - Operaciones atómicas.
+ - Acceso a dispositivos.
+ - Interrupciones.
+
+ (*) Efectos de barrera de E/S del kernel.
+
+ (*) Modelo de orden mínimo de ejecución asumido.
+
+ (*) Efectos de la memoria caché de la CPU.
+
+ - Coherencia de caché.
+ - Coherencia de caché frente a DMA.
+ - Coherencia de caché frente a MMIO.
+
+ (*) Cosas que hacen las CPU.
+
+ - Y luego está el Alfa.
+ - Guests de máquinas virtuales.
+
+ (*) Ejemplos de usos.
+
+ - Buffers circulares.
+
+ (*) Referencias.
+
+
+====================================
+MODELO ABSTRACTO DE ACCESO A MEMORIA
+====================================
+
+Considere el siguiente modelo abstracto del sistema:
+
+ : :
+ : :
+ : :
+ +-------+ : +--------+ : +-------+
+ | | : | | : | |
+ | | : | | : | |
+ | CPU 1 |<----->| Memoria|<----->| CPU 2 |
+ | | : | | : | |
+ | | : | | : | |
+ +-------+ : +--------+ : +-------+
+ ^ : ^ : ^
+ | : | : |
+ | : | : |
+ | : v : |
+ | : +--------+ : |
+ | : | | : |
+ | : | Disposi| : |
+ +---------->| tivo |<----------+
+ : | | :
+ : | | :
+ : +--------+ :
+ : :
+
+Cada CPU ejecuta un programa que genera operaciones de acceso a la memoria.
+En la CPU abstracta, el orden de las operaciones de memoria es muy
+relajado, y una CPU en realidad puede realizar las operaciones de memoria
+en el orden que desee, siempre que la causalidad del programa parezca
+mantenerse. De manera similar, el compilador también puede organizar las
+instrucciones que emite en el orden que quiera, siempre que no afecte al
+funcionamiento aparente del programa.
+
+Entonces, en el diagrama anterior, los efectos de las operaciones de
+memoria realizadas por un CPU son percibidos por el resto del sistema a
+medida que las operaciones cruzan la interfaz entre la CPU y el resto del
+sistema (las líneas discontinuas a puntos).
+
+Por ejemplo, considere la siguiente secuencia de eventos:
+
+ CPU 1 CPU 2
+ =============== ===============
+ { A == 1; B == 2 }
+ A = 3; x = B;
+ B = 4; y = A;
+
+El conjunto de accesos visto por el sistema de memoria en el medio se puede
+organizar en 24 combinaciones diferentes (donde LOAD es cargar y STORE es
+guardar):
+
+STORE A=3, STORE B=4, y=LOAD A->3, x=LOAD B->4
+STORE A=3, STORE B=4, x=LOAD B->4, y=LOAD A->3
+STORE A=3, y=LOAD A->3, STORE B=4, x=LOAD B->4
+STORE A=3, y=LOAD A->3, x=LOAD B->2, STORE B=4
+STORE A=3, x=LOAD B->2, STORE B=4, y=LOAD A->3
+STORE A=3, x=LOAD B->2, y=LOAD A->3, STORE B=4
+STORE B=4, STORE A=3, y=LOAD A->3, x=LOAD B->4
+STORE B=4, ...
+...
+
+y por lo tanto puede resultar en cuatro combinaciones diferentes de
+valores:
+
+x == 2, y == 1
+x == 2, y == 3
+x == 4, y == 1
+x == 4, y == 3
+
+Además, los stores asignados por una CPU al sistema de memoria pueden no
+ser percibidos por los loads realizados por otra CPU en el mismo orden en
+que fueron realizados.
+
+Como otro ejemplo, considere esta secuencia de eventos:
+
+ CPU 1 CPU 2
+ =============== ===============
+ { A == 1, B == 2, C == 3, P == &A, Q == &C }
+ B = 4; Q = P;
+ P = &B; D = *Q;
+
+Aquí hay una dependencia obvia de la dirección, ya que el valor cargado en
+D depende en la dirección recuperada de P por la CPU 2. Al final de la
+secuencia, cualquiera de los siguientes resultados son posibles:
+
+ (Q == &A) y (D == 1)
+ (Q == &B) y (D == 2)
+ (Q == &B) y (D == 4)
+
+Tenga en cuenta que la CPU 2 nunca intentará cargar C en D porque la CPU
+cargará P en Q antes de emitir la carga de *Q.
+
+OPERACIONES DEL DISPOSITIVO
+---------------------------
+
+Algunos dispositivos presentan sus interfaces de control como colecciones
+de ubicaciones de memoria, pero el orden en que se accede a los registros
+de control es muy importante. Por ejemplo, imagine una tarjeta ethernet con
+un conjunto de registros a los que se accede a través de un registro de
+puerto de dirección (A) y un registro de datos del puerto (D). Para leer el
+registro interno 5, el siguiente código podría entonces ser usado:
+
+ *A = 5;
+ x = *D;
+
+pero esto podría aparecer como cualquiera de las siguientes dos secuencias:
+
+ STORE *A = 5, x = LOAD *D
+ x = LOAD *D, STORE *A = 5
+
+el segundo de las cuales casi con certeza resultará en mal funcionamiento,
+ya que se estableció la dirección _después_ de intentar leer el registro.
+
+
+GARANTÍAS
+---------
+
+Hay algunas garantías mínimas que se pueden esperar de una CPU:
+
+ (*) En cualquier CPU dada, los accesos a la memoria dependiente se
+ emitirán en orden, con respeto a sí mismo. Esto significa que para:
+
+ Q = READ_ONCE(P); D = READ_ONCE(*Q);
+
+ donde READ_ONCE() es LEER_UNA_VEZ(), la CPU emitirá las siguientes
+ operaciones de memoria:
+
+ Q = LOAD P, D = LOAD *Q
+
+ y siempre en ese orden. Sin embargo, en DEC Alpha, READ_ONCE() también
+ emite una instrucción de barrera de memoria, de modo que una CPU DEC
+ Alpha, sin embargo emite las siguientes operaciones de memoria:
+
+ Q = LOAD P, MEMORY_BARRIER, D = LOAD *Q, MEMORY_BARRIER
+
+ Ya sea en DEC Alpha o no, READ_ONCE() también evita que el compilador
+ haga cosas inapropiadas.
+
+ (*) Los loads y stores superpuestos dentro de una CPU en particular
+ parecerán ser ordenados dentro de esa CPU. Esto significa que para:
+
+ a = READ_ONCE(*X); WRITE_ONCE(*X, b);
+
+ donde WRITE_ONCE() es ESCRIBIR_UNA_VEZ(), la CPU solo emitirá la
+ siguiente secuencia de operaciones de memoria:
+
+ a = LOAD *X, STORE *X = b
+
+ Y para:
+
+ WRITE_ONCE(*X, c); d = READ_ONCE(*X);
+
+ la CPU solo emitirá:
+
+ STORE *X = c, d = LOAD *X
+
+ (Los loads y stores se superponen si están destinados a piezas
+ superpuestas de memoria).
+
+Y hay una serie de cosas que _deben_ o _no_ deben asumirse:
+
+ (*) _No_debe_ asumirse que el compilador hará lo que usted quiera
+ con referencias de memoria que no están protegidas por READ_ONCE() y
+ WRITE ONCE(). Sin ellos, el compilador tiene derecho a hacer todo tipo
+ de transformaciones "creativas", que se tratan en la sección BARRERA
+ DEL COMPILADOR.
+
+ (*) _No_debe_ suponerse que se emitirán loads y stores independientes
+ en el orden dado. Esto significa que para:
+
+ X = *A; Y = *B; *D = Z;
+
+ podemos obtener cualquiera de las siguientes secuencias:
+
+ X = LOAD *A, Y = LOAD *B, STORE *D = Z
+ X = LOAD *A, STORE *D = Z, Y = LOAD *B
+ Y = LOAD *B, X = LOAD *A, STORE *D = Z
+ Y = LOAD *B, STORE *D = Z, X = LOAD *A
+ STORE *D = Z, X = LOAD *A, Y = LOAD *B
+ STORE *D = Z, Y = LOAD *B, X = LOAD *A
+
+ (*) Se _debe_ suponer que los accesos de memoria superpuestos pueden
+ fusionarse o ser descartados. Esto significa que para:
+
+ X = *A; Y = *(A + 4);
+
+ podemos obtener cualquiera de las siguientes secuencias:
+
+X = LOAD *A; Y = LOAD *(A + 4);
+Y = LOAD *(A + 4); X = LOAD *A;
+{X, Y} = LOAD {*A, *(A + 4) };
+
+ Y para:
+
+*A = X; *(A + 4) = Y;
+
+ podemos obtener cualquiera de:
+
+STORE *A = X; STORE *(A + 4) = Y;
+STORE *(A + 4) = Y; STORE *A = X;
+STORE {*A, *(A + 4) } = {X, Y};
+
+Y hay anti-garantías:
+
+(*) Estas garantías no se aplican a los campos de bits, porque los
+ compiladores a menudo generan código para modificarlos usando
+ secuencias de lectura-modificación-escritura no atómica. No intente
+ utilizar campos de bits para sincronizar algoritmos paralelos.
+
+(*) Incluso en los casos en que los campos de bits están protegidos por
+ cerrojos (o "cerrojos", o "locks"), todos los componentes en un campo
+ de bits dado deben estar protegidos por un candado. Si dos campos en un
+ campo de bits dado están protegidos por diferentes locks, las
+ secuencias de lectura-modificación-escritura no atómicas del lock
+ pueden causar una actualización a una campo para corromper el valor de
+ un campo adyacente.
+
+(*) Estas garantías se aplican solo a escalares correctamente alineados y
+ dimensionados. De "tamaño adecuado" significa actualmente variables que
+ son del mismo tamaño que "char", "short", "int" y "long".
+ "Adecuadamente alineado" significa la alineación natural, por lo tanto,
+ no hay restricciones para "char", alineación de dos bytes para "short",
+ alineación de cuatro bytes para "int", y alineación de cuatro u ocho
+ bytes para "long", en sistemas de 32 y 64 bits, respectivamente. Tenga
+ en cuenta que estos garantías se introdujeron en el estándar C11, así
+ que tenga cuidado cuando utilice compiladores anteriores a C11 (por
+ ejemplo, gcc 4.6). La parte de la norma que contiene esta garantía es
+ la Sección 3.14, que define "ubicación de memoria" de la siguiente
+ manera:
+
+ ubicación de memoria
+ ya sea un objeto de tipo escalar, o una secuencia máxima
+ de campos de bits adyacentes, todos con ancho distinto de cero
+
+ NOTE 1: Dos hilos de ejecución pueden actualizar y acceder
+ ubicaciones de memoria separadas sin interferir entre
+ ellos.
+
+ NOTE 2: Un campo de bits y un miembro adyacente que no es un campo de
+ bits están en ubicaciones de memoria separadas. Lo mismo sucede con
+ dos campos de bits, si uno se declara dentro de un declaración de
+ estructura anidada y el otro no, o si las dos están separados por una
+ declaración de campo de bits de longitud cero, o si están separados por
+ un miembro no declarado como campo de bits. No es seguro actualizar
+ simultáneamente dos campos de bits en la misma estructura si entre
+ todos los miembros declarados también hay campos de bits, sin importar
+ cuál resulta ser el tamaño de estos campos de bits intermedios.
+
+
+==================================
+¿QUÉ SON LAS BARRERAS DE MEMORIA?
+==================================
+
+Como se puede leer arriba, las operaciones independientes de memoria se
+realizan de manera efectiva en orden aleatorio, pero esto puede ser un
+problema para la interacción CPU-CPU y para la E/S ("I/O"). Lo que se
+requiere es alguna forma de intervenir para instruir al compilador y al
+CPU para restringir el orden.
+
+Las barreras de memoria son este tipo de intervenciones. Imponen una
+percepción de orden parcial, sobre las operaciones de memoria a ambos lados
+de la barrera.
+
+Tal cumplimiento es importante porque las CPUs y otros dispositivos en un
+sistema pueden usar una variedad de trucos para mejorar el rendimiento,
+incluido el reordenamiento, diferimiento y combinación de operaciones de
+memoria; cargas especulativas; predicción de "branches" especulativos y
+varios tipos de almacenamiento en caché. Las barreras de memoria se
+utilizan para anular o suprimir estos trucos, permitiendo que el código
+controle sensatamente la interacción de múltiples CPU y/o dispositivos.
+
+
+VARIEDADES DE BARRERA DE MEMORIA
+---------------------------------
+
+Las barreras de memoria vienen en cuatro variedades básicas:
+
+ (1) Barreras de memoria al escribir o almacenar (Write or store memory
+ barriers).
+
+ Una barrera de memoria de escritura garantiza que todas las
+ operaciones de STORE especificadas antes de que la barrera aparezca
+ suceden antes de todas las operaciones STORE especificadas después
+ de la barrera, con respecto a los otros componentes del sistema.
+
+ Una barrera de escritura es un orden parcial solo en los stores; No
+ es requerido que tenga ningún efecto sobre los loads.
+
+ Se puede considerar que una CPU envía una secuencia de operaciones de
+ store al sistema de memoria a medida que pasa el tiempo. Todos los
+ stores _antes_ de una barrera de escritura ocurrirán _antes_ de todos
+ los stores después de la barrera de escritura.
+
+ [!] Tenga en cuenta que las barreras de escritura normalmente deben
+ combinarse con read o barreras de address-dependency barriers
+ (dependencia de dirección); consulte la subsección
+ "Emparejamiento de barreras smp".
+
+
+ (2) Barrera de dependencia de dirección (histórico).
+
+ Una barrera de dependencia de dirección es una forma más débil de
+ barrera de lectura. En el caso de que se realicen dos loads de manera
+ que la segunda dependa del resultado de la primera (por ejemplo: el
+ primer load recupera la dirección a la que se dirigirá el segundo
+ load), una barrera de dependencia de dirección sería necesaria para
+ asegurarse de que el objetivo de la segunda carga esté actualizado
+ después de acceder a la dirección obtenida por la primera carga.
+
+ Una barrera de dependencia de direcciones es una ordenación parcial en
+ laods de direcciones interdependientes; no se requiere que tenga
+ ningún efecto en los stores, ya sean cargas de memoria o cargas
+ de memoria superpuestas.
+
+ Como se mencionó en (1), las otras CPU en el sistema pueden verse como
+ secuencias de stores en el sistema de memoria que la considerada CPU
+ puede percibir. Una barrera de dependencia de dirección emitida por
+ la CPU en cuestión garantiza que para cualquier carga que la preceda,
+ si esa carga toca alguna secuencia de stores de otra CPU, entonces
+ en el momento en que la barrera se complete, los efectos de todos los
+ stores antes del cambio del load serán perceptibles por cualquier
+ carga emitida después la barrera de la dependencia de la dirección.
+
+ Consulte la subsección "Ejemplos de secuencias de barrera de memoria"
+ para ver los diagramas mostrando las restricciones de orden.
+
+ [!] Tenga en cuenta que la primera carga realmente tiene que tener una
+ dependencia de _dirección_ y no es una dependencia de control. Si la
+ dirección para la segunda carga depende de la primera carga, pero la
+ dependencia es a través de un condicional en lugar de -en realidad-
+ cargando la dirección en sí, entonces es una dependencia de _control_
+ y se requiere una barrera de lectura completa o superior. Consulte la
+ subsección "Dependencias de control" para más información.
+
+ [!] Tenga en cuenta que las barreras de dependencia de dirección
+ normalmente deben combinarse con barreras de escritura; consulte la
+ subsección "Emparejamiento de barreras smp".
+
+ [!] Desde el kernel v5.9, se eliminó la API del kernel para barreras
+ de memoria de direcciones explícitas. Hoy en día, las APIs para marcar
+ cargas de variables compartidas, como READ_ONCE() y rcu_dereference(),
+ proporcionan barreras de dependencia de dirección implícitas.
+
+ (3) Barreras de memoria al leer o cargar (Read or load memory
+ barriers).
+
+ Una barrera de lectura es una barrera de dependencia de direcciones,
+ más una garantía de que todas las operaciones de LOAD especificadas
+ antes de la barrera parecerán ocurrir antes de todas las operaciones
+ de LOAD especificadas después de la barrera con respecto a los demás
+ componentes del sistema.
+
+ Una barrera de lectura es un orden parcial solo en cargas; no es
+ necesario que tenga ningún efecto en los stores.
+
+ Las barreras de memoria de lectura implican barreras de dependencia de
+ direcciones, y por tanto puede sustituirlas por estas.
+
+ [!] Tenga en mente que las barreras de lectura normalmente deben
+ combinarse con barreras de escritura; consulte la subsección
+ "Emparejamiento de barreras smp".
+
+ (4) Barreras de memoria generales
+
+ Una barrera de memoria general proporciona la garantía de que todas
+ las operaciones LOAD y STORE especificadas antes de que la barrera
+ aparezca suceden antes de que todas las operaciones LOAD y STORE
+ especificadas después de la barrera con respecto a los demás
+ componentes del sistema.
+
+ Una barrera de memoria general es un orden parcial tanto en
+ operaciones de carga como de almacenamiento.
+
+ Las barreras de memoria generales implican barreras de memoria tanto
+ de lectura como de escritura, de modo que pueden sustituir a
+ cualquiera.
+
+Y un par de variedades implícitas:
+
+ (5) ACQUIRE (de adquisición).
+
+ Esto actúa como una barrera permeable unidireccional. Garantiza que
+ toda las operaciones de memoria después de la operación ACQUIRE
+ parezcan suceder después de la ACQUIRE con respecto a los demás
+ componentes del sistema. Las operaciones ACQUIRE incluyen operaciones
+ LOCK y smp_load_acquire(), y operaciones smp_cond_load_acquire().
+
+ Las operaciones de memoria que ocurren antes de una operación ACQUIRE
+ pueden parecer suceder después de que se complete.
+
+ Una operación ACQUIRE casi siempre debe estar emparejada con una
+ operación RELEASE (de liberación).
+
+
+ (6) Operaciones RELEASE (de liberación).
+
+ Esto también actúa como una barrera permeable unidireccional.
+ Garantiza que todas las operaciones de memoria antes de la operación
+ RELEASE parecerán ocurrir antes de la operación RELEASE con respecto a
+ los demás componentes del sistema. Las operaciones de RELEASE incluyen
+ operaciones de UNLOCK y operaciones smp_store_release().
+
+ Las operaciones de memoria que ocurren después de una operación
+ RELEASE pueden parecer suceder antes de que se complete.
+
+ El uso de las operaciones ACQUIRE y RELEASE generalmente excluye la
+ necesidad de otros tipos de barrera de memoria. Además, un par
+ RELEASE+ACQUIRE NO garantiza actuar como una barrera de memoria
+ completa. Sin embargo, después de un ACQUIRE de una variable dada,
+ todos los accesos a la memoria que preceden a cualquier anterior
+ RELEASE en esa misma variable están garantizados como visibles. En
+ otras palabras, dentro de la sección crítica de una variable dada,
+ todos los accesos de todas las secciones críticas anteriores para esa
+ variable habrán terminado de forma garantizada.
+
+ Esto significa que ACQUIRE actúa como una operación mínima de
+ "adquisición" y RELEASE actúa como una operación mínima de
+ "liberación".
+
+Un subconjunto de las operaciones atómicas descritas en atomic_t.txt
+contiene variantes de ACQUIRE y RELEASE, además de definiciones
+completamente ordenadas o relajadas (sin barrera semántica). Para
+composiciones atómicas que realizan tanto un load como store, la semántica
+ACQUIRE se aplica solo a la carga y la semántica RELEASE se aplica sólo a
+la parte de la operación del store.
+
+Las barreras de memoria solo son necesarias cuando existe la posibilidad de
+interacción entre dos CPU o entre una CPU y un dispositivo. Si se puede
+garantizar que no habrá tal interacción en ninguna pieza de código en
+particular, entonces las barreras de memoria son innecesarias en ese
+fragmento de código.
+
+Tenga en cuenta que estas son las garantías _mínimas_. Diferentes
+arquitecturas pueden proporcionar garantías más sustanciales, pero no se
+puede confiar en estas fuera de esa arquitectura en específico.
+
+
+¿QUÉ NO SE PUEDE ASUMIR SOBRE LAS BARRERAS DE LA MEMORIA?
+---------------------------------------------------------
+
+Hay ciertas cosas que las barreras de memoria del kernel Linux no
+garantizan:
+
+ (*) No hay garantía de que ninguno de los accesos a la memoria
+ especificados antes de una barrera de memoria estará _completo_ al
+ completarse una instrucción de barrera de memoria; se puede considerar
+ que la barrera dibuja una línea en la cola de acceso del CPU que no
+ pueden cruzar los accesos del tipo correspondiente.
+
+ (*) No hay garantía de que la emisión de una barrera de memoria en una CPU
+ tenga cualquier efecto directo en otra CPU o cualquier otro hardware
+ en el sistema. El efecto indirecto será el orden en que la segunda CPU
+ ve los efectos de los primeros accesos que ocurren de la CPU, pero lea
+ el siguiente argumento:
+
+ (*) No hay garantía de que una CPU vea el orden correcto de los efectos
+ de los accesos de una segunda CPU, incluso _si_ la segunda CPU usa una
+ barrera de memoria, a menos que la primera CPU _también_ use una
+ barrera de memoria coincidente (vea el subapartado "Emparejamiento de
+ barrera SMP").
+
+ (*) No hay garantía de que alguna pieza intermedia fuera del hardware[*]
+ del CPU no reordenará los accesos a la memoria. Los mecanismos de
+ coherencia de caché del CPU deben propagar los efectos indirectos de
+ una barrera de memoria entre las CPU, pero es posible que no lo hagan
+ en orden.
+
+ [*] Para obtener información sobre bus mastering DMA y coherencia, lea:
+
+ Documentation/driver-api/pci/pci.rst
+ Documentation/core-api/dma-api-howto.rst
+ Documentation/core-api/dma-api.rst
+
+
+BARRERA DE DEPENDENCIA DE DIRECCIÓN (HISTÓRICO)
+-----------------------------------------------
+
+A partir de la versión 4.15 del kernel Linux, se agregó un smp_mb() a
+READ_ONCE() para DEC Alpha, lo que significa que las únicas personas que
+necesitan prestar atención a esta sección son aquellas que trabajan en el
+código específico de la arquitectura DEC Alpha y aquellas que trabajan en
+READ_ONCE() por dentro. Para aquellos que lo necesitan, y para aquellos que
+estén interesados desde un punto de vista histórico, aquí está la historia
+de las barreras de dependencia de dirección.
+
+[!] Si bien las dependencias de direcciones se observan tanto en carga a
+carga como en relaciones de carga a store, las barreras de dependencia de
+dirección no son necesarias para situaciones de carga a store.
+
+El requisito de las barreras de dependencia de dirección es un poco sutil,
+y no siempre es obvio que sean necesarias. Para ilustrar, considere la
+siguiente secuencia de eventos:
+
+ CPU 1 CPU 2
+ =============== ===============
+ { A == 1, B == 2, C == 3, P == &A, Q == &C }
+ B = 4;
+ <barrera de escritura>
+ WRITE_ONCE(P, &B);
+ Q = READ_ONCE_OLD(P);
+ D = *Q;
+
+[!] READ_ONCE_OLD() corresponde a READ_ONCE() del kernel anterior a 4.15,
+que no implica una barrera de dependencia de direcciones.
+
+Hay una clara dependencia de dirección aquí, y parecería que al final de
+la secuencia, Q debe ser &A o &B, y que:
+
+ (Q == &A) implica (D == 1)
+ (Q == &B) implica (D == 4)
+
+¡Pero! La percepción de la CPU 2 de P puede actualizarse _antes_ de su
+percepción de B, por lo tanto dando lugar a la siguiente situación:
+
+ (Q == &B) y (D == 2) ????
+
+Si bien esto puede parecer una falla en el mantenimiento de la coherencia
+o la causalidad, no lo es, y este comportamiento se puede observar en
+ciertas CPU reales (como DEC Alfa).
+
+Para lidiar con esto, READ_ONCE() proporciona una barrera de dependencia
+de dirección implícita desde el lanzamiento del kernel v4.15:
+
+ CPU 1 CPU 2
+ =============== ===============
+ { A == 1, B == 2, C == 3, P == &A, Q == &C }
+ B = 4;
+ <barrera de escritura>
+ WRITE_ONCE(P, &B);
+ Q = READ_ONCE(P);
+ <barrera de dependencia de dirección implícita>
+ D = *Q;
+
+Esto refuerza la ocurrencia de una de las dos implicaciones, y previene la
+tercera posibilidad de surgir.
+
+
+[!] Tenga en cuenta que esta situación extremadamente contraria a la
+intuición surge más fácilmente en máquinas con cachés divididos, de modo
+que, por ejemplo, un banco de caché procesa líneas de caché pares y el otro
+banco procesa líneas impares de caché. El puntero P podría almacenarse en
+una línea de caché impar y la variable B podría almacenarse en una línea de
+caché con número par. Entonces, si el banco de números pares de la memoria
+caché de la CPU de lectura está extremadamente ocupado mientras que el
+banco impar está inactivo, uno podría ver el nuevo valor del puntero P
+(&B), pero el antiguo valor de la variable B (2).
+
+
+No se requiere una barrera de dependencia de dirección para ordenar
+escrituras dependientes porque las CPU que admite el kernel Linux no
+escriben hasta que están seguros (1) de que la escritura realmente
+sucederá, (2) de la ubicación de la escritura, y (3) del valor a escribir.
+Pero, por favor, lea atentamente la sección "DEPENDENCIAS DEL CONTROL" y el
+archivo Documentation/RCU/rcu_dereference.rst: el compilador puede romperse
+y romper dependencias en muchas formas altamente creativas.
+
+ CPU 1 CPU 2
+ =============== ===============
+ { A == 1, B == 2, C = 3, P == &A, Q == &C }
+ B = 4;
+ <barrera de escritura>
+ WRITE_ONCE(P, &B);
+ Q = READ_ONCE_OLD(P);
+ WRITE_ONCE(*Q, 5);
+
+Por lo tanto, no se requiere ninguna barrera de dependencia de direcciones
+para ordenar la lectura en Q con el load en *Q. En otras palabras, este
+resultado está prohibido, incluso sin una barrera de dependencia de
+dirección implícita del READ_ONCE() moderno:
+
+ (Q == &B) && (B == 4)
+
+Tenga en cuenta que este patrón debe ser raro. Después de todo, el objetivo
+del orden de dependencia es -prevenir- escrituras en la estructura de
+datos, junto con los costosos errores de caché asociados con tales
+escrituras. Este patrón se puede utilizar para registrar raras condiciones
+de error y similares, y el orden natural de las CPUs evita que se pierdan
+tales registros.
+
+
+Tenga en cuenta que el orden proporcionado por una dependencia de dirección
+es local para la CPU que lo contiene. Lea la sección sobre "Atomicidad
+multicopia" para más información.
+
+
+La barrera de dependencia de dirección es muy importante para el sistema
+RCU, por ejemplo. Vea rcu_assign_pointer() y rcu_dereference() en
+include/linux/rcupdate.h. Esto permite que el objetivo actual de un puntero
+RCU sea reemplazado con un nuevo objetivo modificado, sin que el objetivo
+del reemplazo parezca estar inicializado de manera incompleta.
+
+Consulte también la subsección sobre "Coherencia de caché" para obtener un
+ejemplo más completo.
+
+DEPENDENCIAS DE CONTROL
+-----------------------
+
+Las dependencias de control pueden ser un poco complicadas porque los
+compiladores actuales no las entienden. El propósito de esta sección es
+ayudarle a prevenir que la ignorancia del compilador rompa su código.
+
+Una dependencia de control load-load (de carga a carga) requiere una
+barrera de memoria de lectura completa, no simplemente una barrera
+(implícita) de dependencia de direcciones para que funcione correctamente.
+Considere el siguiente fragmento de código:
+
+ q = READ_ONCE(a);
+ <barrera implícita de dependencia de direcciones>
+ if (q) {
+ /* BUG: No hay dependencia de dirección!!! */
+ p = READ_ONCE(b);
+ }
+
+Esto no tendrá el efecto deseado porque no hay una dependencia de dirección
+real, sino más bien una dependencia de control que la CPU puede
+cortocircuitar al intentar predecir el resultado por adelantado, para que
+otras CPU vean la carga de b como si hubiera ocurrido antes que la carga de
+a. En cuyo caso lo que realmente se requiere es:
+
+ q = READ_ONCE(a);
+ if (q) {
+ <barrera de lectura>
+ p = READ_ONCE(b);
+ }
+
+Sin embargo, los stores no se especulan. Esto significa que ordenar -es-
+provisto para dependencias de control de load-store, como en el siguiente
+ejemplo:
+
+ q = READ_ONCE(a);
+ if (q) {
+ WRITE_ONCE(b, 1);
+ }
+
+Las dependencias de control se emparejan normalmente con otros tipos de
+barreras. Dicho esto, tenga en cuenta que ni READ_ONCE() ni WRITE_ONCE()
+son opcionales! Sin READ_ONCE(), el compilador podría combinar la carga de
+'a' con otras cargas de 'a'. Sin WRITE_ONCE(), el compilador podría
+combinar el store de 'b' con otros stores de 'b'. Cualquiera de estos casos
+puede dar lugar a efectos en el orden muy contrarios a la intuición.
+
+Peor aún, si el compilador puede probar (decir) que el valor de la
+variable 'a' siempre es distinta de cero, estaría dentro de sus derechos
+para optimizar el ejemplo original eliminando la declaración "if", como:
+
+ q = a;
+ b = 1; /* BUG: Compilador y CPU pueden ambos reordernar!!! */
+
+Así que no deje de lado READ_ONCE().
+
+Es tentador tratar de hacer cumplir el orden en stores idénticos en ambos
+caminos del "if" de la siguiente manera:
+
+ q = READ_ONCE(a);
+ if (q) {
+ barrier();
+ WRITE_ONCE(b, 1);
+ hacer_algo();
+ } else {
+ barrier();
+ WRITE_ONCE(b, 1);
+ hacer_otra_cosa();
+ }
+
+Desafortunadamente, los compiladores actuales transformarán esto de la
+siguiente manera en casos de alto nivel de optimización:
+
+ q = READ_ONCE(a);
+ barrier();
+ WRITE_ONCE(b, 1); /* BUG: No hay orden en load de a!!! */
+ if (q) {
+ /* WRITE_ONCE(b, 1); -- movido arriba, BUG!!! */
+ hacer_algo();
+ } else {
+ /* WRITE_ONCE(b, 1); -- movido arriba, BUG!!! */
+ hacer_otra_cosa();
+ }
+
+Ahora no hay condicional entre la carga de 'a' y el store de 'b', lo que
+significa que la CPU está en su derecho de reordenarlos: El condicional es
+absolutamente necesario y debe estar presente en el código ensamblador
+incluso después de que se hayan aplicado todas las optimizaciones del
+compilador. Por lo tanto, si necesita ordenar en este ejemplo, necesita
+explícitamente barreras de memoria, por ejemplo, smp_store_release():
+
+
+ q = READ_ONCE(a);
+ if (q) {
+ smp_store_release(&b, 1);
+ hacer_algo();
+ } else {
+ smp_store_release(&b, 1);
+ hacer_otra_cosa();
+ }
+
+Por el contrario, sin barreras de memoria explícita, el control de un if
+con dos opciones está garantizado solo cuando los stores difieren, por
+ejemplo:
+
+ q = READ_ONCE(a);
+ if (q) {
+ WRITE_ONCE(b, 1);
+ hacer_algo();
+ } else {
+ WRITE_ONCE(b, 2);
+ hacer_otra_cosa();
+ }
+
+Aún se requiere el inicial READ_ONCE() para evitar que el compilador toque
+el valor de 'a'.
+
+Además, debe tener cuidado con lo que hace con la variable local 'q', de lo
+contrario, el compilador podría adivinar el valor y volver a eliminar el
+necesario condicional. Por ejemplo:
+
+ q = READ_ONCE(a);
+ if (q % MAX) {
+ WRITE_ONCE(b, 1);
+ hacer_algo();
+ } else {
+ WRITE_ONCE(b, 2);
+ hacer_otra_cosa();
+ }
+
+Si MAX se define como 1, entonces el compilador sabe que (q % MAX) es igual
+a cero, en cuyo caso el compilador tiene derecho a transformar el código
+anterior en el siguiente:
+
+ q = READ_ONCE(a);
+ WRITE_ONCE(b, 2);
+ hacer_otra_cosa();
+
+Dada esta transformación, la CPU no está obligada a respetar el orden entre
+la carga de la variable 'a' y el store de la variable 'b'. Es tentador
+agregar una barrier(), pero esto no ayuda. El condicional se ha ido, y la
+barrera no lo traerá de vuelta. Por lo tanto, si confia en este orden, debe
+asegurarse de que MAX sea mayor que uno, tal vez de la siguiente manera:
+
+ q = READ_ONCE(a);
+ BUILD_BUG_ON(MAX <= 1); /* Orden de carga de a con store de b */
+ if (q % MAX) {
+ WRITE_ONCE(b, 1);
+ hacer_algo();
+ } else {
+ WRITE_ONCE(b, 2);
+ hacer_otra_cosa();
+ }
+
+Tenga en cuenta una vez más que los stores de 'b' difieren. Si fueran
+idénticos, como se señaló anteriormente, el compilador podría sacar ese
+store fuera de la declaración 'if'.
+
+También debe tener cuidado de no confiar demasiado en el cortocircuito
+de la evaluación booleana. Considere este ejemplo:
+
+ q = READ_ONCE(a);
+ if (q || 1 > 0)
+ WRITE_ONCE(b, 1);
+
+Debido a que la primera condición no puede fallar y la segunda condición es
+siempre cierta, el compilador puede transformar este ejemplo de la
+siguiente manera, rompiendo la dependencia del control:
+
+ q = READ_ONCE(a);
+ WRITE_ONCE(b, 1);
+
+Este ejemplo subraya la necesidad de asegurarse de que el compilador no
+pueda adivinar su código. Más generalmente, aunque READ_ONCE() fuerza
+al compilador para emitir código para una carga dada, no fuerza al
+compilador para usar los resultados.
+
+Además, las dependencias de control se aplican solo a la cláusula then y
+la cláusula else de la sentencia if en cuestión. En particular, no se
+aplica necesariamente al código que sigue a la declaración if:
+
+ q = READ_ONCE(a);
+ if (q) {
+ WRITE_ONCE(b, 1);
+ } else {
+ WRITE_ONCE(b, 2);
+ }
+ WRITE_ONCE(c, 1); /* BUG: No hay orden para la lectura de 'a'. */
+
+Es tentador argumentar que, de hecho, existe un orden porque el compilador
+no puede reordenar accesos volátiles y tampoco puede reordenar escrituras
+en 'b' con la condición. Desafortunadamente para esta línea de
+razonamiento, el compilador podría compilar las dos escrituras en 'b' como
+instrucciones de movimiento condicional, como en este fantástico idioma
+pseudo-ensamblador:
+
+ ld r1,a
+ cmp r1,$0
+ cmov,ne r4,$1
+ cmov,eq r4,$2
+ st r4,b
+ st $1,c
+
+Una CPU débilmente ordenada no tendría dependencia de ningún tipo entre la
+carga de 'a' y el store de 'c'. Las dependencias de control se extenderían
+solo al par de instrucciones cmov y el store dependiente de ellas. En
+resumen, las dependencias de control se aplican solo a los stores en la
+cláusula then y la cláusula else de la sentencia if en cuestión (incluidas
+las funciones invocado por esas dos cláusulas), no al código que sigue a
+esa declaración if.
+
+
+Tenga muy en cuenta que el orden proporcionado por una dependencia de
+control es local a la CPU que lo contiene. Vea el apartado de "Atomicidad
+multicopia" para más información.
+
+
+En resumen:
+
+ (*) Las dependencias de control pueden ordenar cargas anteriores para
+ stores posteriores. Sin embargo, no garantizan ningún otro tipo de
+ orden: No cargas previas contra cargas posteriores, ni
+ almacenamientos previos y luego nada. Si necesita tales formas de
+ orden, use smp_rmb(), smp_wmb() o, en el caso de stores anteriores y
+ cargas posteriores, smp_mb().
+
+ (*) Si ambos caminos de la declaración "if" comienzan con stores
+ idénticos de la misma variable, entonces esos stores deben ser
+ ordenados, ya sea precediéndoles a ambos con smp_mb() o usando
+ smp_store_release() para realizar el store. Tenga en cuenta que -no-
+ es suficiente usar barrier() al comienzo de cada caso de la
+ declaración "if" porque, como se muestra en el ejemplo anterior, la
+ optimización de los compiladores puede destruir la dependencia de
+ control respetando al pie de la letra la ley de barrier().
+
+ (*) Las dependencias de control requieren al menos un condicional en
+ tiempo de ejecución entre la carga anterior y el almacenamiento
+ posterior, y este condicional debe implicar la carga previa. Si el
+ compilador es capaz de optimizar el condicional y quitarlo, también
+ habrá optimizado el ordenar. El uso cuidadoso de READ_ONCE() y
+ WRITE_ONCE() puede ayudar a preservar el necesario condicional.
+
+ (*) Las dependencias de control requieren que el compilador evite
+ reordenar las dependencia hasta su inexistencia. El uso cuidadoso de
+ READ_ONCE() o atomic{,64}_read() puede ayudarle a preservar la
+ dependencia de control. Consulte la sección BARRERA DEL COMPILADOR
+ para obtener más información al respecto.
+
+ (*) Las dependencias de control se aplican solo a la cláusula then y la
+ cláusula else de la sentencia "if" que contiene la dependencia de
+ control, incluyendo cualquier función a la que llamen dichas dos
+ cláusulas. Las dependencias de control no se aplican al código que
+ sigue a la instrucción if que contiene la dependencia de control.
+
+ (*) Las dependencias de control se emparejan normalmente con otros tipos
+ de barreras.
+
+ (*) Las dependencias de control no proporcionan atomicidad multicopia. Si
+ usted necesita todas las CPU para ver un store dado al mismo tiempo,
+ emplee smp_mb().
+
+ (*) Los compiladores no entienden las dependencias de control. Por lo
+ tanto es su trabajo asegurarse de que no rompan su código.
+
+
+EMPAREJAMIENTO DE BARRERAS SMP
+------------------------------
+
+Cuando se trata de interacciones CPU-CPU, ciertos tipos de barrera de
+memoria deben estar siempre emparejados. La falta del apropiado
+emparejamiento es casi seguro un error.
+
+Las barreras generales se emparejan entre sí, aunque también se emparejan
+con la mayoría de otro tipo de barreras, aunque sin atomicidad multicopia.
+Una barrera de adquisición se empareja con una barrera de liberación, pero
+ambas también pueden emparejarse con otras barreras, incluidas, por
+supuesto, las barreras generales. Una barrera de escritura se empareja con
+una barrera de dependencia de dirección, una dependencia de control, una
+barrera de adquisición, una barrera de liberación, una barrera de lectura
+o una barrera general. Del mismo modo, una barrera de lectura se empareja
+con una de dependencia de control o barrera de dependencia de dirección con
+una barrera de escritura, una barrera de adquisición, una barrera de
+liberación o una barrera general:
+
+ CPU 1 CPU 2
+ =============== ===============
+ WRITE_ONCE(a, 1);
+ <barrera de escritura>
+ WRITE_ONCE(b, 2); x = READ_ONCE(b);
+ <barrera de lectura>
+ y = READ_ONCE(a);
+
+O bien:
+
+ CPU 1 CPU 2
+ =============== ===============================
+ a = 1;
+ <barrera de escritura>
+ WRITE_ONCE(b, &a); x = READ_ONCE(b);
+ <barrera de dependencia de dirección implícita>
+ y = *x;
+
+O incluso:
+
+ CPU 1 CPU 2
+ =============== ===============================
+ r1 = READ_ONCE(y);
+ <barrera general>
+ WRITE_ONCE(x, 1); if (r2 = READ_ONCE(x)) {
+ <barrera de control implícita>
+ WRITE_ONCE(y, 1);
+ }
+
+ assert(r1 == 0 || r2 == 0);
+
+Básicamente, la barrera de lectura siempre tiene que estar ahí, aunque
+puede ser del tipo "más débil".
+
+[!] Tenga en cuenta que normalmente se esperaría que los stores antes de la
+barrera de escritura se hagan coincidir con los stores después de la
+barrera de lectura o la barrera de dependencia de dirección, y viceversa:
+
+ CPU 1 CPU 2
+ =================== ===================
+ WRITE_ONCE(a, 1); }---- --->{ v = READ_ONCE(c);
+ WRITE_ONCE(b, 2); } \ / { w = READ_ONCE(d);
+ <barrera de escritura> \ <barrera de lectura>
+ WRITE_ONCE(c, 3); } / \ { x = READ_ONCE(a);
+ WRITE_ONCE(d, 4); }---- --->{ y = READ_ONCE(b);
+
+
+EJEMPLOS DE SECUENCIAS DE BARRERA DE MEMORIA
+--------------------------------------------
+
+En primer lugar, las barreras de escritura actúan como orden parcial en las
+operaciones de store. Considere la siguiente secuencia de eventos:
+
+ CPU 1
+ =======================
+ STORE A = 1
+ STORE B = 2
+ STORE C = 3
+ <barrera de escritura>
+ STORE D = 4
+ STORE E = 5
+
+Esta secuencia de eventos es finalizado para con el sistema de coherencia
+de memoria en un orden que el resto del sistema podría percibir como el
+conjunto desordenado { STORE A, STORE B, STORE C} todo ocurriendo antes del
+conjunto desordenado { STORE D, STORE E}:
+
+
+ +-------+ : :
+ | | +------+
+ | |------>| C=3 | } /\
+ | | : +------+ }----- \ -----> Eventos perceptibles para
+ | | : | A=1 | } \/ el resto del sistema
+ | | : +------+ }
+ | CPU 1 | : | B=2 | }
+ | | +------+ }
+ | | wwwwwwwwwwwwwwww } <--- En este momento la barrera de
+ | | +------+ } escritura requiere que todos los
+ | | : | E=5 | } stores anteriores a la barrera
+ | | : +------+ } sean confirmados antes de que otros
+ | |------>| D=4 | } store puedan suceder
+ | | +------+
+ +-------+ : :
+ |
+ | Secuencia por la cual los stores son confirmados al
+ | sistema de memoria por parte del CPU 1
+ V
+
+En segundo lugar, las barreras de dependencia de dirección actúan como
+órdenes parciales sobre la dirección de cargas dependientes. Considere la
+siguiente secuencia de eventos:
+
+ CPU 1 CPU 2
+ ======================= =======================
+ { B = 7; X = 9; Y = 8; C = &Y }
+ STORE A = 1
+ STORE B = 2
+ <barrera de escritura>
+ STORE C = &B LOAD X
+ STORE D = 4 LOAD C (consigue &B)
+ LOAD *C (lee B)
+
+Sin intervención, la CPU 2 puede percibir los eventos en la CPU 1 en orden
+aleatorio a efectos prácticos, a pesar de la barrera de escritura emitida
+por la CPU 1:
+
+ +-------+ : : : :
+ | | +------+ +-------+ | Secuencia de
+ | |------>| B=2 |----- --->| Y->8 | | actualizado de
+ | | : +------+ \ +-------+ | percepción en CPU 2
+ | CPU 1 | : | A=1 | \ --->| C->&Y | V
+ | | +------+ | +-------+
+ | | wwwwwwwwwwwwwwww | : :
+ | | +------+ | : :
+ | | : | C=&B |--- | : : +-------+
+ | | : +------+ \ | +-------+ | |
+ | |------>| D=4 | ----------->| C->&B |------>| |
+ | | +------+ | +-------+ | |
+ +-------+ : : | : : | |
+ | : : | |
+ | : : | CPU 2 |
+ | +-------+ | |
+ Percepción de B ---> | | B->7 |------>| |
+ aparentemente incorrecta! | +-------+ | |
+ | : : | |
+ | +-------+ | |
+ La carga de X frena ---> \ | X->9 |------>| |
+ el mantenimiento de \ +-------+ | |
+ la coherencia de B ----->| B->2 | +-------+
+ +-------+
+ : :
+
+
+En el ejemplo anterior, la CPU 2 percibe que B es 7, a pesar de la carga de
+*C (que sería B) viniendo después del LOAD de C.
+
+Sin embargo, si se colocara una barrera de dependencia de dirección entre
+la carga de C y la carga de *C (es decir: B) en la CPU 2:
+
+ CPU 1 CPU 2
+ ======================= =======================
+ { B = 7; X = 9; Y = 8; C = &Y }
+ STORE A = 1
+ STORE B = 2
+ <barrera de escritura>
+ STORE C = &B LOAD X
+ STORE D = 4 LOAD C (consigue &B)
+ <barrera de dependencia de dirección>
+ LOAD *C (reads B)
+
+entonces ocurrirá lo siguiente:
+
+ +-------+ : : : :
+ | | +------+ +-------+
+ | |------>| B=2 |----- --->| Y->8 |
+ | | : +------+ \ +-------+
+ | CPU 1 | : | A=1 | \ --->| C->&Y |
+ | | +------+ | +-------+
+ | | wwwwwwwwwwwwwwww | : :
+ | | +------+ | : :
+ | | : | C=&B |--- | : : +-------+
+ | | : +------+ \ | +-------+ | |
+ | |------>| D=4 | ----------->| C->&B |------>| |
+ | | +------+ | +-------+ | |
+ +-------+ : : | : : | |
+ | : : | |
+ | : : | CPU 2 |
+ | +-------+ | |
+ | | X->9 |------>| |
+ | +-------+ | |
+ Se asegura de que ---> \ aaaaaaaaaaaaaaaaa | |
+ los efectos anteriores al \ +-------+ | |
+ store de C sean percibidos ----->| B->2 |------>| |
+ por los siguientes loads +-------+ | |
+ : : +-------+
+
+
+Y en tercer lugar, una barrera de lectura actúa como un orden parcial sobre
+las cargas. Considere la siguiente secuencia de eventos:
+
+ CPU 1 CPU 2
+ ======================= =======================
+ { A = 0, B = 9 }
+ STORE A=1
+ <barrera de escritura>
+ STORE B=2
+ LOAD B
+ LOAD A
+
+Sin intervención, la CPU 2 puede elegir percibir los eventos en la CPU 1 en
+algún orden aleatorio a efectos prácticos, a pesar de la barrera de
+escritura emitida por la CPU 1:
+
+ +-------+ : : : :
+ | | +------+ +-------+
+ | |------>| A=1 |------ --->| A->0 |
+ | | +------+ \ +-------+
+ | CPU 1 | wwwwwwwwwwwwwwww \ --->| B->9 |
+ | | +------+ | +-------+
+ | |------>| B=2 |--- | : :
+ | | +------+ \ | : : +-------+
+ +-------+ : : \ | +-------+ | |
+ ---------->| B->2 |------>| |
+ | +-------+ | CPU 2 |
+ | | A->0 |------>| |
+ | +-------+ | |
+ | : : +-------+
+ \ : :
+ \ +-------+
+ ---->| A->1 |
+ +-------+
+ : :
+
+Sin embargo, si se colocara una barrera de lectura entre la carga de B y la
+carga de A en la CPU 2:
+
+ CPU 1 CPU 2
+ ======================= =======================
+ { A = 0, B = 9 }
+ STORE A=1
+ <barrera de escritura>
+ STORE B=2
+ LOAD B
+ <barrera de lectura>
+ LOAD A
+
+entonces el orden parcial impuesto por la CPU 1 será percibido
+correctamente por la CPU 2:
+
+ +-------+ : : : :
+ | | +------+ +-------+
+ | |------>| A=1 |------ --->| A->0 |
+ | | +------+ \ +-------+
+ | CPU 1 | wwwwwwwwwwwwwwww \ --->| B->9 |
+ | | +------+ | +-------+
+ | |------>| B=2 |--- | : :
+ | | +------+ \ | : : +-------+
+ +-------+ : : \ | +-------+ | |
+ ---------->| B->2 |------>| |
+ | +-------+ | CPU 2 |
+ | : : | |
+ | : : | |
+ En este punto la barrera ----> \ rrrrrrrrrrrrrrrrr | |
+ de lectura consigue que \ +-------+ | |
+ todos los efectos anteriores ---->| A->1 |------>| |
+ al almacenamiento de B sean +-------+ | |
+ perceptibles por la CPU 2 : : +-------+
+
+
+Para ilustrar esto de manera más completa, considere lo que podría pasar si
+el código contenía una carga de A a cada lado de la barrera de lectura:
+
+ CPU 1 CPU 2
+ ======================= =======================
+ { A = 0, B = 9 }
+ STORE A=1
+ <barrera de escritura>
+ STORE B=2
+ LOAD B
+ LOAD A [primer load de A]
+ <rbarrera de lectura>
+ LOAD A [segundo load de A]
+
+Aunque las dos cargas de A ocurren después de la carga de B, ambas pueden
+obtener diferentes valores:
+
+ +-------+ : : : :
+ | | +------+ +-------+
+ | |------>| A=1 |------ --->| A->0 |
+ | | +------+ \ +-------+
+ | CPU 1 | wwwwwwwwwwwwwwww \ --->| B->9 |
+ | | +------+ | +-------+
+ | |------>| B=2 |--- | : :
+ | | +------+ \ | : : +-------+
+ +-------+ : : \ | +-------+ | |
+ ---------->| B->2 |------>| |
+ | +-------+ | CPU 2 |
+ | : : | |
+ | : : | |
+ | +-------+ | |
+ | | A->0 |------>| 1st |
+ | +-------+ | |
+ En este punto la barrera ----> \ rrrrrrrrrrrrrrrrr | |
+ de lectura consigue que \ +-------+ | |
+ todos los efectos anteriores ---->| A->1 |------>| |
+ al almacenamiento de B sean +-------+ | |
+ perceptibles por la CPU 2 : : +-------+
+
+Pero puede ser que la actualización a A desde la CPU 1 se vuelva
+perceptible para la CPU 2 antes de que la barrera de lectura se complete de
+todos modos:
+
+ +-------+ : : : :
+ | | +------+ +-------+
+ | |------>| A=1 |------ --->| A->0 |
+ | | +------+ \ +-------+
+ | CPU 1 | wwwwwwwwwwwwwwww \ --->| B->9 |
+ | | +------+ | +-------+
+ | |------>| B=2 |--- | : :
+ | | +------+ \ | : : +-------+
+ +-------+ : : \ | +-------+ | |
+ ---------->| B->2 |------>| |
+ | +-------+ | CPU 2 |
+ | : : | |
+ \ : : | |
+ \ +-------+ | |
+ ---->| A->1 |------>| 1st |
+ +-------+ | |
+ rrrrrrrrrrrrrrrrr | |
+ +-------+ | |
+ | A->1 |------>| 2nd |
+ +-------+ | |
+ : : +-------+
+
+La garantía es que la segunda carga siempre dará como resultado A == 1 si
+la carga de B resultó en B == 2. No existe tal garantía para la primera
+carga de A; esto puede dar como resultado A == 0 o A == 1.
+
+
+BARRERAS DE MEMORIA DE LECTURA FRENTE A ESPECULACIÓN DE CARGA
+-------------------------------------------------------------
+
+Muchas CPU especulan con las cargas: es decir, ven que necesitarán cargar
+un elemento de la memoria, y encuentran un momento en el que no están
+usando el bus para ningún otra carga, y también en la carga por adelantado,
+aunque en realidad no lo hayan llegado a ese punto en el flujo de ejecución
+de instrucciones todavía. Esto permite que la instrucción de carga real
+potencialmente complete de inmediato, porque la CPU ya tiene el valor a
+mano.
+
+Puede resultar que la CPU en realidad no necesitara el valor, tal vez
+porque una condición eludió la carga, en cuyo caso puede descartar el valor
+o simplemente almacenar en caché para su uso posterior.
+
+Considere:
+
+ CPU 1 CPU 2
+ ======================= =======================
+ LOAD B
+ DIVIDE } Instrucciones de división
+ DIVIDE } tardan mucho en terminar
+ LOAD A
+
+donde DIVIDE es DIVIDIR. Que podría aparecer como esto:
+
+ : : +-------+
+ +-------+ | |
+ --->| B->2 |------>| |
+ +-------+ | CPU 2 |
+ : :DIVIDE | |
+ +-------+ | |
+ La CPU ocupada con la división ---> --->| A->0 |~~~~ | |
+ especula sobre el LOAD de A +-------+ ~ | |
+ : : ~ | |
+ : :DIVIDE | |
+ : : ~ | |
+ Una vez completadas las divisiones --> : : ~-->| |
+ la CPU puede realizar el : : | |
+ LOAD con efecto inmediato : : +-------+
+
+
+Colocando una barrera de lectura o una barrera de dependencia de dirección
+justo antes de la segundo carga:
+
+
+
+ CPU 1 CPU 2
+ ======================= =======================
+ LOAD B
+ DIVIDE
+ DIVIDE
+ <rbarrera de lectura>
+ LOAD A
+
+obligará a reconsiderar cualquier valor obtenido especulativamente en una
+medida dependiente del tipo de barrera utilizada. Si no se hizo ningún
+cambio en la ubicación de memoria especulada, entonces el valor especulado
+solo se usará:
+
+ : : +-------+
+ +-------+ | |
+ --->| B->2 |------>| |
+ +-------+ | CPU 2 |
+ : :DIVIDE | |
+ +-------+ | |
+ La CPU ocupada con la división ---> --->| A->0 |~~~~ | |
+ especula sobre el LOAD de A +-------+ ~ | |
+ : : ~ | |
+ : :DIVIDE | |
+ : : ~ | |
+ : : ~ | |
+ rrrrrrrrrrrrrrrr~ | |
+ : : ~ | |
+ : : ~-->| |
+ : : | |
+ : : +-------+
+
+
+pero si había una actualización o una invalidación de otra CPU pendiente,
+entonces la especulación será cancelada y el valor recargado:
+
+ : : +-------+
+ +-------+ | |
+ --->| B->2 |------>| |
+ +-------+ | CPU 2 |
+ : :DIVIDE | |
+ +-------+ | |
+ La CPU ocupada con la división ---> --->| A->0 |~~~~ | |
+ especula sobre el LOAD de A +-------+ ~ | |
+ : : ~ | |
+ : :DIVIDE | |
+ : : ~ | |
+ : : ~ | |
+ rrrrrrrrrrrrrrrrr | |
+ +-------+ | |
+ La especulación es descartada ---> --->| A->1 |------>| |
+ y un valor actualizado +-------+ | |
+ es conseguido : : +-------+
+
+ATOMICIDAD MULTICOPIA
+---------------------
+
+La atomicidad multicopia es una noción profundamente intuitiva sobre el
+orden que no es siempre proporcionada por los sistemas informáticos reales,
+a saber, que un determinada store se vuelve visible al mismo tiempo para
+todos las CPU o, alternativamente, que todas las CPU acuerdan el orden en
+que todos los stores se vuelven visibles. Sin embargo, el soporte para
+atomicidad multicopia completa descartaría valiosas optimizaciones
+hardware, por lo que una versión más débil conocida como ``otra atomicidad
+multicopia'' en cambio, solo garantiza que un store dado se vuelva visible
+al mismo tiempo en todas las -otras- CPUs. El resto de este documento
+discute esta versión más débil, pero por brevedad lo llamaremos simplemente
+``atomicidad multicopia''.
+
+El siguiente ejemplo demuestra la atomicidad multicopia:
+
+ CPU 1 CPU 2 CPU 3
+ ======================= ======================= =======================
+ { X = 0, Y = 0 }
+ STORE X=1 r1=LOAD X (reads 1) LOAD Y (reads 1)
+ <barrera general> <barrera de lectura>
+ STORE Y=r1 LOAD X
+
+Suponga que la carga de la CPU 2 desde X devuelve 1, que luego almacena en
+Y, y la carga de la CPU 3 desde Y devuelve 1. Esto indica que el store de
+la CPU 1 a X precede a la carga de la CPU 2 desde X y el store de esa CPU 2
+a Y precede la carga de la CPU 3 desde Y. Además, las barreras de memoria
+garantizan que la CPU 2 ejecuta su carga antes que su almacenamiento, y la
+CPU 3 carga desde Y antes de cargar desde X. La pregunta entonces es
+"¿Puede la carga de la CPU 3 desde X devolver 0?"
+
+Debido a que la carga de la CPU 3 desde X en cierto sentido viene después
+de la carga de la CPU 2, es natural esperar que la carga de la CPU 3 desde
+X deba devolver 1. Esta expectativa se deriva de la atomicidad multicopia:
+si una carga que se ejecuta en la CPU B sigue una carga de la misma
+variable que se ejecuta en la CPU A (y la CPU A no almacenó originalmente
+el valor que leyó), entonces en sistemas atómicos multicopia, la carga de
+la CPU B debe devolver el mismo valor que hizo la carga de la CPU A o algún
+valor posterior. Sin embargo, el kernel Linux no requiere que los sistemas
+sean atómicos multicopia.
+
+El uso de una barrera de memoria general en el ejemplo anterior compensa
+cualquier falta de atomicidad multicopia. En el ejemplo, si la carga de la
+CPU 2 de X devuelve 1 y la carga de la CPU 3 de Y devuelve 1, entonces la
+carga de la CPU 3 desde X debe de hecho también devolver 1.
+
+Sin embargo, las dependencias, las barreras de lectura y las barreras de
+escritura no siempre son capaces de compensar la atomicidad no multicopia.
+Por ejemplo, supongamos que la barrera general de la CPU 2 se elimina del
+ejemplo anterior, dejando solo la dependencia de datos que se muestra a
+continuación:
+
+ CPU 1 CPU 2 CPU 3
+ ======================= ======================= =======================
+ { X = 0, Y = 0 }
+ STORE X=1 r1=LOAD X (escribe 1) LOAD Y (lee 1)
+ <dependencia de datos> <barrera de lectura>
+ STORE Y=r1 LOAD X (lee 0)
+
+Esta sustitución permite que la atomicidad no multicopia se desenfrene: en
+este ejemplo, es perfectamente legal que la carga de la CPU 2 desde X
+devuelva 1, la carga de la CPU 3 desde Y devuelva 1, y su carga desde X
+tenga valor 0.
+
+El punto clave es que aunque la dependencia de datos de la CPU 2 ordena su
+carga y store, no garantiza ordenar el store de la CPU 1. De forma que, si
+este ejemplo se ejecuta en un sistema atómico no multicopia donde las CPU 1
+y 2 comparten un buffer de almacenamiento o un nivel de caché, la CPU 2
+podría tener acceso anticipado de escritura a CPU 1. Por lo tanto, se
+requieren barreras generales para garantizar que todas las CPU acurden el
+orden combinado de accesos múltiples.
+
+Las barreras generales pueden compensar no solo la atomicidad no
+multicopia, pero también pueden generar orden adicional que puede asegurar
+que -todas- las CPU percibirán el mismo orden de -todas- las operaciones.
+Por el contrario, una cadena de parejas de liberación-adquisición no
+proporciona este orden adicional, lo que significa que solo se garantiza
+que las CPU de la cadena estén de acuerdo en el orden combinado de los
+accesos. Por ejemplo, cambiando a código C en deferencia al fantasma de
+Herman Hollerith:
+
+ int u, v, x, y, z;
+
+ void cpu0(void)
+ {
+ r0 = smp_load_acquire(&x);
+ WRITE_ONCE(u, 1);
+ smp_store_release(&y, 1);
+ }
+
+ void cpu1(void)
+ {
+ r1 = smp_load_acquire(&y);
+ r4 = READ_ONCE(v);
+ r5 = READ_ONCE(u);
+ smp_store_release(&z, 1);
+ }
+
+ void cpu2(void)
+ {
+ r2 = smp_load_acquire(&z);
+ smp_store_release(&x, 1);
+ }
+
+ void cpu3(void)
+ {
+ WRITE_ONCE(v, 1);
+ smp_mb();
+ r3 = READ_ONCE(u);
+ }
+
+Dado que cpu0(), cpu1() y cpu2() participan en una cadena de parejas
+smp_store_release()/smp_load_acquire(), el siguiente resultado estaría
+prohibido:
+
+ r0 == 1 && r1 == 1 && r2 == 1
+
+Además, debido a la relación liberación-adquisición entre cpu0() y cpu1(),
+cpu1() debe ver las escrituras de cpu0(), de modo que el siguiente
+resultado estaría prohibido:
+
+ r1 == 1 && r5 == 0
+
+Sin embargo, el orden proporcionado por una cadena de
+liberación-adquisición es local a las CPU que participan en esa cadena y no
+se aplica a cpu3(), al menos aparte de los stores. Por lo tanto, es posible
+el siguiente resultado:
+
+ r0 == 0 && r1 == 1 && r2 == 1 && r3 == 0 && r4 == 0
+
+Por otro lado, también el siguiente resultado es posible:
+
+ r0 == 0 && r1 == 1 && r2 == 1 && r3 == 0 && r4 == 0 && r5 == 1
+
+Aunque cpu0(), cpu1() y cpu2() verán sus respectivas lecturas y escrituras
+en orden, las CPU que no participan en la cadena de liberación-adquisición
+pueden estar en desacuerdo con el orden. Este desacuerdo se debe al hecho
+de que las instrucciones de barrera de memoria débiles utilizadas para
+implementar smp_load_acquire() y smp_store_release() no son necesarios para
+ordenar stores anteriores contra cargas posteriores en todos los casos.
+Esto significa que cpu3() puede ver el store de cpu0() suceder -después- de
+la carga de cpu1() desde v, aunque tanto cpu0() como cpu1() están de
+acuerdo en que estas dos operaciones ocurrieron en el orden previsto.
+
+Sin embargo, tenga en cuenta que smp_load_acquire() no es mágico. En
+particular, simplemente lee de su argumento en orden. Es decir, -no-
+asegura que se leerá cualquier valor en particular. Por lo tanto, los
+siguiente resultados son posibles:
+
+ r0 == 0 && r1 == 0 && r2 == 0 && r5 == 0
+
+Tenga en cuenta que este resultado puede ocurrir incluso en un mítico
+sistema, consistente en secuencia, donde nunca se reordena nada.
+
+Para reiterar, si su código requiere un orden completo de todas las
+operaciones, utilice barreras generales en todo momento.
+
+
+==============================
+BARRERAS EXPLÍCITAS DEL KERNEL
+==============================
+
+El kernel Linux tiene una variedad de diferentes barreras que actúan a
+diferentes niveles:
+
+ (*) Barrera del compilador.
+
+ (*) Barreras de memoria de la CPU.
+
+
+BARRERA DEL COMPILADOR
+-----------------------
+
+El kernel de Linux tiene una función de barrera del compilador explícita
+que evita que el el compilador mueva los accesos a la memoria de cualquier
+lado al otro:
+
+ barrier();
+
+Esta es una barrera general: no hay variantes de barrier() para casos de
+lectura-lectura o escritura-escritura. Sin embargo, READ_ONCE() y
+WRITE_ONCE() pueden ser considerado como formas débiles de barrier() que
+afectan solo específicos accesos marcados por READ_ONCE() o WRITE_ONCE().
+
+La función barrier() produce los siguientes efectos:
+
+ (*) Evita que el compilador reordene los accesos tras barrier() para
+ preceder a cualquier acceso que preceda a barrier(). Un ejemplo de uso
+ de esta propiedad es facilitar la comunicación entre código del
+ interrupt-handler (encargo de gestionar interrupciones) y el código
+ que fue interrumpido.
+
+ (*) Dentro de un bucle ("loop"), obliga al compilador a cargar las
+ variables utilizadas en ese loop condicional en cada paso a través de
+ ese loop.
+
+Las funciones READ_ONCE() y WRITE_ONCE() pueden evitar cualquier cantidad
+de optimizaciones que, si bien son perfectamente seguras en código de un
+solo subproceso, pueden resultar fatales en código concurrente. Aquí hay
+algunos ejemplos de tal tipo de optimizaciones:
+
+(*) El compilador está en su derecho de reordenar cargas y stores de la
+ misma variable, y en algunos casos, la CPU está dentro de su
+ derecho de reordenar cargas a la misma variable. Esto significa que
+ el siguiente código:
+
+ a[0] = x;
+ a[1] = x;
+
+ Podría resultar en un valor más antiguo de x almacenado en a[1] que en
+ a[0]. Evite que tanto el compilador como la CPU hagan esto de la
+ siguiente manera:
+
+ a[0] = READ_ONCE(x);
+ a[1] = READ_ONCE(x);
+
+ En resumen, READ_ONCE() y WRITE_ONCE() proporcionan coherencia de
+ caché para accesos desde múltiples CPUs a una sola variable.
+
+ (*) El compilador tiene derecho a juntar cargas sucesivas de la misma
+ variable. Tal fusión puede hacer que el compilador "optimice" el
+ siguiente código:
+
+ while (tmp = a)
+ hacer_algo_con(tmp);
+
+ en el siguiente código, que, aunque en cierto sentido es legítimo
+ para un código de un solo subproceso, es casi seguro que no es lo
+ que el desarrollador pretendía:
+
+ if (tmp = a)
+ for (;;)
+ hacer_algo_con(tmp);
+
+ Use READ_ONCE() para evitar que el compilador le haga esto:
+
+ while (tmp = READ_ONCE(a))
+ hacer_algo_con(tmp);
+
+ (*) El compilador tiene derecho a recargar una variable, por ejemplo,
+ en los casos en que la alta presión de los registros impida que el
+ compilador mantenga todos los datos de interés en registros. El
+ compilador podría por lo tanto, optimizar la variable 'tmp' de nuestro
+ ejemplo anterior:
+
+ while (tmp = a)
+ hacer_algo_con(tmp);
+
+ Esto podría resultar en el siguiente código, que es perfectamente
+ seguro en código de subproceso único, pero puede ser fatal en código
+ concurrente:
+
+ while (a)
+ hacer_algo_con(a);
+
+ Por ejemplo, la versión optimizada de este código podría resultar en
+ pasar un cero a hacer_algo_con() en el caso de que la variable a sea
+ modificada por alguna otra CPU, entre la instrucción "while" y la
+ llamada a hacer_algo_con().
+
+ De nuevo, use READ_ONCE() para evitar que el compilador haga esto:
+
+ while (tmp = READ_ONCE(a))
+ hacer_algo_con(tmp);
+
+ Tenga en cuenta que si el compilador se queda sin registros, podría
+ guardar tmp en la pila ("stack"). El overhead (coste en eficiencia) de
+ este guardado y posterior restauración es por lo que los compiladores
+ recargan las variables. Hacerlo es perfectamente seguro para código de
+ subproceso único, por lo que debe informar al compilador sobre los
+ casos donde no sea seguro.
+
+ (*) El compilador está en su derecho de omitir una carga por completo si
+ sabe cual será su valor. Por ejemplo, si el compilador puede probar
+ que el valor de la variable 'a' siempre es cero, puede optimizar este
+ código:
+
+ while (tmp = a)
+ hacer_algo_con(tmp);
+
+ En esto:
+
+ do { } while (0);
+
+ Esta transformación es una victoria para un código de un solo
+ subproceso, porque se deshace de una carga y un branch. El problema es
+ que el compilador llevará a cabo su prueba asumiendo que la CPU actual
+ es la única actualizando la variable 'a'. Si la variable 'a' es
+ compartida, entonces la prueba del compilador será errónea. Use
+ READ_ONCE() para decirle al compilador que no sabe tanto como cree:
+
+ while (tmp = READ_ONCE(a))
+ hacer_algo_con(tmp);
+
+ Pero, por favor, tenga en cuenta que el compilador también está
+ observando de cerca lo que usted hace con el valor después de
+ READ_ONCE(). Por ejemplo, suponga que Ud. hace lo siguiente y MAX es
+ una macro de preprocesador con el valor 1:
+
+ while ((tmp = READ_ONCE(a)) % MAX)
+ hacer_algo_con(tmp);
+
+ Entonces el compilador sabe que el resultado del operador "%" aplicado
+ a MAX siempre será cero, nuevamente permitiendo que el compilador
+ optimice el código hasta su casi inexistencia. (Aún se cargará desde
+ la variable 'a'.)
+
+ (*) De manera similar, el compilador tiene derecho a omitir un store por
+ completo si sabe que la variable ya tiene el valor almacenado.
+ Nuevamente, el compilador asume que la CPU actual es la única que
+ almacena la variable, lo que puede hacer que el compilador haga
+ algo incorrecto para las variables compartidas. Por ejemplo, suponga
+ que tiene lo siguiente:
+
+ a = 0;
+ ... Código que no almacena la variable a ...
+ a = 0;
+
+ El compilador observa que el valor de la variable 'a' ya es cero, por
+ lo que bien podría omitir el segundo store. Esto supondría una fatal
+ sorpresa, si alguna otra CPU hubiera almacenado la variable 'a'
+ mientras tanto.
+
+ Use WRITE_ONCE() para evitar que el compilador haga este tipo de
+ suposición equivocada:
+
+ WRITE_ONCE(a, 0);
+ ... Código que no almacena la variable a ...
+ WRITE_ONCE(a, 0);
+
+ (*) El compilador tiene derecho a reordenar los accesos a memoria a menos
+ que le diga que no. Por ejemplo, considere la siguiente interacción
+ entre el código de nivel de proceso y un controlador de interrupción:
+
+ void nivel_de_procesamiento(void)
+ {
+ msg = ACQUIRE_mensaje();
+ flag = true;
+ }
+
+ void controlador_interrupcion(void)
+ {
+ if (flag)
+ procesar_mensaje(msg);
+ }
+
+ No hay nada que impida que el compilador transforme
+ nivel_de_procesamiento() a lo siguiente, que de hecho, bien podría ser
+ una victoria para código de un solo subproceso:
+
+ void nivel_de_procesamiento(void)
+ {
+ flag = true;
+ msg = ACQUIRE_mensaje();
+ }
+
+ Si la interrupción ocurre entre estas dos declaraciones, entonces
+ controlador_interrupcion() podría recibir un mensaje ilegible. Use
+ READ_ONCE() para evitar esto de la siguiente manera:
+
+ void nivel_de_procesamiento(void)
+ {
+ WRITE_ONCE(msg, ACQUIRE_mensaje());
+ WRITE_ONCE(flag, true);
+ }
+
+ void controlador_interrupcion(void)
+ {
+ if (READ_ONCE(flag))
+ procesar_mensaje(READ_ONCE(msg));
+ }
+
+ Tenga en cuenta que los envoltorios ("wrappers") READ_ONCE() y
+ WRITE_ONCE() en controlador_interrupcion() son necesarios si este
+ controlador de interrupciones puede ser interrumpido por algo que
+ también accede a 'flag' y 'msg', por ejemplo, una interrupción anidada
+ o un NMI. De lo contrario, READ_ONCE() y WRITE_ONCE() no son
+ necesarios en controlador_interrupcion() aparte de con fines de
+ documentación. (Tenga también en cuenta que las interrupciones
+ anidadas no ocurren típicamente en los kernels Linux modernos, de
+ hecho, si un controlador de interrupciones regresa con interrupciones
+ habilitadas, obtendrá un WARN_ONCE().)
+
+ Debe suponer que el compilador puede mover READ_ONCE() y WRITE_ONCE()
+ a código que no contiene READ_ONCE(), WRITE_ONCE(), barrier(), o
+ primitivas similares.
+
+ Este efecto también podría lograrse usando barrier(), pero READ_ONCE()
+ y WRITE_ONCE() son más selectivos: Con READ_ONCE() y WRITE_ONCE(), el
+ compilador solo necesita olvidar el contenido de ubicaciones de
+ memoria indicadas, mientras que con barrier() el compilador debe
+ descartar el valor de todas las ubicaciones de memoria que tiene
+ actualmente almacenadas en caché, en cualquier registro de la máquina.
+ Por supuesto, el compilador también debe respetar el orden en que
+ ocurren READ_ONCE() y WRITE_ONCE(), aunque la CPU, efectivamente, no
+ necesita hacerlo.
+
+ (*) El compilador tiene derecho a inventar stores para una variable,
+ como en el siguiente ejemplo:
+
+ if (a)
+ b = a;
+ else
+ b = 42;
+
+ El compilador podría ahorrar un branch al optimizar esto de la
+ siguiente manera:
+
+ b = 42;
+ if (a)
+ b = a;
+
+ En el código de un solo subproceso, esto no solo es seguro, sino que
+ también ahorra un branch. Desafortunadamente, en código concurrente,
+ esta optimización podría causar que alguna otra CPU vea un valor falso
+ de 42, incluso si la variable 'a' nunca fue cero, al cargar la
+ variable 'b'. Use WRITE_ONCE() para evitar esto de la siguiente
+ manera:
+
+ if (a)
+ WRITE_ONCE(b, a);
+ else
+ WRITE_ONCE(b, 42);
+
+ El compilador también puede inventar cargas. Estos casos suelen ser
+ menos perjudiciales, pero pueden dar como resultado "bouncing" de la
+ línea de caché y, por lo tanto, bajo rendimiento y escalabilidad.
+ Utilice READ_ONCE() para evitar cargas inventadas.
+
+ (*) Para ubicaciones de memoria alineadas cuyo tamaño les permita
+ acceder con una sola instrucción de referencia de memoria, evite el
+ "desgarro de la carga" (load tearing) y "desgarro del store" (store
+ tearing), en el que un solo gran acceso es reemplazado por múltiples
+ accesos menores. Por ejemplo, dada una arquitectura que tiene
+ instrucciones de almacenamiento de 16 bits con campos inmediatos de 7
+ bits, el compilador podría tener la tentación de usar dos
+ instrucciones inmediatas de almacenamiento de 16 bits para implementar
+ el siguiente store de 32 bits:
+
+ p = 0x00010002;
+
+ Tenga en cuenta que GCC realmente usa este tipo de optimización, lo
+ cual no es sorprendente dado que probablemente costaría más de dos
+ instrucciones el construir la constante y luego almacenarla. Por lo
+ tanto, esta optimización puede ser una victoria en un código de un
+ solo subproceso. De hecho, un error reciente (desde que se solucionó)
+ hizo que GCC usara incorrectamente esta optimización en un store
+ volátil. En ausencia de tales errores, el uso de WRITE_ONCE() evita el
+ desgarro del store en el siguiente ejemplo:
+
+ struct __attribute__((__packed__)) foo {
+ short a;
+ int b;
+ short c;
+ };
+ struct foo foo1, foo2;
+ ...
+
+ foo2.a = foo1.a;
+ foo2.b = foo1.b;
+ foo2.c = foo1.c;
+
+ Debido a que no hay envoltorios READ_ONCE() o WRITE_ONCE() y no
+ hay markings volátiles, el compilador estaría en su derecho de
+ implementar estas tres declaraciones de asignación como un par de
+ cargas de 32 bits, seguido de un par de stores de 32 bits. Esto
+ resultaría en una carga con desgarro en 'foo1.b' y store del desgarro
+ en 'foo2.b'. READ_ONCE() y WRITE_ONCE() nuevamente evitan el desgarro
+ en este ejemplo:
+
+ foo2.a = foo1.a;
+ WRITE_ONCE(foo2.b, READ_ONCE(foo1.b));
+ foo2.c = foo1.c;
+
+Aparte de esto, nunca es necesario usar READ_ONCE() y WRITE_ONCE() en una
+variable que se ha marcado como volátil. Por ejemplo, dado que 'jiffies'
+está marcado como volátil, nunca es necesario usar READ_ONCE(jiffies). La
+razón de esto es que READ_ONCE() y WRITE_ONCE() se implementan como
+conversiones volátiles, lo que no tiene efecto cuando su argumento ya está
+marcado como volátil.
+
+Tenga en cuenta que estas barreras del compilador no tienen un efecto
+directo en la CPU, que luego puede reordenar las cosas como quiera.
+
+
+BARRERAS DE MEMORIA DE LA CPU
+-----------------------------
+
+El kernel de Linux tiene siete barreras básicas de memoria de CPU:
+
+TIPO OBLIGATORIO SMP CONDICIONAL
+======================= =============== ===============
+GENERAL mb() smp_mb()
+WRITE wmb() smp_wmb()
+READ rmb() smp_rmb()
+DEPEDENCIA DE DIRECCIÓN READ_ONCE()
+
+
+Todas las barreras de memoria, excepto las barreras de dependencia de
+direcciones, implican una barrera del compilador. Las dependencias de
+direcciones no imponen ningún orden de compilación adicional.
+
+Además: en el caso de las dependencias de direcciones, se esperaría que el
+compilador emita las cargas en el orden correcto (por ejemplo, `a[b]`
+tendría que cargar el valor de b antes de cargar a[b]), sin embargo, no hay
+garantía alguna en la especificación de C sobre que el compilador no puede
+especular el valor de b (por ejemplo, es igual a 1) y carga a[b] antes que
+b (ej. tmp = a[1]; if (b != 1) tmp = a[b]; ). También existe el problema de
+que un compilador vuelva a cargar b después de haber cargado a[b], teniendo
+así una copia más nueva de b que a[b]. Aún no se ha conseguido un consenso
+acerca de estos problemas, sin embargo, el macro READ_ONCE() es un buen
+lugar para empezar a buscar.
+
+Las barreras de memoria SMP se reducen a barreras de compilador cuando se
+compila a monoprocesador, porque se supone que una CPU parecerá ser
+auto-consistente, y ordenará correctamente los accesos superpuestos
+respecto a sí misma. Sin embargo, consulte la subsección "Guests de
+máquinas virtuales" mas adelante.
+
+[!] Tenga en cuenta que las barreras de memoria SMP _deben_ usarse para
+controlar el orden de referencias a memoria compartida en sistemas SMP,
+aunque el uso de bloqueo en su lugar sea suficiente.
+
+Las barreras obligatorias no deben usarse para controlar los efectos de
+SMP, ya que dichas barreras imponen una sobrecarga innecesaria en los
+sistemas SMP y UP. Se pueden, sin embargo, usar para controlar los efectos
+MMIO en los accesos a través de ventanas E/S de memoria relajada. Estas
+barreras son necesarias incluso en sistemas que no son SMP, ya que afectan
+al orden en que las operaciones de memoria aparecen en un dispositivo, al
+prohibir tanto al compilador como a la CPU que sean reordenados.
+
+
+Hay algunas funciones de barrera más avanzadas:
+
+ (*) smp_store_mb(var, valor)
+
+ Asigna el valor a la variable y luego inserta una barrera de memoria
+ completa después de ella. No se garantiza insertar nada más que una
+ barrera del compilador en una compilación UP.
+
+
+ (*) smp_mb__before_atomic();
+ (*) smp_mb__after_atomic();
+
+ Estos se pueden usar con funciones RMW atómicas que no implican
+ barreras de memoria, pero donde el código necesita una barrera de
+ memoria. Ejemplos de funciones RMW atómicas que no implican una
+ barrera de memoria son, por ejemplo, agregar, restar, operaciones
+ condicionales (fallidas), funciones _relaxed, pero no atomic_read o
+ atomic_set. Un ejemplo común donde se puede requerir una barrera es
+ cuando se usan operaciones atómicas como referencia de contador.
+
+ Estos también se utilizan para funciones atómicas RMW bitop que no
+ implican una barrera de memoria (como set_bit y clear_bit).
+
+ Como ejemplo, considere una pieza de código que marca un objeto como
+ muerto y luego disminuye el contador de referencias del objeto:
+
+ obj->dead = 1;
+ smp_mb__before_atomic();
+ atomic_dec(&obj->ref_count);
+
+ Esto asegura que la marca de muerte en el objeto se perciba como
+ fijada *antes* de que disminuya el contador de referencia.
+
+ Consulte Documentation/atomic_{t,bitops}.txt para obtener más
+ información.
+
+
+ (*) dma_wmb();
+ (*) dma_rmb();
+ (*) dma_mb();
+
+ Estos son usados con memoria consistente para garantizar el orden de
+ escrituras o lecturas de memoria compartida accesible tanto para la
+ CPU como para un dispositivo compatible con DMA.
+
+ Por ejemplo, considere un controlador de dispositivo que comparte
+ memoria con otro dispositivo y usa un valor de estado del descriptor
+ para indicar si el descriptor pertenece al dispositivo o a la CPU, y
+ un "doorbell" (timbre, punto de acceso) para avisarle cuando haya
+ nuevos descriptores disponibles:
+
+ if (desc->status != DEVICE_OWN) {
+ /* no leer los datos hasta que tengamos el descriptor */
+ dma_rmb();
+
+ /* leer/modificar datos */
+ read_data = desc->data;
+ desc->data = write_data;
+
+ /* flush de modificaciones antes de la actualización de estado */
+ dma_wmb();
+
+ /* asignar propiedad */
+ desc->status = DEVICE_OWN;
+
+ /* notificar al dispositivo de nuevos descriptores */
+ writel(DESC_NOTIFY, doorbell);
+ }
+
+ El dma_rmb() nos permite garantizar que el dispositivo ha liberado su
+ propiedad antes de que leamos los datos del descriptor, y el dma_wmb()
+ permite garantizar que los datos se escriben en el descriptor antes de
+ que el dispositivo pueda ver que ahora tiene la propiedad. El dma_mb()
+ implica tanto un dma_rmb() como un dma_wmb(). Tenga en cuenta que, al
+ usar writel(), no se necesita un wmb() anterior para garantizar que
+ las escrituras de la memoria caché coherente se hayan completado antes
+ escribiendo a la región MMIO. El writel_relaxed() más barato no
+ proporciona esta garantía y no debe utilizarse aquí.
+
+ Consulte la subsección "Efectos de barrera de E/S del kernel" para
+ obtener más información sobre accesorios de E/S relajados y el archivo
+ Documentation/core-api/dma-api.rst para más información sobre memoria
+ consistente.
+
+ (*) pmem_wmb();
+
+ Es es para uso con memoria persistente para garantizar que los stores
+ para los que las modificaciones se escriben en el almacenamiento
+ persistente llegaron a dominio de durabilidad de la plataforma.
+
+ Por ejemplo, después de una escritura no temporal en la región pmem,
+ usamos pmem_wmb() para garantizar que los stores hayan alcanzado el
+ dominio de durabilidad de la plataforma. Esto garantiza que los stores
+ han actualizado el almacenamiento persistente antes de cualquier
+ acceso a datos o transferencia de datos causada por instrucciones
+ posteriores. Esto es además del orden realizado por wmb().
+
+ Para la carga desde memoria persistente, las barreras de memoria de
+ lectura existentes son suficientes para garantizar el orden de
+ lectura.
+
+ (*) io_stop_wc();
+
+ Para accesos a memoria con atributos de combinación de escritura (por
+ ejemplo, los devueltos por ioremap_wc(), la CPU puede esperar a que
+ los accesos anteriores se junten con posteriores. io_stop_wc() se
+ puede utilizar para evitar la combinación de accesos a memoria de
+ de escritura antes de esta macro, con los posteriores, cuando dicha
+ espera tenga implicaciones en el rendimiento.
+
+=========================================
+BARRERAS DE MEMORIA IMPLÍCITAS DEL KERNEL
+=========================================
+
+Algunas de las otras funciones en el kernel Linux implican barreras de
+memoria, entre estas encontramos funciones de bloqueo y planificación
+("scheduling").
+
+Esta especificación es una garantía _mínima_; cualquier arquitectura
+particular puede proporcionar garantías más sustanciales, pero no se puede
+confiar en estas fuera de código específico de arquitectura.
+
+
+FUNCIONES DE ADQUISICIÓN DE CERROJO
+-----------------------------------
+
+El kernel Linux tiene una serie de abstracciones de bloqueo:
+
+ (*) spin locks (cerrojos en loop)
+ (*) R/W spin lock (cerrojos de escritura/lectura)
+ (*) mutex
+ (*) semáforos
+ (*) R/W semáforos
+
+En todos los casos existen variantes de las operaciones "ACQUIRE" y
+"RELEASE" para cada uno de ellos. Todas estas operaciones implican ciertas
+barreras:
+
+ (1) Implicaciones de la operación ACQUIRE:
+
+ Las operaciones de memoria emitidas después del ACQUIRE se completarán
+ después de que la operación ACQUIRE haya finalizado.
+
+ Las operaciones de memoria emitidas antes de ACQUIRE pueden
+ completarse después que la operación ACQUIRE se ha completado.
+
+ (2) Implicaciones de la operación RELEASE:
+
+ Las operaciones de memoria emitidas antes de la RELEASE se
+ completarán antes de que la operación de RELEASE se haya completado.
+
+ Las operaciones de memoria emitidas después de la RELEASE pueden
+ completarse antes de que la operación de RELEASE se haya completado.
+
+ (3) Implicación de ACQUIRE vs ACQUIRE:
+
+ Todas las operaciones ACQUIRE emitidas antes de otra operación
+ ACQUIRE serán completadas antes de esa operación ACQUIRE.
+
+ (4) Implicación de ACQUIRE vs RELEASE:
+
+ Todas las operaciones ACQUIRE emitidas antes de una operación RELEASE
+ serán completadas antes de la operación RELEASE.
+
+ (5) Implicación de ACQUIRE condicional fallido:
+
+ Ciertas variantes de bloqueo de la operación ACQUIRE pueden fallar, ya
+ sea debido a no poder obtener el bloqueo de inmediato, o debido a que
+ recibieron una señal de desbloqueo mientras dormían esperando que el
+ cerrojo estuviera disponible. Los fallos en cerrojos no implican
+ ningún tipo de barrera.
+
+[!] Nota: una de las consecuencias de que los cerrojos en ACQUIRE y RELEASE
+sean barreras unidireccionales, es que los efectos de las instrucciones
+fuera de una sección crítica pueden filtrarse al interior de la sección
+crítica.
+
+No se puede suponer que un ACQUIRE seguido de una RELEASE sea una barrera
+de memoria completa dado que es posible que un acceso anterior a ACQUIRE
+suceda después del ACQUIRE, y un acceso posterior a la RELEASE suceda antes
+del RELEASE, y los dos accesos puedan entonces cruzarse:
+
+ *A = a;
+ ACQUIRE M
+ RELEASE M
+ *B = b;
+
+puede ocurrir como:
+
+ ACQUIRE M, STORE *B, STORE *A, RELEASE M
+
+Cuando ACQUIRE y RELEASE son bloqueo de adquisición y liberación,
+respectivamente, este mismo orden puede ocurrir si el cerrojo ACQUIRE y
+RELEASE son para la misma variable de bloqueo, pero solo desde la
+perspectiva de otra CPU que no tiene ese bloqueo. En resumen, un ACQUIRE
+seguido de un RELEASE NO puede entenderse como una barrera de memoria
+completa.
+
+De manera similar, el caso inverso de un RELEASE seguido de un ACQUIRE no
+implica una barrera de memoria completa. Por lo tanto, la ejecución de la
+CPU de los tramos críticos correspondientes a la RELEASE y la ACQUIRE
+pueden cruzarse, de modo que:
+
+ *A = a;
+ RELEASE M
+ ACQUIRE N
+ *B = b;
+
+puede ocurrir como:
+
+ ACQUIRE N, STORE *B, STORE *A, RELEASE M
+
+Podría parecer que este nuevo orden podría introducir un punto muerto.
+Sin embargo, esto no puede suceder porque si tal punto muerto amenazara
+con suceder, el RELEASE simplemente se completaría, evitando así el
+interbloqueo ("deadlock", punto muerto).
+
+ ¿Por qué funciona esto?
+
+ Un punto clave es que solo estamos hablando de la CPU re-haciendo el
+ orden, no el compilador. Si el compilador (o, ya puestos, el
+ desarrollador) cambió las operaciones, un deadlock -podría- ocurrir.
+
+ Pero supongamos que la CPU reordenó las operaciones. En este caso, el
+ desbloqueo precede al bloqueo en el código ensamblador. La CPU
+ simplemente eligió intentar ejecutar primero la última operación de
+ bloqueo. Si hay un interbloqueo, esta operación de bloqueo simplemente
+ esperará (o tratará de dormir, pero hablaremos de eso más adelante). La
+ CPU eventualmente ejecutará la operación de desbloqueo (que precedió a la
+ operación de bloqueo en el código ensamblador), lo que desenmascará el
+ potencial punto muerto, permitiendo que la operación de bloqueo tenga
+ éxito.
+
+ Pero, ¿y si el cerrojo es un cerrojo que duerme ("sleeplock")? En tal
+ caso, el código intentará entrar al scheduler, donde eventualmente
+ encontrará una barrera de memoria, que forzará la operación de desbloqueo
+ anterior para completar, nuevamente desentrañando el punto muerto. Podría
+ haber una carrera de desbloqueo del sueño ("sleep-unlock race"), pero la
+ primitiva de bloqueo necesita resolver tales carreras correctamente en
+ cualquier caso.
+
+Es posible que los cerrojos y los semáforos no proporcionen ninguna
+garantía de orden en sistemas compilados en UP, por lo que no se puede
+contar con tal situación para lograr realmente nada en absoluto,
+especialmente con respecto a los accesos de E/S, a menos que se combinen
+con operaciones de inhabilitación de interrupciones.
+
+Consulte también la sección "Efectos de barrera adquiriendo intra-CPU".
+
+
+Como ejemplo, considere lo siguiente:
+
+ *A = a;
+ *B = b;
+ ACQUIRE
+ *C = c;
+ *D = d;
+ RELEASE
+ *E = e;
+ *F = f;
+
+La siguiente secuencia de eventos es aceptable:
+
+ ACQUIRE, {*F,*A}, *E, {*C,*D}, *B, RELEASE
+
+ [+] Tenga en cuenta que {*F,*A} indica un acceso combinado.
+
+Pero ninguno de los siguientes lo son:
+
+ {*F,*A}, *B, ACQUIRE, *C, *D, RELEASE, *E
+ *A, *B, *C, ACQUIRE, *D, RELEASE, *E, *F
+ *A, *B, ACQUIRE, *C, RELEASE, *D, *E, *F
+ *B, ACQUIRE, *C, *D, RELEASE, {*F,*A}, *E
+
+
+
+FUNCIONES DE DESACTIVACIÓN DE INTERRUPCIONES
+--------------------------------------------
+
+Las funciones que deshabilitan interrupciones (equivalentes a ACQUIRE) y
+habilitan interrupciones (equivalentes a RELEASE) actuarán únicamente como
+barrera del compilador. Por consiguiente, si la memoria o la E/S requieren
+barreras en tal situación, deben ser provistas por algún otro medio.
+
+
+FUNCIONES DE DORMIR Y DESPERTAR
+-------------------------------
+
+Dormir y despertar son eventos marcados ("flagged") en los datos globales
+que se pueden ver como una interacción entre dos piezas de datos: el estado
+de la task (hilo, proceso, tarea) que espera el evento y los datos globales
+utilizados para indicar el evento. Para asegurarse de que estos parezcan
+suceder en el orden correcto, las primitivas para comenzar el proceso de ir
+a dormir, y las primitivas para iniciar un despertar implican ciertas
+barreras.
+
+En primer lugar, el agente durmiente normalmente sigue algo similar a esta
+secuencia de eventos:
+
+ for (;;) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ if (evento_indicado)
+ break;
+ schedule(); // planificar
+ }
+
+Una barrera de memoria general se obtiene automáticamente mediante
+set_current_state() después de haber alterado el estado de la tarea:
+
+ CPU 1
+ ===============================
+ set_current_state(); // hacer_estado_actual()
+ smp_store_mb();
+ STORE current->state
+ <barrera general>
+ LOAD evento_indicado
+
+set_current_state() puede estar envuelto por:
+
+ prepare_to_wait(); // preparese_para_esperar();
+ prepare_to_wait_exclusive(); // prepararse_para_solo_esperar();
+
+que por lo tanto también implican una barrera de memoria general después de
+establecer el estado. Toda la secuencia anterior está disponible en varias
+formas, todas las cuales obtienen la barrera de memoria en el lugar
+correcto:
+
+ wait_event();
+ wait_event_interruptible();
+ wait_event_interruptible_exclusive();
+ wait_event_interruptible_timeout();
+ wait_event_killable();
+ wait_event_timeout();
+ wait_on_bit();
+ wait_on_bit_lock();
+
+
+En segundo lugar, el código que realiza una activación normalmente se
+asemeja a algo como esto:
+
+ evento_indicado = 1;
+ wake_up(&event_wait_queue); // despertar
+
+o:
+
+ evento_indicado = 1;
+ wake_up_process(event_daemon); // despertar proceso
+
+wake_up() ejecuta una barrera de memoria general si despierta algo. Si no
+despierta nada, entonces una barrera de memoria puede o no ser ejecutada;
+no debe confiar en ello. La barrera se produce antes del acceso al estado
+de la tarea. En particular, se encuentra entre el STORE para indicar el
+evento y el STORE para configurar TASK_RUNNING (hilo ejecutando):
+
+ CPU 1 (Durmiente) CPU 2 (Despertadora)
+ =============================== ===============================
+ set_current_state(); STORE evento_indicado
+ smp_store_mb(); wake_up();
+ STORE current->state ...
+ <barrera general> <barrera general>
+ LOAD evento_indicado if ((LOAD task->state) & TASK_NORMAL)
+ STORE task->state
+
+donde "task" es el subproceso que se está despertando y es igual al
+"current" (hilo actual) de la CPU 1.
+
+Para reiterar, se garantiza la ejecución de una barrera de memoria general
+mediante wake_up() si algo está realmente despierto, pero de lo contrario
+no existe tal garantía. Para entender esto, considere la siguiente
+secuencia de eventos, donde X e Y son ambos cero inicialmente:
+
+ CPU 1 CPU 2
+ =============================== ===============================
+ X = 1; Y = 1;
+ smp_mb(); wake_up();
+ LOAD Y LOAD X
+
+Si ocurre una reactivación ("wakeup"), una (al menos) de las dos cargas
+debe ver 1. Si, por otro lado, no ocurre una reactivación, ambas cargas
+pueden ver 0.
+
+wake_up_process() siempre ejecuta una barrera de memoria general. La
+barrera, de nuevo, ocurre antes de que se acceda al estado del hilo. En
+particular, si wake_up(), en el fragmento anterior, fuera reemplazado por
+una llamada a wake_up_process(), las dos cargas verían 1, garantizado.
+
+Las funciones de activación disponibles incluyen:
+
+ complete();
+ wake_up();
+ wake_up_all();
+ wake_up_bit();
+ wake_up_interruptible();
+ wake_up_interruptible_all();
+ wake_up_interruptible_nr();
+ wake_up_interruptible_poll();
+ wake_up_interruptible_sync();
+ wake_up_interruptible_sync_poll();
+ wake_up_locked();
+ wake_up_locked_poll();
+ wake_up_nr();
+ wake_up_poll();
+ wake_up_process();
+
+En términos de orden de la memoria, todas estas funciones proporcionan las
+mismas garantías que un wake_up() (o más fuertes).
+
+[!] Tenga en cuenta que las barreras de la memoria implicadas por el
+durmiente y el despierto _no_ ordenan varios stores antes del despertar con
+respecto a cargas de los valores guardados después de que el durmiente haya
+llamado a set_current_state(). Por ejemplo, si el durmiente hace:
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (evento_indicado)
+ break;
+ __set_current_state(TASK_RUNNING);
+ hacer_algo(my_data);
+
+y el que despierta hace:
+
+ my_data = valor;
+ evento_indicado = 1;
+ wake_up(&event_wait_queue);
+
+no existe garantía de que el cambio a event_indicated sea percibido por
+el durmiente de manera que venga después del cambio a my_data. En tal
+circunstancia, el código en ambos lados debe sacar sus propias barreras de
+memoria entre los separados accesos a datos. Por lo tanto, el durmiente
+anterior debería hacer:
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (evento_indicado) {
+ smp_rmb();
+ hacer_algo(my_data);
+ }
+
+y el que despierta debería hacer:
+
+ my_data = value;
+ smp_wmb();
+ evento_indicado = 1;
+ wake_up(&event_wait_queue);
+
+FUNCIONES VARIAS
+----------------
+
+Otras funciones que implican barreras:
+
+ (*) schedule() y similares implican barreras completas de memoria.
+
+
+========================================
+EFECTOS DE BARRERA ADQUIRIENDO INTRA-CPU
+========================================
+
+En los sistemas SMP, las primitivas de bloqueo proveen una forma más
+sustancial de barrera: una que afecta el orden de acceso a la memoria en
+otras CPU, dentro del contexto de conflicto en cualquier bloqueo en
+particular.
+
+
+ADQUISICIÓN VS ACCESOS A MEMORIA
+--------------------------------
+
+Considere lo siguiente: el sistema tiene un par de spinlocks (M) y (Q), y
+tres CPU; entonces la siguiente secuencia de eventos debería ocurrir:
+
+ CPU 1 CPU 2
+ =============================== ===============================
+ WRITE_ONCE(*A, a); WRITE_ONCE(*E, e);
+ ACQUIRE M ACQUIRE Q
+ WRITE_ONCE(*B, b); WRITE_ONCE(*F, f);
+ WRITE_ONCE(*C, c); WRITE_ONCE(*G, g);
+ RELEASE M RELEASE Q
+ WRITE_ONCE(*D, d); WRITE_ONCE(*H, h);
+
+Entonces no hay garantía sobre en qué orden verá la CPU 3 los accesos a *A
+hasta que *H ocurra, además de las restricciones impuestas por los bloqueos
+separados en las distintas CPUs. Podría, por ejemplo, ver:
+
+ *E, ACQUIRE M, ACQUIRE Q, *G, *C, *F, *A, *B, RELEASE Q, *D, *H, RELEASE M
+
+Pero no verá ninguno de:
+
+ *B, *C or *D preceding ACQUIRE M
+ *A, *B or *C following RELEASE M
+ *F, *G or *H preceding ACQUIRE Q
+ *E, *F or *G following RELEASE Q
+
+========================================
+¿DÓNDE SE NECESITAN BARRERAS DE MEMORIA?
+========================================
+
+Bajo operación normal, el re-ordenamiento de una operación de memoria
+generalmente no va a suponer un problema, ya que para una pieza de código
+lineal de un solo subproceso seguirá pareciendo que funciona correctamente,
+incluso si está en un kernel SMP. Existen, sin embargo, cuatro
+circunstancias en las que reordenar definitivamente _podría_ ser un
+problema:
+
+ (*) Interacción entre procesadores.
+
+ (*) Operaciones atómicas.
+
+ (*) Acceso a dispositivos.
+
+ (*) Interrupciones.
+
+
+INTERACCIÓN ENTRE PROCESADORES
+------------------------------
+
+Cuando se da un sistema con más de un procesador, más de una CPU en el
+sistema puede estar trabajando en el mismo conjunto de datos al mismo
+tiempo. Esto puede causar problemas de sincronización, y la forma habitual
+de tratar con estos es utilizar cerrojos. Sin embargo, los cerrojos son
+bastante caros, por lo que puede ser preferible operar sin el uso de un
+cerrojo a ser posible. En cuyo caso, es posible que las operaciones que
+afectan a ambas CPU deban ordenarse cuidadosamente para evitar un
+funcionamiento incorrecto.
+
+Considere, por ejemplo, la ruta lenta del semáforo R/W. Aquí hay un proceso
+de espera en cola del semáforo, en virtud de que tiene una parte de su pila
+vinculada a la lista de procesos en espera del semáforo:
+
+ struct rw_semaphore {
+ ...
+ spinlock_t lock;
+ struct list_head waiters;
+ };
+
+ struct rwsem_waiter {
+ struct list_head list;
+ struct task_struct *task;
+ };
+
+Para despertar a un proceso que espera ("waiter") en particular, las
+funciones up_read() o up_write() tienen que:
+
+ (1) leer el siguiente puntero del registro de este proceso que espera,
+ para saber dónde está el registro del siguiente waiter;
+
+ (2) leer el puntero a la estructura de tareas del waiter;
+
+ (3) borrar el puntero de la tarea para decirle al waiter que se le ha dado
+ el semáforo;
+
+ (4) llamar a wake_up_process() en la tarea; y
+
+ (5) liberar la referencia retenida en la estructura de tareas del waiter.
+
+En otras palabras, tiene que realizar esta secuencia de eventos:
+
+ LOAD waiter->list.next;
+ LOAD waiter->task;
+ STORE waiter->task;
+ CALL wakeup
+ RELEASE task
+
+y si alguno de estos pasos ocurre fuera de orden, entonces todo puede que
+funcione defectuosamente.
+
+Una vez que se ha puesto en cola y soltado el bloqueo de semáforo, el
+proceso que espera no consigue el candado de nuevo; en cambio, solo espera
+a que se borre su puntero de tarea antes de continuar. Dado que el registro
+está en la pila del proceso que espera, esto significa que si el puntero de
+la tarea se borra _antes_ de que se lea el siguiente puntero de la lista,
+otra CPU podría comenzar a procesar el proceso que espera y podría romper
+el stack del proceso que espera antes de que la función up*() tenga la
+oportunidad de leer el puntero que sigue.
+
+Considere entonces lo que podría suceder con la secuencia de eventos
+anterior:
+
+ CPU 1 CPU 2
+ =============================== ===============================
+ down_xxx()
+ Poner waiter en la "queue" (cola)
+ Dormir
+ up_yyy()
+ LOAD waiter->task;
+ STORE waiter->task;
+ Despertado por otro evento
+ <preempt>
+ Reanudar el procesamiento
+ down_xxx() regresa
+ llamada a foo()
+ foo() estropea *waiter
+ </preempt>
+ LOAD waiter->list.next;
+ --- OOPS ---
+
+Esto podría solucionarse usando el bloqueo de semáforo, pero luego la
+función down_xxx() tiene que obtener innecesariamente el spinlock
+nuevamente, después de ser despertado el hilo.
+
+La forma de lidiar con esto es insertar una barrera de memoria SMP general:
+
+ LOAD waiter->list.next;
+ LOAD waiter->task;
+ smp_mb();
+ STORE waiter->task;
+ CALL wakeup
+ RELEASE task
+
+En este caso, la barrera garantiza que todos los accesos a memoria antes de
+la barrera parecerán suceder antes de todos los accesos a memoria después
+de dicha barrera con respecto a las demás CPU del sistema. _No_ garantiza
+que todos los accesos a memoria antes de la barrera se completarán en el
+momento en que la instrucción de la barrera en sí se complete.
+
+En un sistema UP, donde esto no sería un problema, la función smp_mb() es
+solo una barrera del compilador, asegurándose así de que el compilador
+emita las instrucciones en el orden correcto sin realmente intervenir en la
+CPU. Como solo hay un CPU, la lógica de orden de dependencias de esa CPU se
+encargará de todo lo demás.
+
+
+OPERACIONES ATÓMICAS
+--------------------
+
+Si bien son, técnicamente, consideraciones de interacción entre
+procesadores, las operaciones atómicas se destacan especialmente porque
+algunas de ellas implican barreras de memoria completa y algunas otras no,
+pero se confía mucho en ellos en su conjunto a lo largo del kernel.
+
+Consulte Documentation/atomic_t.txt para obtener más información.
+
+
+ACCESO A DISPOSITIVOS
+---------------------
+
+Un driver puede ser interrumpido por su propia rutina de servicio de
+interrupción y, por lo tanto, las dos partes del driver pueden interferir
+con los intentos de controlar o acceder al dispositivo.
+
+Esto puede aliviarse, al menos en parte, desactivando las interrupciones
+locales (una forma de bloqueo), de modo que las operaciones críticas sean
+todas contenidas dentro la sección de interrupción desactivada en el
+controlador. Mientras la interrupción del driver está ejecutando la rutina,
+es posible que el "core" del controlador no se ejecute en la misma CPU y no
+se permita que su interrupción vuelva a ocurrir hasta que la interrupción
+actual haya sido resuelta, por lo tanto, el controlador de interrupción no
+necesita bloquearse contra esto.
+
+Sin embargo, considere un driver que estaba hablando con una tarjeta
+ethernet que tiene un registro de direcciones y un registro de datos. Si
+el core de ese controlador habla con la tarjeta estando en desactivación de
+interrupción y luego se invoca el controlador de interrupción del
+controlador:
+
+ IRQ LOCALES DESACTIVADAS
+ writew(ADDR, 3);
+ writew(DATA, y);
+ IRQ LOCALES ACTIVADAS
+ <interrupción>
+ writew(ADDR, 4);
+ q = readw(DATA);
+ </interrupción>
+
+El almacenamiento en el registro de datos puede ocurrir después del segundo
+almacenamiento en el registro de direcciones si las reglas de orden son lo
+suficientemente relajadas:
+
+ STORE *ADDR = 3, STORE *ADDR = 4, STORE *DATA = y, q = LOAD *DATA
+
+Si se relajan las reglas de orden, se debe asumir que los accesos
+realizados dentro de la sección con interrupción deshabilitada pueden
+filtrarse fuera de esta y pueden intercalarse con accesos realizados en una
+interrupción - y viceversa - a menos que se utilicenn barreras implícita o
+explícitas.
+
+Normalmente, esto no será un problema porque los accesos de E/S realizados
+dentro de tales secciones incluirán operaciones de carga síncronas en
+registros E/S estrictamente ordenados, que forman barreras de E/S
+implícitas.
+
+
+Una situación similar puede ocurrir entre una rutina de interrupción y dos
+rutinas ejecutándose en separadas CPU que se comunican entre sí. Si tal
+caso es probable, entonces se deben usar bloqueos de desactivación de
+interrupciones para garantizar el orden.
+
+
+=====================================
+ Efectos de barrera de E/S del kernel
+=====================================
+
+La interfaz con periféricos a través de accesos de E/S es profundamente
+específica para cada arquitectura y dispositivo. Por lo tanto, los drivers
+que son inherentemente no portátiles pueden depender de comportamientos
+específicos de sus sistemas de destino, con el fin de lograr la
+sincronización de la manera más ligera posible. Para drivers que deseen ser
+portátiles entre múltiples arquitecturas e implementaciones de bus, el
+kernel ofrece una serie de funciones de acceso que proporcionan varios
+grados de garantías de orden:
+
+ (*) readX(), writeX():
+
+ Las funciones de acceso MMIO readX() y writeX() usan un puntero al
+ periférico al que se accede como un parámetro __iomem *. para punteros
+ asignados los atributos de E/S predeterminados (por ejemplo, los
+ devueltos por ioremap()), las garantías de orden son las siguientes:
+
+ 1. Se ordenan todos los accesos readX() y writeX() a un mismo periférico
+ entre estos. Esto asegura que los registros de acceso MMIO por el
+ mismo subproceso de la CPU a un dispositivo en particular llegarán en
+ el orden del programa.
+
+ 2. Se ordena un writeX() emitido por un subproceso de CPU que contiene un
+ spinlock antes de un writeX() al mismo periférico desde otro
+ subproceso de CPU, si emitido después de una adquisición posterior del
+ mismo spinlock. Esto garantiza que ese registro MMIO escribe en un
+ dispositivo en particular, mientras que se obtiene un spinlock en un
+ orden consistente con las adquisiciones del cerrojo.
+
+ 3. Un writeX() por un subproceso de la CPU al periférico primero esperará
+ a la finalización de todas las escrituras anteriores en la memoria
+ emitidas por, o bien propagadas por, el mismo subproceso. Esto asegura
+ que las escrituras de la CPU a un búfer DMA de salida asignadas por
+ dma_alloc_coherent() serán visibles para un motor ("engine") DMA
+ cuando la CPU escriba en sus registros de control MMIO, para activar
+ la transferencia.
+
+ 4. Un readX() de un subproceso del CPU, desde el periférico, se
+ completará antes de que cualquier lectura subsiguiente de memoria por
+ el mismo subproceso pueda comenzar. Esto asegura que las lecturas de
+ la CPU desde un búfer DMA entrantes asignadas por
+ dma_alloc_coherent(), no verán datos obsoletos después de leer el
+ registro de estado MMIO del motor DMA, para establecer que la
+ transferencia DMA se haya completado.
+
+ 5. Un readX() por un subproceso del CPU, desde el periférico, se
+ completará antes de que cualquier bucle delay() subsiguiente pueda
+ comenzar a ejecutarse en el mismo subproceso. Esto asegura que dos
+ escrituras del CPU a registros MMIO en un periférico llegarán al menos
+ con 1us de diferencia, si la primera escritura se lee inmediatamente
+ de vuelta con readX() y se llama a udelay(1) antes del segundo
+ writeX():
+
+ writel(42, DEVICE_REGISTER_0); // Llega al dispositivo ...
+ readl(DEVICE_REGISTER_0);
+ udelay(1);
+ writel(42, DEVICE_REGISTER_1); // al menos 1us antes de esto....
+
+Las propiedades de orden de los punteros __iomem obtenidos con valores de
+atributos que no sean los valores por defecto (por ejemplo, los devueltos
+por ioremap_wc()) son específicos de la arquitectura subyacente y, por lo
+tanto, las garantías enumeradas anteriormente no pueden por lo general ser
+aseguradas para accesos a este tipo de "mappings" (asignaciones).
+
+ (*) readX_relaxed(), writeX_relaxed():
+
+ Son similares a readX() y writeX(), pero proporcionan una garantía de
+ orden de memoria más débil. Específicamente, no garantizan orden con
+ respecto al bloqueo, los accesos normales a la memoria o los bucles
+ delay() (es decir, los puntos 2-5 arriba) pero todavía se garantiza que
+ se ordenarán con respecto a otros accesos desde el mismo hilo de la CPU,
+ al mismo periférico, cuando se opera en punteros __iomem asignados con el
+ valor predeterminado para los atributos de E/S.
+
+ (*) readsX(), writesX():
+
+ Los puntos de entrada readsX() y writesX() MMIO están diseñados para
+ acceder FIFOs mapeados en memoria y basados en registros que residen en
+ periféricos, que no son capaces de realizar DMA. Por tanto, sólo
+ proporcionan garantías de orden readX_relaxed() y writeX_relaxed(), como
+ se documentó anteriormente.
+
+ (*) inX(), outX():
+
+ Los puntos de entrada inX() y outX() están destinados a acceder a mapas
+ de puertos "legacy" (antiguos) de periféricos de E/S, que pueden requerir
+ instrucciones especiales en algunas arquitecturas (especialmente, en
+ x86). El número de puerto del periférico que se está accedido se pasa
+ como un argumento.
+
+ Dado que muchas arquitecturas de CPU acceden finalmente a estos
+ periféricos a través de un mapeo interno de memoria virtual, las
+ garantías de orden portátiles proporcionadas por inX() y outX() son las
+ mismas que las proporcionadas por readX() y writeX(), respectivamente, al
+ acceder a una asignación con los valores de atributos de E/S
+ predeterminados (los que haya por defecto).
+
+ Los drivers de dispositivos pueden esperar que outX() emita una
+ transacción de escritura no publicada, que espera una respuesta de
+ finalización del periférico de E/S antes de regresar. Esto no está
+ garantizado por todas las arquitecturas y por lo tanto no forma parte de
+ la semántica de orden portátil.
+
+ (*) insX(), outsX():
+
+ Como arriba, los puntos de entrada insX() y outsX() proporcionan el mismo
+ orden garantizado por readsX() y writesX() respectivamente, al acceder a
+ un mapping con los atributos de E/S predeterminados.
+
+ (*) ioreadX(), iowriteX():
+
+ Estos funcionarán adecuadamente para el tipo de acceso que realmente están
+ haciendo, ya sea inX()/outX() o readX()/writeX().
+
+Con la excepción de los puntos de entrada (insX(), outsX(), readsX() y
+writesX()), todo lo anterior supone que el periférico subyacente es
+little-endian y, por lo tanto, realizará operaciones de intercambio de
+bytes en arquitecturas big-endian.
+
+
+===========================================
+MODELO DE ORDEN MÍNIMO DE EJECUCIÓN ASUMIDO
+===========================================
+
+Debe suponerse que la CPU conceptual está débilmente ordenada, pero que
+mantiene la apariencia de causalidad del programa con respecto a sí misma.
+Algunas CPU (como i386 o x86_64) están más limitadas que otras (como
+powerpc o frv), por lo que el caso más relajado (es decir, DEC Alpha) se
+debe asumir fuera de código específico de arquitectura.
+
+Esto significa que se debe considerar que la CPU ejecutará su flujo de
+instrucciones en el orden que se quiera - o incluso en paralelo - siempre
+que si una instrucción en el flujo depende de una instrucción anterior,
+entonces dicha instrucción anterior debe ser lo suficientemente completa[*]
+antes de que la posterior instrucción puede proceder; en otras palabras:
+siempre que la apariencia de causalidad se mantenga.
+
+ [*] Algunas instrucciones tienen más de un efecto, como cambiar el
+ código de condición, cambio de registros o cambio de memoria - y
+ distintas instrucciones pueden depender de diferentes efectos.
+
+Una CPU puede también descartar cualquier secuencia de instrucciones que
+termine sin tener efecto final. Por ejemplo, si dos instrucciones
+adyacentes cargan un valor inmediato en el mismo registro, la primera puede
+descartarse.
+
+
+De manera similar, se debe suponer que el compilador podría reordenar la
+corriente de instrucciones de la manera que crea conveniente, nuevamente
+siempre que la apariencia de causalidad se mantenga.
+
+
+=====================================
+EFECTOS DE LA MEMORIA CACHÉ DE LA CPU
+=====================================
+
+La forma en que se perciben las operaciones de memoria caché en todo el
+sistema se ve afectada, hasta cierto punto, por los cachés que se
+encuentran entre las CPU y la memoria, y por el sistema de coherencia en
+memoria que mantiene la consistencia de estado en el sistema.
+
+En cuanto a la forma en que una CPU interactúa con otra parte del sistema a
+través del caché, el sistema de memoria tiene que incluir los cachés de la
+CPU y barreras de memoria, que en su mayor parte actúan en la interfaz
+entre la CPU y su caché (las barreras de memoria lógicamente actúan sobre
+la línea de puntos en el siguiente diagrama):
+
+ <--- CPU ---> : <----------- Memoria ----------->
+ :
+ +--------+ +--------+ : +--------+ +-----------+
+ | Core | | Cola | : | Cache | | | +---------+
+ | CPU | | de | : | CPU | | | | |
+ | |--->| acceso |----->| |<-->| | | |
+ | | | a | : | | | |--->| Memoria |
+ | | | memoria| : | | | | | |
+ +--------+ +--------+ : +--------+ | Mecanismo | | |
+ : | de | +---------+
+ : | Coherencia|
+ : | de la | +--------+
+ +--------+ +--------+ : +--------+ | cache | | |
+ | Core | | Cola | : | Cache | | | | |
+ | CPU | | de | : | CPU | | |--->| Dispos |
+ | |--->| acceso |----->| |<-->| | | itivo |
+ | | | a | : | | | | | |
+ | | | memoria| : | | | | +--------+
+ +--------+ +--------+ : +--------+ +-----------+
+ :
+ :
+
+Aunque es posible que una carga o store en particular no aparezca fuera de
+la CPU que lo emitió, ya que puede haber sido satisfecha dentro del propio
+caché de la CPU, seguirá pareciendo como si el acceso total a la memoria
+hubiera tenido lugar para las otras CPUs, ya que los mecanismos de
+coherencia de caché migrarán la cacheline sobre la CPU que accede y se
+propagarán los efectos en caso de conflicto.
+
+El núcleo de la CPU puede ejecutar instrucciones en el orden que considere
+adecuado, siempre que parezca mantenerse la causalidad esperada del
+programa. Algunas de las instrucciones generan operaciones de carga y
+almacenamiento que luego van a la cola de accesos a memoria a realizar. El
+núcleo puede colocarlos en la cola en cualquier orden que desee, y
+continuar su ejecución hasta que se vea obligado a esperar que una
+instrucción sea completada.
+
+De lo que se ocupan las barreras de la memoria es de controlar el orden en
+que los accesos cruzan, desde el lado de la CPU, hasta el lado de memoria,
+y el orden en que los otros observadores perciben los efectos en el sistema
+que sucedan por esto.
+
+[!] Las barreras de memoria _no_ son necesarias dentro de una CPU
+determinada, ya que las CPU siempre ven sus propias cargas y stores como si
+hubieran sucedido en el orden del programa.
+
+[!] Los accesos a MMIO u otros dispositivos pueden pasar por alto el
+sistema de caché. Esto depende de las propiedades de la ventana de memoria
+a través de la cual se accede a los dispositivos y/o el uso de
+instrucciones especiales de comunicación con dispositivo que pueda tener la
+CPU.
+
+
+COHERENCIA DE CACHÉ FRENTE A DMA
+---------------------------------
+
+No todos los sistemas mantienen coherencia de caché con respecto a los
+dispositivos que realizan DMA. En tales casos, un dispositivo que intente
+DMA puede obtener datos obsoletos de la RAM, porque las líneas de caché
+"sucias" pueden residir en los cachés de varias CPU, y es posible que no
+se hayan vuelto a escribir en la RAM todavía. Para hacer frente a esto, la
+parte apropiada del kernel debe vaciar los bits superpuestos de caché en
+cada CPU (y tal vez también invalidarlos).
+
+Además, los datos enviados por DMA a RAM, por un dispositivo, pueden ser
+sobrescritos por líneas de caché sucias que se escriben de nuevo en la RAM
+desde el caché de una CPU, después de que el dispositivo haya puesto sus
+propios datos, o las líneas de caché presentes en el caché de la CPU pueden
+simplemente ocultar el hecho de que la memoria RAM se haya actualizado,
+hasta el momento en que la caché se descarta de la memoria caché de la CPU
+y se vuelve a cargar. Para hacer frente a esto, la parte apropiada del
+kernel debe invalidar los bits superpuestos del caché en cada CPU.
+
+Consulte Documentation/core-api/cachetlb.rst para obtener más información
+sobre administración de la memoria caché.
+
+
+COHERENCIA DE CACHÉ FRENTE A MMIO
+---------------------------------
+
+La E/S mapeada en memoria generalmente se lleva a cabo a través de
+ubicaciones de memoria que forman parte de una ventana del espacio de
+memoria de la CPU, que tiene diferentes propiedades asignadas que la
+ventana habitual dirigida a RAM.
+
+Entre dichas propiedades, suele existir el hecho de que tales accesos
+eluden el almacenamiento en caché por completo e ir directamente a los
+buses del dispositivo. Esto significa que los accesos MMIO pueden, en
+efecto, superar los accesos a la memoria caché que se emitieron
+anteriormente. Una barrera de memoria no es suficiente en tal caso, sino
+que el caché debe ser vaciado entre la escritura de la memoria caché, y el
+acceso MMIO, si los dos son de cualquier manera dependiente.
+
+
+=======================
+COSAS QUE HACEN LAS CPU
+=======================
+
+Un programador podría dar por sentado que la CPU realizará las operaciones
+de memoria exactamente en el orden especificado, de modo que si a la CPU se
+entrega, por ejemplo, el siguiente fragmento de código a ejecutar:
+
+ a = READ_ONCE(*A);
+ WRITE_ONCE(*B, b);
+ c = READ_ONCE(*C);
+ d = READ_ONCE(*D);
+ WRITE_ONCE(*E, e);
+
+esperarían entonces que la CPU complete la operación de memoria para cada
+instrucción antes de pasar a la siguiente, lo que lleva a una definida
+secuencia de operaciones vistas por observadores externos en el sistema:
+
+ LOAD *A, STORE *B, LOAD *C, LOAD *D, STORE *E.
+
+La realidad es, por supuesto, mucho más intrincada. Para muchas CPU y
+compiladores, la anterior suposición no se sostiene porque:
+
+ (*) es más probable que las cargas deban completarse de inmediato para
+ permitir progreso en la ejecución, mientras que los stores a menudo se
+ pueden aplazar sin problema;
+
+ (*) las cargas se pueden hacer especulativamente, y el resultado es
+ descartado si resulta innecesario;
+
+ (*) las cargas se pueden hacer de forma especulativa, lo que lleva a que
+ se haya obtenido el resultado en el momento equivocado de la secuencia
+ de eventos esperada;
+
+ (*) el orden de los accesos a memoria se puede reorganizar para promover
+ un mejor uso de los buses y cachés de la CPU;
+
+ (*) las cargas y los stores se pueden combinar para mejorar el rendimiento
+ cuando se habla con memoria o hardware de E/S, que puede realizar
+ accesos por lotes a ubicaciones adyacentes, reduciendo así los costes
+ de configuración de transacciones (la memoria y los dispositivos PCI
+ pueden ambos pueden hacer esto); y
+
+ (*) la caché de datos de la CPU puede afectar al orden, y mientras sus
+ mecanismos de coherencia pueden aliviar esto, una vez que el store
+ haya accedido al caché- no hay garantía de que la gestión de la
+ coherencia se propague en orden a otras CPU.
+
+Entonces, digamos que lo que otra CPU podría observar en el fragmento de
+código anterior es:
+
+ LOAD *A, ..., LOAD {*C,*D}, STORE *E, STORE *B
+
+ (Donde "LOAD {*C,*D}" es una carga combinada)
+
+
+Sin embargo, se garantiza que una CPU es autoconsistente: verá que sus
+ _propios_ accesos parecen estar correctamente ordenados, sin necesidad de
+barrera de memoria. Por ejemplo con el siguiente código:
+
+ U = READ_ONCE(*A);
+ WRITE_ONCE(*A, V);
+ WRITE_ONCE(*A, W);
+ X = READ_ONCE(*A);
+ WRITE_ONCE(*A, Y);
+ Z = READ_ONCE(*A);
+
+y asumiendo que no hay intervención de una influencia externa, se puede
+suponer que el resultado final se parecerá a:
+
+ U == el valor original de *A
+ X == W
+ Z == Y
+ *A == Y
+
+El código anterior puede hacer que la CPU genere la secuencia completa de
+accesos de memoria:
+
+ U=LOAD *A, STORE *A=V, STORE *A=W, X=LOAD *A, STORE *A=Y, Z=LOAD *A
+
+en ese orden, pero, sin intervención, la secuencia puede contener casi
+cualquier combinación de elementos combinados o descartados, siempre que la
+perspectiva del programa del mundo siga siendo consistente. Tenga en cuenta
+que READ_ONCE() y WRITE_ONCE() -no- son opcionales en el ejemplo anterior,
+ya que hay arquitecturas donde una CPU determinada podría reordenar cargas
+sucesivas en la misma ubicación. En tales arquitecturas, READ_ONCE() y
+WRITE_ONCE() hacen lo que sea necesario para evitar esto, por ejemplo, en
+Itanium los casts volátiles utilizados por READ_ONCE() y WRITE_ONCE() hacen
+que GCC emita las instrucciones especiales ld.acq y st.rel
+(respectivamente) que impiden dicha reordenación.
+
+El compilador también puede combinar, descartar o diferir elementos de la
+secuencia antes incluso de que la CPU los vea.
+
+Por ejemplo:
+
+ *A = V;
+ *A = W;
+
+puede reducirse a:
+
+ *A = W;
+
+ya que, sin una barrera de escritura o WRITE_ONCE(), puede que se asuma
+que el efecto del almacenamiento de V a *A se pierde. Similarmente:
+
+ *A = Y;
+ Z = *A;
+
+puede, sin una barrera de memoria o un READ_ONCE() y WRITE_ONCE(), esto
+sea reducido a:
+
+ *A = Y;
+ Z = Y;
+
+y la operación LOAD nunca aparezca fuera de la CPU.
+
+
+Y LUEGO ESTÁ EL ALFA
+--------------------
+
+La CPU DEC Alpha es una de las CPU más relajadas que existen. No solo eso,
+algunas versiones de la CPU Alpha tienen un caché de datos dividido, lo que
+les permite tener dos líneas de caché relacionadas semánticamente,
+actualizadas en momentos separados. Aquí es donde la barrera de dependencia
+de dirección realmente se vuelve necesaria, ya que se sincronizan ambos
+cachés con el sistema de coherencia de memoria, lo que hace que parezca un
+cambio en el puntero, frente a que los nuevos datos se produzcan en el
+orden correcto.
+
+Alpha define el modelo de memoria del kernel Linux, aunque a partir de
+v4.15, la adición al kernel de Linux de smp_mb() a READ_ONCE() en Alpha
+redujo en gran medida su impacto en el modelo de memoria.
+
+
+GUESTS DE MÁQUINAS VIRTUALES
+-----------------------------
+
+Los "guests" (invitados) que se ejecutan en máquinas virtuales pueden verse
+afectados por los efectos de SMP incluso si el "host" (huésped) en sí se
+compila sin compatibilidad con SMP. Este es un efecto de la interacción con
+un host SMP mientras ejecuta un kernel UP. El uso obligatorio de barreras
+para este caso de uso sería posible, pero a menudo no son óptimas.
+
+Para hacer frente a este caso de manera óptima, están disponibles macros de
+bajo nivel virt_mb() etc. Estas tienen el mismo efecto que smp_mb(), etc.
+cuando SMP está habilitado, pero generan código idéntico para sistemas SMP
+y no SMP. Por ejemplo, los invitados de máquinas virtuales debería usar
+virt_mb() en lugar de smp_mb() al sincronizar contra un (posiblemente SMP)
+anfitrión.
+
+Estos son equivalentes a sus contrapartes smp_mb() etc. en todos los demás
+aspectos, en particular, no controlan los efectos MMIO: para controlar los
+efectos MMIO, utilice barreras obligatorias.
+
+
+================
+EJEMPLOS DE USOS
+================
+
+BUFFERS CIRCULARES
+------------------
+
+Las barreras de memoria se pueden utilizar para implementar almacenamiento
+en búfer circular, sin necesidad de un cerrojo para serializar al productor
+con el consumidor. Vea:
+
+ Documentation/core-api/circular-buffers.rst
+
+para más detalles.
+
+
+===========
+REFERENCIAS
+===========
+
+Alpha AXP Architecture Reference Manual, Segunda Edición (por Sites & Witek,
+Digital Press)
+ Capítulo 5.2: Physical Address Space Characteristics
+ Capítulo 5.4: Caches and Write Buffers
+ Capítulo 5.5: Data Sharing
+ Capítulo 5.6: Read/Write Ordering
+
+AMD64 Architecture Programmer's Manual Volumen 2: System Programming
+ Capítulo 7.1: Memory-Access Ordering
+ Capítulo 7.4: Buffering and Combining Memory Writes
+
+ARM Architecture Reference Manual (ARMv8, for ARMv8-A architecture profile)
+ Capítulo B2: The AArch64 Application Level Memory Model
+
+IA-32 Intel Architecture Software Developer's Manual, Volumen 3:
+System Programming Guide
+ Capítulo 7.1: Locked Atomic Operations
+ Capítulo 7.2: Memory Ordering
+ Capítulo 7.4: Serializing Instructions
+
+The SPARC Architecture Manual, Version 9
+ Capítulo 8: Memory Models
+ Appendix D: Formal Specification of the Memory Models
+ Appendix J: Programming with the Memory Models
+
+Storage in the PowerPC (por Stone and Fitzgerald)
+
+UltraSPARC Programmer Reference Manual
+ Capítulo 5: Memory Accesses and Cacheability
+ Capítulo 15: Sparc-V9 Memory Models
+
+UltraSPARC III Cu User's Manual
+ Capítulo 9: Memory Models
+
+UltraSPARC IIIi Processor User's Manual
+ Capítulo 8: Memory Models
+
+UltraSPARC Architecture 2005
+ Capítulo 9: Memory
+ Appendix D: Formal Specifications of the Memory Models
+
+UltraSPARC T1 Supplement to the UltraSPARC Architecture 2005
+ Capítulo 8: Memory Models
+ Appendix F: Caches and Cache Coherency
+
+Solaris Internals, Core Kernel Architecture, p63-68:
+ Capítulo 3.3: Hardware Considerations for Locks and
+ Synchronization
+
+Unix Systems for Modern Architectures, Symmetric Multiprocessing and Caching
+for Kernel Programmers:
+ Capítulo 13: Other Memory Models
+
+Intel Itanium Architecture Software Developer's Manual: Volumen 1:
+ Sección 2.6: Speculation
+ Sección 4.4: Memory Access
diff --git a/Documentation/translations/sp_SP/process/adding-syscalls.rst b/Documentation/translations/sp_SP/process/adding-syscalls.rst
new file mode 100644
index 000000000000..f21504c612b2
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/adding-syscalls.rst
@@ -0,0 +1,632 @@
+.. include:: ../disclaimer-sp.rst
+
+:Original: :ref:`Documentation/process/adding-syscalls.rst <addsyscalls>`
+:Translator: Mauricio Fuentes <mauriciofb@gmail.com>
+
+.. _sp_addsyscalls:
+
+Agregando una Nueva Llamada del Sistema
+=======================================
+
+Este documento describe qué involucra agregar una nueva llamada del sistema
+al kernel Linux, más allá de la presentación y consejos normales en
+:ref:`Documentation/process/submitting-patches.rst <submittingpatches>` que
+también puede encontrar traducido a este idioma.
+
+Alternativas a Llamadas del Sistema
+-----------------------------------
+
+La primera cosa a considerar cuando se agrega una llamada al sistema es si
+alguna alternativa es adecuada en su lugar. Aunque las llamadas al sistema
+son los puntos de interacción entre el userspace y el kernel más obvios y
+tradicionales, existen otras posibilidades -- elija la que mejor se adecúe
+a su interfaz.
+
+ - Si se puede hacer que la operación se parezca a un objeto filesystem,
+ podría tener más sentido crear un nuevo sistema de ficheros o
+ dispositivo. Esto también hará más fácil encapsular la nueva
+ funcionalidad en un módulo del kernel en vez de requerir que sea
+ construido junto al kernel principal.
+
+ - Si la nueva funcionalidad involucra operaciones donde el kernel
+ notifica al userspace que algo ha pasado, entonces retornar un nuevo
+ descriptor de archivo para el objeto relevante permite al userspace
+ usar ``poll``/``select``/``epoll`` para recibir esta notificación.
+
+ - Sin embargo, operaciones que no mapean a operaciones similares a
+ :manpage:`read(2)`/:manpage:`write(2)` tienen que ser implementadas
+ como solicitudes :manpage:`ioctl(2)`, las cuales pueden llevar a un
+ API algo opaca.
+
+ - Si sólo está exponiendo información del runtime, un nuevo nodo en sysfs
+ (mire ``Documentation/filesystems/sysfs.rst``) o el filesystem ``/proc``
+ podría ser más adecuado. Sin embargo, acceder a estos mecanismos
+ requiere que el filesystem relevante esté montado, lo que podría no ser
+ siempre el caso (e.g. en un ambiente namespaced/sandboxed/chrooted).
+ Evite agregar cualquier API a debugfs, ya que no se considera una
+ interfaz (interface) de 'producción' para el userspace.
+
+ - Si la operación es específica a un archivo o descriptor de archivo
+ específico, entonces la opción de comando adicional :manpage:`fcntl(2)`
+ podría ser más apropiada. Sin embargo, :manpage:`fcntl(2)` es una
+ llamada al sistema multiplexada que esconde mucha complejidad, así que
+ esta opción es mejor cuando la nueva funcion es analogamente cercana a
+ la funcionalidad existente :manpage:`fcntl(2)`, o la nueva funcionalidad
+ es muy simple (por ejemplo, definir/obtener un flag simple relacionado a
+ un descriptor de archivo).
+
+ - Si la operación es específica a un proceso o tarea particular, entonces
+ un comando adicional :manpage:`prctl(2)` podría ser más apropiado. Tal
+ como con :manpage:`fcntl(2)`, esta llamada al sistema es un multiplexor
+ complicado así que está reservado para comandos análogamente cercanos
+ del existente ``prctl()`` u obtener/definir un flag simple relacionado a
+ un proceso.
+
+Diseñando el API: Planeando para extensiones
+--------------------------------------------
+
+Una nueva llamada del sistema forma parte del API del kernel, y tiene que
+ser soportada indefinidamente. Como tal, es una muy buena idea discutir
+explícitamente el interface en las listas de correo del kernel, y es
+importante planear para futuras extensiones del interface.
+
+(La tabla syscall está poblada con ejemplos históricos donde esto no se
+hizo, junto con los correspondientes seguimientos de los system calls --
+``eventfd``/``eventfd2``, ``dup2``/``dup3``, ``inotify_init``/``inotify_init1``,
+``pipe``/``pipe2``, ``renameat``/``renameat2`` -- así que aprenda de la
+historia del kernel y planee extensiones desde el inicio.)
+
+Para llamadas al sistema más simples que sólo toman un par de argumentos,
+la forma preferida de permitir futuras extensiones es incluir un argumento
+flag a la llamada al sistema. Para asegurarse que el userspace pueda usar
+de forma segura estos flags entre versiones del kernel, revise si los flags
+contienen cualquier flag desconocido, y rechace la llamada al sistema (con
+``EINVAL``) si ocurre::
+
+ if (flags & ~(THING_FLAG1 | THINGFLAG2 | THING_FLAG3))
+ return -EINVAL;
+
+(Si no hay valores de flags usados aún, revise que los argumentos del flag
+sean cero.)
+
+Para llamadas al sistema más sofisticadas que involucran un gran número de
+argumentos, es preferible encapsular la mayoría de los argumentos en una
+estructura que sea pasada a través de un puntero. Tal estructura puede
+hacer frente a futuras extensiones mediante la inclusión de un argumento de
+tamaño en la estructura::
+
+ struct xyzzy_params {
+ u32 size; /* userspace define p->size = sizeof(struct xyzzy_params) */
+ u32 param_1;
+ u64 param_2;
+ u64 param_3;
+ };
+
+Siempre que cualquier campo añadido subsecuente, digamos ``param_4``, sea
+diseñado de forma tal que un valor cero, devuelva el comportamiento previo,
+entonces permite versiones no coincidentes en ambos sentidos:
+
+ - Para hacer frente a programas del userspace más modernos, haciendo
+ llamadas a un kernel más antiguo, el código del kernel debe revisar que
+ cualquier memoria más allá del tamaño de la estructura sea cero (revisar
+ de manera efectiva que ``param_4 == 0``).
+ - Para hacer frente a programas antiguos del userspace haciendo llamadas a
+ un kernel más nuevo, el código del kernel puede extender con ceros, una
+ instancia más pequeña de la estructura (definiendo efectivamente
+ ``param_4 == 0``).
+
+Revise :manpage:`perf_event_open(2)` y la función ``perf_copy_attr()`` (en
+``kernel/events/code.c``) para un ejemplo de esta aproximación.
+
+
+Diseñando el API: Otras consideraciones
+---------------------------------------
+
+Si su nueva llamada al sistema permite al userspace hacer referencia a un
+objeto del kernel, esta debería usar un descriptor de archivo como el
+manipulador de ese objeto -- no invente un nuevo tipo de objeto manipulador
+userspace cuando el kernel ya tiene mecanismos y semánticas bien definidas
+para usar los descriptores de archivos.
+
+Si su nueva llamada a sistema :manpage:`xyzzy(2)` retorna un nuevo
+descriptor de archivo, entonces el argumento flag debe incluir un valor que
+sea equivalente a definir ``O_CLOEXEC`` en el nuevo FD. Esto hace posible
+al userspace acortar la brecha de tiempo entre ``xyzzy()`` y la llamada a
+``fcntl(fd, F_SETFD, FD_CLOEXEC)``, donde un ``fork()`` inesperado y
+``execve()`` en otro hilo podrían filtrar un descriptor al programa
+ejecutado. (Sin embargo, resista la tentación de reusar el valor actual de
+la constante ``O_CLOEXEC``, ya que es específica de la arquitectura y es
+parte de un espacio numerado de flags ``O_*`` que está bastante lleno.)
+
+Si su llamada de sistema retorna un nuevo descriptor de archivo, debería
+considerar también que significa usar la familia de llamadas de sistema
+:manpage:`poll(2)` en ese descriptor de archivo. Hacer un descriptor de
+archivo listo para leer o escribir es la forma normal para que el kernel
+indique al espacio de usuario que un evento ha ocurrido en el
+correspondiente objeto del kernel.
+
+Si su nueva llamada de sistema :manpage:`xyzzy(2)` involucra algún nombre
+de archivo como argumento::
+
+ int sys_xyzzy(const char __user *path, ..., unsigned int flags);
+
+debería considerar también si una versión :manpage:`xyzzyat(2)` es mas
+apropiada::
+
+ int sys_xyzzyat(int dfd, const char __user *path, ..., unsigned int flags);
+
+Esto permite más flexibilidad en como el userspace especifica el archivo en
+cuestión; en particular esto permite al userspace pedir la funcionalidad a
+un descriptor de archivo ya abierto usando el flag ``AT_EMPTY_PATH``,
+efectivamente dando una operación :manpage:`fxyzzy(3)` gratis::
+
+ - xyzzyat(AT_FDCWD, path, ..., 0) es equivalente a xyzzy(path, ...)
+ - xyzzyat(fd, "", ..., AT_EMPTY_PATH) es equivalente a fxyzzy(fd, ...)
+
+(Para más detalles sobre la explicación racional de las llamadas \*at(),
+revise el man page :manpage:`openat(2)`; para un ejemplo de AT_EMPTY_PATH,
+mire el man page :manpage:`fstatat(2)` manpage.)
+
+Si su nueva llamada de sistema :manpage:`xyzzy(2)` involucra un parámetro
+describiendo un describiendo un movimiento dentro de un archivo, ponga de
+tipo ``loff_t`` para que movimientos de 64-bit puedan ser soportados
+incluso en arquitecturas de 32-bit.
+
+Si su nueva llamada de sistema :manpage:`xyzzy` involucra una
+funcionalidad privilegiada, esta necesita ser gobernada por la capability
+bit linux apropiada (revisado con una llamada a ``capable()``), como se
+describe en el man page :manpage:`capabilities(7)`. Elija una parte de
+capability linux que govierne las funcionalidades relacionadas, pero trate
+de evitar combinar muchas funciones sólo relacionadas vagamente bajo la
+misma sección, ya que va en contra de los propósitos de las capabilities de
+dividir el poder del usuario root. En particular, evite agregar nuevos usos
+de la capacidad ya demasiado general de la capabilities ``CAP_SYS_ADMIN``.
+
+Si su nueva llamada de sistema :manpage:`xyzzy(2)` manipula un proceso que
+no es el proceso invocado, este debería ser restringido (usando una llamada
+a ``ptrace_may_access()``) de forma que el único proceso con los mismos
+permisos del proceso objetivo, o con las capacidades (capabilities)
+necesarias, pueda manipulador el proceso objetivo.
+
+Finalmente, debe ser conciente de que algunas arquitecturas no-x86 tienen
+un manejo más sencillo si los parámetros que son explícitamente 64-bit
+caigan en argumentos enumerados impares (i.e. parámetros 1,3,5), para
+permitir el uso de pares contiguos de registros 32-bits. (Este cuidado no
+aplica si el argumento es parte de una estructura que se pasa a través de
+un puntero.)
+
+Proponiendo el API
+------------------
+
+Para hacer una nueva llamada al sistema fácil de revisar, es mejor dividir
+el patchset (conjunto de parches) en trozos separados. Estos deberían
+incluir al menos los siguientes items como commits distintos (cada uno de
+los cuales se describirá más abajo):
+
+ - La implementación central de la llamada al sistema, junto con
+ prototipos, numeración genérica, cambios Kconfig e implementaciones de
+ rutinas de respaldo (fallback stub)
+ - Conectar la nueva llamada a sistema a una arquitectura particular,
+ usualmente x86 (incluyendo todas las x86_64, x86_32 y x32).
+ - Una demostración del use de la nueva llamada a sistema en el userspace
+ vía un selftest en ``tools/testing/selftest/``.
+ - Un borrador de man-page para la nueva llamada a sistema, ya sea como
+ texto plano en la carta de presentación, o como un parche (separado)
+ para el repositorio man-pages.
+
+Nuevas propuestas de llamadas de sistema, como cualquier cambio al API del
+kernel, debería siempre ser copiado a linux-api@vger.kernel.org.
+
+
+Implementation de Llamada de Sistema Generica
+---------------------------------------------
+
+La entrada principal a su nueva llamada de sistema :manpage:`xyzzy(2)` será
+llamada ``sys_xyzzy()``, pero incluya este punto de entrada con la macro
+``SYSCALL_DEFINEn()`` apropiada en vez de explicitamente. El 'n' indica el
+numero de argumentos de la llamada de sistema, y la macro toma el nombre de
+la llamada de sistema seguida por el par (tipo, nombre) para los parámetros
+como argumentos. Usar esta macro permite a la metadata de la nueva llamada
+de sistema estar disponible para otras herramientas.
+
+El nuevo punto de entrada también necesita un prototipo de función
+correspondiente en ``include/linux/syscalls.h``, marcado como asmlinkage
+para calzar en la manera en que las llamadas de sistema son invocadas::
+
+ asmlinkage long sys_xyzzy(...);
+
+Algunas arquitecturas (e.g. x86) tienen sus propias tablas de syscall
+específicas para la arquitectura, pero muchas otras arquitecturas comparten
+una tabla de syscall genéricas. Agrega su nueva llamada de sistema a la
+lista genérica agregando una entrada a la lista en
+``include/uapi/asm-generic/unistd.h``::
+
+ #define __NR_xyzzy 292
+ __SYSCALL(__NR_xyzzy, sys_xyzzy )
+
+También actualice el conteo de __NR_syscalls para reflejar la llamada de
+sistema adicional, y note que si multiples llamadas de sistema nuevas son
+añadidas en la misma ventana unida, su nueva llamada de sistema podría
+tener que ser ajustada para resolver conflictos.
+
+El archivo ``kernel/sys_ni.c`` provee una implementación fallback stub
+(rutina de respaldo) para cada llamada de sistema, retornando ``-ENOSYS``.
+Incluya su nueva llamada a sistema aquí también::
+
+ COND_SYSCALL(xyzzy);
+
+Su nueva funcionalidad del kernel, y la llamada de sistema que la controla,
+debería normalmente ser opcional, así que incluya una opción ``CONFIG``
+(tipicamente en ``init/Kconfig``) para ella. Como es usual para opciones
+``CONFIG`` nuevas:
+
+ - Incluya una descripción para la nueva funcionalidad y llamada al sistema
+ controlada por la opción.
+ - Haga la opción dependiendo de EXPERT si esta debe estar escondida de los
+ usuarios normales.
+ - Haga que cualquier nuevo archivo fuente que implemente la función
+ dependa de la opción CONFIG en el Makefile (e.g.
+ ``obj-$(CONFIG_XYZZY_SYSCALL) += xyzzy.o``).
+ - Revise dos veces que el kernel se siga compilando con la nueva opción
+ CONFIG apagada.
+
+Para resumir, necesita un commit que incluya:
+
+ - una opción ``CONFIG`` para la nueva función, normalmente en ``init/Kconfig``
+ - ``SYSCALL_DEFINEn(xyzzy, ...)`` para el punto de entrada
+ - El correspondiente prototipo en ``include/linux/syscalls.h``
+ - Una entrada genérica en ``include/uapi/asm-generic/unistd.h``
+ - fallback stub en ``kernel/sys_ni.c``
+
+
+Implementación de Llamada de Sistema x86
+----------------------------------------
+
+Para conectar su nueva llamada de sistema a plataformas x86, necesita
+actualizar las tablas maestras syscall. Asumiendo que su nueva llamada de
+sistema ni es especial de alguna manera (revise abajo), esto involucra una
+entrada "común" (para x86_64 y x86_32) en
+arch/x86/entry/syscalls/syscall_64.tbl::
+
+ 333 common xyzz sys_xyzzy
+
+y una entrada "i386" en ``arch/x86/entry/syscalls/syscall_32.tbl``::
+
+ 380 i386 xyzz sys_xyzzy
+
+De nuevo, estos número son propensos de ser cambiados si hay conflictos en
+la ventana de integración relevante.
+
+
+Compatibilidad de Llamadas de Sistema (Genérica)
+------------------------------------------------
+
+Para la mayoría de llamadas al sistema la misma implementación 64-bit puede
+ser invocada incluso cuando el programa de userspace es en si mismo 32-bit;
+incluso si los parámetros de la llamada de sistema incluyen un puntero
+explícito, esto es manipulado de forma transparente.
+
+Sin embargo, existe un par de situaciones donde se necesita una capa de
+compatibilidad para lidiar con las diferencias de tamaño entre 32-bit y
+64-bit.
+
+La primera es si el kernel 64-bit también soporta programas del userspace
+32-bit, y por lo tanto necesita analizar areas de memoria del (``__user``)
+que podrían tener valores tanto 32-bit como 64-bit. En particular esto se
+necesita siempre que un argumento de la llamada a sistema es:
+
+ - un puntero a un puntero
+ - un puntero a un struc conteniendo un puntero (por ejemplo
+ ``struct iovec __user *``)
+ - un puntero a un type entero de tamaño entero variable (``time_t``,
+ ``off_t``, ``long``, ...)
+ - un puntero a un struct conteniendo un type entero de tamaño variable.
+
+La segunda situación que requiere una capa de compatibilidad es cuando uno
+de los argumentos de la llamada a sistema tiene un argumento que es
+explícitamente 64-bit incluso sobre arquitectura 32-bit, por ejemplo
+``loff_t`` o ``__u64``. En este caso, el valor que llega a un kernel 64-bit
+desde una aplicación de 32-bit se separará en dos valores de 32-bit, los
+que luego necesitan ser reensamblados en la capa de compatibilidad.
+
+(Note que un argumento de una llamada a sistema que sea un puntero a un
+type explicitamente de 64-bit **no** necesita una capa de compatibilidad;
+por ejemplo, los argumentos de :manpage:`splice(2)`) del tipo
+``loff_t __user *`` no significan la necesidad de una llamada a sistema
+``compat_``.)
+
+La versión compatible de la llamada de sistema se llama
+``compat_sys_xyzzy()``, y se agrega con la macro
+``COMPAT_SYSCALL_DEFINEn``, de manera análoga a SYSCALL_DEFINEn. Esta
+versión de la implementación se ejecuta como parte de un kernel de 64-bit,
+pero espera recibir parametros con valores 32-bit y hace lo que tenga que
+hacer para tratar con ellos. (Típicamente, la versión ``compat_sys_``
+convierte los valores a versiones de 64 bits y llama a la versión ``sys_``
+o ambas llaman a una función de implementación interna común.)
+
+El punto de entrada compat también necesita un prototipo de función
+correspondiente, en ``include/linux/compat.h``, marcado como asmlinkage
+para igualar la forma en que las llamadas al sistema son invocadas::
+
+ asmlinkage long compat_sys_xyzzy(...);
+
+Si la nueva llamada al sistema involucra una estructura que que se dispone
+de forma distinta en sistema de 32-bit y 64-bit, digamos
+``struct xyzzy_args``, entonces el archivo de cabecera
+include/linux/compat.h también debería incluir una versión compatible de la
+estructura (``struct compat_xyzzy_args``) donde cada campo de tamaño
+variable tiene el tipo ``compat_`` apropiado que corresponde al tipo en
+``struct xyzzy_args``. La rutina ``compat_sys_xyzzy()`` puede entonces usar
+esta estructura ``compat_`` para analizar los argumentos de una invocación
+de 32-bit.
+
+Por ejemplo, si hay campos::
+
+ struct xyzzy_args {
+ const char __user *ptr;
+ __kernel_long_t varying_val;
+ u64 fixed_val;
+ /* ... */
+ };
+
+en struct xyzzy_args, entonces struct compat_xyzzy_args debe tener::
+
+ struct compat_xyzzy_args {
+ compat_uptr_t ptr;
+ compat_long_t varying_val;
+ u64 fixed_val;
+ /* ... */
+ };
+
+la lista genérica de llamadas al sistema también necesita ajustes para
+permitir la versión compat; la entrada en
+``include/uapi/asm-generic/unistd.h`` debería usar ``__SC_COMP`` en vez de
+``__SYSCALL``::
+
+ #define __NR_xyzzy 292
+ __SC_COMP(__NR_xyzzy, sys_xyzzy, compat_sys_xyzzy)
+
+Para resumir, necesita:
+
+ - una ``COMPAT_SYSCALL_DEFINEn(xyzzy, ...)`` para el punto de entrada de compat.
+ - el prototipo correspondiente en ``include/linux/compat.h``
+ - (en caso de ser necesario) un struct de mapeo de 32-bit en ``include/linux/compat.h``
+ - una instancia de ``__SC_COMP`` no ``__SYSCALL`` en ``include/uapi/asm-generic/unistd.h``
+
+Compatibilidad de Llamadas de Sistema (x86)
+-------------------------------------------
+
+Para conectar la arquitectura x86 de una llamada al sistema con una versión
+de compatibilidad, las entradas en las tablas de syscall deben ser
+ajustadas.
+
+Primero, la entrada en ``arch/x86/entry/syscalls/syscall_32.tbl`` recibe
+una columna extra para indicar que un programa del userspace de 32-bit
+corriendo en un kernel de 64-bit debe llegar al punto de entrada compat::
+
+ 380 i386 xyzzy sys_xyzzy __ia32_compat_sys_xyzzy
+
+Segundo, tienes que averiguar qué debería pasar para la versión x32 ABI de
+la nueva llamada al sistema. Aquí hay una elección: el diseño de los
+argumentos debería coincidir con la versión de 64-bit o la versión de
+32-bit.
+
+Si hay involucrado un puntero-a-puntero, la decisión es fácil: x32 es
+ILP32, por lo que el diseño debe coincidir con la versión 32-bit, y la
+entrada en ``arch/x86/entry/syscalls/syscall_64.tbl`` se divide para que
+progamas 32-bit lleguen al envoltorio de compatibilidad::
+
+ 333 64 xyzzy sys_xyzzy
+ ...
+ 555 x32 xyzzy __x32_compat_sys_xyzzy
+
+Si no hay punteros involucrados, entonces es preferible reutilizar el system
+call 64-bit para el x32 ABI (y consecuentemente la entrada en
+arch/x86/entry/syscalls/syscall_64.tbl no se cambia).
+
+En cualquier caso, debes revisar que lo tipos involucrados en su diseño de
+argumentos de hecho asigne exactamente de x32 (-mx32) a 32-bit(-m32) o
+equivalentes 64-bit (-m64).
+
+
+Llamadas de Sistema Retornando a Otros Lugares
+----------------------------------------------
+
+Para la mayoría de las llamadas al sistema, una vez que se la llamada al
+sistema se ha completado el programa de usuario continúa exactamente donde
+quedó -- en la siguiente instrucción, con el stack igual y la mayoría de
+los registros igual que antes de la llamada al sistema, y con el mismo
+espacio en la memoria virtual.
+
+Sin embargo, unas pocas llamadas al sistema hacen las cosas diferente.
+Estas podrían retornar a una ubicación distinta (``rt_sigreturn``) o
+cambiar el espacio de memoria (``fork``/``vfork``/``clone``) o incluso de
+arquitectura (``execve``/``execveat``) del programa.
+
+Para permitir esto, la implementación del kernel de la llamada al sistema
+podría necesitar guardar y restaurar registros adicionales al stak del
+kernel, brindandole control completo de donde y cómo la ejecución continúa
+después de la llamada a sistema.
+
+Esto es arch-specific, pero típicamente involucra definir puntos de entrada
+assembly que guardan/restauran registros adicionales e invocan el punto de
+entrada real de la llamada a sistema.
+
+Para x86_64, esto es implementado como un punto de entrada ``stub_xyzzy``
+en ``arch/x86/entry/entry_64.S``, y la entrada en la tabla syscall
+(``arch/x86/entry/syscalls/syscall_32.tbl``) es ajustada para calzar::
+
+ 333 common xyzzy stub_xyzzy
+
+El equivalente para programas 32-bit corriendo en un kernel 64-bit es
+normalmente llamado ``stub32_xyzzy`` e implementado en
+``arch/x86/entry/entry_64_compat.S``, con el correspondiente ajuste en la
+tabla syscall en ``arch/x86/syscalls/syscall_32.tbl``::
+
+ 380 i386 xyzzy sys_xyzzy stub32_xyzzy
+
+Si la llamada a sistema necesita una capa de compatibilidad (como en la
+sección anterior) entonces la versión ``stub32_`` necesita llamar a la
+versión ``compat_sys_`` de la llamada a sistema, en vez de la versión
+nativa de 64-bit. También, si la implementación de la versión x32 ABI no es
+comun con la versión x86_64, entonces su tabla syscall también necesitará
+invocar un stub que llame a la versión ``compat_sys_``
+
+Para completar, también es agradable configurar un mapeo de modo que el
+user-mode linux todavía funcione -- su tabla syscall referenciará
+stub_xyzzy, pero el UML construido no incluye una implementación
+``arch/x86/entry/entry_64.S``. Arreglar esto es tan simple como agregar un
+#define a ``arch/x86/um/sys_call_table_64.c``::
+
+ #define stub_xyzzy sys_xyzzy
+
+
+Otros detalles
+--------------
+
+La mayoría del kernel trata las llamadas a sistema de manera genérica, pero
+está la excepción ocasional que pueda requerir actualización para su
+llamada a sistema particular.
+
+El subsistema de auditoría es un caso especial; este incluye funciones
+(arch-specific) que clasifican algunos tipos especiales de llamadas al
+sistema -- específicamente file open (``open``/``openat``), program
+execution (``execve`` /``execveat``) o operaciones multiplexores de socket
+(``socketcall``). Si su nueva llamada de sistema es análoga a alguna de
+estas, entonces el sistema auditor debe ser actualizado.
+
+Más generalmente, si existe una llamada al sistema que sea análoga a su
+nueva llamada al sistema, entonces vale la pena hacer un grep a todo el
+kernel de la llamada a sistema existente, para revisar que no exista otro
+caso especial.
+
+
+Testing
+-------
+
+Una nueva llamada al sistema debe obviamente ser probada; también es útil
+proveer a los revisores con una demostración de cómo los programas del
+userspace usarán la llamada al sistema. Una buena forma de combinar estos
+objetivos es incluir un simple programa self-test en un nuevo directorio
+bajo ``tools/testing/selftests/``.
+
+Para una nueva llamada al sistema, obviamente no habrá una función
+envoltorio libc por lo que el test necesitará ser invocado usando
+``syscall()``; también, si la llamada al sistema involucra una nueva
+estructura userspace-visible, el encabezado correspondiente necesitará ser
+instalado para compilar el test.
+
+Asegure que selftest corra satisfactoriamente en todas las arquitecturas
+soportadas. Por ejemplo, revise si funciona cuando es compilado como un
+x86_64 (-m64), x86_32 (-m32) y x32 (-mx32) programa ABI.
+
+Para pruebas más amplias y exhautivas de la nueva funcionalidad, también
+debería considerar agregar tests al Linus Test Project, o al proyecto
+xfstests para cambios filesystem-related
+
+ - https://linux-test-project.github.io/
+ - git://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git
+
+
+Man Page
+--------
+
+Todas las llamada al sistema nueva deben venir con un man page completo,
+idealmente usando groff markup, pero texto plano también funciona. Si se
+usa groff, es útil incluir una versión ASCII pre-renderizada del man-page
+en el cover del email para el patchset, para la conveniencia de los
+revisores.
+
+El man page debe ser cc'do a linux-man@vger.kernel.org
+Para más detalles, revise https://www.kernel.org/doc/man-pages/patches.html
+
+
+No invoque las llamadas de sistemas en el kernel
+------------------------------------------------
+
+Las llamadas al sistema son, cómo se declaró más arriba, puntos de
+interacción entre el userspace y el kernel. Por lo tanto, las funciones de
+llamada al sistema como ``sys_xyzzy()`` o ``compat_sys_xyzzy()`` deberían
+ser llamadas sólo desde el userspace vía la tabla de syscall, pero no de
+otro lugar en el kernel. Si la funcionalidad syscall es útil para ser usada
+dentro del kernel, necesita ser compartida entre syscalls nuevas o
+antiguas, o necesita ser compartida entre una syscall y su variante de
+compatibilidad, esta debería ser implementada mediante una función "helper"
+(como ``ksys_xyzzy()``). Esta función del kernel puede ahora ser llamada
+dentro del syscall stub (``sys_xyzzy()``), la syscall stub de
+compatibilidad (``compat_sys_xyzzy()``), y/o otro código del kernel.
+
+Al menos en 64-bit x86, será un requerimiento duro desde la v4.17 en
+adelante no invocar funciones de llamada al sistema (system call) en el
+kernel. Este usa una convención de llamada diferente para llamadas al
+sistema donde ``struct pt_regs`` es decodificado on-the-fly en un
+envoltorio syscall que luego entrega el procesamiento al syscall real. Esto
+significa que sólo aquellos parámetros que son realmente necesarios para
+una syscall específica son pasados durante la entrada del syscall, en vez
+de llenar en seis registros de CPU con contenido random del userspace todo
+el tiempo (los cuales podrían causar serios problemas bajando la cadena de
+llamadas).
+
+Más aún, reglas sobre cómo se debería acceder a la data pueden diferir
+entre la data del kernel y la data de usuario. Esta es otra razón por la
+cual llamar a ``sys_xyzzy()`` es generalmente una mala idea.
+
+Excepciones a esta regla están permitidas solamente en overrides
+específicos de arquitectura, envoltorios de compatibilidad específicos de
+arquitectura, u otro código en arch/.
+
+
+Referencias y fuentes
+---------------------
+
+ - Artículo LWN de Michael Kerrisk sobre el uso de argumentos flags en llamadas al
+ sistema:
+ https://lwn.net/Articles/585415/
+ - Artículo LWN de Michael Kerrisk sobre cómo manejar flags desconocidos en una
+ llamada al sistema: https://lwn.net/Articles/588444/
+ - Artículo LWN de Jake Edge describiendo restricciones en argumentos en
+ 64-bit system call: https://lwn.net/Articles/311630/
+ - Par de artículos LWN de David Drysdale que describen la ruta de implementación
+ de llamadas al sistema en detalle para v3.14:
+
+ - https://lwn.net/Articles/604287/
+ - https://lwn.net/Articles/604515/
+
+ - Requerimientos arquitectura-específicos para llamadas al sistema son discutidos en el
+ :manpage:`syscall(2)` man-page:
+ http://man7.org/linux/man-pages/man2/syscall.2.html#NOTES
+ - Recopilación de emails de Linus Torvalds discutiendo problemas con ``ioctl()``:
+ https://yarchive.net/comp/linux/ioctl.html
+ - "How to not invent kernel interfaces", Arnd Bergmann,
+ https://www.ukuug.org/events/linux2007/2007/papers/Bergmann.pdf
+ - Artículo LWN de Michael Kerrisk sobre evitar nuevos usos de CAP_SYS_ADMIN:
+ https://lwn.net/Articles/486306/
+ - Recomendaciones de Andrew Morton que toda la información relacionada a una nueva
+ llamada al sistema debe venir en el mismo hilo de correos:
+ https://lore.kernel.org/r/20140724144747.3041b208832bbdf9fbce5d96@linux-foundation.org
+ - Recomendaciones de Michael Kerrisk que una nueva llamada al sistema debe venir
+ con un man-page: https://lore.kernel.org/r/CAKgNAkgMA39AfoSoA5Pe1r9N+ZzfYQNvNPvcRN7tOvRb8+v06Q@mail.gmail.com
+ - Sugerencias de Thomas Gleixner que conexiones x86 deben ir en commits
+ separados: https://lore.kernel.org/r/alpine.DEB.2.11.1411191249560.3909@nanos
+ - Sugerencias de Greg Kroah-Hartman que es bueno para las nueva llamadas al sistema
+ que vengan con man-page y selftest: https://lore.kernel.org/r/20140320025530.GA25469@kroah.com
+ - Discusión de Michael Kerrisk de nuevas system call vs. extensiones :manpage:`prctl(2)`:
+ https://lore.kernel.org/r/CAHO5Pa3F2MjfTtfNxa8LbnkeeU8=YJ+9tDqxZpw7Gz59E-4AUg@mail.gmail.com
+ - Sugerencias de Ingo Molnar que llamadas al sistema que involucran múltiples
+ argumentos deben encapsular estos argumentos en una estructura, la cual incluye
+ un campo de tamaño para futura extensibilidad: https://lore.kernel.org/r/20150730083831.GA22182@gmail.com
+ - Enumerando rarezas por la (re-)utilización de O_* numbering space flags:
+
+ - commit 75069f2b5bfb ("vfs: renumber FMODE_NONOTIFY and add to uniqueness
+ check")
+ - commit 12ed2e36c98a ("fanotify: FMODE_NONOTIFY and __O_SYNC in sparc
+ conflict")
+ - commit bb458c644a59 ("Safer ABI for O_TMPFILE")
+
+ - Discusión de Matthew Wilcox sobre las restricciones en argumentos 64-bit:
+ https://lore.kernel.org/r/20081212152929.GM26095@parisc-linux.org
+ - Recomendaciones de Greg Kroah-Hartman sobre flags desconocidos deben ser
+ vigilados: https://lore.kernel.org/r/20140717193330.GB4703@kroah.com
+ - Recomendaciones de Linus Torvalds que las llamadas al sistema x32 deben favorecer
+ compatibilidad con versiones 64-bit sobre versiones 32-bit:
+ https://lore.kernel.org/r/CA+55aFxfmwfB7jbbrXxa=K7VBYPfAvmu3XOkGrLbB1UFjX1+Ew@mail.gmail.com
diff --git a/Documentation/translations/sp_SP/process/code-of-conduct.rst b/Documentation/translations/sp_SP/process/code-of-conduct.rst
new file mode 100644
index 000000000000..adc6c770cc37
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/code-of-conduct.rst
@@ -0,0 +1,97 @@
+.. include:: ../disclaimer-sp.rst
+
+:Original: :ref:`Documentation/process/code-of-conduct.rst <code_of_conduct>`
+:Translator: Contributor Covenant and Carlos Bilbao <carlos.bilbao@amd.com>
+
+.. _sp_code_of_conduct:
+
+Código de Conducta para Contribuyentes
++++++++++++++++++++++++++++++++++++++++
+
+Nuestro Compromiso
+==================
+
+Nosotros, como miembros, contribuyentes y administradores nos comprometemos
+a hacer de la participación en nuestra comunidad una experiencia libre de
+acoso para todo el mundo, independientemente de la edad, dimensión corporal,
+minusvalía visible o invisible, etnicidad, características sexuales,
+identidad y expresión de género, nivel de experiencia, educación, nivel
+socio-económico, nacionalidad, apariencia personal, raza, religión, o
+identidad u orientación sexual. Nos comprometemos a actuar e interactuar de
+maneras que contribuyan a una comunidad abierta, acogedora, diversa,
+inclusiva y sana.
+
+Nuestros Estándares
+===================
+
+Ejemplos de comportamiento que contribuyen a crear un ambiente positivo
+para nuestra comunidad:
+
+* Demostrar empatía y amabilidad ante otras personas
+* Respeto a diferentes opiniones, puntos de vista y experiencias
+* Dar y aceptar adecuadamente retroalimentación constructiva
+* Aceptar la responsabilidad y disculparse ante quienes se vean afectados
+ por nuestros errores, aprendiendo de la experiencia
+* Centrarse en lo que sea mejor no sólo para nosotros como individuos, sino
+ para la comunidad en general
+
+
+Ejemplos de comportamiento inaceptable:
+
+* El uso de lenguaje o imágenes sexualizadas, y aproximaciones o
+ atenciones sexuales de cualquier tipo
+* Comentarios despectivos (trolling), insultantes o derogatorios, y ataques
+ personales o políticos
+* El acoso en público o privado
+* Publicar información privada de otras personas, tales como direcciones
+ físicas o de correo
+ electrónico, sin su permiso explícito
+* Otras conductas que puedan ser razonablemente consideradas como
+ inapropiadas en un entorno profesional
+
+
+Aplicación de las responsabilidades
+===================================
+
+Los administradores de la comunidad son responsables de aclarar y hacer
+cumplir nuestros estándares de comportamiento aceptable y tomarán acciones
+apropiadas y correctivas de forma justa en respuesta a cualquier
+comportamiento que consideren inapropiado, amenazante, ofensivo o dañino.
+
+Los administradores de la comunidad tendrán el derecho y la responsabilidad
+de eliminar, editar o rechazar comentarios, commits, código, ediciones de
+páginas de wiki, issues y otras contribuciones que no se alineen con este
+Código de Conducta, y comunicarán las razones para sus decisiones de
+moderación cuando sea apropiado.
+
+Alcance
+=======
+
+Este código de conducta aplica tanto a espacios del proyecto como a
+espacios públicos donde un individuo esté en representación del proyecto o
+comunidad. Ejemplos de esto incluyen el uso de la cuenta oficial de correo
+electrónico, publicaciones a través de las redes sociales oficiales, o
+presentaciones con personas designadas en eventos en línea o no.
+
+Aplicación
+==========
+
+Instancias de comportamiento abusivo, acosador o inaceptable de otro modo
+podrán ser reportadas contactando el Code of Conduct Commitee a través de
+<conduct@kernel.org>. Todas las quejas serán evaluadas e investigadas de
+una manera puntual y justa. El Code of Condut Commitee está obligados a
+respetar la privacidad y la seguridad de quienes reporten incidentes.
+Detalles de políticas y aplicación en particular, serán incluidos por
+separado.
+
+Atribución
+==========
+
+Este Código de Conducta es una adaptación del Contributor Covenant, versión
+1.4, disponible en https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+Interpretación
+==============
+
+Consulte el documento :ref:`code_of_conduct_interpretation` para ver cómo
+interpretará la comunidad del kernel Linux este documento.
diff --git a/Documentation/translations/sp_SP/process/coding-style.rst b/Documentation/translations/sp_SP/process/coding-style.rst
new file mode 100644
index 000000000000..a0261ba5b902
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/coding-style.rst
@@ -0,0 +1,1315 @@
+.. include:: ../disclaimer-sp.rst
+
+:Original: :ref:`Documentation/process/coding-style.rst <submittingpatches>`
+:Translator: Carlos Bilbao <carlos.bilbao@amd.com>
+
+.. _sp_codingstyle:
+
+Estilo en el código del kernel Linux
+=====================================
+
+Este es un breve documento que describe el estilo preferido en el código
+del kernel Linux. El estilo de código es muy personal y no **forzaré** mi
+puntos de vista sobre nadie, pero esto vale para todo lo que tengo que
+mantener, y preferiría que para la mayoría de otras cosas también. Por
+favor, por lo menos considere los argumentos expuestos aquí.
+
+En primer lugar, sugeriría imprimir una copia de los estándares de código
+GNU, y NO leerlo. Quémelos, es un gran gesto simbólico.
+
+De todos modos, aquí va:
+
+
+1) Sangría
+-----------
+
+Las tabulaciones tienen 8 caracteres y, por lo tanto, las sangrías también
+tienen 8 caracteres. Hay movimientos heréticos que intentan hacer sangría
+de 4 (¡o incluso 2!) caracteres de longitud, y eso es similar a tratar de
+definir el valor de PI como 3.
+
+Justificación: La idea detrás de la sangría es definir claramente dónde
+comienza y termina un bloque de control. Especialmente, cuando ha estado
+buscando en su pantalla durante 20 horas seguidas, le resultará mucho más
+fácil ver cómo funciona la sangría si tiene sangrías grandes.
+
+Bueno, algunas personas dirán que tener sangrías de 8 caracteres hace que
+el código se mueva demasiado a la derecha y dificulta la lectura en una
+pantalla de terminal de 80 caracteres. La respuesta a eso es que si
+necesita más de 3 niveles de sangría, está en apuros de todos modos y
+debería arreglar su programa.
+
+En resumen, las sangrías de 8 caracteres facilitan la lectura y tienen la
+ventaja añadida de advertirle cuando está anidando sus funciones demasiado
+profundo. Preste atención a esa advertencia.
+
+La forma preferida de facilitar múltiples niveles de sangría en una
+declaración de switch es para alinear el ``switch`` y sus etiquetas
+``case`` subordinadas en la misma columna, en lugar de hacer ``doble
+sangría`` (``double-indenting``) en etiquetas ``case``. Por ejemplo:
+
+.. code-block:: c
+
+ switch (suffix) {
+ case 'G':
+ case 'g':
+ mem <<= 30;
+ break;
+ case 'M':
+ case 'm':
+ mem <<= 20;
+ break;
+ case 'K':
+ case 'k':
+ mem <<= 10;
+ fallthrough;
+ default:
+ break;
+ }
+
+No ponga varias declaraciones en una sola línea a menos que tenga algo que
+ocultar:
+
+.. code-block:: c
+
+ if (condición) haz_esto;
+ haz_otra_cosa;
+
+No use comas para evitar el uso de llaves:
+
+.. code-block:: c
+
+ if (condición)
+ haz_esto(), haz_eso();
+
+Siempre use llaves para múltiples declaraciones:
+
+.. code-block:: c
+
+ if (condición) {
+ haz_esto();
+ haz_eso();
+ }
+
+Tampoco ponga varias asignaciones en una sola línea. El estilo de código
+del kernel es súper simple. Evite las expresiones engañosas.
+
+
+Aparte de los comentarios, la documentación y excepto en Kconfig, los
+espacios nunca se utilizan para la sangría, y el ejemplo anterior se rompe
+deliberadamente.
+
+Consiga un editor decente y no deje espacios en blanco al final de las
+líneas.
+
+2) Rompiendo líneas y strings largos
+------------------------------------
+
+El estilo de código tiene todo que ver con la legibilidad y la
+mantenibilidad usando herramientas disponibles comúnmente.
+
+El límite preferido en la longitud de una sola línea es de 80 columnas.
+
+Las declaraciones de más de 80 columnas deben dividirse en partes, a menos
+que exceder las 80 columnas aumente significativamente la legibilidad y no
+oculte información.
+
+Los descendientes siempre son sustancialmente más cortos que el padre y
+se colocan sustancialmente a la derecha. Un estilo muy usado es alinear
+descendientes a un paréntesis de función abierto.
+
+Estas mismas reglas se aplican a los encabezados de funciones con una larga
+lista de argumentos.
+
+Sin embargo, nunca rompa los strings visibles para el usuario, como los
+mensajes printk, porque eso rompe la capacidad de grep a estos.
+
+
+3) Colocación de llaves y espacios
+----------------------------------
+
+El otro problema que siempre surge en el estilo C es la colocación de
+llaves. A diferencia del tamaño de la sangría, existen pocas razones
+técnicas para elegir una estrategia de ubicación sobre la otra, pero la
+forma preferida, como mostraron los profetas Kernighan y Ritchie, es poner
+la llave de apertura en la línea, y colocar la llave de cierre primero,
+así:
+
+.. code-block:: c
+
+ if (x es verdad) {
+ hacemos y
+ }
+
+Esto se aplica a todos los bloques de declaraciones que no son funciones
+(if, switch, for, while, do). Por ejemplo:
+
+.. code-block:: c
+
+ switch (action) {
+ case KOBJ_ADD:
+ return "add";
+ case KOBJ_REMOVE:
+ return "remove";
+ case KOBJ_CHANGE:
+ return "change";
+ default:
+ return NULL;
+ }
+
+Sin embargo, hay un caso especial, a saber, las funciones: tienen la llave
+de apertura al comienzo de la siguiente línea, así:
+
+.. code-block:: c
+
+ int funcion(int x)
+ {
+ cuerpo de la función
+ }
+
+Gente hereje de todo el mundo ha afirmado que esta inconsistencia es...
+bueno... inconsistente, pero todas las personas sensatas saben que
+(a) K&R tienen **razón** y (b) K&R tienen razón. Además, las funciones son
+especiales de todos modos (no puede anidarlas en C).
+
+Tenga en cuenta que la llave de cierre está vacía en su línea propia,
+**excepto** en los casos en que es seguida por una continuación de la misma
+declaración, es decir, un ``while`` en una sentencia do o un ``else`` en
+una sentencia if, como en:
+
+.. code-block:: c
+
+ do {
+ cuerpo del bucle do
+ } while (condition);
+
+y
+
+.. code-block:: c
+
+ if (x == y) {
+ ..
+ } else if (x > y) {
+ ...
+ } else {
+ ....
+ }
+
+Justificación: K&R.
+
+Además, tenga en cuenta que esta colocación de llaves también minimiza el
+número de líneas vacías (o casi vacías), sin pérdida de legibilidad. Así,
+como el suministro de nuevas líneas en su pantalla no es un recurso
+renovable (piense en pantallas de terminal de 25 líneas), tienes más líneas
+vacías para poner comentarios.
+
+No use llaves innecesariamente donde una sola declaración sea suficiente.
+
+.. code-block:: c
+
+ if (condition)
+ accion();
+
+y
+
+.. code-block:: none
+
+ if (condición)
+ haz_esto();
+ else
+ haz_eso();
+
+Esto no aplica si solo una rama de una declaración condicional es una sola
+declaración; en este último caso utilice llaves en ambas ramas:
+
+.. code-block:: c
+
+ if (condición) {
+ haz_esto();
+ haz_eso();
+ } else {
+ en_otro_caso();
+ }
+
+Además, use llaves cuando un bucle contenga más de una declaración simple:
+
+.. code-block:: c
+
+ while (condición) {
+ if (test)
+ haz_eso();
+ }
+
+3.1) Espacios
+*************
+
+El estilo del kernel Linux para el uso de espacios depende (principalmente)
+del uso de función versus uso de palabra clave. Utilice un espacio después
+de (la mayoría de) las palabras clave. Las excepciones notables son sizeof,
+typeof, alignof y __attribute__, que parecen algo así como funciones (y
+generalmente se usan con paréntesis en Linux, aunque no son requeridos en
+el idioma, como en: ``sizeof info`` después de que ``struct fileinfo info;``
+se declare).
+
+Así que use un espacio después de estas palabras clave::
+
+ if, switch, case, for, do, while
+
+pero no con sizeof, typeof, alignof, o __attribute__. Por ejemplo,
+
+.. code-block:: c
+
+
+ s = sizeof(struct file);
+
+No agregue espacios alrededor (dentro) de expresiones entre paréntesis.
+Este ejemplo es **malo**:
+
+.. code-block:: c
+
+
+ s = sizeof( struct file );
+
+Al declarar datos de puntero o una función que devuelve un tipo de puntero,
+el uso preferido de ``*`` es adyacente al nombre del dato o nombre de la
+función y no junto al nombre del tipo. Ejemplos:
+
+.. code-block:: c
+
+
+ char *linux_banner;
+ unsigned long long memparse(char *ptr, char **retptr);
+ char *match_strdup(substring_t *s);
+
+Use un espacio alrededor (a cada lado de) la mayoría de los operadores
+binarios y ternarios, como cualquiera de estos::
+
+ = + - < > * / % | & ^ <= >= == != ? :
+
+pero sin espacio después de los operadores unarios::
+
+ & * + - ~ ! sizeof typeof alignof __attribute__ defined
+
+sin espacio antes de los operadores unarios de incremento y decremento del
+sufijo::
+
+ ++ --
+
+y sin espacio alrededor de los operadores de miembros de estructura ``.`` y
+``->``.
+
+No deje espacios en blanco al final de las líneas. Algunos editores con
+``inteligente`` sangría insertarán espacios en blanco al comienzo de las
+nuevas líneas como sea apropiado, para que pueda comenzar a escribir la
+siguiente línea de código de inmediato. Sin embargo, algunos de estos
+editores no eliminan los espacios en blanco si finalmente no termina
+poniendo una línea de código allí, como si dejara una línea en blanco. Como
+resultado, termina con líneas que contienen espacios en blanco al final.
+
+Git le advertirá sobre los parches que introducen espacios en blanco al
+final y puede, opcionalmente, eliminar los espacios en blanco finales por
+usted; sin embargo, si se aplica una serie de parches, esto puede hacer que
+los parches posteriores de la serie fallen al cambiar sus líneas de
+contexto.
+
+
+4) Nomenclatura
+---------------
+
+C es un lenguaje espartano, y sus convenciones de nomenclatura deberían
+seguir su ejemplo. A diferencia de los programadores de Modula-2 y Pascal,
+los programadores de C no usan nombres cuquis como
+EstaVariableEsUnContadorTemporal. Un programador de C lo llamaría
+variable ``tmp``, que es mucho más fácil de escribir, y no es mas difícil
+de comprender.
+
+SIN EMBARGO, mientras que los nombres de mayúsculas y minúsculas están mal
+vistos, los nombres descriptivos para las variables globales son
+imprescindibles. Llamar a una función global ``foo`` es un delito.
+
+Una variable GLOBAL (para usar solo si **realmente** las necesita) necesita
+tener un nombre descriptivo, al igual que las funciones globales. Si tiene
+una función que cuenta el número de usuarios activos, debe llamar a esta
+``contar_usuarios_activos()`` o similar, **no** debe llamarlo ``cntusr()``.
+
+Codificar el tipo de una función en el nombre (lo llamado notación húngara)
+es estúpido: el compilador conoce los tipos de todos modos y puede
+verificar estos, y solo confunde al programador.
+
+Los nombres de las variables LOCALES deben ser breves y directos. Si usted
+tiene algún contador aleatorio de tipo entero, probablemente debería
+llamarse ``i``. Llamarlo ``loop_counter`` no es productivo, si no hay
+posibilidad de ser mal entendido. De manera similar, ``tmp`` puede ser casi
+cualquier tipo de variable que se utiliza para contener un valor temporal.
+
+Si tiene miedo de mezclar los nombres de las variables locales, tiene otro
+problema, que se denomina síndrome de
+función-crecimiento-desequilibrio-de-hormona. Vea el capítulo 6 (Funciones).
+
+Para nombres de símbolos y documentación, evite introducir nuevos usos de
+'master / slave' (maestro / esclavo) (o 'slave' independientemente de
+'master') y 'lista negra / lista blanca' (backlist / whitelist).
+
+Los reemplazos recomendados para 'maestro / esclavo' son:
+ '{primary,main} / {secondary,replica,subordinate}'
+ '{initiator,requester} / {target,responder}'
+ '{controller,host} / {device,worker,proxy}'
+ 'leader / follower'
+ 'director / performer'
+
+Los reemplazos recomendados para 'backlist / whitelist' son:
+ 'denylist / allowlist'
+ 'blocklist / passlist'
+
+Las excepciones para la introducción de nuevos usos son mantener en espacio
+de usuario una ABI/API, o al actualizar la especificación del código de un
+hardware o protocolo existente (a partir de 2020) que requiere esos
+términos. Para nuevas especificaciones, traduzca el uso de la terminología
+de la especificación al estándar de código del kernel donde sea posible.
+
+5) Typedefs
+-----------
+
+Por favor no use cosas como ``vps_t``.
+Es un **error** usar typedef para estructuras y punteros. cuando ve un
+
+.. code-block:: c
+
+
+ vps_t a;
+
+en el código fuente, ¿qué significa?
+En cambio, si dice
+
+.. code-block:: c
+
+ struct virtual_container *a;
+
+puede decir qué es ``a`` en realidad.
+
+Mucha gente piensa que los typedefs ``ayudan a la legibilidad``. No. Son
+útiles solamente para:
+
+ (a) objetos totalmente opacos (donde el typedef se usa activamente para
+ **ocultar** cuál es el objeto).
+
+ Ejemplo: ``pte_t`` etc. objetos opacos a los que solo puede acceder
+ usando las funciones de acceso adecuadas.
+
+ .. note::
+
+ La opacidad y las ``funciones de acceso`` no son buenas por sí
+ mismas. La razón por la que los tenemos para cosas como pte_t, etc.
+ es que hay real y absolutamente **cero** información accesible de
+ forma portátil allí.
+
+ (b) Tipos enteros claros, donde la abstracción **ayuda** a evitar
+ confusiones, ya sea ``int`` o ``long``.
+
+ u8/u16/u32 son definiciones tipográficas perfectamente correctas
+ aunque encajan en la categoría (d) mejor que aquí.
+
+ .. note::
+
+ De nuevo - debe haber una **razón** para esto. si algo es
+ ``unsigned long``, entonces no hay razón para hacerlo
+
+ typedef unsigned long mis_flags_t;
+
+ pero si hay una razón clara de por qué bajo ciertas circunstancias
+ podría ser un ``unsigned int`` y bajo otras configuraciones podría
+ ser ``unsigned long``, entonces, sin duda, adelante y use un typedef.
+
+ (c) cuando lo use para crear literalmente un tipo **nuevo** para
+ comprobación de tipos.
+
+ (d) Nuevos tipos que son idénticos a los tipos estándar C99, en ciertas
+ circunstancias excepcionales.
+
+ Aunque sólo costaría un corto período de tiempo para los ojos y
+ cerebro para acostumbrarse a los tipos estándar como ``uint32_t``,
+ algunas personas se oponen a su uso de todos modos.
+
+ Por lo tanto, los tipos ``u8/u16/u32/u64`` específicos de Linux y sus
+ equivalentes con signo, que son idénticos a los tipos estándar son
+ permitidos, aunque no son obligatorios en el nuevo código de su
+ elección.
+
+ Al editar código existente que ya usa uno u otro conjunto de tipos,
+ debe ajustarse a las opciones existentes en ese código.
+
+ (e) Tipos seguros para usar en el espacio de usuario.
+
+ En ciertas estructuras que son visibles para el espacio de usuario, no
+ podemos requerir tipos C99 y o utilizat el ``u32`` anterior. Por lo
+ tanto, usamos __u32 y tipos similares en todas las estructuras que se
+ comparten con espacio de usuario.
+
+Tal vez también haya otros casos, pero la regla básicamente debería ser
+NUNCA JAMÁS use un typedef a menos que pueda coincidir claramente con una
+de estas reglas.
+
+En general, un puntero o una estructura que tiene elementos que pueden
+ser razonablemente accedidos directamente, **nunca** deben ser un typedef.
+
+6) Funciones
+------------
+
+Las funciones deben ser cortas y dulces, y hacer una sola cosa. Deberían
+caber en una o dos pantallas de texto (el tamaño de pantalla ISO/ANSI es
+80x24, como todos sabemos), y hacer una cosa y hacerla bien.
+
+La longitud máxima de una función es inversamente proporcional a la
+complejidad y el nivel de sangría de esa función. Entonces, si tiene una
+función conceptualmente simple que es solo una larga (pero simple)
+declaración de case, donde tiene que hacer un montón de pequeñas cosas para
+un montón de diferentes casos, está bien tener una función más larga.
+
+Sin embargo, si tiene una función compleja y sospecha que un estudiante de
+primer año de secundaria menos que dotado podría no comprender de qué se
+trata la función, debe adherirse a los límites máximos tanto más de
+cerca. Use funciones auxiliares con nombres descriptivos (puede pedirle al
+compilador que los alinee si cree que es crítico para el rendimiento, y
+probablemente lo hará mejor de lo que usted hubiera hecho).
+
+Otra medida de la función es el número de variables locales. Estas no deben
+exceder de 5 a 10, o está haciendo algo mal. Piense de nuevo en la función
+y divida en partes más pequeñas. Un cerebro humano puede generalmente
+realiza un seguimiento de aproximadamente 7 cosas diferentes, cualquier
+elemento más y se confunde. Usted sabe que es brillante, pero tal vez le
+gustaría entender lo que hizo dentro de 2 semanas.
+
+En los archivos fuente, separe las funciones con una línea en blanco. Si la
+función es exportada, la macro **EXPORT** debería ponerse inmediatamente
+después de la función de cierre de línea de llave. Por ejemplo:
+
+.. code-block:: c
+
+ int sistema_corriendo(void)
+ {
+ return estado_sistema == SISTEMA_CORRIENDO;
+ }
+ EXPORT_SYMBOL(sistema_corriendo);
+
+6.1) Prototipos de funciones
+****************************
+
+En los prototipos de funciones, incluya nombres de parámetros con sus tipos
+de datos. Aunque esto no es requerido por el lenguaje C, se prefiere en
+Linux porque es una forma sencilla de añadir información valiosa para el
+lector.
+
+No utilice la palabra clave ``extern`` con declaraciones de función ya que
+esto hace las líneas más largas y no es estrictamente necesario.
+
+Al escribir prototipos de funciones, mantenga el `orden de los elementos regular
+<https://lore.kernel.org/mm-commits/CAHk-=wiOCLRny5aifWNhr621kYrJwhfURsa0vFPeUEm8mF0ufg@mail.gmail.com/>`_.
+Por ejemplo, usando este ejemplo de declaración de función::
+
+ __init void * __must_check action(enum magic value, size_t size, u8 count,
+ char *fmt, ...) __printf(4, 5) __malloc;
+
+El orden preferido de elementos para un prototipo de función es:
+
+- clase de almacenamiento (a continuación, ``static __always_inline``,
+ teniendo en cuenta que ``__always_inline`` es técnicamente un atributo
+ pero se trata como ``inline``)
+- atributos de clase de almacenamiento (aquí, ``__init`` -- es decir,
+ declaraciones de sección, pero también cosas como ``__cold``)
+- tipo de retorno (aquí, ``void *``)
+- atributos de tipo de retorno (aquí, ``__must_check``)
+- nombre de la función (aquí, ``action``)
+- parámetros de la función (aquí, ``(enum magic value, size_t size, u8 count, char *fmt, ...)``,
+ teniendo en cuenta que los nombres de los parámetros siempre deben
+ incluirse)
+- atributos de parámetros de función (aquí, ``__printf(4, 5)``)
+- atributos de comportamiento de la función (aquí, ``__malloc``)
+
+Tenga en cuenta que para una **definición** de función (es decir, el cuerpo
+real de la función), el compilador no permite atributos de parámetros de
+función después de parámetros de la función. En estos casos, deberán ir
+tras los atributos de clase (por ejemplo, tenga en cuenta el cambio de
+posición de ``__printf(4, 5)`` a continuación, en comparación con el
+ejemplo de **declaración** anterior)::
+
+ static __always_inline __init __printf(4, 5) void * __must_check action(enum magic value,
+ size_t size, u8 count, char *fmt, ...) __malloc
+ {
+ ...
+ }
+
+7) Salida centralizada de funciones
+-----------------------------------
+
+Aunque desaprobado por algunas personas, el equivalente de la instrucción
+goto es utilizado con frecuencia por los compiladores, en forma de
+instrucción de salto incondicional.
+
+La declaración goto es útil cuando una función sale desde múltiples
+ubicaciones y se deben realizar algunos trabajos comunes, como la limpieza.
+Si no se necesita limpieza, entonces simplemente haga return directamente.
+
+Elija nombres de etiquetas que digan qué hace el goto o por qué existe el
+goto. Un ejemplo de un buen nombre podría ser ``out_free_buffer:``
+(``salida_liberar_buffer``) si al irse libera ``buffer``. Evite usar
+nombres GW-BASIC como ``err1:`` y ``err2:``, ya que tendría que volver a
+numerarlos si alguna vez agrega o elimina rutas de salida, y hacen que sea
+difícil de verificar que sean correctos, de todos modos.
+
+La razón para usar gotos es:
+
+- Las declaraciones incondicionales son más fáciles de entender y seguir.
+- se reduce el anidamiento
+- errores al no actualizar los puntos de salida individuales al hacer
+ modificaciones son evitados
+- ahorra el trabajo del compilador de optimizar código redundante ;)
+
+.. code-block:: c
+
+ int fun(int a)
+ {
+ int result = 0;
+ char *buffer;
+
+ buffer = kmalloc(SIZE, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ if (condition1) {
+ while (loop1) {
+ ...
+ }
+ result = 1;
+ goto out_free_buffer;
+ }
+ ...
+ out_free_buffer:
+ kfree(buffer);
+ return result;
+ }
+
+Un tipo común de error a tener en cuenta es "un error de error" que es algo
+así:
+
+.. code-block:: c
+
+ err:
+ kfree(foo->bar);
+ kfree(foo);
+ return ret;
+
+El error en este código es que en algunas rutas de salida, ``foo`` es NULL.
+Normalmente la solución para esto es dividirlo en dos etiquetas de error
+``err_free_bar:`` y ``err_free_foo:``:
+
+.. code-block:: c
+
+ err_free_bar:
+ kfree(foo->bar);
+ err_free_foo:
+ kfree(foo);
+ return ret;
+
+Idealmente, debería simular errores para probar todas las rutas de salida.
+
+
+8) Comentarios
+--------------
+
+Los comentarios son buenos, pero también existe el peligro de comentar
+demasiado. NUNCA trate de explicar CÓMO funciona su código en un
+comentario: es mucho mejor escribir el código para que el
+**funcionamiento** sea obvio y es una pérdida de tiempo explicar código mal
+escrito.
+
+Generalmente, desea que sus comentarios digan QUÉ hace su código, no CÓMO.
+Además, trate de evitar poner comentarios dentro del cuerpo de una función:
+si la función es tan compleja que necesita comentar por separado partes de
+esta, probablemente debería volver al capítulo 6 una temporada. Puede
+hacer pequeños comentarios para notar o advertir sobre algo particularmente
+inteligente (o feo), pero trate de evitar el exceso. En su lugar, ponga los
+comentarios al principio de la función, diga a la gente lo que hace y
+posiblemente POR QUÉ hace esto.
+
+Al comentar las funciones de la API del kernel, utilice el formato
+kernel-doc. Consulte los archivos en :ref:`Documentation/doc-guide/ <doc_guide>`
+y ``scripts/kernel-doc`` para más detalles.
+
+El estilo preferido para comentarios largos (de varias líneas) es:
+
+.. code-block:: c
+
+ /*
+ * Este es el estilo preferido para comentarios
+ * multilínea en el código fuente del kernel Linux.
+ * Por favor, utilícelo constantemente.
+ *
+ * Descripción: Una columna de asteriscos en el lado izquierdo,
+ * con líneas iniciales y finales casi en blanco.
+ */
+
+Para archivos en net/ y drivers/net/, el estilo preferido para comentarios
+largos (multi-linea) es un poco diferente.
+
+.. code-block:: c
+
+ /* El estilo de comentario preferido para archivos en net/ y drivers/net
+ * se asemeja a esto.
+ *
+ * Es casi lo mismo que el estilo de comentario generalmente preferido,
+ * pero no hay una línea inicial casi en blanco.
+ */
+
+También es importante comentar los datos, ya sean tipos básicos o
+derivados. Para este fin, use solo una declaración de datos por línea (sin
+comas para múltiples declaraciones de datos). Esto le deja espacio para un
+pequeño comentario sobre cada elemento, explicando su uso.
+
+9) Has hecho un desastre
+---------------------------
+
+Está bien, todos lo hacemos. Probablemente un antiguo usuario de Unix le
+haya dicho que ``GNU emacs`` formatea automáticamente las fuentes C por
+usted, y ha notado que sí, lo hace, pero los por defecto que tiene son
+menos que deseables (de hecho, son peores que los aleatorios) escribiendo -
+un número infinito de monos escribiendo en GNU emacs nunca harán un buen
+programa).
+
+Por lo tanto, puede deshacerse de GNU emacs o cambiarlo y usar valores más
+sanos. Para hacer esto último, puede pegar lo siguiente en su archivo
+.emacs:
+
+.. code-block:: none
+
+ (defun c-lineup-arglist-tabs-only (ignored)
+ "Line up argument lists by tabs, not spaces"
+ (let* ((anchor (c-langelem-pos c-syntactic-element))
+ (column (c-langelem-2nd-pos c-syntactic-element))
+ (offset (- (1+ column) anchor))
+ (steps (floor offset c-basic-offset)))
+ (* (max steps 1)
+ c-basic-offset)))
+
+ (dir-locals-set-class-variables
+ 'linux-kernel
+ '((c-mode . (
+ (c-basic-offset . 8)
+ (c-label-minimum-indentation . 0)
+ (c-offsets-alist . (
+ (arglist-close . c-lineup-arglist-tabs-only)
+ (arglist-cont-nonempty .
+ (c-lineup-gcc-asm-reg c-lineup-arglist-tabs-only))
+ (arglist-intro . +)
+ (brace-list-intro . +)
+ (c . c-lineup-C-comments)
+ (case-label . 0)
+ (comment-intro . c-lineup-comment)
+ (cpp-define-intro . +)
+ (cpp-macro . -1000)
+ (cpp-macro-cont . +)
+ (defun-block-intro . +)
+ (else-clause . 0)
+ (func-decl-cont . +)
+ (inclass . +)
+ (inher-cont . c-lineup-multi-inher)
+ (knr-argdecl-intro . 0)
+ (label . -1000)
+ (statement . 0)
+ (statement-block-intro . +)
+ (statement-case-intro . +)
+ (statement-cont . +)
+ (substatement . +)
+ ))
+ (indent-tabs-mode . t)
+ (show-trailing-whitespace . t)
+ ))))
+
+ (dir-locals-set-directory-class
+ (expand-file-name "~/src/linux-trees")
+ 'linux-kernel)
+
+Esto hará que emacs funcione mejor con el estilo de código del kernel para
+C en archivos bajo ``~/src/linux-trees``.
+
+Pero incluso si no logra que emacs realice un formateo correcto, no todo
+está perdido: use ``indent``.
+
+Ahora bien, de nuevo, la sangría de GNU tiene la misma configuración de
+muerte cerebral que GNU emacs tiene, por lo que necesita darle algunas
+opciones de línea de comando. Sin embargo, eso no es tan malo, porque
+incluso los creadores de GNU indent reconocen la autoridad de K&R (la gente
+de GNU no es mala, solo están gravemente equivocados en este asunto), por
+lo que simplemente de a la sangría las opciones ``-kr -i8`` (significa
+``K&R, guiones de 8 caracteres``), o use ``scripts/Lindent``, que indenta
+con ese estilo.
+
+``indent`` tiene muchas opciones, y especialmente cuando se trata de
+comentar reformateos, es posible que desee echar un vistazo a la página del
+manual. Pero recuerde: ``indent`` no es la solución para una mala
+programación.
+
+Tenga en cuenta que también puede usar la herramienta ``clang-format`` para
+ayudarlo con estas reglas, para volver a formatear rápidamente partes de su
+código automáticamente, y revisar archivos completos para detectar errores
+de estilo del código, errores tipográficos y posibles mejoras. También es
+útil para ordenar ``#includes``, para alinear variables/macros, para
+redistribuir texto y otras tareas similares. Vea el archivo
+:ref:`Documentation/process/clang-format.rst <clangformat>` para más
+detalles.
+
+10) Archivos de configuración de Kconfig
+----------------------------------------
+
+Para todos los archivos de configuración de Kconfig* en todo el árbol
+fuente, la sangría es algo diferente. Las líneas bajo una definición
+``config`` están indentadas con una tabulación, mientras que el texto de
+ayuda tiene una sangría adicional de dos espacios. Ejemplo::
+
+ config AUDIT
+ bool "Soporte para auditar"
+ depends on NET
+ help
+ Habilita la infraestructura de auditoría que se puede usar con otro
+ subsistema kernel, como SELinux (que requiere esto para
+ registro de salida de mensajes avc). No hace auditoría de llamadas al
+ sistema sin CONFIG_AUDITSYSCALL.
+
+Características seriamente peligrosas (como soporte de escritura para
+ciertos filesystems) deben anunciar esto de forma destacada en su cadena de
+solicitud::
+
+ config ADFS_FS_RW
+ bool "ADFS write support (DANGEROUS)"
+ depends on ADFS_FS
+ ...
+
+Para obtener la documentación completa sobre los archivos de configuración,
+consulte el archivo Documentation/kbuild/kconfig-language.rst.
+
+
+11) Estructuras de datos
+------------------------
+
+Las estructuras de datos que tienen visibilidad fuera del contexto de un
+solo subproceso en el que son creadas y destruidas, siempre debe tener
+contadores de referencia. En el kernel, la recolección de basura no existe
+(y fuera, la recolección de basura del kernel es lenta e ineficiente), lo
+que significa que absolutamente **tiene** para hacer referencia y contar
+todos sus usos.
+
+El conteo de referencias significa que puede evitar el bloqueo y permite
+que múltiples usuarios tengan acceso a la estructura de datos en paralelo -
+y no tengan que preocuparse de que la estructura, de repente, desaparezca
+debajo de su control, solo porque durmieron o hicieron otra cosa por un
+tiempo.
+
+Tenga en cuenta que el bloqueo **no** reemplaza el recuento de referencia.
+El bloqueo se utiliza para mantener la coherencia de las estructuras de
+datos, mientras que la referencia y contar es una técnica de gestión de
+memoria. Por lo general, ambos son necesarios, y no deben confundirse entre
+sí.
+
+De hecho, muchas estructuras de datos pueden tener dos niveles de conteo de
+referencias, cuando hay usuarios de diferentes ``clases``. El conteo de
+subclases cuenta el número de usuarios de la subclase y disminuye el conteo
+global solo una vez, cuando el recuento de subclases llega a cero.
+
+Se pueden encontrar ejemplos de este tipo de ``recuento de referencias de
+niveles múltiples`` en la gestión de memoria (``struct mm_struct``:
+mm_users y mm_count), y en código del sistema de archivos
+(``struct super_block``: s_count y s_active).
+
+Recuerde: si otro hilo puede encontrar su estructura de datos y usted no
+tiene un recuento de referencias, es casi seguro que tiene un error.
+
+12) Macros, Enums y RTL
+------------------------
+
+Los nombres de macros que definen constantes y etiquetas en enumeraciones
+(enums) están en mayúsculas.
+
+.. code-block:: c
+
+ #define CONSTANTE 0x12345
+
+Se prefieren los enums cuando se definen varias constantes relacionadas.
+
+Se aprecian los nombres de macro en MAYÚSCULAS, pero las macros que se
+asemejan a funciones puede ser nombradas en minúscula.
+
+Generalmente, las funciones en línea son preferibles a las macros que se
+asemejan a funciones.
+
+Las macros con varias instrucciones deben contenerse en un bloque do-while:
+
+.. code-block:: c
+
+ #define macrofun(a, b, c) \
+ do { \
+ if (a == 5) \
+ haz_esto(b, c); \
+ } while (0)
+
+Cosas a evitar al usar macros:
+
+1) macros que afectan el flujo de control:
+
+.. code-block:: c
+
+ #define FOO(x) \
+ do { \
+ if (blah(x) < 0) \
+ return -EBUGGERED; \
+ } while (0)
+
+es una **muy** mala idea. Parece una llamada de función pero sale de la
+función de ``llamada``; no rompa los analizadores internos de aquellos que
+leerán el código.
+
+2) macros que dependen de tener una variable local con un nombre mágico:
+
+.. code-block:: c
+
+ #define FOO(val) bar(index, val)
+
+puede parecer algo bueno, pero es confuso como el infierno cuando uno lee
+el código, y es propenso a romperse por cambios aparentemente inocentes.
+
+3) macros con argumentos que se usan como valores l: FOO(x) = y; le van
+a morder si alguien, por ejemplo, convierte FOO en una función en línea.
+
+4) olvidarse de la precedencia: las macros que definen constantes usando
+expresiones deben encerrar la expresión entre paréntesis. Tenga cuidado con
+problemas similares con macros usando parámetros.
+
+.. code-block:: c
+
+ #define CONSTANTE 0x4000
+ #define CONSTEXP (CONSTANTE | 3)
+
+5) colisiones de espacio de nombres ("namespace") al definir variables
+locales en macros que se asemejan a funciones:
+
+.. code-block:: c
+
+ #define FOO(x) \
+ ({ \
+ typeof(x) ret; \
+ ret = calc_ret(x); \
+ (ret); \
+ })
+
+ret es un nombre común para una variable local -es menos probable que
+__foo_ret colisione (coincida) con una variable existente.
+
+El manual de cpp trata las macros de forma exhaustiva. El manual interno de
+gcc también cubre RTL, que se usa frecuentemente con lenguaje ensamblador
+en el kernel.
+
+13) Imprimir mensajes del kernel
+--------------------------------
+
+A los desarrolladores del kernel les gusta ser vistos como alfabetizados.
+Cuide la ortografía de los mensajes del kernel para causar una buena
+impresión. No utilice contracciones incorrectas como ``dont``; use
+``do not`` o ``don't`` en su lugar. Haga sus mensajes concisos, claros e
+inequívocos.
+
+Los mensajes del kernel no tienen que terminar con un punto.
+
+Imprimir números entre paréntesis (%d) no agrega valor y debe evitarse.
+
+Hay varias modelos de macros de diagnóstico de driver en <linux/dev_printk.h>
+que debe usar para asegurarse de que los mensajes coincidan con el
+dispositivo correcto y driver, y están etiquetados con el nivel correcto:
+dev_err(), dev_warn(), dev_info(), y así sucesivamente. Para mensajes que
+no están asociados con un dispositivo particular, <linux/printk.h> define
+pr_notice(), pr_info(), pr_warn(), pr_err(), etc.
+
+Crear buenos mensajes de depuración puede ser todo un desafío; y una vez
+los tiene, pueden ser de gran ayuda para la resolución remota de problemas.
+Sin embargo, la impresión de mensajes de depuración se maneja de manera
+diferente a la impresión de otros mensajes que no son de depuración.
+Mientras que las otras funciones pr_XXX() se imprimen incondicionalmente,
+pr_debug() no lo hace; se compila fuera por defecto, a menos que DEBUG sea
+definido o se establezca CONFIG_DYNAMIC_DEBUG. Eso es cierto para dev_dbg()
+también, y una convención relacionada usa VERBOSE_DEBUG para agregar
+mensajes dev_vdbg() a los ya habilitados por DEBUG.
+
+Muchos subsistemas tienen opciones de depuración de Kconfig para activar
+-DDEBUG en el Makefile correspondiente; en otros casos, los archivos
+usan #define DEBUG. Y cuando un mensaje de depuración debe imprimirse
+incondicionalmente, por ejemplo si es ya dentro de una sección #ifdef
+relacionada con la depuración, printk(KERN_DEBUG ...) puede ser usado.
+
+14) Reservando memoria
+----------------------
+
+El kernel proporciona los siguientes asignadores de memoria de propósito
+general: kmalloc(), kzalloc(), kmalloc_array(), kcalloc(), vmalloc() y
+vzalloc(). Consulte la documentación de la API para obtener más información.
+a cerca de ellos. :ref:`Documentation/core-api/memory-allocation.rst
+<memory_allocation>`
+
+La forma preferida para pasar el tamaño de una estructura es la siguiente:
+
+.. code-block:: c
+
+ p = kmalloc(sizeof(*p), ...);
+
+La forma alternativa donde se deletrea el nombre de la estructura perjudica
+la legibilidad, y presenta una oportunidad para un error cuando se cambia
+el tipo de variable de puntero, pero el tamaño correspondiente de eso que
+se pasa a un asignador de memoria no.
+
+Convertir el valor devuelto, que es un puntero vacío, es redundante. La
+conversión desde el puntero vacío a cualquier otro tipo de puntero está
+garantizado por la programación en idioma C.
+
+La forma preferida para asignar una matriz es la siguiente:
+
+.. code-block:: c
+
+ p = kmalloc_array(n, sizeof(...), ...);
+
+La forma preferida para asignar una matriz a cero es la siguiente:
+
+.. code-block:: c
+
+ p = kcalloc(n, sizeof(...), ...);
+
+Ambos casos verifican el desbordamiento en el tamaño de asignación n *
+sizeof (...), y devuelven NULL si esto ocurrió.
+
+Todas estas funciones de asignación genéricas emiten un volcado de pila
+(" stack dump") en caso de fallo cuando se usan sin __GFP_NOWARN, por lo
+que no sirve de nada emitir un mensaje de fallo adicional cuando se
+devuelva NULL.
+
+15) La enfermedad de inline
+----------------------------
+
+Parece haber una común percepción errónea de que gcc tiene una magica
+opción "hazme más rápido" de aceleración, llamada ``inline`` (en línea).
+Mientras que el uso de inlines puede ser apropiado (por ejemplo, como un
+medio para reemplazar macros, consulte el Capítulo 12), muy a menudo no lo
+es. El uso abundante de la palabra clave inline conduce a una mayor kernel,
+que a su vez ralentiza el sistema en su conjunto, debido a una mayor huella
+de icache para la CPU, y sencillamente porque hay menos memoria disponible
+para el pagecache. Solo piense en esto; un fallo en la memoria caché de la
+página provoca una búsqueda de disco, que tarda fácilmente 5 milisegundos.
+Hay MUCHOS ciclos de CPU que puede entrar en estos 5 milisegundos.
+
+Una razonable regla general es no poner funciones inline que tengan más de
+3 líneas de código en ellas. Una excepción a esta regla son los casos en
+que se sabe que un parámetro es una constante en tiempo de compilación, y
+como resultado de esto, usted *sabe*, el compilador podrá optimizar la
+mayor parte de su función en tiempo de compilación. Para un buen ejemplo de
+este último caso, véase la función en línea kmalloc().
+
+A menudo, la gente argumenta que agregar funciones en línea que son
+estáticas y se usan solo una vez, es siempre una victoria ya que no hay
+perdida de espacio. Mientras esto es técnicamente correcto, gcc es capaz de
+incorporarlos automáticamente sin ayuda, y esta el problema de
+mantenimiento de eliminar el inline, cuando un segundo usuario supera el
+valor potencial de la pista que le dice a gcc que haga algo que habría
+hecho de todos modos.
+
+16) Valores devueltos por función y sus nombres
+-----------------------------------------------
+
+Las funciones pueden devolver valores de muchos tipos diferentes, y uno de
+lo más común es un valor que indica si la función tuvo éxito o ha fallado.
+Dicho valor se puede representar como un número entero de código de error
+(-Exxx = falla, 0 = éxito) o un booleano ``con éxito`` (0 = falla, distinto
+de cero = éxito).
+
+La mezcla de estos dos tipos de representaciones es una fuente fértil de
+errores difíciles de encontrar. Si el lenguaje C incluyera una fuerte
+distinción entre enteros y booleanos, el compilador encontraría estos
+errores por nosotros... pero no lo hace. Para ayudar a prevenir tales
+errores, siga siempre esta convención::
+
+ Si el nombre de una función es una acción o un comando imperativo,
+ la función debe devolver un número entero de código de error. si el nombre
+ es un predicado, la función debe devolver un valor booleano "exitoso".
+
+Por ejemplo, ``agregar trabajo`` es un comando, y la función
+agregar_trabajo() devuelve 0 en caso de éxito o -EBUSY en caso de fracaso.
+De la misma manera, ``dispositivo PCI presente`` es un predicado, y la
+función pci_dev_present() devuelve 1 si tiene éxito en encontrar un
+dispositivo coincidente o 0 si no es así.
+
+Todas las funciones EXPORTed (exportadas) deben respetar esta convención,
+al igual que todas las funciones publicas. Las funciones privadas
+(estáticas) no lo necesitan, pero es recomendado que lo hagan.
+
+Las funciones cuyo valor devuelto es el resultado real de un cálculo, en
+lugar de una indicación de si el cómputo tuvo éxito, no están sujetas a
+esta regla. Generalmente indican fallo al devolver valores fuera del rango
+de resultados. Los ejemplos típicos serían funciones que devuelven
+punteros; estos usan NULL o el mecanismo ERR_PTR para informar de fallos.
+
+17) Usando bool
+----------------
+
+El tipo bool del kernel Linux es un alias para el tipo C99 _Bool. Los
+valores booleanos pueden solo evaluar a 0 o 1, y la conversión implícita o
+explícita a bool convierte automáticamente el valor en verdadero o falso.
+Cuando se utilizan tipos booleanos,
+!! no se necesita construcción, lo que elimina una clase de errores.
+
+Cuando se trabaja con valores booleanos, se deben usar las definiciones
+verdadera y falsa, en lugar de 1 y 0.
+
+Los tipos de devolución de función bool y las variables de pila siempre
+se pueden usar cuando esto sea adecuado. Se recomienda el uso de bool para
+mejorar la legibilidad y, a menudo, es una mejor opción que 'int' para
+almacenar valores booleanos.
+
+No use bool si el diseño de la línea de caché o el tamaño del valor son
+importantes, ya que su tamaño y la alineación varía según la arquitectura
+compilada. Las estructuras que son optimizadas para la alineación y el
+tamaño no debe usar bool.
+
+Si una estructura tiene muchos valores verdadero/falso, considere
+consolidarlos en un bitfield con miembros de 1 bit, o usando un tipo de
+ancho fijo apropiado, como u8.
+
+De manera similar, para los argumentos de función, se pueden consolidar
+muchos valores verdaderos/falsos en un solo argumento bit a bit 'flags' y
+'flags' a menudo, puede ser una alternativa de argumento más legible si los
+sitios de llamada tienen constantes desnudas de tipo verdaderas/falsas.
+
+De lo contrario, el uso limitado de bool en estructuras y argumentos puede
+mejorar la legibilidad.
+
+18) No reinvente las macros del kernel
+---------------------------------------
+
+El archivo de cabecera include/linux/kernel.h contiene una serie de macros
+que debe usar, en lugar de programar explícitamente alguna variante de
+estos por usted mismo. Por ejemplo, si necesita calcular la longitud de una
+matriz, aproveche la macro
+
+.. code-block:: c
+
+ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+De manera similar, si necesita calcular el tamaño de algún miembro de la
+estructura, use
+
+.. code-block:: c
+
+ #define sizeof_field(t, f) (sizeof(((t*)0)->f))
+
+También hay macros min() y max() que realizan una verificación estricta de
+tipos si lo necesita. Siéntase libre de leer detenidamente ese archivo de
+encabezado para ver qué más ya está definido y que no debe reproducir en su
+código.
+
+19) Editores modeline y otros desastres
+---------------------------------------
+
+Algunos editores pueden interpretar la información de configuración
+incrustada en los archivos fuente, indicado con marcadores especiales. Por
+ejemplo, emacs interpreta las líneas marcadas como esto:
+
+.. code-block:: c
+
+ -*- mode: c -*-
+
+O así:
+
+.. code-block:: c
+
+ /*
+ Local Variables:
+ compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c"
+ End:
+ */
+
+Vim interpreta los marcadores que se ven así:
+
+.. code-block:: c
+
+ /* vim:set sw=8 noet */
+
+No incluya ninguno de estos en los archivos fuente. La gente tiene sus
+propias configuraciones del editor, y sus archivos de origen no deben
+anularlos. Esto incluye marcadores para sangría y configuración de modo.
+La gente puede usar su propio modo personalizado, o puede tener algún otro
+método mágico para que la sangría funcione correctamente.
+
+
+20) Ensamblador inline
+-----------------------
+
+En el código específico de arquitectura, es posible que deba usar
+ensamblador en línea para interactuar con funcionalidades de CPU o
+plataforma. No dude en hacerlo cuando sea necesario. Sin embargo, no use
+ensamblador en línea de forma gratuita cuando C puede hacer el trabajo.
+Puede y debe empujar el hardware desde C cuando sea posible.
+
+Considere escribir funciones auxiliares simples que envuelvan bits comunes
+de ensamblador, en lugar de escribirlos repetidamente con ligeras
+variaciones. Recuerde que el ensamblador en línea puede usar parámetros C.
+
+Las funciones de ensamblador grandes y no triviales deben ir en archivos .S,
+con su correspondientes prototipos de C definidos en archivos de encabezado
+en C. Los prototipos de C para el ensamblador deben usar ``asmlinkage``.
+
+Es posible que deba marcar su declaración asm como volátil, para evitar que
+GCC la elimine si GCC no nota ningún efecto secundario. No siempre es
+necesario hacerlo, sin embargo, y hacerlo innecesariamente puede limitar la
+optimización.
+
+Al escribir una sola declaración de ensamblador en línea que contiene
+múltiples instrucciones, ponga cada instrucción en una línea separada en
+una string separada, y termine cada string excepto la última con ``\n\t``
+para indentar correctamente la siguiente instrucción en la salida en
+ensamblador:
+
+.. code-block:: c
+
+ asm ("magic %reg1, #42\n\t"
+ "more_magic %reg2, %reg3"
+ : /* outputs */ : /* inputs */ : /* clobbers */);
+
+21) Compilación condicional
+---------------------------
+
+Siempre que sea posible, no use condicionales de preprocesador (#if,
+#ifdef) en archivos .c; de lo contrario, el código es más difícil de leer y
+la lógica más difícil de seguir. En cambio, use dichos condicionales en un
+archivo de encabezado que defina funciones para usar en esos archivos .c,
+proporcionando versiones de código auxiliar sin operación en el caso #else,
+y luego llame a estas funciones incondicionalmente desde archivos .c. El
+compilador evitará generar cualquier código para las llamadas restantes,
+produciendo resultados idénticos, pero la lógica es fácil de seguir.
+
+Prefiera compilar funciones completas, en lugar de porciones de funciones o
+porciones de expresiones. En lugar de poner un ifdef en una expresión,
+divida la totalidad de la expresión con una función de ayuda independiente
+y aplique el condicional a esa función.
+
+Si tiene una función o variable que puede potencialmente quedar sin usar en
+una configuración en particular, y el compilador advertiría sobre su
+definición sin usar, marque la definición como __maybe_unused en lugar de
+envolverla en un preprocesador condicional. (Sin embargo, si una función o
+variable *siempre* acaba sin ser usada, bórrela.)
+
+Dentro del código, cuando sea posible, use la macro IS_ENABLED para
+convertir un símbolo Kconfig en una expresión booleana de C, y utilícelo en
+un condicional de C normal:
+
+.. code-block:: c
+
+ if (IS_ENABLED(CONFIG_SOMETHING)) {
+ ...
+ }
+
+El compilador "doblará"" constantemente el condicional e incluirá o
+excluirá el bloque de código al igual que con un #ifdef, por lo que esto no
+agregará ningún tiempo de gastos generales en ejecución. Sin embargo, este
+enfoque todavía permite que el compilador de C vea el código dentro del
+bloque, y verifique que sea correcto (sintaxis, tipos, símbolo, referencias,
+etc.). Por lo tanto, aún debe usar un #ifdef si el código dentro del bloque
+hace referencia a símbolos que no existirán si no se cumple la condición.
+
+Al final de cualquier bloque #if o #ifdef no trivial (más de unas pocas
+líneas), incluya un comentario después de #endif en la misma línea,
+anotando la expresión condicional utilizada. Por ejemplo:
+
+.. code-block:: c
+
+ #ifdef CONFIG_SOMETHING
+ ...
+ #endif /* CONFIG_SOMETHING */
+
+22) No rompa el kernel
+-----------------------
+
+En general, la decisión de romper el kernel pertenece al usuario, más que
+al desarrollador del kernel.
+
+Evite el panic()
+****************
+
+panic() debe usarse con cuidado y principalmente solo durante el arranque
+del sistema. panic() es, por ejemplo, aceptable cuando se queda sin memoria
+durante el arranque y no puede continuar.
+
+Use WARN() en lugar de BUG()
+****************************
+
+No agregue código nuevo que use cualquiera de las variantes BUG(), como
+BUG(), BUG_ON() o VM_BUG_ON(). En su lugar, use una variante WARN*(),
+preferiblemente WARN_ON_ONCE(), y posiblemente con código de recuperación.
+El código de recuperación no es requerido si no hay una forma razonable de
+recuperar, al menos parcialmente.
+
+"Soy demasiado perezoso para tener en cuenta los errores" no es una excusa
+para usar BUG(). Importantes corrupciones internas sin forma de continuar
+aún pueden usar BUG(), pero necesitan una buena justificación.
+
+Use WARN_ON_ONCE() en lugar de WARN() o WARN_ON()
+*************************************************
+
+Generalmente, se prefiere WARN_ON_ONCE() a WARN() o WARN_ON(), porque es
+común que una condición de advertencia dada, si ocurre, ocurra varias
+veces. Esto puede llenar el registro del kernel, e incluso puede ralentizar
+el sistema lo suficiente como para que el registro excesivo se convierta en
+su propio, adicional problema.
+
+No haga WARN a la ligera
+************************
+
+WARN*() está diseñado para situaciones inesperadas que nunca deberían
+suceder. Las macros WARN*() no deben usarse para nada que se espera que
+suceda durante un funcionamiento normal. No hay "checkeos" previos o
+posteriores a la condición, por ejemplo. De nuevo: WARN*() no debe usarse
+para una condición esperada que vaya a activarse fácilmente, por ejemplo,
+mediante acciones en el espacio del usuario. pr_warn_once() es una
+alternativa posible, si necesita notificar al usuario de un problema.
+
+No se preocupe sobre panic_on_warn de usuarios
+**********************************************
+
+Algunas palabras más sobre panic_on_warn: Recuerde que ``panic_on_warn`` es
+una opción disponible del kernel, y que muchos usuarios configuran esta
+opción. Esta es la razón por la que hay un artículo de "No haga WARN a la
+ligera", arriba. Sin embargo, la existencia de panic_on_warn de usuarios no
+es una razón válida para evitar el uso juicioso de WARN*(). Esto se debe a
+que quien habilita panic_on_warn, explícitamente pidió al kernel que
+fallara si se dispara un WARN*(), y tales usuarios deben estar preparados
+para afrontar las consecuencias de un sistema que es algo más probable que
+se rompa.
+
+Use BUILD_BUG_ON() para aserciones en tiempo de compilación
+***********************************************************
+
+El uso de BUILD_BUG_ON() es aceptable y recomendado, porque es una aserción
+en tiempo de compilación, que no tiene efecto en tiempo de ejecución.
+
+Apéndice I) Referencias
+-----------------------
+
+The C Programming Language, Segunda edicion
+por Brian W. Kernighan and Dennis M. Ritchie.
+Prentice Hall, Inc., 1988.
+ISBN 0-13-110362-8 (paperback), 0-13-110370-9 (hardback).
+
+The Practice of Programming
+por Brian W. Kernighan and Rob Pike.
+Addison-Wesley, Inc., 1999.
+ISBN 0-201-61586-X.
+
+manuales GCC - en cumplimiento con K&R y este texto - para cpp, gcc,
+detalles de gcc y sangría, todo disponible en https://www.gnu.org/manual/
+
+WG14 es el grupo de trabajo de estandarización internacional de la
+programación en lenguaje C, URL: http://www.open-std.org/JTC1/SC22/WG14/
+
+:ref:`process/coding-style.rst <codingstyle>` del kernel, por greg@kroah.com at OLS 2002:
+http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
diff --git a/Documentation/translations/sp_SP/process/contribution-maturity-model.rst b/Documentation/translations/sp_SP/process/contribution-maturity-model.rst
new file mode 100644
index 000000000000..cc052ae8183d
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/contribution-maturity-model.rst
@@ -0,0 +1,120 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-sp.rst
+
+:Original: Documentation/process/contribution-maturity-model.rst
+:Translator: Avadhut Naik <avadhut.naik@amd.com>
+
+====================================================
+Modelo de Madurez de Contribución al Kernel de Linux
+====================================================
+
+
+Los Antecedentes
+================
+
+Como parte de la cumbre de mantenedores del kernel de Linux 2021, hubo
+una `discusión <https://lwn.net/Articles/870581/>`_ sobre los desafíos
+en el reclutamiento de mantenedores del kernel, así como la sucesión de
+los mantenedores. Algunas de las conclusiones de esa discusión incluyeron
+que las empresas que forman parte de la comunidad del kernel de Linux
+necesitan permitir que los ingenieros sean mantenedores como parte de su
+trabajo, para que puedan convertirse en lideres respetados y finalmente,
+en mantenedores del kernel. Para apoyar una fuente solida de talento, se
+debe permitir y alentar a los desarrolladores a asumir contribuciones
+upstream, como revisar los parches de otras personas, reestructurar la
+infraestructura del kernel y escribir documentación.
+
+Con ese fin, Technical Advisory Board (TAB) de la Fundación Linux propone
+este Modelo de Madurez de Contribución al Kernel de Linux. Estas
+expectativas comunes para la participación con la comunidad upstream
+tienen como objetivo aumentar la influencia de los desarrolladores
+individuales, aumentar la colaboración de las organizaciones y mejorar
+la salud general del ecosistema del kernel de Linux.
+
+El TAB insta a las organizaciones a evaluar continuamente su modelo de
+madurez de Código Abierto y comprometerse a realizar mejoras para
+alinearse con este modelo. Para ser eficaz, esta evaluación debe
+incorporar la reacción de toda la organización, incluyendo la gerencia
+y los desarrolladores en todos los niveles de antigüedad. En el espíritu
+de Código Abierto, alentamos a las organizaciones a publicar sus
+evaluaciones y planes para mejorar su participación con la comunidad
+upstream.
+
+Nivel 0
+=======
+
+* A los ingenieros de software no se les permite contribuir con parches
+ al kernel de Linux.
+
+Nivel 1
+=======
+
+* A los ingenieros de software se les permite contribuir con parches al
+ kernel de Linux, ya sea como parte de sus responsabilidades de trabajo
+ o en su propio tiempo.
+
+Nivel 2
+=======
+
+* Se espera que los ingenieros de software contribuyan al kernel de Linux
+ como parte de sus responsabilidades de trabajo.
+* Se proporcionará apoyo a los ingenieros de software para asistir a
+ conferencias relacionadas con Linux como parte de su trabajo.
+* Las contribuciones de código upstream de un ingeniero de software se
+ considerarán en la promoción y las revisiones de rendimiento.
+
+Nivel 3
+=======
+
+* Se espera que los ingenieros de software revisen los parches (incluidos
+ los parches escritos por ingenieros de otras empresas) como parte de
+ sus responsabilidades de trabajo.
+* Contribuir con presentaciones o ponencias a conferencias relacionadas
+ con Linux o académicas (como las organizadas por la Fundación Linux,
+ Usenix, ACM, etc.), se consideran parte del trabajo de un ingeniero.
+* Las contribuciones a la comunidad de un ingeniero de software se
+ considerarán en la promoción y las revisiones de rendimiento.
+* Las organizaciones informarán regularmente sobre las métricas de sus
+ contribuciones de código abierto y harán un seguimiento de estas
+ métricas a lo largo del tiempo. Estas métricas pueden publicarse
+ solo internamente dentro de la organización, o a discreción de la
+ organización, algunas o todas pueden publicarse externamente. Las
+ métricas que se sugieren encarecidamente incluyen:
+
+ * El número de contribuciones al kernel upstream por equipo u
+ organización (por ejemplo, todas las personas que reportan a un
+ gerente o director o vicepresidente).
+ * El porcentaje de desarrolladores del kernel que han realizado
+ contribuciones upstream relativo al total de desarrolladores
+ del kernel en la organización.
+ * El intervalo de tiempo entre los kernels utilizados en los servidores
+ y/o productos de la organización y la fecha de publicación del kernel
+ upstream en el que se basa el kernel interno.
+ * El número de commits fuera del árbol de desarrollo presentes en los
+ kernels internos.
+
+Nivel 4
+=======
+
+* Se anima a los ingenieros de software a pasar una parte de su tiempo de
+ trabajo centrado en el Trabajo Ascendente, que se define como revisar
+ parches, servir en los comités de programas, mejorar la infraestructura
+ del proyecto central como escribir o mantener pruebas, reducir la deuda
+ de tecnología upstream, escribir documentación, etc.
+* Los ingenieros de software son apoyados para ayudar a organizar
+ conferencias relacionadas con Linux.
+* Las organizaciones considerarán los comentarios de los miembros de la
+ comunidad en las revisiones oficiales de rendimiento.
+
+Nivel 5
+=======
+
+* El desarrollo del kernel upstream se considera un puesto de trabajo
+ formal, con al menos un tercio del tiempo del ingeniero pasado a hacer
+ el Trabajo Ascendente.
+* Las organizaciones buscarán activamente las reacciones de los miembros
+ de la comunidad como un factor en las revisiones oficiales de
+ rendimiento.
+* Las organizaciones informarán regularmente internamente sobre la ratio
+ de trabajo upstream a trabajo enfocado en perseguir directamente los
+ objetivos comerciales.
diff --git a/Documentation/translations/sp_SP/process/deprecated.rst b/Documentation/translations/sp_SP/process/deprecated.rst
new file mode 100644
index 000000000000..d52120e0d753
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/deprecated.rst
@@ -0,0 +1,381 @@
+.. include:: ../disclaimer-sp.rst
+
+:Original: :ref:`Documentation/process/deprecated.rst <deprecated>`
+:Translator: Sergio Gonzalez <sergio.collado@gmail.com>
+
+.. _sp_deprecated:
+
+============================================================================
+Interfaces obsoletos, Características del lenguaje, Atributos y Convenciones
+============================================================================
+
+En un mundo perfecto, sería posible convertir todas las instancias de
+alguna API obsoleta en una nueva API y quitar la API anterior en un
+único ciclo de desarrollo. Desafortunadamente, debido al tamaño del kernel,
+la jerarquía de mantenimiento, y el tiempo, no siempre es posible hacer
+estos cambios de una única vez. Esto significa que las nuevas instancias
+han de ir creándose en el kernel, mientras que las antiguas se quitan,
+haciendo que la cantidad de trabajo para limpiar las APIs crezca. Para
+informar a los desarrolladores sobre qué ha sido declarado obsoleto y por
+qué, ha sido creada esta lista como un lugar donde indicar cuando los usos
+obsoletos son propuestos para incluir en el kernel.
+
+__deprecated
+------------
+Mientras que este atributo señala visualmente que un interface ha sido
+declarado obsoleto, este `no produce más avisos durante las compilaciones
+<https://git.kernel.org/linus/771c035372a036f83353eef46dbb829780330234>`_
+porque uno de los objetivos del kernel es que compile sin avisos, y
+nadie ha hecho nada para quitar estos interfaces obsoletos. Mientras
+que usar `__deprecated` es sencillo para anotar una API obsoleta en
+un archivo de cabecera, no es la solución completa. Dichos interfaces
+deben o bien ser quitados por completo, o añadidos a este archivo para
+desanimar a otros a usarla en el futuro.
+
+BUG() y BUG_ON()
+----------------
+Use WARN() y WARN_ON() en su lugar, y gestione las condiciones de error
+"imposibles" tan elegantemente como se pueda. Mientras que la familia de
+funciones BUG() fueron originalmente diseñadas para actuar como una
+"situación imposible", confirmar y disponer de un hilo del kernel de forma
+"segura", estas funciones han resultado ser demasiado arriesgadas. (e.g.
+"¿en qué orden se necesitan liberar los locks? ¿Se han restaurado sus
+estados?). La popular función BUG() desestabilizará el sistema o lo romperá
+totalmente, lo cual hace imposible depurarlo o incluso generar reportes de
+crash. Linus tiene una `opinión muy fuerte
+<https://lore.kernel.org/lkml/CA+55aFy6jNLsywVYdGp83AMrXBo_P-pkjkphPGrO=82SPKCpLQ@mail.gmail.com/>`_
+y sentimientos `sobre esto
+<https://lore.kernel.org/lkml/CAHk-=whDHsbK3HTOpTF=ue_o04onRwTEaK_ZoJp_fjbqq4+=Jw@mail.gmail.com/>`_.
+
+Nótese que la familia de funciones WARN() únicamente debería ser usada
+en situaciones que se "esperan no sean alcanzables". Si se quiere
+avisar sobre situaciones "alcanzables pero no deseadas", úsese la familia
+de funciones pr_warn(). Los responsables del sistema pueden haber definido
+*panic_on_warn* sysctl para asegurarse que sus sistemas no continúan
+ejecutándose en presencia del condiciones "no alcanzables". (Por ejemplo,
+véase commits como `este
+<https://git.kernel.org/linus/d4689846881d160a4d12a514e991a740bcb5d65a>`_.)
+
+Operaciones aritméticas en los argumentos de reserva de memoria
+---------------------------------------------------------------
+Los cálculos dinámicos de tamaño (especialmente multiplicaciones) no
+deberían realizarse en los argumentos de reserva de memoria (o similares)
+debido al riesgo de desbordamiento. Esto puede llevar a valores rotando y
+que se realicen reservas de memoria menores que las que se esperaban. El
+uso de esas reservas puede llevar a desbordamientos en el 'heap' de memoria
+y otros funcionamientos incorrectos. (Una excepción a esto son los valores
+literales donde el compilador si puede avisar si estos puede desbordarse.
+De todos modos, el método recomendado en estos caso es reescribir el código
+como se sugiere a continuación para evitar las operaciones aritméticas en
+la reserva de memoria.)
+
+Por ejemplo, no utilice `count * size`` como argumento, como en::
+
+ foo = kmalloc(count * size, GFP_KERNEL);
+
+En vez de eso, utilice la reserva con dos argumentos::
+
+ foo = kmalloc_array(count, size, GFP_KERNEL);
+
+Específicamente, kmalloc() puede ser sustituido con kmalloc_array(),
+kzalloc() puede ser sustituido con kcalloc().
+
+Si no existen funciones con dos argumentos, utilice las funciones que se
+saturan, en caso de desbordamiento::
+
+ bar = vmalloc(array_size(count, size));
+
+Otro caso común a evitar es calcular el tamaño de una estructura com
+la suma de otras estructuras, como en::
+
+ header = kzalloc(sizeof(*header) + count * sizeof(*header->item),
+ GFP_KERNEL);
+
+En vez de eso emplee::
+
+ header = kzalloc(struct_size(header, item, count), GFP_KERNEL);
+
+.. note:: Si se usa struct_size() en una estructura que contiene un elemento
+ de longitud cero o un array de un único elemento como un array miembro,
+ por favor reescribir ese uso y cambiar a un `miembro array flexible
+ <#zero-length-and-one-element-arrays>`_
+
+
+Para otros cálculos, por favor use las funciones de ayuda: size_mul(),
+size_add(), and size_sub(). Por ejemplo, en el caso de::
+
+ foo = krealloc(current_size + chunk_size * (count - 3), GFP_KERNEL);
+
+Re-escríbase, como::
+
+ foo = krealloc(size_add(current_size,
+ size_mul(chunk_size,
+ size_sub(count, 3))), GFP_KERNEL);
+
+Para más detalles, mire también array3_size() y flex_array_size(),
+como también la familia de funciones relacionadas check_mul_overflow(),
+check_add_overflow(), check_sub_overflow(), y check_shl_overflow().
+
+
+simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull()
+----------------------------------------------------------------------
+Las funciones: simple_strtol(), simple_strtoll(), simple_strtoul(), y
+simple_strtoull() explícitamente ignoran los desbordamientos, lo que puede
+llevar a resultados inesperados por las funciones que las llaman. Las
+funciones respectivas kstrtol(), kstrtoll(), kstrtoul(), y kstrtoull()
+tienden a ser reemplazos correctos, aunque nótese que necesitarán que la
+cadena de caracteres termine en NUL o en el carácter de línea nueva.
+
+
+strcpy()
+--------
+strcpy() no realiza verificaciones de los límites del buffer de destino.
+Esto puede resultar en desbordamientos lineals más allá del fin del buffer,
+causando todo tipo de errores. Mientras `CONFIG_FORTIFY_SOURCE=y` otras
+varias opciones de compilación reducen el riesgo de usar esta función, no
+hay ninguna buena razón para añadir nuevos usos de esta. El remplazo seguro
+es la función strscpy(), aunque se ha de tener cuidado con cualquier caso
+en el el valor retornado por strcpy() sea usado, ya que strscpy() no
+devuelve un puntero a el destino, sino el número de caracteres no nulos
+compilados (o el valor negativo de errno cuando se trunca la cadena de
+caracteres).
+
+strncpy() en cadenas de caracteres terminadas en NUL
+----------------------------------------------------
+El uso de strncpy() no garantiza que el buffer de destino esté terminado en
+NUL. Esto puede causar varios errores de desbordamiento en lectura y otros
+tipos de funcionamiento erróneo debido a que falta la terminación en NUL.
+Esta función también termina la cadena de caracteres en NUL en el buffer de
+destino si la cadena de origen es más corta que el buffer de destino, lo
+cual puede ser una penalización innecesaria para funciones usen esta
+función con cadenas de caracteres que sí están terminadas en NUL.
+
+Cuando se necesita que la cadena de destino sea terminada en NUL,
+el mejor reemplazo es usar la función strscpy(), aunque se ha de tener
+cuidado en los casos en los que el valor de strncpy() fuera usado, ya que
+strscpy() no devuelve un puntero al destino, sino el número de
+caracteres no nulos copiados (o el valor negativo de errno cuando se trunca
+la cadena de caracteres). Cualquier caso restante que necesitase todavía
+ser terminado en el caracter nulo, debería usar strscpy_pad().
+
+Si una función usa cadenas de caracteres que no necesitan terminar en NUL,
+debería usarse strtomem(), y el destino debería señalarse con el atributo
+`__nonstring
+<https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html>`_
+para evitar avisos futuros en el compilador. Para casos que todavía
+necesitan cadenas de caracteres que se rellenen al final con el
+caracter NUL, usar strtomem_pad().
+
+strlcpy()
+---------
+strlcpy() primero lee por completo el buffer de origen (ya que el valor
+devuelto intenta ser el mismo que el de strlen()). Esta lectura puede
+sobrepasar el límite de tamaño del destino. Esto ineficiente y puede causar
+desbordamientos de lectura si la cadena de origen no está terminada en el
+carácter NUL. El reemplazo seguro de esta función es strscpy(), pero se ha
+de tener cuidado que en los casos en lso que se usase el valor devuelto de
+strlcpy(), ya que strscpy() devolverá valores negativos de erno cuando se
+produzcan truncados.
+
+Especificación de formato %p
+----------------------------
+Tradicionalmente,el uso de "%p" en el formato de cadenas de caracteres
+resultaría en exponer esas direcciones en dmesg, proc, sysfs, etc. En vez
+de dejar que sean una vulnerabilidad, todos los "%p" que se usan en el
+kernel se imprimen como un hash, haciéndolos efectivamente inutilizables
+para usarlos como direcciones de memoria. Nuevos usos de "%p" no deberían
+ser añadidos al kernel. Para textos de direcciones, usar "%pS" es
+mejor, ya que resulta en el nombre del símbolo. Para prácticamente el
+resto de casos, mejor no usar "%p" en absoluto.
+
+Parafraseando las actuales `direcciones de Linus <https://lore.kernel.org/lkml/CA+55aFwQEd_d40g4mUCSsVRZzrFPUJt74vc6PPpb675hYNXcKw@mail.gmail.com/>`_:
+
+- Si el valor "hasheado" "%p" no tienen ninguna finalidad, preguntarse si el
+ puntero es realmente importante. ¿Quizás se podría quitar totalmente?
+- Si realmente se piensa que el valor del puntero es importante, ¿porqué
+ algún estado del sistema o nivel de privilegio de usuario es considerado
+ "especial"? Si piensa que puede justificarse (en comentarios y mensajes
+ del commit), de forma suficiente como para pasar el escrutinio de Linux,
+ quizás pueda usar el "%p", a la vez que se asegura que tiene los permisos
+ correspondientes.
+
+Si está depurando algo donde el "%p" hasheado está causando problemas,
+se puede arrancar temporalmente con la opción de depuración "`no_hash_pointers
+<https://git.kernel.org/linus/5ead723a20e0447bc7db33dc3070b420e5f80aa6>`_".
+
+
+Arrays de longitud variable (VLAs)
+----------------------------------
+Usando VLA en la pila (stack) produce un código mucho peor que los arrays
+de tamaño estático. Mientras que estos errores no triviales de `rendimiento
+<https://git.kernel.org/linus/02361bc77888>`_ son razón suficiente
+para no usar VLAs, esto además son un riesgo de seguridad. El crecimiento
+dinámico del array en la pila, puede exceder la memoria restante en
+el segmento de la pila. Esto podría llevara a un fallo, posible sobre-escritura
+de contenido al final de la pila (cuando se construye sin
+`CONFIG_THREAD_INFO_IN_TASK=y`), o sobre-escritura de la memoria adyacente
+a la pila (cuando se construye sin `CONFIG_VMAP_STACK=y`).
+
+
+Switch case fall-through implícito
+----------------------------------
+El lenguaje C permite a las sentencias 'switch' saltar de un caso al
+siguiente caso cuando la sentencia de ruptura "break" no aparece al final
+del caso. Esto, introduce ambigüedad en el código, ya que no siempre está
+claro si el 'break' que falta es intencionado o un olvido. Por ejemplo, no
+es obvio solamente mirando al código si `STATE_ONE` está escrito para
+intencionadamente saltar en `STATE_TWO`::
+
+ switch (value) {
+ case STATE_ONE:
+ do_something();
+ case STATE_TWO:
+ do_other();
+ break;
+ default:
+ WARN("unknown state");
+ }
+
+Ya que ha habido una larga lista de defectos `debidos a declaraciones de "break"
+que faltan <https://cwe.mitre.org/data/definitions/484.html>`_, no se
+permiten 'fall-through' implícitos. Para identificar 'fall-through'
+intencionados, se ha adoptado la pseudo-palabra-clave macro "falltrhrough",
+que expande las extensiones de gcc `__attribute__((__fallthrough__))
+<https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html>`_.
+(Cuando la sintaxis de C17/c18 `[[fallthrough]]` sea más comúnmente
+soportadas por los compiladores de C, analizadores estáticos, e IDEs,
+se puede cambiar a usar esa sintaxis para esa pseudo-palabra-clave.
+
+Todos los bloques switch/case deben acabar en uno de:
+
+* break;
+* fallthrough;
+* continue;
+* goto <label>;
+* return [expression];
+
+
+Arrays de longitud cero y un elemento
+-------------------------------------
+Hay una necesidad habitual en el kernel de proveer una forma para declarar
+un grupo de elementos consecutivos de tamaño dinámico en una estructura.
+El código del kernel debería usar siempre `"miembros array flexible" <https://en.wikipedia.org/wiki/Flexible_array_member>`_
+en estos casos. El estilo anterior de arrays de un elemento o de longitud
+cero, no deben usarse más.
+
+En el código C más antiguo, los elementos finales de tamaño dinámico se
+obtenían especificando un array de un elemento al final de una estructura::
+
+ struct something {
+ size_t count;
+ struct foo items[1];
+ };
+
+En código C más antiguo, elementos seguidos de tamaño dinámico eran creados
+especificando una array de un único elemento al final de una estructura::
+
+ struct something {
+ size_t count;
+ struct foo items[1];
+ };
+
+Esto llevó a resultados incorrectos en los cálculos de tamaño mediante
+sizeof() (el cual hubiera necesitado eliminar el tamaño del último elemento
+para tener un tamaño correcto de la "cabecera"). Una `extensión de GNU C
+<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_ se empezó a usar
+para permitir los arrays de longitud cero, para evitar estos tipos de
+problemas de tamaño::
+
+ struct something {
+ size_t count;
+ struct foo items[0];
+ };
+
+Pero esto llevó a otros problemas, y no solucionó algunos otros problemas
+compartidos por ambos estilos, como no ser capaz de detectar cuando ese array
+accidentalmente _no_ es usado al final de la estructura (lo que podía pasar
+directamente, o cuando dicha estructura era usada en uniones, estructuras
+de estructuras, etc).
+
+C99 introdujo "los arrays miembros flexibles", los cuales carecen de un
+tamaño numérico en su declaración del array::
+
+ struct something {
+ size_t count;
+ struct foo items[];
+ };
+
+Esta es la forma en la que el kernel espera que se declaren los elementos
+de tamaño dinámico concatenados. Esto permite al compilador generar
+errores, cuando el array flexible no es declarado en el último lugar de la
+estructura, lo que ayuda a prevenir errores en él código del tipo
+`comportamiento indefinido <https://git.kernel.org/linus/76497732932f15e7323dc805e8ea8dc11bb587cf>`_.
+Esto también permite al compilador analizar correctamente los tamaños de
+los arrays (via sizeof(), `CONFIG_FORTIFY_SOURCE`, y `CONFIG_UBSAN_BOUNDS`).
+Por ejemplo, si no hay un mecanismo que avise que el siguiente uso de
+sizeof() en un array de longitud cero, siempre resulta en cero::
+
+ struct something {
+ size_t count;
+ struct foo items[0];
+ };
+
+ struct something *instance;
+
+ instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL);
+ instance->count = count;
+
+ size = sizeof(instance->items) * instance->count;
+ memcpy(instance->items, source, size);
+
+En la última línea del código anterior, ``zero`` vale ``cero``, cuando uno
+podría esperar que representa el tamaño total en bytes de la memoria dinámica
+reservada para el array consecutivo ``items``. Aquí hay un par de ejemplos
+más sobre este tema: `link 1
+<https://git.kernel.org/linus/f2cd32a443da694ac4e28fbf4ac6f9d5cc63a539>`_,
+`link 2
+<https://git.kernel.org/linus/ab91c2a89f86be2898cee208d492816ec238b2cf>`_.
+Sin embargo, los array de miembros flexibles tienen un type incompleto, y
+no se ha de aplicar el operador sizeof()<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_,
+así cualquier mal uso de dichos operadores será detectado inmediatamente en
+el momento de compilación.
+
+Con respecto a los arrays de un único elemento, se ha de ser consciente de
+que dichos arrays ocupan al menos tanto espacio como un único objeto del
+tipo https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_, de ahí que
+estos contribuyan al tamaño de la estructura que los contiene. Esto es
+proclive a errores cada vez que se quiere calcular el tamaño total de la
+memoria dinámica para reservar una estructura que contenga un array de este
+tipo como su miembro::
+
+ struct something {
+ size_t count;
+ struct foo items[1];
+ };
+
+ struct something *instance;
+
+ instance = kmalloc(struct_size(instance, items, count - 1), GFP_KERNEL);
+ instance->count = count;
+
+ size = sizeof(instance->items) * instance->count;
+ memcpy(instance->items, source, size);
+
+En el ejemplo anterior, hemos de recordar calcular ``count - 1``, cuando se
+usa la función de ayuda struct_size(), de otro modo estaríamos
+--desintencionadamente--reservando memoria para un ``items`` de más. La
+forma más clara y menos proclive a errores es implementar esto mediante el
+uso de `array miembro flexible`, junto con las funciones de ayuda:
+struct_size() y flex_array_size()::
+
+ struct something {
+ size_t count;
+ struct foo items[];
+ };
+
+ struct something *instance;
+
+ instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL);
+ instance->count = count;
+
+ memcpy(instance->items, source, flex_array_size(instance, items, instance->count));
diff --git a/Documentation/translations/sp_SP/process/email-clients.rst b/Documentation/translations/sp_SP/process/email-clients.rst
new file mode 100644
index 000000000000..fdf1e51b84e4
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/email-clients.rst
@@ -0,0 +1,374 @@
+.. include:: ../disclaimer-sp.rst
+
+:Original: :ref:`Documentation/process/email-clients.rst <email_clients>`
+:Translator: Carlos Bilbao <carlos.bilbao@amd.com>
+
+.. _sp_email_clients:
+
+Información de clientes de correo electrónico para Linux
+========================================================
+
+Git
+---
+
+A día de hoy, la mayoría de los desarrolladores usan ``git send-email`` en
+lugar de los clientes de correo electrónico normales. La página de manual
+para esto es bastante buena. En la recepción del correo, los maintainers
+usan ``git am`` para aplicar los parches.
+
+Si es usted nuevo en ``git`` entonces envíese su primer parche. Guárdelo
+como texto sin formato, incluidos todos los encabezados. Ejecute ``git am raw_email.txt``
+y luego revise el registro de cambios con ``git log``. Cuando eso funcione,
+envíe el parche a la(s) lista(s) de correo apropiada(s).
+
+Preferencias Generales
+----------------------
+
+Los parches para el kernel de Linux se envían por correo electrónico,
+preferiblemente como texto en línea en el cuerpo del correo electrónico.
+Algunos maintainers aceptan archivos adjuntos, pero entonces los archivos
+adjuntos deben tener tipo de contenido ``text/plain``. Sin embargo, los
+archivos adjuntos generalmente están mal vistos porque hacen que citar
+partes del parche sea más difícil durante el proceso de revisión del
+parche.
+
+También se recomienda encarecidamente que utilice texto sin formato en el
+cuerpo del correo electrónico, para parches y otros correos electrónicos
+por igual. https://useplaintext.email puede ser útil para obtener
+información sobre cómo configurar su cliente de correo electrónico
+preferido, así como una lista de clientes de correo electrónico
+recomendados si aún no tiene una preferencia.
+
+Los clientes de correo electrónico que se utilizan para los parches del
+kernel Linux deben enviar el texto del parche intacto. Por ejemplo, no
+deben modificar ni eliminar pestañas o espacios, incluso al principio o al
+final de las líneas.
+
+No envíe parches con ``format=flowed``. Esto puede causar saltos de línea
+no deseados e inesperados.
+
+No deje que su cliente de correo electrónico ajuste automáticamente las
+palabras por usted. Esto también puede corromper su parche.
+
+Los clientes de correo electrónico no deben modificar la codificación del
+de caracteres del texto. Los parches enviados por correo electrónico deben
+estar en codificación ASCII o UTF-8 únicamente. Si configura su cliente de
+correo electrónico para enviar correos electrónicos con codificación UTF-8,
+evite algunos posibles problemas con los caracteres.
+
+Los clientes de correo electrónico deben generar y mantener los
+encabezados "References:" o "In-Reply-To:" para que el hilo de correo no
+se rompa.
+
+Copiar y pegar (o cortar y pegar) generalmente no funciona para los
+parches, porque las tabulaciones se convierten en espacios. Utilizar
+xclipboard, xclip y/o xcutsel puede funcionar, pero es mejor probarlo usted
+mismo o simplemente evitar copiar y pegar.
+
+No utilice firmas PGP/GPG en el correo que contiene parches.
+Esto rompe muchos scripts que leen y aplican los parches.
+(Esto debería ser reparable.)
+
+Es una buena idea enviarse un parche a sí mismo, guardar el mensaje
+recibido, y aplicarlo con éxito con 'patch' antes de enviar el parche a las
+listas de correo de Linux.
+
+Algunas sugerencias para el cliente de correo electrónico (MUA)
+---------------------------------------------------------------
+
+Aquí hay algunos consejos específicos de configuración de MUA para editar y
+enviar parches para el kernel de Linux. Estos no pretenden cubrir todo
+detalle de configuración de los paquetes de software.
+
+Leyenda:
+
+- TUI = text-based user interface (interfaz de usuario basada en texto)
+- GUI = graphical user interface (interfaz de usuario gráfica)
+
+Alpine (TUI)
+************
+
+Opciones de configuración:
+
+En la sección :menuselection:`Sending Preferences`:
+
+- :menuselection: `Do Not Send Flowed Text` debe estar ``enabled``
+- :menuselection:`Strip Whitespace Before Sending` debe estar ``disabled``
+
+Al redactar el mensaje, el cursor debe colocarse donde el parche debería
+aparecer, y luego presionando :kbd:`CTRL-R` se le permite especificar e
+archivo de parche a insertar en el mensaje.
+
+Claws Mail (GUI)
+****************
+
+Funciona. Algunos usan esto con éxito para los parches.
+
+Para insertar un parche haga :menuselection:`Message-->Insert File` (:kbd:`CTRL-I`)
+o use un editor externo.
+
+Si el parche insertado debe editarse en la ventana de composición de Claws
+"Auto wrapping" en
+:menuselection:`Configuration-->Preferences-->Compose-->Wrapping` debe
+permanecer deshabilitado.
+
+Evolution (GUI)
+***************
+
+Algunos usan esto con éxito para sus parches.
+
+Cuando escriba un correo seleccione: Preformat
+ desde :menuselection:`Format-->Paragraph Style-->Preformatted` (:kbd:`CTRL-7`)
+ o en la barra de herramientas
+
+Luego haga:
+:menuselection:`Insert-->Text File...` (:kbd:`ALT-N x`)
+para insertar el parche.
+
+También puede hacer ``diff -Nru old.c new.c | xclip``, seleccione
+:menuselection:`Preformat`, luego pege con el boton del medio.
+
+Kmail (GUI)
+***********
+
+Algunos usan Kmail con éxito para los parches.
+
+La configuración predeterminada de no redactar en HTML es adecuada; no haga
+cambios en esto.
+
+Al redactar un correo electrónico, en las opciones, desmarque "word wrap".
+La única desventaja es que cualquier texto que escriba en el correo
+electrónico no se ajustará a cada palabra, por lo que tendrá que ajustar
+manualmente el texto antes del parche. La forma más fácil de evitar esto es
+redactar su correo electrónico con Word Wrap habilitado, luego guardar
+como borrador. Una vez que lo vuelva a sacar de sus borradores, estará
+envuelto por palabras y puede desmarcar "word wrap" sin perder el existente
+texto.
+
+En la parte inferior de su correo electrónico, coloque el delimitador de
+parche de uso común antes de insertar su parche: tres guiones (``---``).
+
+Luego desde la opción de menu :menuselection:`Message` seleccione
+:menuselection:`insert file` y busque su parche.
+De forma adicional, puede personalizar el menú de la barra de herramientas
+de creación de mensajes y poner el icono :menuselection:`insert file`.
+
+Haga que la ventana del editor sea lo suficientemente ancha para que no se
+envuelva ninguna línea. A partir de KMail 1.13.5 (KDE 4.5.4), KMail
+aplicará ajuste de texto al enviar el correo electrónico si las líneas se
+ajustan en la ventana del redactor. Tener ajuste de palabras deshabilitado
+en el menú Opciones no es suficiente. Por lo tanto, si su parche tiene
+líneas muy largas, debe hacer que la ventana del redactor sea muy amplia
+antes de enviar el correo electrónico. Consulte: https://bugs.kde.org/show_bug.cgi?id=174034
+
+You can safely GPG sign attachments, but inlined text is preferred for
+patches so do not GPG sign them. Signing patches that have been inserted
+as inlined text will make them tricky to extract from their 7-bit encoding.
+
+Puede firmar archivos adjuntos con GPG de forma segura, pero se prefiere el
+texto en línea para parches, así que no los firme con GPG. Firmar parches
+que se han insertado como texto en línea hará que sea difícil extraerlos de
+su codificación de 7 bits.
+
+Si es absolutamente necesario enviar parches como archivos adjuntos en
+lugar de como texto en línea, haga clic con el botón derecho en el archivo
+adjunto y seleccione :menuselection:`properties`, y luego
+:menuselection:`Suggest automatic display` para hacer que el archivo
+adjunto esté en línea para que sea más visible.
+
+Al guardar parches que se envían como texto en línea, seleccione el correo
+electrónico que contiene el parche del panel de la lista de mensajes, haga
+clic con el botón derecho y seleccione :menuselection:`save as`. Puede usar
+todo el correo electrónico sin modificar como un parche de estar bien
+compuesto. Los correos electrónicos se guardan como lectura y escritura
+solo para el usuario, por lo que tendrá que cambiarlos para que sean
+legibles en grupo y en todo el mundo si copia estos en otro lugar.
+
+Notas de Lotus (GUI)
+********************
+
+Huya de este.
+
+IBM Verse (Web GUI)
+*******************
+
+Vea notas sobre Lotus.
+
+Mutt (TUI)
+**********
+
+Muchos desarrolladores de Linux usan ``mutt``, por lo que debe funcionar
+bastante bien.
+
+Mutt no viene con un editor, por lo que cualquier editor que use debe ser
+utilizado de forma que no haya saltos de línea automáticos. La mayoría de
+los editores tienen una opción :menuselection:`insert file` que inserta el
+contenido de un archivo inalterado.
+
+Para usar ``vim`` con mutt::
+
+ set editor="vi"
+
+Si utiliza xclip, escriba el comando::
+
+ :set paste
+
+antes del boton del medio o shift-insert o use::
+
+ :r filename
+
+si desea incluir el parche en línea.
+(a)ttach (adjuntar) funciona bien sin ``set paste``.
+
+También puedes generar parches con ``git format-patch`` y luego usar Mutt
+para enviarlos::
+
+ $ mutt -H 0001-some-bug-fix.patch
+
+Opciones de configuración:
+
+Debería funcionar con la configuración predeterminada.
+Sin embargo, es una buena idea establecer ``send_charset`` en:
+
+ set send_charset="us-ascii:utf-8"
+
+Mutt es altamente personalizable. Aquí tiene una configuración mínima para
+empezar a usar Mutt para enviar parches a través de Gmail::
+
+ # .muttrc
+ # ================ IMAP ====================
+ set imap_user = 'suusuario@gmail.com'
+ set imap_pass = 'sucontraseña'
+ set spoolfile = imaps://imap.gmail.com/INBOX
+ set folder = imaps://imap.gmail.com/
+ set record="imaps://imap.gmail.com/[Gmail]/Sent Mail"
+ set postponed="imaps://imap.gmail.com/[Gmail]/Drafts"
+ set mbox="imaps://imap.gmail.com/[Gmail]/All Mail"
+
+ # ================ SMTP ====================
+ set smtp_url = "smtp://username@smtp.gmail.com:587/"
+ set smtp_pass = $imap_pass
+ set ssl_force_tls = yes # Requerir conexión encriptada
+
+ # ================ Composición ====================
+ set editor = `echo \$EDITOR`
+ set edit_headers = yes # Ver los encabezados al editar
+ set charset = UTF-8 # valor de $LANG; also fallback for send_charset
+ # El remitente, la dirección de correo electrónico y la línea de firma deben coincidir
+ unset use_domain # Porque joe@localhost es simplemente vergonzoso
+ set realname = "SU NOMBRE"
+ set from = "username@gmail.com"
+ set use_from = yes
+
+Los documentos Mutt tienen mucha más información:
+
+ https://gitlab.com/muttmua/mutt/-/wikis/UseCases/Gmail
+
+ http://www.mutt.org/doc/manual/
+
+Pine (TUI)
+**********
+
+Pine ha tenido algunos problemas de truncamiento de espacios en blanco en
+el pasado, pero estos todo debería estar arreglados ahora.
+
+Use alpine (sucesor de pino) si puede.
+
+Opciones de configuración:
+
+- ``quell-flowed-text`` necesitado para versiones actuales
+- la opción ``no-strip-whitespace-before-send`` es necesaria
+
+
+Sylpheed (GUI)
+**************
+
+- Funciona bien para insertar texto (o usar archivos adjuntos).
+- Permite el uso de un editor externo.
+- Es lento en carpetas grandes.
+- No realizará la autenticación TLS SMTP en una conexión que no sea SSL.
+- Tiene una útil barra de reglas en la ventana de redacción.
+- Agregar direcciones a la libreta de direcciones no las muestra
+ adecuadamente.
+
+Thunderbird (GUI)
+*****************
+
+Thunderbird es un clon de Outlook al que le gusta alterar el texto, pero
+hay formas para obligarlo a comportarse.
+
+Después de hacer las modificaciones, que incluye instalar las extensiones,
+necesita reiniciar Thunderbird.
+
+- Permitir el uso de un editor externo:
+
+ Lo más fácil de hacer con Thunderbird y los parches es usar extensiones
+ que abran su editor externo favorito.
+
+ Aquí hay algunas extensiones de ejemplo que son capaces de hacer esto.
+
+ - "External Editor Revived"
+
+ https://github.com/Frederick888/external-editor-revived
+
+ https://addons.thunderbird.net/en-GB/thunderbird/addon/external-editor-revived/
+
+ Requiere instalar un "native messaging host".
+ Por favor, lea la wiki que se puede encontrar aquí:
+ https://github.com/Frederick888/external-editor-revived/wiki
+
+ - "External Editor"
+
+ https://github.com/exteditor/exteditor
+
+ Para hacer esto, descargue e instale la extensión, luego abra la ventana
+ :menuselection:`compose`, agregue un botón para ello usando
+ :menuselection:`View-->Toolbars-->Customize...`
+ luego simplemente haga clic en el botón nuevo cuando desee usar el editor
+ externo.
+
+ Tenga en cuenta que "External Editor" requiere que su editor no haga
+ fork, o en otras palabras, el editor no debe regresar antes de cerrar.
+ Es posible que deba pasar flags adicionales o cambiar la configuración
+ de su editor. En particular, si está utilizando gvim, debe pasar la
+ opción -f a gvim poniendo ``/usr/bin/gvim --nofork"`` (si el binario
+ está en ``/usr/bin``) al campo del editor de texto en los ajustes
+ :menuselection:`external editor`. Si está utilizando algún otro editor,
+ lea su manual para saber cómo hacer esto.
+
+Para sacarle algo de sentido al editor interno, haga esto:
+
+- Edite sus ajustes de configuración de Thunderbird para que no utilice ``format=flowed``!
+ Vaya a su ventana principal y busque el botón de su menú desplegable principal.
+ :menuselection:`Main Menu-->Preferences-->General-->Config Editor...`
+ para abrir el editor de registro de Thunderbird.
+
+ - Seleccione ``mailnews.send_plaintext_flowed`` como ``false``
+
+ - Seleccione ``mailnews.wraplength`` de ``72`` a ``0``
+
+- ¡No escriba mensajes HTML! Acuda a la ventana principal
+ :menuselection:`Main Menu-->Account Settings-->youracc@server.something-->Composition & Addressing`!
+ Ahí puede deshabilitar la opción "Compose messages in HTML format".
+
+- ¡Abra mensajes solo como texto sin formato! Acuda a la ventana principal
+ :menuselection:`Main Menu-->View-->Message Body As-->Plain Text`!
+
+TkRat (GUI)
+***********
+
+Funciona. Utilice "Insert file..." o un editor externo.
+
+Gmail (Web GUI)
+***************
+
+No funciona para enviar parches.
+
+El cliente web de Gmail convierte las tabulaciones en espacios automáticamente.
+
+Al mismo tiempo, envuelve líneas cada 78 caracteres con saltos de línea de
+estilo CRLF aunque el problema de tab2space se puede resolver con un editor
+externo.
+
+Otro problema es que Gmail codificará en base64 cualquier mensaje que tenga
+un carácter no ASCII. Eso incluye cosas como nombres europeos.
diff --git a/Documentation/translations/sp_SP/process/embargoed-hardware-issues.rst b/Documentation/translations/sp_SP/process/embargoed-hardware-issues.rst
new file mode 100644
index 000000000000..c261b428b3f0
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/embargoed-hardware-issues.rst
@@ -0,0 +1,341 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-sp.rst
+
+:Original: Documentation/process/embargoed-hardware-issues.rst
+:Translator: Avadhut Naik <avadhut.naik@amd.com>
+
+Problemas de hardware embargados
+================================
+
+Alcance
+-------
+
+Los problemas de hardware que resultan en problemas de seguridad son una
+categoría diferente de errores de seguridad que los errores de software
+puro que solo afectan al kernel de Linux.
+
+Los problemas de hardware como Meltdown, Spectre, L1TF, etc. deben
+tratarse de manera diferente porque usualmente afectan a todos los
+sistemas operativos (“OS”) y, por lo tanto, necesitan coordinación entre
+vendedores diferentes de OS, distribuciones, vendedores de hardware y
+otras partes. Para algunos de los problemas, las mitigaciones de software
+pueden depender de actualizaciones de microcódigo o firmware, los cuales
+necesitan una coordinación adicional.
+
+.. _Contacto:
+
+Contacto
+--------
+
+El equipo de seguridad de hardware del kernel de Linux es separado del
+equipo regular de seguridad del kernel de Linux.
+
+El equipo solo maneja la coordinación de los problemas de seguridad de
+hardware embargados. Los informes de errores de seguridad de software puro
+en el kernel de Linux no son manejados por este equipo y el "reportero"
+(quien informa del error) será guiado a contactar el equipo de seguridad
+del kernel de Linux (:doc:`errores de seguridad <security-bugs>`) en su
+lugar.
+
+El equipo puede contactar por correo electrónico en
+<hardware-security@kernel.org>. Esta es una lista privada de oficiales de
+seguridad que lo ayudarán a coordinar un problema de acuerdo con nuestro
+proceso documentado.
+
+La lista esta encriptada y el correo electrónico a la lista puede ser
+enviado por PGP o S/MIME encriptado y debe estar firmado con la llave de
+PGP del reportero o el certificado de S/MIME. La llave de PGP y el
+certificado de S/MIME de la lista están disponibles en las siguientes
+URLs:
+
+ - PGP: https://www.kernel.org/static/files/hardware-security.asc
+ - S/MIME: https://www.kernel.org/static/files/hardware-security.crt
+
+Si bien los problemas de seguridad del hardware a menudo son manejados por
+el vendedor de hardware afectado, damos la bienvenida al contacto de
+investigadores o individuos que hayan identificado una posible falla de
+hardware.
+
+Oficiales de seguridad de hardware
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+El equipo actual de oficiales de seguridad de hardware:
+
+ - Linus Torvalds (Linux Foundation Fellow)
+ - Greg Kroah-Hartman (Linux Foundation Fellow)
+ - Thomas Gleixner (Linux Foundation Fellow)
+
+Operación de listas de correo
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Las listas de correo encriptadas que se utilizan en nuestro proceso están
+alojados en la infraestructura de IT de la Fundación Linux. Al proporcionar
+este servicio, los miembros del personal de operaciones de IT de la
+Fundación Linux técnicamente tienen la capacidad de acceder a la
+información embargada, pero están obligados a la confidencialidad por su
+contrato de trabajo. El personal de IT de la Fundación Linux también es
+responsable para operar y administrar el resto de la infraestructura de
+kernel.org.
+
+El actual director de infraestructura de proyecto de IT de la Fundación
+Linux es Konstantin Ryabitsev.
+
+Acuerdos de no divulgación
+--------------------------
+
+El equipo de seguridad de hardware del kernel de Linux no es un organismo
+formal y, por lo tanto, no puede firmar cualquier acuerdo de no
+divulgación. La comunidad del kernel es consciente de la naturaleza
+delicada de tales problemas y ofrece un Memorando de Entendimiento en su
+lugar.
+
+Memorando de Entendimiento
+--------------------------
+
+La comunidad del kernel de Linux tiene una comprensión profunda del
+requisito de mantener los problemas de seguridad de hardware bajo embargo
+para la coordinación entre diferentes vendedores de OS, distribuidores,
+vendedores de hardware y otras partes.
+
+La comunidad del kernel de Linux ha manejado con éxito los problemas de
+seguridad del hardware en el pasado y tiene los mecanismos necesarios para
+permitir el desarrollo compatible con la comunidad bajo restricciones de
+embargo.
+
+La comunidad del kernel de Linux tiene un equipo de seguridad de hardware
+dedicado para el contacto inicial, el cual supervisa el proceso de manejo
+de tales problemas bajo las reglas de embargo.
+
+El equipo de seguridad de hardware identifica a los desarrolladores
+(expertos en dominio) que formarán el equipo de respuesta inicial para un
+problema en particular. El equipo de respuesta inicial puede involucrar
+más desarrolladores (expertos en dominio) para abordar el problema de la
+mejor manera técnica.
+
+Todos los desarrolladores involucrados se comprometen a adherirse a las
+reglas del embargo y a mantener confidencial la información recibida. La
+violación de la promesa conducirá a la exclusión inmediata del problema
+actual y la eliminación de todas las listas de correo relacionadas.
+Además, el equipo de seguridad de hardware también excluirá al
+delincuente de problemas futuros. El impacto de esta consecuencia es un
+elemento de disuasión altamente efectivo en nuestra comunidad. En caso de
+que ocurra una violación, el equipo de seguridad de hardware informará a
+las partes involucradas inmediatamente. Si usted o alguien tiene
+conocimiento de una posible violación, por favor, infórmelo inmediatamente
+a los oficiales de seguridad de hardware.
+
+Proceso
+^^^^^^^
+
+Debido a la naturaleza distribuida globalmente del desarrollo del kernel
+de Linux, las reuniones cara a cara hacen imposible abordar los
+problemas de seguridad del hardware. Las conferencias telefónicas son
+difíciles de coordinar debido a las zonas horarias y otros factores y
+solo deben usarse cuando sea absolutamente necesario. El correo
+electrónico encriptado ha demostrado ser el método de comunicación más
+efectivo y seguro para estos tipos de problemas.
+
+Inicio de la divulgación
+""""""""""""""""""""""""
+
+La divulgación comienza contactado al equipo de seguridad de hardware del
+kernel de Linux por correo electrónico. Este contacto inicial debe
+contener una descripción del problema y una lista de cualquier hardware
+afectado conocido. Si su organización fabrica o distribuye el hardware
+afectado, le animamos a considerar también que otro hardware podría estar
+afectado.
+
+El equipo de seguridad de hardware proporcionará una lista de correo
+encriptada específica para el incidente que se utilizará para la discusión
+inicial con el reportero, la divulgación adicional y la coordinación.
+
+El equipo de seguridad de hardware proporcionará a la parte reveladora una
+lista de desarrolladores (expertos de dominios) a quienes se debe informar
+inicialmente sobre el problema después de confirmar con los
+desarrolladores que se adherirán a este Memorando de Entendimiento y al
+proceso documentado. Estos desarrolladores forman el equipo de respuesta
+inicial y serán responsables de manejar el problema después del contacto
+inicial. El equipo de seguridad de hardware apoyará al equipo de
+respuesta, pero no necesariamente involucrandose en el proceso de desarrollo
+de mitigación.
+
+Si bien los desarrolladores individuales pueden estar cubiertos por un
+acuerdo de no divulgación a través de su empleador, no pueden firmar
+acuerdos individuales de no divulgación en su papel de desarrolladores
+del kernel de Linux. Sin embargo, aceptarán adherirse a este proceso
+documentado y al Memorando de Entendimiento.
+
+La parte reveladora debe proporcionar una lista de contactos para todas
+las demás entidades ya que han sido, o deberían ser, informadas sobre el
+problema. Esto sirve para varios propósitos:
+
+ - La lista de entidades divulgadas permite la comunicación en toda la
+ industria, por ejemplo, otros vendedores de OS, vendedores de HW, etc.
+
+ - Las entidades divulgadas pueden ser contactadas para nombrar a expertos
+ que deben participar en el desarrollo de la mitigación.
+
+ - Si un experto que se requiere para manejar un problema es empleado por
+ una entidad cotizada o un miembro de una entidad cotizada, los equipos
+ de respuesta pueden solicitar la divulgación de ese experto a esa
+ entidad. Esto asegura que el experto también forme parte del equipo de
+ respuesta de la entidad.
+
+Divulgación
+"""""""""""
+
+La parte reveladora proporcionará información detallada al equipo de
+respuesta inicial a través de la lista de correo encriptada especifica.
+
+Según nuestra experiencia, la documentación técnica de estos problemas
+suele ser un punto de partida suficiente y es mejor hacer aclaraciones
+técnicas adicionales a través del correo electrónico.
+
+Desarrollo de la mitigación
+"""""""""""""""""""""""""""
+
+El equipo de respuesta inicial configura una lista de correo encriptada o
+reutiliza una existente si es apropiada.
+
+El uso de una lista de correo está cerca del proceso normal de desarrollo
+de Linux y se ha utilizado con éxito en el desarrollo de mitigación para
+varios problemas de seguridad de hardware en el pasado.
+
+La lista de correo funciona en la misma manera que el desarrollo normal de
+Linux. Los parches se publican, discuten y revisan y, si se acuerda, se
+aplican a un repositorio git no público al que solo pueden acceder los
+desarrolladores participantes a través de una conexión segura. El
+repositorio contiene la rama principal de desarrollo en comparación con
+el kernel principal y las ramas backport para versiones estables del
+kernel según sea necesario.
+
+El equipo de respuesta inicial identificará a más expertos de la
+comunidad de desarrolladores del kernel de Linux según sea necesario. La
+incorporación de expertos puede ocurrir en cualquier momento del proceso
+de desarrollo y debe manejarse de manera oportuna.
+
+Si un experto es empleado por o es miembro de una entidad en la lista de
+divulgación proporcionada por la parte reveladora, entonces se solicitará
+la participación de la entidad pertinente.
+
+Si no es así, entonces se informará a la parte reveladora sobre la
+participación de los expertos. Los expertos están cubiertos por el
+Memorando de Entendimiento y se solicita a la parte reveladora que
+reconozca la participación. En caso de que la parte reveladora tenga una
+razón convincente para objetar, entonces esta objeción debe plantearse
+dentro de los cinco días laborables y resolverse con el equipo de
+incidente inmediatamente. Si la parte reveladora no reacciona dentro de
+los cinco días laborables, esto se toma como un reconocimiento silencioso.
+
+Después del reconocimiento o la resolución de una objeción, el experto es
+revelado por el equipo de incidente y se incorpora al proceso de
+desarrollo.
+
+Lanzamiento coordinado
+""""""""""""""""""""""
+
+Las partes involucradas negociarán la fecha y la hora en la que termina el
+embargo. En ese momento, las mitigaciones preparadas se integran en los
+árboles de kernel relevantes y se publican.
+
+Si bien entendemos que los problemas de seguridad del hardware requieren
+un tiempo de embargo coordinado, el tiempo de embargo debe limitarse al
+tiempo mínimo que se requiere para que todas las partes involucradas
+desarrollen, prueben y preparen las mitigaciones. Extender el tiempo de
+embargo artificialmente para cumplir con las fechas de discusión de la
+conferencia u otras razones no técnicas está creando más trabajo y carga
+para los desarrolladores y los equipos de respuesta involucrados, ya que
+los parches necesitan mantenerse actualizados para seguir el desarrollo en
+curso del kernel upstream, lo cual podría crear cambios conflictivos.
+
+Asignación de CVE
+"""""""""""""""""
+
+Ni el equipo de seguridad de hardware ni el equipo de respuesta inicial
+asignan CVEs, ni se requieren para el proceso de desarrollo. Si los CVEs
+son proporcionados por la parte reveladora, pueden usarse con fines de
+documentación.
+
+Embajadores del proceso
+-----------------------
+
+Para obtener asistencia con este proceso, hemos establecido embajadores
+en varias organizaciones, que pueden responder preguntas o proporcionar
+orientación sobre el proceso de reporte y el manejo posterior. Los
+embajadores no están involucrados en la divulgación de un problema en
+particular, a menos que lo solicite un equipo de respuesta o una parte
+revelada involucrada. La lista de embajadores actuales:
+
+ ============= ========================================================
+ AMD Tom Lendacky <thomas.lendacky@amd.com>
+ Ampere Darren Hart <darren@os.amperecomputing.com>
+ ARM Catalin Marinas <catalin.marinas@arm.com>
+ IBM Power Anton Blanchard <anton@linux.ibm.com>
+ IBM Z Christian Borntraeger <borntraeger@de.ibm.com>
+ Intel Tony Luck <tony.luck@intel.com>
+ Qualcomm Trilok Soni <tsoni@codeaurora.org>
+ Samsung Javier González <javier.gonz@samsung.com>
+
+ Microsoft James Morris <jamorris@linux.microsoft.com>
+ Xen Andrew Cooper <andrew.cooper3@citrix.com>
+
+ Canonical John Johansen <john.johansen@canonical.com>
+ Debian Ben Hutchings <ben@decadent.org.uk>
+ Oracle Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+ Red Hat Josh Poimboeuf <jpoimboe@redhat.com>
+ SUSE Jiri Kosina <jkosina@suse.cz>
+
+ Google Kees Cook <keescook@chromium.org>
+
+ LLVM Nick Desaulniers <ndesaulniers@google.com>
+ ============= ========================================================
+
+Si quiere que su organización se añada a la lista de embajadores, por
+favor póngase en contacto con el equipo de seguridad de hardware. El
+embajador nominado tiene que entender y apoyar nuestro proceso
+completamente y está idealmente bien conectado en la comunidad del kernel
+de Linux.
+
+Listas de correo encriptadas
+----------------------------
+
+Usamos listas de correo encriptadas para la comunicación. El principio de
+funcionamiento de estas listas es que el correo electrónico enviado a la
+lista se encripta con la llave PGP de la lista o con el certificado S/MIME
+de la lista. El software de lista de correo descifra el correo electrónico
+y lo vuelve a encriptar individualmente para cada suscriptor con la llave
+PGP del suscriptor o el certificado S/MIME. Los detalles sobre el software
+de la lista de correo y la configuración que se usa para asegurar la
+seguridad de las listas y la protección de los datos se pueden encontrar
+aquí: https://korg.wiki.kernel.org/userdoc/remail.
+
+Llaves de lista
+^^^^^^^^^^^^^^^
+
+Para el contacto inicial, consulte :ref:`Contacto`. Para las listas de
+correo especificas de incidentes, la llave y el certificado S/MIME se
+envían a los suscriptores por correo electrónico desde la lista
+especifica.
+
+Suscripción a listas específicas de incidentes
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+La suscripción es manejada por los equipos de respuesta. Las partes
+reveladas que quieren participar en la comunicación envían una lista de
+suscriptores potenciales al equipo de respuesta para que el equipo de
+respuesta pueda validar las solicitudes de suscripción.
+
+Cada suscriptor necesita enviar una solicitud de suscripción al equipo de
+respuesta por correo electrónico. El correo electrónico debe estar firmado
+con la llave PGP del suscriptor o el certificado S/MIME. Si se usa una
+llave PGP, debe estar disponible desde un servidor de llave publica y esta
+idealmente conectada a la red de confianza PGP del kernel de Linux. Véase
+también: https://www.kernel.org/signature.html.
+
+El equipo de respuesta verifica que la solicitud del suscriptor sea válida
+y añade al suscriptor a la lista. Después de la suscripción, el suscriptor
+recibirá un correo electrónico de la lista que está firmado con la llave
+PGP de la lista o el certificado S/MIME de la lista. El cliente de correo
+electrónico del suscriptor puede extraer la llave PGP o el certificado
+S/MIME de la firma, de modo que el suscriptor pueda enviar correo
+electrónico encriptado a la lista.
diff --git a/Documentation/translations/sp_SP/process/handling-regressions.rst b/Documentation/translations/sp_SP/process/handling-regressions.rst
new file mode 100644
index 000000000000..aa0988985c55
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/handling-regressions.rst
@@ -0,0 +1,797 @@
+.. include:: ../disclaimer-sp.rst
+
+:Translator: Sergio González Collado <sergio.collado@gmail.com>
+
+.. _sp_handling_regressions:
+
+Gestión de regresiones
+++++++++++++++++++++++
+
+*No causamos regresiones* -- este documento describe la que es la "primera
+regla del desarrollo del kernel de Linux" y que implica en la práctica para
+los desarrolladores. Y complementa la documentación:
+Documentation/admin-guide/reporting-regressions.rst, que cubre el tema
+desde el punto de vista de un usuario; si nunca ha leído ese texto, realice
+al menos una lectura rápida del mismo antes de continuar.
+
+Las partes importantes (el "TL;DR")
+===================================
+
+#. Asegúrese de que los suscriptores a la lista `regression mailing list
+ <https://lore.kernel.org/regressions/>`_ (regressions@lists.linux.dev)
+ son conocedores con rapidez de cualquier nuevo informe de regresión:
+
+ * Cuando se reciba un correo que no incluyó a la lista, inclúyalo en la
+ conversación de los correos, mandando un breve "Reply-all" con la
+ lista en CCed.
+
+ * Mande o redirija cualquier informe originado en los gestores de bugs
+ a la lista.
+
+#. Haga que el bot del kernel de Linux "regzbot" realice el seguimiento del
+ incidente (esto es opcional, pero recomendado).
+
+ * Para reportes enviados por correo, verificar si contiene alguna línea
+ como ``#regzbot introduced v5.13..v5.14-rc1``. Si no, mandar una
+ respuesta (con la lista de regresiones en CC) que contenga un párrafo
+ como el siguiente, lo que le indica a regzbot cuando empezó a suceder
+ el incidente::
+
+ #regzbot ^introduced 1f2e3d4c5b6a
+
+ * Cuando se mandan informes desde un gestor de incidentes a la lista de
+ regresiones(ver más arriba), incluir un párrafo como el siguiente::
+
+ #regzbot introduced: v5.13..v5.14-rc1
+ #regzbot from: Some N. Ice Human <some.human@example.com>
+ #regzbot monitor: http://some.bugtracker.example.com/ticket?id=123456789
+
+#. Cuando se manden correcciones para las regresiones, añadir etiquetas
+ "Link:" a la descripción, apuntado a todos los sitios donde se informó
+ del incidente, como se indica en el documento:
+ Documentation/process/submitting-patches.rst y
+ :ref:`Documentation/process/5.Posting.rst <development_posting>`.
+
+#. Intente arreglar las regresiones rápidamente una vez la causa haya sido
+ identificada; las correcciones para la mayor parte de las regresiones
+ deberían ser integradas en menos de dos semanas, pero algunas pueden
+ resolverse en dos o tres días.
+
+Detalles importantes para desarrolladores en la regresiones de kernel de Linux
+==============================================================================
+
+Puntos básicos importantes más en detalle
+-----------------------------------------
+
+Qué hacer cuando se recibe un aviso de regresión.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Asegúrese de que el programa de gestión de regresiones del kernel de Linux
+y los subscritos a la lista de correo `regression mailing list
+<https://lore.kernel.org/regressions/>`_ (regressions@lists.linux.dev) son
+conocedores de cualquier nuevo informe de regresión:
+
+ * Cuando se recibe un informe por email que no tiene en CC la lista,
+ inmediatamente meterla en el la cadena de emails mandado al menos un
+ breve "Reply-all" con la lista en CC; Intentar asegurar que la lista es
+ añadida en CC de nuevo en caso de que alguna respuesta la omita de la
+ lista.
+
+ * Si un informe enviado a un gestor de defectos, llega a su correo,
+ reenvíelo o redirijalo a la lista. Considere verificar los archivos de
+ la lista de antemano, si la persona que lo ha informado, lo ha enviado
+ anteriormente, como se indica en:
+ Documentation/admin-guide/reporting-issues.rst.
+
+Cuando se realice cualquiera de las acciones anteriores, considere
+inmediatamente iniciar el seguimiento de la regresión con "regzbot" el
+gestor de regresiones del kernel de Linux.
+
+ * Para los informes enviados por email, verificar si se ha incluido un
+ comando a "regzbot", como ``#regzbot introduced 1f2e3d4c5b6a``. Si no es
+ así, envíe una respuesta (con la lista de regresiones en CC) con un
+ párrafo como el siguiente::
+
+ #regzbot ^introduced: v5.13..v5.14-rc1
+
+ Esto indica a regzbot el rango de versiones en el cual es defecto
+ comenzó a suceder; Puede especificar un rango usando los identificadores
+ de los commits así como un único commit, en caso en el que el informante
+ haya identificado el commit causante con 'bisect'.
+
+ Tenga en cuenta que el acento circunflejo (^) antes de "introduced":
+ Esto indica a regzbot, que debe tratar el email padre (el que ha sido
+ respondido) como el informeinicial para la regresión que quiere ser
+ seguida. Esto es importante, ya que regzbot buscará más tarde parches
+ con etiquetas "Link:" que apunten al al informe de losarchivos de
+ lore.kernel.org.
+
+ * Cuando mande informes de regresiones a un gestor de defectos, incluya un
+ párrafo con los siguientes comandos a regzbot::
+
+ #regzbot introduced: 1f2e3d4c5b6a
+ #regzbot from: Some N. Ice Human <some.human@example.com>
+ #regzbot monitor: http://some.bugtracker.example.com/ticket?id=123456789
+
+ Regzbot asociará automáticamente parches con el informe que contengan
+ las etiquetas "Link:" apuntando a su email o el ticket indicado.
+
+Qué es importante cuando se corrigen regresiones
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+No se necesita hacer nada especial cuando se mandan las correcciones para
+las regresiones únicamente recordar lo que se explica en los documentos:
+Documentation/process/submitting-patches.rst,
+:ref:`Documentation/process/5.Posting.rst <development_posting>`, y
+Documentation/process/stable-kernel-rules.rst
+
+ * Apunte a todos los lugares donde el incidente se reportó usando la
+ etiqueta "Link:" ::
+
+ Link: https://lore.kernel.org/r/30th.anniversary.repost@klaava.Helsinki.FI/
+ Link: https://bugzilla.kernel.org/show_bug.cgi?id=1234567890
+
+ * Añada la etiqueta "Fixes:" para indicar el commit causante de la
+ regresión.
+
+ * Si el culpable ha sido "mergeado" en un ciclo de desarrollo anterior,
+ marque explícitamente el fix para retro-importarlo usando la etiqueta
+ ``Cc: stable@vger.kernel.org`` tag.
+
+Todo esto se espera y es importante en una regresión, ya que estas
+etiquetas son de gran valor para todos (incluido usted) que pueda estar
+mirando en ese incidente semanas, meses o años después. Estas etiquetas son
+también cruciales para las herramientas y scripts usados por otros
+desarrolladores del kernel o distribuciones de Linux; una de esas
+herramientas es regzbot, el cual depende mucho de las etiquetas "Link:"
+para asociar los informes por regresiones con los cambios que las
+resuelven.
+
+
+Priorización del trabajo en arreglar regresiones
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Al final, los desarrolladores deberían hacer lo posible para evitar a los
+usuarios situaciones donde una regresión les deje solo tres opciones:
+
+ * Ejecutar el kernel con una regresión que afecta seriamente al uso.
+
+ * Cambiar a un kernel nuevo o mas antiguo -- rebajarse a una versión
+ soportada del kernel que no tenga las funcionalidades requeridas.
+
+ * Continuar ejecutando una versión desfasada y potencialmente insegura del
+ kernel por más de dos semanas después de que el causante de una regresión
+ fuese identificado.
+
+Cómo se ejecuta esto depende mucho de la situación. A continuación se
+presentan unas reglas generales, en orden de importancia:
+
+ * Priorice el trabajo en la gestión de los informes de la regresión y
+ arreglar la regresión por encima de cualquier otro trabajo en el kernel
+ de Linux, a menos que lo último afecte profundamente a efectos de
+ seguridad, o cause errores en los que haya pérdida o daño de datos.
+
+ * Considere siempre revertir los commits responsables y re-aplicarlos
+ después, junto con las correcciones necesarias, ya que esto puede la
+ forma menos peligrosa y más rápida de arreglar la regresión.
+
+ * Los desarrolladores deberían gestionar la regresión en todos los kernels
+ soportados de la serie, pero son libres de delegar el trabajo al equipo
+ permanente el incidente no hubiese ocurrido en la línea principal.
+
+ * Intente resolver cualquier regresión que apareciera en el ciclo de
+ desarrollo antes de que este acabe. Si se teme que una corrección
+ pudiera ser demasiado arriesgada para aplicarla días antes de una
+ liberación de la línea principal de desarrollo, dejar decidir a Linus:
+ mande la corrección a él de forma separada, tan pronto como sea posible
+ con una explicación de la situación. El podrá decidir, y posponer la
+ liberación si fuese necesario, por ejemplo si aparecieran múltiples
+ cambios como ese.
+
+ * Gestione las regresiones en la rama estable, de largo término, o la
+ propia rama principal de las versiones, con más urgencia que la
+ regresiones en las preliberaciones. Esto cambia después de la liberación
+ de la quinta pre-liberación, aka "-rc5": la rama principal entonces se
+ vuelve más importante, asegurar que todas las mejoras y correcciones son
+ idealmente testeados juntos por al menos una semana antes de que Linux
+ libere la nueva versión en la rama principal.
+
+ * Intente arreglar regresiones en un intervalo de una semana después de
+ que se ha identificado el responsable, si el incidente fue introducido
+ en alguno de los siguientes casos:
+
+ * una versión estable/largo-plazo reciente
+
+ * en el último ciclo de desarrollo de la rama principal
+
+ En el último caso (por ejemplo v5.14), intentar gestionar las
+ regresiones incluso más rápido, si la versión estable precedente (v5.13)
+ ha de ser abandonada pronto o ya se ha etiquetado como de final de vida
+ (EOL de las siglas en inglés End-of-Life) -- esto sucede usualmente
+ sobre tres o cuatro semanas después de una liberación de una versión en
+ la rama principal.
+
+ * Intente arreglar cualquier otra regresión en un periodo de dos semanas
+ después de que el culpable haya sido identificado. Dos o tres semanas
+ adicionales son aceptables para regresiones de rendimiento y otros
+ incidentes que son molestos, pero no bloquean a nadie la ejecución de
+ Linux (a menos que se un incidente en el ciclo de desarrollo actual, en
+ ese caso se debería gestionar antes de la liberación de la versión).
+ Unas semanas son aceptables si la regresión únicamente puede ser
+ arreglada con un cambio arriesgado y al mismo tiempo únicamente afecta a
+ unos pocos usuarios; también está bien si se usa tanto tiempo como fuera
+ necesario si la regresión está presente en la segunda versión más nueva
+ de largo plazo del kernel.
+
+Nota: Los intervalos de tiempo mencionados anteriormente para la resolución
+de las regresiones, incluyen la verificación de esta, revisión e inclusión
+en la rama principal, idealmente con la corrección incluida en la rama
+"linux-next" al menos brevemente. Esto conllevará retrasos que también se
+tienen tener en cuenta.
+
+Se espera que los maintainers de los subsistemas, ayuden en conseguir esos
+tiempos, haciendo revisiones con prontitud y gestionando con rapidez los
+parches aceptados. Esto puede resultar en tener que mandar peticiones de
+git-pull antes o de forma más frecuente que lo normal; dependiendo del
+arreglo, podría incluso ser aceptable saltarse la verificación en
+linux-next. Especialmente para las correcciones en las ramas de los kernels
+estable y de largo plazo necesitan ser gestionadas rápidamente, y las
+correcciones necesitan ser incluidas en la rama principal antes de que
+puedan ser incluidas posteriormente a las series precedentes.
+
+
+Más aspectos sobre regresiones que los desarrolladores deben saber
+------------------------------------------------------------------
+
+Cómo tratar con cambios donde se sabe que hay riesgo de regresión
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Evalué cómo de grande es el riesgo de una regresión, por ejemplo realizando
+una búsqueda en las distribuciones de linux y en Git forges. Considere
+también preguntar a otros desarrolladores o proyectos que pudieran ser
+afectados para evaluar o incluso testear el cambio propuesto; si
+apareciesen problemas, quizás se pudiera encontrar una solución aceptable
+para todos.
+
+Si al final, el riesgo de la regresión parece ser relativamente pequeño,
+entonces adelante con el cambio, pero siempre informe a todas las partes
+involucradas del posible riesgo. Por tanto, asegúrese de que la descripción
+del parche, se hace explícito este hecho. Una vez el cambio ha sido
+integrado, informe al gestor de regresiones de Linux y a las listas de
+correo de regresiones sobre el riesgo, de manera que cualquiera que tenga
+el cambio en el radar, en el caso de que aparezcan reportes. Dependiendo
+del riesgo, quizás se quiera preguntar al mantenedor del subsistema, que
+mencione el hecho en su línea principal de desarrollo.
+
+¿Qué más hay que saber sobre regresiones?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Repase la documentación: Documentation/admin-guide/reporting-regressions.rst,
+esta cubre otros aspectos a tener a en cuenta y conocer:
+
+ * la finalidad de la "regla de no regresión"
+
+ * qué incidencias no se califican como regresión
+
+ * quién es el responsable de identificar la causa raíz de una regresión
+
+ * cómo gestionar situaciones difíciles, como por ejemplo cuando una
+ regresión es causada por una corrección de seguridad o cuando una
+ regresión causa otra regresión
+
+A quién preguntar por consejo cuando se trata de regresiones
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Mande un email a la lista de correo de regresiones
+(regressions@lists.linux.dev) y CC al seguidor de regresiones del kernel de
+Linux (regressions@leemhuis.info); Si el incidente pudiera ser mejor
+gestionarlo en privado, puede omitirse la lista.
+
+
+Más sobre la gestión de regresiones con regzbot
+-----------------------------------------------
+
+¿Por qué el kernel de Linux tiene un gestor de regresiones, y por qué se usa regzbot?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Reglas como "no regresiones" necesitan asegurar que se cumplen, de otro
+modo se romperían accidentalmente o a propósito. La historia ha mostrado
+que esto es verdad también para el kernel de Linux. Esto es por lo que
+Thorsten Leemhuis se ofreció como voluntario para dar una solución a esto,
+con el gestor de regresiones del kernel de Linux. A nadie se le paga por
+hacer esto, y esa es la razón por la gestión de regresiones es un servicio
+con el "mejor esfuerzo".
+
+Intentos iniciales de gestionar manualmente las regresiones han demostrado
+que es una tarea extenuante y frustrante, y por esa razón se dejaron de
+hacer después de un tiempo. Para evitar que volviese a suceder esto,
+Thorsten desarrollo regbot para facilitar el trabajo, con el objetivo a
+largo plazo de automatizar la gestión de regresiones tanto como fuese
+posible para cualquiera que estuviese involucrado.
+
+¿Cómo funciona el seguimiento de regresiones con regzbot?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+El bot monitoriza las respuestas de los informes de las regresiones
+identificadas. Adicionalmente mira si se han publicado o enviado parches
+que hagan referencia a esos informes con la etiqueta: "Link:"; respuestas a
+esos parches también se siguen. Combinando esta información, también
+proporciona una buena imagen del estado actual del proceso de corrección.
+
+Regzbot intenta hacer todo este trabajo con tan poco retraso como sea
+posible tanto para la gente que lo reporta, como para los desarrolladores.
+De hecho, solo los informantes son requeridos para una tarea adicional:
+necesitan informar a regzbot con el comando ``#regzbot introduced``
+indicado anteriormente; si no hacen esto, alguien más puede hacerlo usando
+``#regzbot ^introduced``.
+
+Para los desarrolladores normalmente no hay un trabajo adicional que
+realizar, únicamente necesitan asegurarse una cosa, que ya se hacía mucho
+antes de que regzbot apareciera: añadir las etiquetas "Link:" a la
+descripción del parche apuntando a todos los informes sobre el error
+corregido.
+
+¿Tengo que usar regzbot?
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Hacerlo es por el bien de todo el mundo, tanto los mantenedores del kernel,
+como Linus Torvalds dependen parcialmente en regzbot para seguir su trabajo
+-- por ejemplo cuando deciden liberar una nueva versión o ampliar la fase de
+desarrollo. Para esto necesitan conocer todas las regresiones que están sin
+corregir; para esto, es conocido que Linux mira los informes semanales que
+manda regzbot.
+
+¿He de informar a regzbot cada regresión que encuentre?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Idealmente, sí: todos somos humanos y olvidamos fácilmente los problemas
+cuando algo más importante aparece inesperadamente -- por ejemplo un
+problema mayor en el kernel de Linux o algo en la vida real que nos mantenga
+alejados de los teclados por un tiempo. Por eso es mejor informar a regzbot
+sobre cada regresión, excepto cuando inmediatamente escribimos un parche y
+los mandamos al árbol de desarrollo en el que se integran habitualmente a
+la serie del kernel.
+
+¿Cómo ver qué regresiones esta siguiendo regbot actualmente?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Verifique el `interfaz web de regzbot <https://linux-regtracking.leemhuis.info/regzbot/>`_
+para ver la última información; o `busque el último informe de regresiones
+<https://lore.kernel.org/lkml/?q=%22Linux+regressions+report%22+f%3Aregzbot>`_,
+el cual suele ser enviado por regzbot una vez a la semana el domingo por la
+noche (UTC), lo cual es unas horas antes de que Linus normalmente anuncie
+las "(pre-)releases".
+
+¿Qué sitios supervisa regzbot?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Regzbot supervisa las listas de correo más importantes de Linux, como
+también las de los repositorios linux-next, mainline y stable/longterm.
+
+
+¿Qué tipos de incidentes han de ser monitorizados por regzbot?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+El bot debe hacer seguimiento de las regresiones, y por tanto por favor,
+no involucre a regzbot para incidencias normales. Pero es correcto para
+el gestor de incidencias de kernel de Linux, monitorizar incidentes
+graves, como informes sobre cuelgues, corrupción de datos o errores
+internos (Panic, Oops, BUG(), warning, ...).
+
+
+¿Puedo añadir una regresión detectada por un sistema de CI al seguimiento de regzbot?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Siéntase libre de hacerlo, si la regresión en concreto puede tener un
+impacto en casos de uso prácticos y por tanto ser detectado por los usuarios;
+Así, por favor no involucre a regzbot en regresiones teóricas que
+difícilmente pudieran manifestarse en un uso real.
+
+¿Cómo interactuar con regzbot?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Usando el comando 'regzbot' en una respuesta directa o indirecta al correo
+con el informe de regresión. Ese comando necesita estar en su propio
+párrafo (debe estar separado del resto del texto usando líneas en blanco):
+
+Por ejemplo ``#regzbot introduced <version or commit>``, que hace que regzbot
+considere el correo como un informe de regressión que se ha de añadir al
+seguimiento, como se ha descrito anteriormente; ``#regzbot ^introduced <version or commit>``
+es otro ejemplo del comando, el cual indica a regzbot que considere el email
+anterior como el informe de una regresión que se ha de comenzar a monitorizar.
+
+Una vez uno de esos dos comandos se ha utilizado, se pueden usar otros
+comandos regzbot en respuestas directas o indirectas al informe. Puede
+escribirlos debajo de uno de los comandos anteriormente usados o en las
+respuestas al correo en el que se uso como respuesta a ese correo:
+
+ * Definir o actualizar el título::
+
+ #regzbot title: foo
+
+ * Monitorizar una discusión o un tiquet de bugzilla.kernel.org donde
+ aspectos adicionales del incidente o de la corrección se están
+ comentando -- por ejemplo presentar un parche que corrige la regresión::
+
+ #regzbot monitor: https://lore.kernel.org/all/30th.anniversary.repost@klaava.Helsinki.FI/
+
+ Monitorizar solamente funciona para lore.kernel.org y bugzilla.kernel.org;
+ regzbot considerará todos los mensajes en ese hilo o el tiquet como
+ relacionados al proceso de corrección.
+
+ * Indicar a un lugar donde más detalles de interés, como un mensaje en una
+ lista de correo o un tiquet en un gestor de incidencias que pueden estar
+ levemente relacionados, pero con un tema diferente::
+
+ #regzbot link: https://bugzilla.kernel.org/show_bug.cgi?id=123456789
+
+ * Identificar una regresión como corregida por un commit que se ha mandado
+ aguas arriba o se ha publicado::
+
+ #regzbot fixed-by: 1f2e3d4c5d
+
+
+ * Identificar una regresión como un duplicado de otra que ya es seguida
+ por regzbot::
+
+ #regzbot dup-of: https://lore.kernel.org/all/30th.anniversary.repost@klaava.Helsinki.FI/
+
+ * Identificar una regresión como inválida::
+
+ #regzbot invalid: wasn't a regression, problem has always existed
+
+
+¿Algo más que decir sobre regzbot y sus comandos?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Hay información más detallada y actualizada sobre el bot de seguimiento de
+regresiones del kernel de Linux en: `project page <https://gitlab.com/knurd42/regzbot>`_,
+y entre otros contiene una `guia de inicio <https://gitlab.com/knurd42/regzbot/-/blob/main/docs/getting_started.md>`_
+y `documentación de referencia <https://gitlab.com/knurd42/regzbot/-/blob/main/docs/reference.md>`_
+Ambos contienen más detalles que las secciones anteriores.
+
+
+Citas de Linus sobre regresiones
+--------------------------------
+
+A continuación se encuentran unos ejemplos reales (traducidos) de como
+Linus Torvalds espera que se gestionen las regresiones:
+
+
+ * De 2017-10-26 (1/2)
+ <https://lore.kernel.org/lkml/CA+55aFwiiQYJ+YoLKCXjN_beDVfu38mg=Ggg5LFOcqHE8Qi7Zw@mail.gmail.com/>`_::
+
+ Si rompes la configuración de los espacios de usuario ESO ES UNA REGRESIÓN.
+
+ No está bien decir "pero nosotros arreglaremos la configuración del espacio
+ de usuario".
+
+ Realmente. NO ESTÁ BIEN.
+
+ [...]
+
+ La primera regla es:
+
+ - no causamos regresiones
+
+ y el corolario es que cuando una regresión pasa, lo admitimos y lo
+ arreglamos, en vez de echar la culpa al espacio de usuario.
+
+ El hecho de que aparentemente se haya negado la regresión durante
+ tres semanas, significa que lo revertiré y dejaré de integrar peticiones
+ de apparmor hasta que la gente involucrada entienda como se hace
+ el desarrollo del kernel.
+
+
+ * De `2017-10-26 (2/2)
+ <https://lore.kernel.org/lkml/CA+55aFxW7NMAMvYhkvz1UPbUTUJewRt6Yb51QAx5RtrWOwjebg@mail.gmail.com/>`_::
+
+ La gente debería sentirse libre de actualizar su kernel y simplemente
+ no preocuparse por ello.
+
+ Me niego a imponer una limitación del tipo "solo puede actualizar
+ el kernel si actualiza otro programa". Si el kernel trabaja para tí,
+ la regla es que continúe trabajando para tí.
+
+ Ha habido algunas excepciones, pero son pocas y separadas entre sí, y
+ generalmente tienen una razón fundamental para haber sucedido, que era
+ básicamente inevitable, y la gente intentó evitarlas por todos los
+ medios. Quizás no podamos mantener el hardware más, después de que han
+ pasado décadas y nadie los usacon kernel modernos. Quizás haya un
+ problema de seguridad serio con cómo hicimos las cosas, y la gente
+ depende de un modelo fundamentalmente roto. Quizás haya algún otro roto
+ fundamental, que tenga que tener una _flag_ y por razones internas y
+ fundamentales.
+
+ Y nótese que esto trata sobre *romper* los entornos de la gente.
+
+ Cambios de comportamiento pasan, y quizás no se mantengan algunas
+ funcionalidades más. Hay un número de campos en /proc/<pid>/stat que
+ se imprimen como ceros, simplemente porque ni siquiera existen ya en
+ kernel, o porque mostrarlos era un error (típica una fuga de
+ información). Pero los números se sustituyeron por ceros, así que
+ el código que se usaba para parsear esos campos todavía existe. El
+ usuario puede no ver todo lo que podía ver antes, y por eso el
+ omportamiento es claramente diferente, pero las cosas todavía
+ _funcionan_, incluso si no se puede mostrar información sensible
+ (o que no es ya importante).
+
+ Pero si algo realmente se rompe, entonces el cambio debe de arreglarse
+ o revertirse. Y se arregla en el *kernel*. No diciendo "bueno, arreglaremos
+ tu espacio de usuario". Ha sido un cambio en el kernel el que creo
+ el problema, entonces ha de ser el kernel el que lo corrija, porque
+ tenemos un modelo de "actualización". Pero no tenemos una "actualización
+ con el nuevo espacio de usuario".
+
+ Y yo seriamente me negaré a coger código de gente que no entiende y
+ honre esta sencilla regla.
+
+ Y esta regla no va a cambiar.
+
+ Y sí, me doy cuenta que el kernel es "especial" en este respecto. Y
+ estoy orgulloso de ello.
+
+ Y he visto, y puedo señalar, muchos proyectos que dicen "Tenemos que
+ romper ese caso de uso para poder hacer progresos" o "estabas basandote
+ en comportamientos no documentados, debe ser duro ser tú" o "hay una
+ forma mejor de hacer lo que quieres hacer, y tienes que cambiar a esa
+ nueva forma", y yo simplemente no pienso que eso sea aceptable fuera
+ de una fase alfa muy temprana que tenga usuarios experimentales que
+ saben a lo que se han apuntado. El kernel no ha estado en esta
+ situación en las dos últimas décadas.
+
+ Nosotros rompemos la API _dentro_ del kernel todo el tiempo. Y
+ arreglaremos los problemas internos diciendo "tú ahora necesitas
+ hacer XYZ", pero entonces es sobre la API interna del kernel y la
+ gente que hace esto entonces tendrá obviamente que arreglar todos
+ los usos de esa API del kernel. Nadie puede decir "ahora, yo he roto
+ la API que usas, y ahora tú necesitas arreglarlo". Quién rompa algo,
+ lo arregla también.
+
+ Y nosotros, simplemente, no rompemos el espacio de usuario.
+
+ * De `2020-05-21
+ <https://lore.kernel.org/all/CAHk-=wiVi7mSrsMP=fLXQrXK_UimybW=ziLOwSzFTtoXUacWVQ@mail.gmail.com/>`_::
+
+ Las reglas sobre regresiones nunca han sido sobre ningún tipo de
+ comportamiento documentado, o dónde está situado el código.
+
+ Las reglas sobre regresiones son siempre sobre "roturas en el
+ flujo de trabajo del usuario".
+
+ Los usuarios son literalmente la _única_ cosa que importa.
+
+ Argumentaciones como "no debería haber usado esto" o "ese
+ comportamiento es indefinido, es su culpa que su aplicación no
+ funcione" o "eso solía funcionar únicamente por un bug del kernel" son
+ irrelevantes.
+
+ Ahora, la realidad nunca es blanca o negra. Así hemos tenido situaciones
+ como "un serio incidente de seguridad" etc que solamente nos fuerza
+ a hacer cambios que pueden romper el espacio de usuario. Pero incluso
+ entonces la regla es que realmente no hay otras opciones para que
+ las cosas sigan funcionando.
+
+ Y obviamente, si los usuarios tardan años en darse cuenta que algo
+ se ha roto, o si hay formas adecuadas para sortear la rotura que
+ no causen muchos problemas para los usuarios (por ejemplo: "hay un
+ puñado de usuarios, y estos pueden usar la línea de comandos del
+ kernel para evitarlos"; ese tipo de casos), en esos casos se ha sido
+ un poco menos estricto.
+
+ Pero no, "eso que está documentado que está roto" (si es dado a que
+ el código estaba en preparación o porque el manual dice otra cosa) eso
+ es irrelevante. Si preparar el código es tan útil que la gente,
+ acaba usando, esto implica que básicamente es código del kernel con
+ una señal diciendo "por favor limpiar esto".
+
+ El otro lado de la moneda es que la gente que habla sobre "estabilidad
+ de las APIs" están totalmente equivocados. Las APIs tampoco importan.
+ Se puede hacer cualquier cambio que se quiera a una API ... siempre y
+ cuando nadie se de cuenta.
+
+ De nuevo, la regla de las regresiones no trata sobre la documentación,
+ tampoco sobre las APIs y tampoco sobre las fases de la Luna.
+
+ Únicamente trata sobre "hemos causado problemas al espacio de usuario que
+ antes funcionaba".
+
+ * De `2017-11-05
+ <https://lore.kernel.org/all/CA+55aFzUvbGjD8nQ-+3oiMBx14c_6zOj2n7KLN3UsJ-qsd4Dcw@mail.gmail.com/>`_::
+
+ Y nuestra regla sobre las regresiones nunca ha sido "el comportamiento
+ no cambia". Eso podría significar que nunca podríamos hacer ningún
+ cambio.
+
+ Por ejemplo, hacemos cosas como añadir una nueva gestión de
+ errores etc todo el tiempo, con lo cual a veces incluso añadimos
+ tests en el directorio de kselftest.
+
+ Así que claramente cambia el comportamiento todo el tiempo y
+ nosotros no consideramos eso una regresión per se.
+
+ La regla para regresiones para el kernel es para cuando se
+ rompe algo en el espacio de usuario. No en algún test. No en
+ "mira, antes podía hacer X, y ahora no puedo".
+
+ * De `2018-08-03
+ <https://lore.kernel.org/all/CA+55aFwWZX=CXmWDTkDGb36kf12XmTehmQjbiMPCqCRG2hi9kw@mail.gmail.com/>`_::
+
+ ESTÁS OLVIDANDO LA REGLA #1 DEL KERNEL.
+
+ No hacemos regresiones, y no hacemos regresiones porque estás 100%
+ equivocado.
+
+ Y la razón que apuntas en tú opinión es exactamente *PORQUÉ* estás
+ equivocado.
+
+ Tus "buenas razones" son honradas y pura basura.
+
+ El punto de "no hacemos regresiones" es para que la gente pueda
+ actualizar el kernel y nunca tengan que preocuparse por ello.
+
+ > El kernel tiene un bug que ha de ser arreglado
+
+ Eso es *TOTALMENTE* insustancial.
+
+ Chicos, si algo estaba roto o no, NO IMPORTA.
+
+ ¿Porqué?
+
+ Los errores pasan. Eso es un hecho de la vida. Discutir que
+ "tenemos que romper algo porque estábamos arreglando un error" es
+ una locura. Arreglamos decenas de errores cada dia, pensando que
+ "arreglando un bug" significa que podemos romper otra cosa es algo
+ que simplemente NO ES VERDAD.
+
+ Así que los bugs no son realmente relevantes para la discusión. Estos
+ suceden y se detectan, se arreglan, y no tienen nada que ver con
+ "rompemos a los usuarios".
+
+ Porque la única cosa que importa ES EL USUARIO.
+
+ ¿Cómo de complicado es eso de comprender?
+
+ Cualquier persona que use "pero no funcionaba correctamente" es
+ un argumento no tiene la razón. Con respecto al USUARIO, no era
+ erróneo - funcionaba para él/ella.
+
+ Quizás funcionaba *porque* el usuario había tenido el bug en cuenta,
+ y quizás funcionaba porque el usuario no lo había notado - de nuevo
+ no importa. Funcionaba para el usuario.
+
+ Romper el flujo del trabajo de un usuario, debido a un "bug" es la
+ PEOR razón que se pueda usar.
+
+ Es básicamente decir "He cogido algo que funcionaba, y lo he roto,
+ pero ahora es mejor". ¿No ves que un argumento como este es j*didamente
+ absurdo?
+
+ y sin usuarios, tu programa no es un programa, es una pieza de
+ código sin finalidad que puedes perfectamente tirar a la basura.
+
+ Seriamente. Esto es *porque* la regla #1 para el desarrollo del
+ kernel es "no rompemos el espacio de usuario". Porque "He arreglado
+ un error" PARA NADA ES UN ARGUMENTO si esa corrección del código
+ rompe el espacio de usuario.
+
+ si actualizamos el kernel TODO EL TIEMPO, sin actualizar ningún otro
+ programa en absoluto. Y esto es absolutamente necesario, porque
+ las dependencias son terribles.
+
+ Y esto es necesario simplemente porque yo como desarrollador del
+ kernel no actualizo al azar otras herramientas que ni siquiera me
+ importan como desarrollador del kernel, y yo quiero que mis usuarios
+ se sientan a salvo haciendo lo mismo.
+
+ Así que no. Tu regla está COMPLETAMENTE equivocada. Si no puedes
+ actualizar el kernel sin actualizar otro binario al azar, entonces
+ tenemos un problema.
+
+ * De `2021-06-05
+ <https://lore.kernel.org/all/CAHk-=wiUVqHN76YUwhkjZzwTdjMMJf_zN4+u7vEJjmEGh3recw@mail.gmail.com/>`_::
+
+ NO HAY ARGUMENTOS VÁLIDOS PARA UNA REGRESIÓN.
+
+ Honestamente, la gente de seguridad necesita entender que "no funciona"
+ no es un caso de éxito sobre seguridad. Es un caso de fallo.
+
+ Sí, "no funciona" puede ser seguro. Pero en este caso es totalmente
+ inutil.
+
+ * De `2011-05-06 (1/3)
+ <https://lore.kernel.org/all/BANLkTim9YvResB+PwRp7QTK-a5VNg2PvmQ@mail.gmail.com/>`_::
+
+ La compatibilidad de los binarios es más importante.
+
+ Y si los binarios no usan el interfaz para parsear el formato
+ (o justamente lo parsea incorrectamente - como el reciente ejemplo
+ de añadir uuid al /proc/self/mountinfo), entonces es una regresión.
+
+ Y las regresiones se revierten, a menos que haya problemas de
+ seguridad o similares que nos hagan decir "Dios mío, realmente
+ tenemos que romper las cosas".
+
+ No entiendo porqué esta simple lógica es tan difícil para algunos
+ desarrolladores del kernel. La realidad importa. Sus deseos personales
+ NO IMPORTAN NADA.
+
+ Si se crea un interface que puede usarse sin parsear la
+ descripción del interface, entonces estaḿos atascados en el interface.
+ La teoría simplemente no importa.
+
+ Podrias alludar a arreglar las herramientas, e intentar evitar los
+ errores de compatibilidad de ese modo. No hay tampoco tantos de esos.
+
+ De `2011-05-06 (2/3)
+ <https://lore.kernel.org/all/BANLkTi=KVXjKR82sqsz4gwjr+E0vtqCmvA@mail.gmail.com/>`_::
+
+ Esto claramente NO es un tracepoint interno. Por definición. Y está
+ siendo usado por powertop.
+
+ De `2011-05-06 (3/3)
+ <https://lore.kernel.org/all/BANLkTinazaXRdGovYL7rRVp+j6HbJ7pzhg@mail.gmail.com/>`_::
+
+ Tenemos programas que usan esa ABI y si eso se rompe eso es una
+ regresión.
+
+ * De `2012-07-06 <https://lore.kernel.org/all/CA+55aFwnLJ+0sjx92EGREGTWOx84wwKaraSzpTNJwPVV8edw8g@mail.gmail.com/>`_::
+
+ > Ahora esto me ha dejado preguntandome si Debian _inestable_
+ realmente califica
+ > como espacio de usuario estándar.
+
+ Oh, si el kernel rompe algún espacio de usuario estándar, eso cuenta.
+ Muchísima gente usa Debian inestable.
+
+ * De `2019-09-15
+ <https://lore.kernel.org/lkml/CAHk-=wiP4K8DRJWsCo=20hn_6054xBamGKF2kPgUzpB5aMaofA@mail.gmail.com/>`_::
+
+ Una reversión _en particular_ en el último minuto en el último commit
+ (no teniendo en cuenta el propio cambio de versión) justo antes
+ de la liberación, y aunque es bastante incómodo, quizás también es
+ instructivo.
+
+ Lo que es instructivo sobre esto es que he revertido un commit que no
+ tenía ningún error. De hecho, hacía exactamente lo que pretendía, y lo
+ hacía muy bien. De hecho lo hacía _tan_ bien que los muy mejorados
+ patrones de IO que causaba han acabado revelando una regresión observable
+ desde el espacio de usuario, debido a un error real en un componente
+ no relacionado en absoluto.
+
+ De todas maneras, los detalles actuales de esta regresión no son la
+ razón por la que señalo esto como instructivo. Es más que es un ejemplo
+ ilustrativo sobre lo que cuenta como una regresión, y lo que conlleva
+ la regla del kernel de "no regresiones". El commit que ha sido revertido
+ no cambiaba ninguna API, y no introducía ningún error nuevo en el código.
+ Pero acabó exponiendo otro problema, y como eso causaba que la
+ actualización del kernel fallara para el usuario. Así que ha sido
+ revertido.
+
+ El foco aquí, es que hemos hecho la reversión basándonos en el
+ comportamiento reportado en el espacio de usuario, no basado en
+ conceptos como "cambios de ABI" o "provocaba un error". Los mejores
+ patrones de IO que se han presentado debido al cambio únicamente han
+ expuesto un viejo error, y la gente ya dependía del benigno
+ comportamiento de ese viejo error.
+
+ Y que no haya miedo, reintroduciremos el arreglo que mejoraba los
+ patrones de IO una vez hayamos decidido cómo gestionar el hecho de
+ que hay una interacción incorrecta con un interfaz en el que la
+ gente dependía de ese comportamiento previo. Es únicamente que
+ tenemos que ver cómo gestionamos y cómo lo hacemos (no hay menos de
+ tres parches diferentes de tres desarrolladores distintos que estamos
+ evaluando, ... puede haber más por llegar). Mientras tanto, he
+ revertido lo que exponía el problema a los usuarios de esta release,
+ incluso cuando espero que el fix será reintroducido (quizás insertado
+ a posteriormente como un parche estable) una vez lleguemos a un
+ acuerdo sobre cómo se ha de exponer el error.
+
+ Lo que hay que recordar de todo el asunto no es sobre si el cambio
+ de kernel-espacio-de-usuario ABI, o la corrección de un error, o si
+ el código antiguo "en primer lugar nunca debería haber estado ahí".
+ Es sobre si algo rompe el actual flujo de trabajo del usuario.
+
+ De todas formas, esto era mi pequeña aclaración en todo este
+ tema de la regresión. Ya que es la "primera regla de la programación
+ del kernel", me ha parecido que quizás es bueno mencionarlo de
+ vez en cuando.
diff --git a/Documentation/translations/sp_SP/process/howto.rst b/Documentation/translations/sp_SP/process/howto.rst
new file mode 100644
index 000000000000..dd793c0f8574
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/howto.rst
@@ -0,0 +1,617 @@
+.. include:: ../disclaimer-sp.rst
+
+:Original: :ref:`Documentation/process/howto.rst <process_howto>`
+:Translator: Carlos Bilbao <carlos.bilbao@amd.com>
+
+.. _sp_process_howto:
+
+Cómo participar en el desarrollo del kernel de Linux
+====================================================
+
+Este documento es el principal punto de partida. Contiene instrucciones
+sobre cómo convertirse en desarrollador del kernel de Linux y explica cómo
+trabajar con el y en su desarrollo. El documento no tratará ningún aspecto
+técnico relacionado con la programación del kernel, pero le ayudará
+guiándole por el camino correcto.
+
+Si algo en este documento quedara obsoleto, envíe parches al maintainer de
+este archivo, que se encuentra en la parte superior del documento.
+
+Introducción
+------------
+¿De modo que quiere descubrir como convertirse en un/a desarrollador/a del
+kernel de Linux? Tal vez su jefe le haya dicho, "Escriba un driver de
+Linux para este dispositivo." El objetivo de este documento en enseñarle
+todo cuanto necesita para conseguir esto, describiendo el proceso por el
+que debe pasar, y con indicaciones de como trabajar con la comunidad.
+También trata de explicar las razones por las cuales la comunidad trabaja
+de la forma en que lo hace.
+
+El kernel esta principalmente escrito en C, con algunas partes que son
+dependientes de la arquitectura en ensamblador. Un buen conocimiento de C
+es necesario para desarrollar en el kernel. Lenguaje ensamblador (en
+cualquier arquitectura) no es necesario excepto que planee realizar
+desarrollo de bajo nivel para dicha arquitectura. Aunque no es un perfecto
+sustituto para una educación sólida en C y/o años de experiencia, los
+siguientes libros sirven, como mínimo, como referencia:
+
+- "The C Programming Language" de Kernighan e Ritchie [Prentice Hall]
+- "Practical C Programming" de Steve Oualline [O'Reilly]
+- "C: A Reference Manual" de Harbison and Steele [Prentice Hall]
+
+El kernel está escrito usando GNU C y la cadena de herramientas GNU. Si
+bien se adhiere al estándar ISO C89, utiliza una serie de extensiones que
+no aparecen en dicho estándar. El kernel usa un C independiente de entorno,
+sin depender de la biblioteca C estándar, por lo que algunas partes del
+estándar C no son compatibles. Divisiones de long long arbitrarios o
+de coma flotante no son permitidas. En ocasiones, puede ser difícil de
+entender las suposiciones que el kernel hace respecto a la cadena de
+herramientas y las extensiones que usa, y desafortunadamente no hay
+referencia definitiva para estas. Consulte las páginas de información de
+gcc (`info gcc`) para obtener información al respecto.
+
+Recuerde que está tratando de aprender a trabajar con una comunidad de
+desarrollo existente. Es un grupo diverso de personas, con altos estándares
+de código, estilo y procedimiento. Estas normas han sido creadas a lo
+largo del tiempo en función de lo que se ha encontrado que funciona mejor
+para un equipo tan grande y geográficamente disperso. Trate de aprender
+tanto como le sea posible acerca de estos estándares antes de tiempo, ya
+que están bien documentados; no espere que la gente se adapte a usted o a
+la forma de hacer las cosas en su empresa.
+
+Cuestiones legales
+------------------
+El código fuente del kernel de Linux se publica bajo licencia GPL. Por
+favor, revise el archivo COPYING, presente en la carpeta principal del
+código fuente, para detalles de la licencia. Si tiene alguna otra pregunta
+sobre licencias, contacte a un abogado, no pregunte en listas de discusión
+del kernel de Linux. La gente en estas listas no son abogadas, y no debe
+confiar en sus opiniones en materia legal.
+
+Para preguntas y respuestas más frecuentes sobre la licencia GPL, consulte:
+
+ https://www.gnu.org/licenses/gpl-faq.html
+
+Documentación
+--------------
+El código fuente del kernel de Linux tiene una gran variedad de documentos
+que son increíblemente valiosos para aprender a interactuar con la
+comunidad del kernel. Cuando se agregan nuevas funciones al kernel, se
+recomienda que se incluyan nuevos archivos de documentación que expliquen
+cómo usar la función. Cuando un cambio en el kernel hace que la interfaz
+que el kernel expone espacio de usuario cambie, se recomienda que envíe la
+información o un parche en las páginas del manual que expliquen el cambio
+a mtk.manpages@gmail.com, y CC la lista linux-api@vger.kernel.org.
+
+Esta es la lista de archivos que están en el código fuente del kernel y son
+de obligada lectura:
+
+ :ref:`Documentation/admin-guide/README.rst <readme>`
+ Este archivo ofrece una breve descripción del kernel de Linux y
+ describe lo que es necesario hacer para configurar y compilar el
+ kernel. Quienes sean nuevos en el kernel deben comenzar aquí.
+
+ :ref:`Documentation/process/changes.rst <changes>`
+ Este archivo proporciona una lista de los niveles mínimos de varios
+ paquetes que son necesarios para construir y ejecutar el kernel
+ exitosamente.
+
+ :ref:`Documentation/process/coding-style.rst <codingstyle>`
+ Esto describe el estilo de código del kernel de Linux y algunas de los
+ razones detrás de esto. Se espera que todo el código nuevo siga las
+ directrices de este documento. La mayoría de los maintainers solo
+ aceptarán parches si se siguen estas reglas, y muchas personas solo
+ revisan el código si tiene el estilo adecuado.
+
+ :ref:`Documentation/process/submitting-patches.rst <submittingpatches>`
+ Este archivo describe en gran detalle cómo crear con éxito y enviar un
+ parche, que incluye (pero no se limita a):
+
+ - Contenidos del correo electrónico (email)
+ - Formato del email
+ - A quien se debe enviar
+
+ Seguir estas reglas no garantiza el éxito (ya que todos los parches son
+ sujetos a escrutinio de contenido y estilo), pero en caso de no seguir
+ dichas reglas, el fracaso es prácticamente garantizado.
+ Otras excelentes descripciones de cómo crear parches correctamente son:
+
+ "The Perfect Patch"
+ https://www.ozlabs.org/~akpm/stuff/tpp.txt
+
+ "Linux kernel patch submission format"
+ https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html
+
+ :ref:`Documentation/process/stable-api-nonsense.rst <stable_api_nonsense>`
+ Este archivo describe la lógica detrás de la decisión consciente de
+ no tener una API estable dentro del kernel, incluidas cosas como:
+
+ - Capas intermedias del subsistema (por compatibilidad?)
+ - Portabilidad de drivers entre sistemas operativos
+ - Mitigar el cambio rápido dentro del árbol de fuentes del kernel (o
+ prevenir cambios rápidos)
+
+ Este documento es crucial para comprender la filosofía del desarrollo
+ de Linux y es muy importante para las personas que se mudan a Linux
+ tras desarrollar otros sistemas operativos.
+
+ :ref:`Documentation/process/security-bugs.rst <securitybugs>`
+ Si cree que ha encontrado un problema de seguridad en el kernel de
+ Linux, siga los pasos de este documento para ayudar a notificar a los
+ desarrolladores del kernel y ayudar a resolver el problema.
+
+ :ref:`Documentation/process/management-style.rst <managementstyle>`
+ Este documento describe cómo operan los maintainers del kernel de Linux
+ y los valores compartidos detrás de sus metodologías. Esta es una
+ lectura importante para cualquier persona nueva en el desarrollo del
+ kernel (o cualquier persona que simplemente sienta curiosidad por
+ el campo IT), ya que clarifica muchos conceptos erróneos y confusiones
+ comunes sobre el comportamiento único de los maintainers del kernel.
+
+ :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
+ Este archivo describe las reglas sobre cómo se suceden las versiones
+ del kernel estable, y qué hacer si desea obtener un cambio en una de
+ estas publicaciones.
+
+ :ref:`Documentation/process/kernel-docs.rst <kernel_docs>`
+ Una lista de documentación externa relativa al desarrollo del kernel.
+ Por favor consulte esta lista si no encuentra lo que están buscando
+ dentro de la documentación del kernel.
+
+ :ref:`Documentation/process/applying-patches.rst <applying_patches>`
+ Una buena introducción que describe exactamente qué es un parche y cómo
+ aplicarlo a las diferentes ramas de desarrollo del kernel.
+
+El kernel también tiene una gran cantidad de documentos que pueden ser
+generados automáticamente desde el propio código fuente o desde
+ReStructuredText markups (ReST), como este. Esto incluye un descripción
+completa de la API en el kernel y reglas sobre cómo manejar cerrojos
+(locking) correctamente.
+
+Todos estos documentos se pueden generar como PDF o HTML ejecutando::
+
+ make pdfdocs
+ make htmldocs
+
+respectivamente desde el directorio fuente principal del kernel.
+
+Los documentos que utilizan el markup ReST se generarán en
+Documentation/output. También se pueden generar en formatos LaTeX y ePub
+con::
+
+ make latexdocs
+ make epubdocs
+
+Convertirse en un/a desarrollador/a de kernel
+---------------------------------------------
+
+Si no sabe nada sobre el desarrollo del kernel de Linux, debería consultar
+el proyecto Linux KernelNewbies:
+
+ https://kernelnewbies.org
+
+Consiste en una útil lista de correo donde puede preguntar casi cualquier
+tipo de pregunta básica de desarrollo del kernel (asegúrese de buscar en
+los archivos primero, antes de preguntar algo que ya ha sido respondido en
+el pasado.) También tiene un canal IRC que puede usar para hacer preguntas
+en tiempo real, y una gran cantidad de documentación útil para ir
+aprendiendo sobre el desarrollo del kernel de Linux.
+
+El sitio web tiene información básica sobre la organización del código,
+subsistemas, y proyectos actuales (tanto dentro como fuera del árbol).
+También describe alguna información logística básica, como cómo compilar
+un kernel y aplicar un parche.
+
+Si no sabe por dónde quiere empezar, pero quieres buscar alguna tarea que
+comenzar a hacer para unirse a la comunidad de desarrollo del kernel,
+acuda al proyecto Linux Kernel Janitor:
+
+ https://kernelnewbies.org/KernelJanitors
+
+Es un gran lugar para comenzar. Describe una lista de problemas
+relativamente simples que deben limpiarse y corregirse dentro del código
+fuente del kernel de Linux árbol de fuentes. Trabajando con los
+desarrolladores a cargo de este proyecto, aprenderá los conceptos básicos
+para incluir su parche en el árbol del kernel de Linux, y posiblemente
+descubrir en la dirección en que trabajar a continuación, si no tiene ya
+una idea.
+
+Antes de realizar cualquier modificación real al código del kernel de
+Linux, es imperativo entender cómo funciona el código en cuestión. Para
+este propósito, nada es mejor que leerlo directamente (lo más complicado
+está bien comentado), tal vez incluso con la ayuda de herramientas
+especializadas. Una de esas herramientas que se recomienda especialmente
+es el proyecto Linux Cross-Reference, que es capaz de presentar el código
+fuente en un formato de página web indexada y autorreferencial. Una
+excelente puesta al día del repositorio del código del kernel se puede
+encontrar en:
+
+ https://elixir.bootlin.com/
+
+El proceso de desarrollo
+------------------------
+
+El proceso de desarrollo del kernel de Linux consiste actualmente de
+diferentes "branches" (ramas) con muchos distintos subsistemas específicos
+a cada una de ellas. Las diferentes ramas son:
+
+ - El código principal de Linus (mainline tree)
+ - Varios árboles estables con múltiples major numbers
+ - Subsistemas específicos
+ - linux-next, para integración y testing
+
+Mainline tree (Árbol principal)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+El mainline tree es mantenido por Linus Torvalds, y puede encontrarse en
+https://kernel.org o en su repo. El proceso de desarrollo es el siguiente:
+
+ - Tan pronto como se lanza un nuevo kernel, se abre una ventana de dos
+ semanas, durante este período de tiempo, los maintainers pueden enviar
+ grandes modificaciones a Linus, por lo general los parches que ya se
+ han incluido en el linux-next durante unas semanas. La forma preferida
+ de enviar grandes cambios es usando git (la herramienta de
+ administración de código fuente del kernel, más información al respecto
+ en https://git-scm.com/), pero los parches simples también son validos.
+ - Después de dos semanas, se lanza un kernel -rc1 y la atención se centra
+ en hacer el kernel nuevo lo más estable ("solido") posible. La mayoría
+ de los parches en este punto deben arreglar una regresión. Los errores
+ que siempre han existido no son regresiones, por lo tanto, solo envíe
+ este tipo de correcciones si son importantes. Tenga en cuenta que se
+ podría aceptar un controlador (o sistema de archivos) completamente
+ nuevo después de -rc1 porque no hay riesgo de causar regresiones con
+ tal cambio, siempre y cuando el cambio sea autónomo y no afecte áreas
+ fuera del código que se está agregando. git se puede usar para enviar
+ parches a Linus después de que se lance -rc1, pero los parches también
+ deben ser enviado a una lista de correo pública para su revisión.
+ - Se lanza un nuevo -rc cada vez que Linus considera que el árbol git
+ actual esta en un estado razonablemente sano y adecuado para la prueba.
+ La meta es lanzar un nuevo kernel -rc cada semana.
+ - El proceso continúa hasta que el kernel se considera "listo", y esto
+ puede durar alrededor de 6 semanas.
+
+Vale la pena mencionar lo que Andrew Morton escribió en las listas de
+correo del kernel de Linux, sobre lanzamientos del kernel (traducido):
+
+ *"Nadie sabe cuándo se publicara un nuevo kernel, pues esto sucede
+ según el estado de los bugs, no de una cronología preconcebida."*
+
+Varios árboles estables con múltiples major numbers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Los kernels con versiones de 3 partes son kernels estables. Estos contienen
+correcciones relativamente pequeñas y críticas para problemas de seguridad
+o importantes regresiones descubiertas para una publicación de código.
+Cada lanzamiento en una gran serie estable incrementa la tercera parte de
+la versión número, manteniendo las dos primeras partes iguales.
+
+Esta es la rama recomendada para los usuarios que quieren la versión
+estable más reciente del kernel, y no están interesados en ayudar a probar
+versiones en desarrollo/experimentales.
+
+Los árboles estables son mantenidos por el equipo "estable"
+<stable@vger.kernel.org>, y se liberan (publican) según lo dicten las
+necesidades. El período de liberación normal es de aproximadamente dos
+semanas, pero puede ser más largo si no hay problemas apremiantes. Un
+problema relacionado con la seguridad, en cambio, puede causar un
+lanzamiento casi instantáneamente.
+
+El archivo :ref:`Documentación/proceso/stable-kernel-rules.rst <stable_kernel_rules>`
+en el árbol del kernel documenta qué tipos de cambios son aceptables para
+el árbol estable y cómo funciona el proceso de lanzamiento.
+
+Subsistemas específicos
+~~~~~~~~~~~~~~~~~~~~~~~~
+Los maintainers de los diversos subsistemas del kernel --- y también muchos
+desarrolladores de subsistemas del kernel --- exponen su estado actual de
+desarrollo en repositorios fuente. De esta manera, otros pueden ver lo que
+está sucediendo en las diferentes áreas del kernel. En áreas donde el
+desarrollo es rápido, se le puede pedir a un desarrollador que base sus
+envíos en tal árbol del subsistema del kernel, para evitar conflictos entre
+este y otros trabajos ya en curso.
+
+La mayoría de estos repositorios son árboles git, pero también hay otros
+SCM en uso, o colas de parches que se publican como series quilt. Las
+direcciones de estos repositorios de subsistemas se enumeran en el archivo
+MAINTAINERS. Muchos de estos se pueden ver en https://git.kernel.org/.
+
+Antes de que un parche propuesto se incluya con dicho árbol de subsistemas,
+es sujeto a revisión, que ocurre principalmente en las listas de correo
+(ver la sección respectiva a continuación). Para varios subsistemas del
+kernel, esta revisión se rastrea con la herramienta patchwork. Patchwork
+ofrece una interfaz web que muestra publicaciones de parches, cualquier
+comentario sobre un parche o revisiones a él, y los maintainers pueden
+marcar los parches como en revisión, aceptado, o rechazado. La mayoría de
+estos sitios de trabajo de parches se enumeran en
+
+https://patchwork.kernel.org/.
+
+linux-next, para integración y testing
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Antes de que las actualizaciones de los árboles de subsistemas se combinen
+con el árbol principal, necesitan probar su integración. Para ello, existe
+un repositorio especial de pruebas en el que se encuentran casi todos los
+árboles de subsistema, actualizado casi a diario:
+
+ https://git.kernel.org/?p=linux/kernel/git/next/linux-next.git
+
+De esta manera, linux-next ofrece una perspectiva resumida de lo que se
+espera que entre en el kernel principal en el próximo período de "merge"
+(fusión de código). Los testers aventureros son bienvenidos a probar
+linux-next en ejecución.
+
+Reportar bugs
+-------------
+
+El archivo 'Documentación/admin-guide/reporting-issues.rst' en el
+directorio principal del kernel describe cómo informar un posible bug del
+kernel y detalles sobre qué tipo de información necesitan los
+desarrolladores del kernel para ayudar a rastrear la fuente del problema.
+
+Gestión de informes de bugs
+------------------------------
+
+Una de las mejores formas de poner en práctica sus habilidades de hacking
+es arreglando errores reportados por otras personas. No solo ayudará a
+hacer el kernel más estable, también aprenderá a solucionar problemas del
+mundo real y mejora sus habilidades, y otros desarrolladores se darán
+cuenta de tu presencia. La corrección de errores es una de las mejores
+formas de ganar méritos entre desarrolladores, porque no a muchas personas
+les gusta perder el tiempo arreglando los errores de otras personas.
+
+Para trabajar en informes de errores ya reportados, busque un subsistema
+que le interese. Verifique el archivo MAINTAINERS donde se informan los
+errores de ese subsistema; con frecuencia será una lista de correo, rara
+vez un rastreador de errores (bugtracker). Busque en los archivos de dicho
+lugar para informes recientes y ayude donde lo crea conveniente. También es
+posible que desee revisar https://bugzilla.kernel.org para informes de
+errores; solo un puñado de subsistemas del kernel lo emplean activamente
+para informar o rastrear; sin embargo, todos los errores para todo el kernel
+se archivan allí.
+
+Listas de correo
+-----------------
+
+Como se explica en algunos de los documentos anteriores, la mayoría de
+desarrolladores del kernel participan en la lista de correo del kernel de
+Linux. Detalles sobre cómo para suscribirse y darse de baja de la lista se
+pueden encontrar en:
+
+ http://vger.kernel.org/vger-lists.html#linux-kernel
+
+Existen archivos de la lista de correo en la web en muchos lugares
+distintos. Utilice un motor de búsqueda para encontrar estos archivos. Por
+ejemplo:
+
+ http://dir.gmane.org/gmane.linux.kernel
+
+Es muy recomendable que busque en los archivos sobre el tema que desea
+tratar, antes de publicarlo en la lista. Un montón de cosas ya discutidas
+en detalle solo se registran en los archivos de la lista de correo.
+
+La mayoría de los subsistemas individuales del kernel también tienen sus
+propias lista de correo donde hacen sus esfuerzos de desarrollo. Revise el
+archivo MAINTAINERS para obtener referencias de lo que estas listas para
+los diferentes grupos.
+
+Muchas de las listas están alojadas en kernel.org. La información sobre
+estas puede ser encontrada en:
+
+ http://vger.kernel.org/vger-lists.html
+
+Recuerde mantener buenos hábitos de comportamiento al usar las listas.
+Aunque un poco cursi, la siguiente URL tiene algunas pautas simples para
+interactuar con la lista (o cualquier lista):
+
+ http://www.albion.com/netiquette/
+
+Si varias personas responden a su correo, el CC (lista de destinatarios)
+puede hacerse bastante grande. No elimine a nadie de la lista CC: sin una
+buena razón, o no responda solo a la dirección de la lista. Acostúmbrese
+a recibir correos dos veces, una del remitente y otra de la lista, y no
+intente ajustar esto agregando encabezados de correo astutos, a la gente no
+le gustará.
+
+Recuerde mantener intacto el contexto y la atribución de sus respuestas,
+mantenga las líneas "El hacker John Kernel escribió ...:" en la parte
+superior de su respuesta, y agregue sus declaraciones entre las secciones
+individuales citadas en lugar de escribiendo en la parte superior del
+correo electrónico.
+
+Si incluye parches en su correo, asegúrese de que sean texto legible sin
+formato como se indica en :ref:`Documentation/process/submitting-patches.rst <submittingpatches>`.
+Los desarrolladores del kernel no quieren lidiar con archivos adjuntos o
+parches comprimidos; y pueden querer comentar líneas individuales de su
+parche, que funciona sólo de esa manera. Asegúrese de emplear un programa
+de correo que no altere los espacios ni los tabuladores. Una buena primera
+prueba es enviarse el correo a usted mismo, e intentar aplicar su
+propio parche. Si eso no funciona, arregle su programa de correo o
+reemplace hasta que funcione.
+
+Sobretodo, recuerde de ser respetuoso con otros subscriptores.
+
+Colaborando con la comunidad
+----------------------------
+
+El objetivo de la comunidad del kernel es proporcionar el mejor kernel
+posible. Cuando envíe un parche para su aceptación, se revisará en sus
+méritos técnicos solamente. Entonces, ¿qué deberías ser?
+
+ - críticas
+ - comentarios
+ - peticiones de cambios
+ - peticiones de justificaciones
+ - silencio
+
+Recuerde, esto es parte de introducir su parche en el kernel. Tiene que ser
+capaz de recibir críticas y comentarios sobre sus parches, evaluar
+a nivel técnico y re-elaborar sus parches o proporcionar razonamiento claro
+y conciso de por qué no se deben hacer tales cambios. Si no hay respuestas
+a su publicación, espere unos días e intente de nuevo, a veces las cosas se
+pierden dado el gran volumen.
+
+¿Qué no debería hacer?
+
+ - esperar que su parche se acepte sin preguntas
+ - actuar de forma defensiva
+ - ignorar comentarios
+ - enviar el parche de nuevo, sin haber aplicados los cambios pertinentes
+
+En una comunidad que busca la mejor solución técnica posible, siempre habrá
+diferentes opiniones sobre lo beneficioso que es un parche. Tiene que ser
+cooperativo y estar dispuesto a adaptar su idea para que encaje dentro
+del kernel, o al menos esté dispuesto a demostrar que su idea vale la pena.
+Recuerde, estar equivocado es aceptable siempre y cuando estés dispuesto a
+trabajar hacia una solución que sea correcta.
+
+Es normal que las respuestas a su primer parche sean simplemente una lista
+de una docena de cosas que debe corregir. Esto **no** implica que su
+parche no será aceptado, y **no** es personal. Simplemente corrija todos
+los problemas planteados en su parche, y envié otra vez.
+
+Diferencias entre la comunidad kernel y las estructuras corporativas
+--------------------------------------------------------------------
+
+La comunidad del kernel funciona de manera diferente a la mayoría de los
+entornos de desarrollo tradicionales en empresas. Aquí hay una lista de
+cosas que puede intentar hacer para evitar problemas:
+
+ Cosas buenas que decir respecto a los cambios propuestos:
+
+ - "Esto arregla múltiples problemas."
+ - "Esto elimina 2000 lineas de código."
+ - "Aquí hay un parche que explica lo que intento describir."
+ - "Lo he testeado en 5 arquitecturas distintas..."
+ - "Aquí hay una serie de parches menores que..."
+ - "Esto mejora el rendimiento en maquinas típicas..."
+
+ Cosas negativas que debe evitar decir:
+
+ - "Lo hicimos así en AIX/ptx/Solaris, de modo que debe ser bueno..."
+ - "Llevo haciendo esto 20 años, de modo que..."
+ - "Esto lo necesita mi empresa para ganar dinero"
+ - "Esto es para la linea de nuestros productos Enterprise"
+ - "Aquí esta el documento de 1000 paginas describiendo mi idea"
+ - "Llevo 6 meses trabajando en esto..."
+ - "Aquí esta un parche de 5000 lineas que..."
+ - "He rescrito todo el desastre actual, y aquí esta..."
+ - "Tengo un deadline, y este parche debe aplicarse ahora."
+
+Otra forma en que la comunidad del kernel es diferente a la mayoría de los
+entornos de trabajo tradicionales en ingeniería de software, es la
+naturaleza sin rostro de interacción. Una de las ventajas de utilizar el
+correo electrónico y el IRC como formas principales de comunicación es la
+no discriminación por motivos de género o raza. El entorno de trabajo del
+kernel de Linux acepta a mujeres y minorías porque todo lo que eres es una
+dirección de correo electrónico. El aspecto internacional también ayuda a
+nivelar el campo de juego porque no puede adivinar el género basado en
+el nombre de una persona. Un hombre puede llamarse Andrea y una mujer puede
+llamarse Pat. La mayoría de las mujeres que han trabajado en el kernel de
+Linux y han expresado una opinión han tenido experiencias positivas.
+
+La barrera del idioma puede causar problemas a algunas personas que no se
+sientes cómodas con el inglés. Un buen dominio del idioma puede ser
+necesario para transmitir ideas correctamente en las listas de correo, por
+lo que le recomendamos que revise sus correos electrónicos para asegurarse
+de que tengan sentido en inglés antes de enviarlos.
+
+Divida sus cambios
+---------------------
+
+La comunidad del kernel de Linux no acepta con gusto grandes fragmentos de
+código, sobretodo a la vez. Los cambios deben introducirse correctamente,
+discutidos y divididos en pequeñas porciones individuales. Esto es casi
+exactamente lo contrario de lo que las empresas están acostumbradas a hacer.
+Su propuesta también debe introducirse muy temprano en el proceso de
+desarrollo, de modo que pueda recibir comentarios sobre lo que está
+haciendo. También deje que la comunidad sienta que está trabajando con
+ellos, y no simplemente usándolos como un vertedero para su función. Sin
+embargo, no envíe 50 correos electrónicos a una vez a una lista de correo,
+su serie de parches debe casi siempre ser más pequeña que eso.
+
+Las razones para dividir las cosas son las siguientes:
+
+1) Los cambios pequeños aumentan la probabilidad de que sus parches sean
+ aplicados, ya que no requieren mucho tiempo o esfuerzo para verificar su
+ exactitud. Un parche de 5 líneas puede ser aplicado por un maintainer
+ con apenas una segunda mirada. Sin embargo, un parche de 500 líneas
+ puede tardar horas en ser revisado en términos de corrección (el tiempo
+ que toma es exponencialmente proporcional al tamaño del parche, o algo
+ así).
+
+ Los parches pequeños también facilitan la depuración cuando algo falla.
+ Es mucho más fácil retirar los parches uno por uno que diseccionar un
+ parche muy grande después de haber sido aplicado (y roto alguna cosa).
+
+2) Es importante no solo enviar pequeños parches, sino también reescribir
+ y simplificar (o simplemente reordenar) los parches antes de enviarlos.
+
+Esta es una analogía del desarrollador del kernel Al Viro (traducida):
+
+ *"Piense en un maestro que califica la tarea de un estudiante de
+ matemáticas. El maestro no quiere ver los intentos y errores del
+ estudiante antes de que se les ocurriera la solución. Quiere ver la
+ respuesta más limpia y elegante. Un buen estudiante lo sabe, y nunca
+ presentaría su trabajo intermedio antes de tener la solución final.*
+
+ *Lo mismo ocurre con el desarrollo del kernel. Los maintainers y
+ revisores no quieren ver el proceso de pensamiento detrás de la solución
+ al problema que se está resolviendo. Quieren ver un solución simple y
+ elegante."*
+
+Puede resultar un reto mantener el equilibrio entre presentar una solución
+elegante y trabajar junto a la comunidad, discutiendo su trabajo inacabado.
+Por lo tanto, es bueno comenzar temprano en el proceso para obtener
+"feedback" y mejorar su trabajo, pero también mantenga sus cambios en
+pequeños trozos que pueden ser aceptados, incluso cuando toda su labor no
+está listo para inclusión en un momento dado.
+
+También tenga en cuenta que no es aceptable enviar parches para su
+inclusión que están sin terminar y serán "arreglados más tarde".
+
+Justifique sus cambios
+----------------------
+
+Además de dividir sus parches, es muy importante que deje a la comunidad de
+Linux sabe por qué deberían agregar este cambio. Nuevas características
+debe justificarse como necesarias y útiles.
+
+Documente sus cambios
+---------------------
+
+Cuando envíe sus parches, preste especial atención a lo que dice en el
+texto de su correo electrónico. Esta información se convertirá en el
+ChangeLog del parche, y se conservará para que todos la vean, todo el
+tiempo. Debe describir el parche por completo y contener:
+
+ - por qué los cambios son necesarios
+ - el diseño general de su propuesta
+ - detalles de implementación
+ - resultados de sus experimentos
+
+Para obtener más detalles sobre cómo debería quedar todo esto, consulte la
+sección ChangeLog del documento:
+
+ "The Perfect Patch"
+ https://www.ozlabs.org/~akpm/stuff/tpp.txt
+
+Todas estas cuestiones son a veces son muy difíciles de conseguir. Puede
+llevar años perfeccionar estas prácticas (si es que lo hace). Es un proceso
+continuo de mejora que requiere mucha paciencia y determinación. Pero no se
+rinda, es posible. Muchos lo han hecho antes, y cada uno tuvo que comenzar
+exactamente donde está usted ahora.
+
+----------
+
+Gracias a Paolo Ciarrocchi que permitió que la sección "Development Process"
+se basara en el texto que había escrito (https://lwn.net/Articles/94386/),
+y a Randy Dunlap y Gerrit Huizenga por algunas de la lista de cosas que
+debes y no debes decir. También gracias a Pat Mochel, Hanna Linder, Randy
+Dunlap, Kay Sievers, Vojtech Pavlik, Jan Kara, Josh Boyer, Kees Cook,
+Andrew Morton, Andi Kleen, Vadim Lobanov, Jesper Juhl, Adrian Bunk,
+Keri Harris, Frans Pop, David A. Wheeler, Junio Hamano, Michael Kerrisk y
+Alex Shepard por su revisión, comentarios y contribuciones. Sin su ayuda,
+este documento no hubiera sido posible.
+
+Maintainer: Greg Kroah-Hartman <greg@kroah.com>
diff --git a/Documentation/translations/sp_SP/process/index.rst b/Documentation/translations/sp_SP/process/index.rst
new file mode 100644
index 000000000000..2239373b3999
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/index.rst
@@ -0,0 +1,30 @@
+.. raw:: latex
+
+ \renewcommand\thesection*
+ \renewcommand\thesubsection*
+
+.. include:: ../disclaimer-sp.rst
+
+.. _sp_process_index:
+
+.. toctree::
+ :maxdepth: 1
+
+ submitting-patches
+ kernel-docs
+ coding-style
+ code-of-conduct
+ kernel-enforcement-statement
+ email-clients
+ magic-number
+ programming-language
+ deprecated
+ adding-syscalls
+ researcher-guidelines
+ contribution-maturity-model
+ security-bugs
+ embargoed-hardware-issues
+ handling-regressions
+ management-style
+ submit-checklist
+ howto
diff --git a/Documentation/translations/sp_SP/process/kernel-docs.rst b/Documentation/translations/sp_SP/process/kernel-docs.rst
new file mode 100644
index 000000000000..2f9b3df8f8fa
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/kernel-docs.rst
@@ -0,0 +1,187 @@
+.. include:: ../disclaimer-sp.rst
+
+:Original: :ref:`Documentation/process/kernel-docs.rst <kernel_docs>`
+:Translator: Carlos Bilbao <carlos.bilbao@amd.com>
+
+.. _sp_kernel_docs:
+
+Índice de documentación adicional del kernel
+============================================
+
+La necesidad de un documento como este se hizo evidente en la lista de
+correo de linux-kernel cuando las mismas preguntas, solicitando sugerencias
+e información, aparecieron una y otra vez.
+
+Afortunadamente, a medida que más y más gente accede a GNU/Linux, más
+desarrolladores se interesan por el kernel. Sin embargo, leer las fuentes
+no siempre es suficiente. Es fácil entender el código, pero se pierden los
+conceptos, la filosofía y decisiones de diseño detrás de dicho código.
+
+Desafortunadamente, no existen muchos documentos disponibles para que los
+principiantes comiencen. Y, aunque existieran, no habría ningún lugar
+"conocido" que les pudiera seguir la pista. Estas líneas tratan de cubrir
+esta carencia.
+
+POR FAVOR, si conoce algún documento que no figura aquí, o si escribe un
+nuevo documento, incluya una referencia aquí, siguiendo el proceso de envío
+de parches del kernel. Cualquier corrección, idea o comentario también es
+bienvenida.
+
+Todos los documentos se catalogan con los siguientes campos: el "Título",
+el "Autor"/es, la "URL" donde se encuentran, algunas "Palabras clave"
+útiles para buscar temas específicos, y una breve "Descripción" del
+documento en cuestión.
+
+.. note::
+
+ Los documentos de cada sección en este documento están ordenados por su
+ fecha de publicación, del más reciente al más antiguo. Los maintainers
+ deben ir retirando recursos obsoletos o anticuados.
+
+Documentos en el árbol del kernel Linux
+-----------------------------------------
+
+Los libros de Sphinx deben compilarse con ``make {htmldocs | pdfdocs | epubdocs}``.
+
+ * Título: **linux/Documentation**
+
+ :Autor: Many.
+ :Ubicación: Documentation/
+ :Palabras Clave: archivos de texto, Sphinx.
+ :Descripción: Documentación que viene con las fuentes del kernel,
+ dentro del directorio Documentation. Algunas páginas de este documento
+ (incluido este documento en sí) se han trasladado allí, y podrían
+ estar más actualizadas que la versión web.
+
+Documentos en línea
+-------------------
+
+ * Título: **Linux Kernel Mailing List Glossary**
+
+ :Autor: various
+ :URL: https://kernelnewbies.org/KernelGlossary
+ :Fecha: rolling version
+ :Palabras Clave: glosario terminos, linux-kernel.
+ :Descripción: De la Introducción: "This glossary is intended as
+ a brief description of some of the acronyms and terms you may hear
+ during discussion of the Linux kernel".
+
+ * Título: **The Linux Kernel Module Programming Guide**
+
+ :Autor: Peter Jay Salzman, Michael Burian, Ori Pomerantz, Bob Mottram,
+ Jim Huang.
+ :URL: https://sysprog21.github.io/lkmpg/
+ :Fecha: 2021
+ :Palabras Clave: modules, GPL book, /proc, ioctls, system calls,
+ interrupt handlers, llamadas al sistema, interrupciones.
+ :Descripción: Un muy buen libro GPL sobre el tema de la programación
+ de módulos. Muchos ejemplos. Actualmente la nueva versión está
+ siendo mantenida activamente ent https://github.com/sysprog21/lkmpg.
+
+Libros publicados
+-----------------
+
+ * Título: **Linux Kernel Programming: A Comprehensive Guide to Kernel Internals, Writing Kernel Modules, and Kernel Synchronization**
+
+ :Autor: Kaiwan N. Billimoria
+ :Publica: Packt Publishing Ltd
+ :Fecha: 2021
+ :Paginas: 754
+ :ISBN: 978-1789953435
+
+ * Título: **Linux Kernel Development, 3rd Edition**
+
+ :Autor: Robert Love
+ :Publica: Addison-Wesley
+ :Fecha: July, 2010
+ :Paginas: 440
+ :ISBN: 978-0672329463
+ :Notas: Libro fundacional
+
+.. _sp_ldd3_published:
+
+ * Título: **Linux Device Drivers, 3rd Edition**
+
+ :Authors: Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman
+ :Publica: O'Reilly & Associates
+ :Fecha: 2005
+ :Paginas: 636
+ :ISBN: 0-596-00590-3
+ :Notas: Libro fundacional. Más información en
+ http://www.oreilly.com/catalog/linuxdrive3/
+ formato PDF, URL: https://lwn.net/Kernel/LDD3/
+
+ * Título: **The Design of the UNIX Operating System**
+
+ :Autor: Maurice J. Bach
+ :Publica: Prentice Hall
+ :Fecha: 1986
+ :Paginas: 471
+ :ISBN: 0-13-201757-1
+ :Notas: Libro fundacional
+
+Recursos varios
+---------------
+
+ * Título: **Cross-Referencing Linux**
+
+ :URL: https://elixir.bootlin.com/
+ :Palabras Clave: Browsing source code.
+ :Descripción: Otro navegador de código fuente del kernel Linux que se
+ encuentra en la web. Muchas referencias cruzadas a variables y
+ funciones. Puedes ver dónde se definen y dónde se utilizan.
+
+ * Título: **Linux Weekly News**
+
+ :URL: https://lwn.net
+ :Palabras Clave: latest kernel news, noticias del kernel Linux.
+ :Descripción: El título lo dice todo (Noticias Semanales de Linux).
+ Hay una sección fija sobre el kernel, resumiendo el trabajo de sus
+ desarrolladores, correcciones de errores, nuevas funciones y
+ versiones, producido durante la semana.
+
+ * Título: **The home page of Linux-MM**
+
+ :Autor: The Linux-MM team.
+ :URL: https://linux-mm.org/
+ :Palabras Clave: memory management, Linux-MM, mm patches, TODO, docs,
+ mailing list, administración de memoria, Linux-MM, parches mm, listas
+ de correo.
+ :Descripción: Sitio dedicado al desarrollo de la gestión de memoria
+ de Linux. Parches relacionados con la memoria, HOWTOs, enlaces,
+ desarrolladores de mm... ¡Si está interesado en el desarrollo de la
+ gestión de memoria no te lo pierdas!
+
+ * Título: **Kernel Newbies IRC Channel and Website**
+
+ :URL: https://www.kernelnewbies.org
+ :Palabras Clave: IRC, newbies, channel, asking doubts, canal, dudas,
+ novatos, preguntar.
+ :Descripción: #kernelnewbies en irc.oftc.net.
+ #kernelnewbies es una red de IRC dedicada al hacker del kernel
+ 'novato'. La audiencia se compone principalmente de personas que
+ quieren aprender sobre el kernel, trabajar en proyectos del kernel
+ o hackers profesionales del kernel que quieren ayudar a la gente
+ menos experimentada.
+ #kernelnewbies es parte de la red OFTC IRC.
+ Pruebe con irc.oftc.net como su servidor y luego haga /join
+ #kernelnewbies.
+ El sitio web kernelnewbies también alberga artículos, documentos, FAQs...
+
+ * Título: **linux-kernel mailing list archives and search engines**
+
+ :URL: http://vger.kernel.org/vger-lists.html
+ :URL: http://www.uwsg.indiana.edu/hypermail/linux/kernel/index.html
+ :URL: http://groups.google.com/group/mlist.linux.kernel
+ :Palabras Clave: linux-kernel, archives, buscar, search, archivos.
+ :Descripción: Algunos de los archivadores de listas de correo del
+ kernel de Linux. Si usted tiene uno mejor/otro, por favor hágamelo
+ saber.
+
+-------
+
+Este documento se basaba originalmente en:
+
+ https://www.dit.upm.es/~jmseyas/linux/kernel/hackers-docs.html
+
+escrito por Juan-Mariano de Goyenche
diff --git a/Documentation/translations/sp_SP/process/kernel-enforcement-statement.rst b/Documentation/translations/sp_SP/process/kernel-enforcement-statement.rst
new file mode 100644
index 000000000000..d66902694089
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/kernel-enforcement-statement.rst
@@ -0,0 +1,174 @@
+.. include:: ../disclaimer-sp.rst
+
+:Original: :ref:`Documentation/process/kernel-enforcement-statement.rst <process_statement_kernel>`
+:Translator: Carlos Bilbao <carlos.bilbao@amd.com>
+
+.. _sp_process_statement_kernel:
+
+Aplicación de la licencia en el kernel Linux
+============================================
+
+Como desarrolladores del kernel Linux, tenemos un gran interés en cómo se
+se utiliza nuestro software y cómo se aplica la licencia de nuestro software.
+El cumplimiento de las obligaciones de intercambio recíproco de GPL-2.0 son
+fundamentales en el largo plazo para la sostenibilidad de nuestro software
+y comunidad.
+
+Aunque existe el derecho de hacer valer un copyright distinto en las
+contribuciones hechas a nuestra comunidad, compartimos el interés de
+asegurar que las acciones individuales para proteger estos se lleven a cabo
+de una manera que beneficia a nuestra comunidad y no tenga un indeseado
+impacto negativo en la salud y crecimiento de nuestro ecosistema de software.
+Con el fin de disuadir la aplicación inútil de acciones, estamos de acuerdo
+en que es en el mejor interés de nuestro desarrollo como comunidad asumir
+el siguiente compromiso con los usuarios del kernel Linux, en nombre
+nuestro y de cualquier sucesor de nuestros derechos de autor (copyright):
+
+ Sin perjuicio de las disposiciones de terminación de GPL-2.0, aceptamos
+ que es en el mejor interés de nuestra comunidad de desarrollo adoptar
+ las siguientes disposiciones de GPL-3.0 como permisos adicionales bajo
+ nuestra licencia, con respecto a cualquier interposición de alegación
+ de infringimiento (en inglés, "non-defensive assertion") de los
+ derechos bajo la licencia.
+
+ Sin embargo, si deja de violar esta Licencia, entonces su licencia
+ de copyright como particular se restablece (a) provisionalmente,
+ a menos que y hasta que el titular de los derechos de autor explícita
+ y finalmente rescinda su licencia, y (b) de forma permanente, si el
+ titular de los derechos de autor no le notifica la violación por algún
+ medio razonable antes de 60 días después del cese.
+
+ Además, su licencia de un titular de derechos de autor en particular es
+ restablecida permanentemente si el titular de los derechos de autor le
+ notifica de la violación por algún medio razonable, esta es la primera
+ vez que ha recibido notificación de violación de esta Licencia (para
+ cualquier trabajo) de ese titular de los derechos de autor, y subsana
+ la infracción antes de los 30 días posteriores de recibir el aviso.
+
+Nuestra intención al proporcionar estas garantías es fomentar un mayor uso
+del software. Queremos que empresas y particulares utilicen, modifiquen y
+distribuyan este software. Queremos trabajar con los usuarios de forma
+abierta y transparente para eliminar cualquier incertidumbre sobre nuestras
+expectativas con respecto al cumplimiento que podría limitar la adopción de
+nuestro software. Entendemos la acción legal como último recurso, que se
+iniciará solo cuando otros esfuerzos de la comunidad no hayan podido
+resolver el problema.
+
+Finalmente, una vez que se resuelva un problema de incumplimiento,
+esperamos que el usuario se sienta bienvenido a unirse a nosotros en
+nuestros esfuerzos con este proyecto. Trabajando juntos, somos más fuertes.
+
+Excepto donde se indica a continuación, hablamos solo por nosotros mismos y
+no por ninguna compañía donde puede que trabajemos hoy, o hayamos trabajado
+en el pasado, o trabajaremos en el futuro.
+
+- Laura Abbott
+- Bjorn Andersson (Linaro)
+- Andrea Arcangeli
+- Neil Armstrong
+- Jens Axboe
+- Pablo Neira Ayuso
+- Khalid Aziz
+- Ralf Baechle
+- Felipe Balbi
+- Arnd Bergmann
+- Ard Biesheuvel
+- Tim Bird
+- Paolo Bonzini
+- Christian Borntraeger
+- Mark Brown (Linaro)
+- Paul Burton
+- Javier Martinez Canillas
+- Rob Clark
+- Kees Cook (Google)
+- Jonathan Corbet
+- Dennis Dalessandro
+- Vivien Didelot (Savoir-faire Linux)
+- Hans de Goede
+- Mel Gorman (SUSE)
+- Sven Eckelmann
+- Alex Elder (Linaro)
+- Fabio Estevam
+- Larry Finger
+- Bhumika Goyal
+- Andy Gross
+- Juergen Gross
+- Shawn Guo
+- Ulf Hansson
+- Stephen Hemminger (Microsoft)
+- Tejun Heo
+- Rob Herring
+- Masami Hiramatsu
+- Michal Hocko
+- Simon Horman
+- Johan Hovold (Hovold Consulting AB)
+- Christophe JAILLET
+- Olof Johansson
+- Lee Jones (Linaro)
+- Heiner Kallweit
+- Srinivas Kandagatla
+- Jan Kara
+- Shuah Khan (Samsung)
+- David Kershner
+- Jaegeuk Kim
+- Namhyung Kim
+- Colin Ian King
+- Jeff Kirsher
+- Greg Kroah-Hartman (Linux Foundation)
+- Christian König
+- Vinod Koul
+- Krzysztof Kozlowski
+- Viresh Kumar
+- Aneesh Kumar K.V
+- Julia Lawall
+- Doug Ledford
+- Chuck Lever (Oracle)
+- Daniel Lezcano
+- Shaohua Li
+- Xin Long
+- Tony Luck
+- Catalin Marinas (Arm Ltd)
+- Mike Marshall
+- Chris Mason
+- Paul E. McKenney
+- Arnaldo Carvalho de Melo
+- David S. Miller
+- Ingo Molnar
+- Kuninori Morimoto
+- Trond Myklebust
+- Martin K. Petersen (Oracle)
+- Borislav Petkov
+- Jiri Pirko
+- Josh Poimboeuf
+- Sebastian Reichel (Collabora)
+- Guenter Roeck
+- Joerg Roedel
+- Leon Romanovsky
+- Steven Rostedt (VMware)
+- Frank Rowand
+- Ivan Safonov
+- Anna Schumaker
+- Jes Sorensen
+- K.Y. Srinivasan
+- David Sterba (SUSE)
+- Heiko Stuebner
+- Jiri Kosina (SUSE)
+- Willy Tarreau
+- Dmitry Torokhov
+- Linus Torvalds
+- Thierry Reding
+- Rik van Riel
+- Luis R. Rodriguez
+- Geert Uytterhoeven (Glider bvba)
+- Eduardo Valentin (Amazon.com)
+- Daniel Vetter
+- Linus Walleij
+- Richard Weinberger
+- Dan Williams
+- Rafael J. Wysocki
+- Arvind Yadav
+- Masahiro Yamada
+- Wei Yongjun
+- Lv Zheng
+- Marc Zyngier (Arm Ltd)
+
diff --git a/Documentation/translations/sp_SP/process/magic-number.rst b/Documentation/translations/sp_SP/process/magic-number.rst
new file mode 100644
index 000000000000..7c7dfb4ba80b
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/magic-number.rst
@@ -0,0 +1,89 @@
+.. include:: ../disclaimer-sp.rst
+
+:Original: :ref:`Documentation/process/magic-number.rst <magicnumbers>`
+:Translator: Carlos Bilbao <carlos.bilbao@amd.com>
+
+.. _sp_magicnumbers:
+
+Números mágicos de Linux
+========================
+
+Este archivo es un registro de los números mágicos que están en uso. Cuando
+usted incluya un número mágico a una estructura, también debe agregarlo a
+este documento, ya que es mejor si los números mágicos utilizados por
+varias estructuras son únicos.
+
+Es una muy buena idea proteger las estructuras de datos del kernel con
+números mágicos. Esto le permite verificar en tiempo de ejecución si (a)
+una estructura ha sido manipulada, o (b) ha pasado la estructura incorrecta
+a una rutina. Esto último es especialmente útil --- particularmente cuando
+pasa punteros a estructuras a través de un puntero void \*. El código tty,
+por ejemplo, hace esto con frecuencia para pasar información específica del
+driver y líneas de estructuras específicas de protocolo de un lado al
+otro.
+
+La forma de usar números mágicos es declararlos al principio de la
+estructura, así::
+
+ struct tty_ldisc {
+ int magic;
+ ...
+ };
+
+Por favor, siga este método cuando agregue futuras mejoras al kernel! Me ha
+ahorrado innumerables horas de depuración, especialmente en los casos
+complicados donde una matriz ha sido invadida y las estructuras que siguen
+a la matriz se han sobrescrito. Usando este método, estos casos se detectan
+de forma rápida y segura.
+
+Changelog::
+
+ Theodore Ts'o
+ 31 Mar 94
+
+ La tabla mágica ha sido actualizada para Linux 2.1.55.
+
+ Michael Chastain
+ <mailto:mec@shout.net>
+ 22 Sep 1997
+
+ Ahora debería estar actualizada con Linux 2.1.112. Porque
+ estamos en fase de "feature freeze", es muy poco probable que
+ algo cambiará antes de 2.2.x. Las entradas son
+ ordenados por campo numérico.
+
+ Krzysztof G. Baranowski
+ <mailto: kgb@knm.org.pl>
+ 29 Jul 1998
+
+ Se actualizó la tabla mágica a Linux 2.5.45. Justo sobre el feature
+ freeze, pero es posible que algunos nuevos números mágicos se cuelen en
+ el kernel antes de 2.6.x todavía.
+
+ Petr Baudis
+ <pasky@ucw.cz>
+ 03 Nov 2002
+
+ La tabla mágica ha sido actualizada para Linux 2.5.74.
+
+ Fabian Frederick
+ <ffrederick@users.sourceforge.net>
+ 09 Jul 2003
+
+===================== ================ ======================== ==========================================
+Magic Name Number Structure File
+===================== ================ ======================== ==========================================
+PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/pg.h``
+APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
+FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
+SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
+BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c``
+HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
+KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``
+CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h``
+YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c``
+CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c``
+QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c``
+QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c``
+NMI_MAGIC 0x48414d4d455201 nmi_s ``arch/mips/include/asm/sn/nmi.h``
+===================== ================ ======================== ==========================================
diff --git a/Documentation/translations/sp_SP/process/management-style.rst b/Documentation/translations/sp_SP/process/management-style.rst
new file mode 100644
index 000000000000..4db33fbf8941
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/management-style.rst
@@ -0,0 +1,299 @@
+.. include:: ../disclaimer-sp.rst
+
+:Original: Documentation/process/management-style.rst
+:Translator: Avadhut Naik <avadhut.naik@amd.com>
+
+.. _sp_managementstyle:
+
+
+Estilo de gestión del kernel de Linux
+=====================================
+
+Este es un documento breve que describe el estilo de gestión preferido (o
+inventado, dependiendo de a quién le preguntes) para el kernel de Linux.
+Está destinado a reflejar el documento
+:ref:`translations/sp_SP/process/coding-style.rst <sp_codingstyle>` hasta
+cierto punto y está escrito principalmente para evitar responder a [#f1]_
+las mismas preguntas (o similares) una y otra vez.
+
+El estilo de gestión es muy personal y mucho más difícil de cuantificar
+que reglas simples de estilo de codificación, por lo que este documento
+puede o no tener relación con la realidad. Comenzó como una broma, pero
+eso no significa que no pueda ser realmente cierto. Tendrás que decidir
+por ti mismo.
+
+Por cierto, cuando se hable de “gerente de kernel”, se refiere a las
+personas lideres técnicas, no de las personas que hacen la gestión
+tradicional dentro de las empresas. Si firmas pedidos de compra o tienes
+alguna idea sobre el presupuesto de tu grupo, es casi seguro que no eres
+un gerente de kernel. Estas sugerencias pueden o no aplicarse a usted.
+
+En primer lugar, sugeriría comprar “Seven Habits of Highly Effective
+People” y NO leerlo. Quemarlo, es un gran gesto simbólico.
+
+.. [#f1] Este documento lo hace no tanto respondiendo a la pregunta, sino
+ haciendo dolorosamente obvio para el interrogador que no tenemos ni idea
+ de cuál es la respuesta.
+
+De todos modos, aquí va:
+
+.. _decisiones:
+
+1) Decisiones
+-------------
+
+Todos piensan que los gerentes toman decisiones, y que la toma de
+decisiones en importante. Cuanto más grande y dolorosa sea la decisión,
+más grande debe ser el gerente para tomarla. Eso es muy profundo y obvio,
+pero en realidad no es cierto.
+
+El nombre del partido es **evitar** tener que tomar una decisión. En
+particular, si alguien te dice “elige (a) o (b), realmente necesitamos
+que decidas sobre esto”, estas en problemas como gerente. Es mejor que
+las personas a las que diriges conozcan los detalles mejor que tú, así
+que, si acuden a ti para tomar una decisión técnica, estas jodido.
+Claramente no eres competente para tomar una decisión por ellos.
+
+(Corolario: Si las personas a las que diriges no conocen los detalles
+mejor que tú, también estas jodido, aunque por una razón totalmente
+diferente. Es decir, que estas en el trabajo equivocado y que **ellos**
+deberían gestionando tu brillantez en su lugar).
+
+Así que el nombre del partido es **evitar** las decisiones, al menos las
+grandes y dolorosas. Tomar decisiones pequeñas y sin consecuencias está
+bien, y te hace parecer que sabes lo que estás haciendo, así que lo que
+un gerente de kernel necesita hacer es convertir las decisiones grandes
+y dolorosas en cosas pequeñas a los que a nadie realmente le importa.
+
+Ayuda darse cuenta de que la diferencia clave entre una decisión grande
+y una pequeña es si puede arreglar su decisión después. Cualquier
+decisión se puede hacer pequeña simplemente asegurándose siempre de que
+si te equivocaste (u **estarás** equivocado), siempre puede deshacer el
+daño más tarde retrocediendo. De repente, llegas a ser doblemente
+gerencial por tomar **dos** decisiones intrascendentes - la equivocada
+**y** la correcta.
+
+Y las personas incluso verán eso como un verdadero liderazgo (*tos*
+mierda *tos*).
+
+Por lo tanto, la llave para evitar las grandes decisiones se convierte en
+simplemente evitar hacer cosas que no se pueden deshacer. No te dejes
+llevar a una esquina del que no puedas escapar. Una rata acorralada puede
+ser peligrosa – un gerente acorralado es directamente lamentable.
+
+Resulta que, dado que nadie sería tan estúpido como para dejar que un
+gerente de kernel tenga una gran responsabilidad **de todos modos**,
+generalmente es bastante fácil retroceder. Dado que no vas a poder
+malgastar grandes cantidades de dinero que tal vez no puedas pagar, lo
+único que puedes revertir es una decisión técnica, y ahí retroceder es
+muy fácil: simplemente diles a todos que fuiste un bobo incompetente,
+pide disculpas y deshaz todo el trabajo inútil que hiciste trabajar a la
+gente durante el año pasado. De repente, la decisión que tomaste hace un
+año no era una gran decisión después de todo, ya que se podía deshacer
+fácilmente.
+
+Resulta que algunas personas tienen problemas con este enfoque, por dos
+razones:
+
+ - admitir que eras un idiota es más difícil de lo que parece. A todos
+ nos gusta mantener las apariencias, y salir en público a decir que te
+ equivocaste a veces es muy duro.
+ - que alguien te diga que lo que trabajaste durante el último año no
+ valió la pena después de todo también puede ser duro para los pobres
+ ingenieros humildes, y aunque el **trabajo** real fue bastante fácil
+ de deshacer simplemente eliminándolo, es posible que hayas perdido
+ irrevocablemente la confianza de ese ingeniero. Y recuerda:
+ “irrevocablemente” fue lo que tratamos de evitar en primer lugar, y
+ tu decisión terminó siendo muy grande después de todo.
+
+Afortunadamente, estas dos razones pueden mitigarse eficazmente
+simplemente admitiendo inicialmente que no tienes ni idea, y diciéndole
+a la gente que tu decisión es puramente preliminar, y podría ser la cosa
+equivocada. Siempre te debes reservar el derecho de cambiar de opinión, y
+hacer que la gente sea muy **consciente** de eso. Y es mucho más fácil
+admitir que eres estúpido cuando **aun** no has hecho la cosa realmente
+estúpida.
+
+Entonces, cuando realmente resulta ser estúpido, la gente simplemente
+pone los ojos y dice “Ups, otra vez no”.
+
+Esta admisión preventiva de incompetencia también podría hacer que las
+personas que realmente hacen el trabajo piensen dos veces sobre si vale la
+pena hacerlo o no. Después de todo, si **ellos** no están seguros de si es
+una buena idea, seguro que no deberías alentarlos prometiéndoles que lo
+que trabajan será incluido. Haz que al menos lo piensen dos veces antes de
+embarcarse en un gran esfuerzo.
+
+Recuerda: Es mejor que sepan más sobre los detalles que tú, y
+generalmente ya piensan que tienen la respuesta a todo. Lo mejor que puede
+hacer como gerente no es inculcar confianza, sino más bien una dosis
+saludable de pensamiento crítico sobre lo que hacen.
+
+Por cierto, otra forma de evitar una decisión es quejarse lastimeramente
+de “no podemos hacer ambas cosas?” y parecer lamentable. Créeme, funciona.
+Si no está claro cuál enfoque es mejor, lo descubrirán. La respuesta puede
+terminar siendo que ambos equipos se sientan tan frustrados por la
+situación que simplemente se den por vencidos.
+
+Eso puede sonar como un fracaso, pero generalmente es una señal de que
+había algo mal con ambos proyectos, y la razón por la que las personas
+involucradas no pudieron decidir fue que ambos estaban equivocados.
+Terminas oliendo a rosas y evitaste otra decisión que podrías haber
+metido la pata.
+
+2) Gente
+--------
+
+La mayoría de las personas son idiotas, y ser gerente significa que
+tendrás que lidiar con eso, y quizás lo más importante, que **ellos**
+tienen que lidiar **contigo**.
+
+Resulta que, si bien es fácil deshacer los errores técnicos, no es tan
+fácil deshacer los trastornos de personalidad. Solo tienes que vivir
+con los suyos - y el tuyo.
+
+Sin embargo, para prepararse como gerente del kernel, es mejor recordar
+no quemar ningún puente, bombardear a ningún aldeano inocente o alienar
+a demasiados desarrolladores del kernel. Resulta que alienar a las
+personas es bastante fácil, y desalienarlas es difícil. Por lo tanto,
+“alienar” cae inmediatamente debajo del título “no reversible”, y se
+convierte en un no-no según :ref:`decisiones`.
+
+Aquí solo hay algunas reglas simples:
+
+ (1) No llames a la gente pen*ejos (al menos no en público)
+ (2) Aprende a disculparte cuando olvidaste la regla (1)
+
+El problema con #1 es que es muy fácil de hacer, ya que puedes decir
+“eres un pen*ejo” de millones de manera diferentes [#f2]_, a veces sin
+siquiera darte cuenta, y casi siempre con una convicción ardiente de que
+tienes razón.
+
+Y cuanto más convencido estés de que tienes razón (y seamos sinceros,
+puedes llamar a casi **cualquiera** un pen*ejo, y a menudo **tendrás**
+razón), más difícil termina siendo disculparse después.
+
+Para resolver este problema, realmente solo tienes dos opciones:
+
+ - Se muy buenos en las disculpas.
+ - Difunde el “amor” de manera tan uniforme que nadie termina sintiendo
+ que es atacado injustamente. Hazlo lo suficientemente ingenioso, e
+ incluso podría divertirse.
+
+La opción de ser infaliblemente educado realmente no existe. Nadie
+confiará en alguien que está ocultando tan claramente su verdadero
+carácter.
+
+.. [#f2] Paul Simon cantó “Cincuenta maneras de dejar a tu amante” porque,
+ francamente, “Un millón de maneras de decirle a un desarrollador que es
+ un pen*ejo” no escanea tan bien. Pero estoy seguro de que lo pensó.
+
+3) Gente II – el Buen Tipo
+--------------------------
+
+Aunque resulta que la mayoría de las personas son idiotas, el corolario
+de eso es, tristemente, que tú también seas uno, y aunque todos podemos
+disfrutar del conocimiento seguro de que somos mejores que la persona
+promedio (somos realistas, nadie cree que nunca que son promedio o debajo
+del promedio), también debemos admitir que no somos el cuchillo más
+afilado alrededor, y habrá otras personas que son menos idiotas que tú.
+
+Algunas personas reaccionan mal a las personas inteligentes. Otras se
+aprovechan de ellos.
+
+Asegúrate de que tú, como mantenedor del kernel, estás en el segundo
+grupo. Aguanta con ellos, porque son las personas que te facilitarán el
+trabajo. En particular, podrán tomar tus decisiones por ti, que es de lo
+que se trata el juego.
+
+Así que cuando encuentras a alguien más inteligente que tú, simplemente
+sigue adelante. Sus responsabilidades de gestión se convierten en gran
+medida en las de decir “Suena como una buena idea, - hazlo sin
+restricciones”, o “Eso suena bien, pero ¿qué pasa con xxx?". La segunda
+versión en particular es una excelente manera de aprender algo nuevo
+sobre “xxx” o parecer **extra** gerencial al señalar algo que la persona
+más inteligente no había pensado. En cualquier caso, sales ganando.
+
+Una cosa para tener en cuenta es darse cuenta de que la grandeza en un
+área no necesariamente se traduce en otras áreas. Así que puedes impulsar
+a la gente en direcciones específicas, pero seamos realistas, pueden ser
+buenos en lo que hacen, y ser malos en todo lo demás. La buena noticia es
+que las personas tienden a gravitar naturalmente hacia lo que son buenos,
+por lo que no es como si estuvieras haciendo algo irreversible cuando los
+impulsas en alguna dirección, simplemente no presiones demasiado.
+
+4) Colocar la culpa
+-------------------
+
+Las cosas saldrán mal, y la gente quiere culpar a alguien. Etiqueta, tú
+lo eres.
+
+En realidad, no es tan difícil aceptar la culpa, especialmente si la gente
+se da cuenta de que no fue **toda** tu culpa. Lo que nos lleva a la mejor
+manera de asumir la culpa: hacerlo por otra persona. Te sentirás bien por
+asumir la caída, ellos se sentirán bien por no ser culpados, y la persona
+que perdió toda su colección de pornografía de 36 GB debido a tu
+incompetencia admitirá a regañadientes que al menos intentaste escapar
+de ella.
+
+Luego haz que el desarrollador que realmente metió la pata (si puedes
+encontrarlo) sepa **en privado** que metió la pata. No solo para que
+pueda evitarlo en futuro, sino para que sepan que te deben uno. Y, quizás
+aún más importante, también es probable que sea la persona que puede
+solucionarlo. Porque, seamos sinceros, seguro que no eres tú.
+
+Asumir la culpa también es la razón por la que llegas a ser un gerente
+en primer lugar. Es parte de lo que hace que la gente confíe en ti y te
+permita la gloria potencial porque eres tú quien puede decir “metí la
+pata”. Y si has seguido las reglas anteriores, ya serás bastante bueno
+para decir eso.
+
+5) Cosas que evitar
+-------------------
+
+Hay una cosa que la gente odia incluso más que ser llamado “pen*ejo”,
+y que es ser llamado “pen*ejo” en una voz mojigata. Por lo primero,
+puedes disculparte, por lo segundo, realmente, no tendrás la oportunidad.
+Es probable que ya no estén escuchando, incluso si de lo contrario haces
+un buen trabajo.
+
+Todos pensamos que somos mejores que los demás, lo que significa que
+cuando alguien más se da aires, **realmente** nos molesta. Puedes ser
+moral e intelectualmente superior a todos los que te rodean, pero no
+trates de hacerlo demasiado obvio a menos que tengas **la intención**
+real de irritar a alguien [#f3]_.
+
+Del mismo modo, no seas demasiado educado o sutil acerca de las cosas. La
+cortesía fácilmente termina yendo demasiado lejos y ocultado el problema,
+y como dicen “En internet, nadie puede oírte ser sutil”. Usa un gran
+objeto contundente para enfatizar el punto, porque realmente no puedes
+depender de que las personas entiendan tu punto de otra manera.
+
+Un poco de humor puede ayudar a suavizar tanto la franqueza como la
+moralización. Exagerar hasta el punto de ser ridículo puede reforzar un
+punto sin hacer que sea doloroso para el destinatario, quien simplemente
+piensa que estas siendo tonto. Por lo tanto, puede ayudarnos a superar el
+bloqueo mental personal que todos tenemos sobre la crítica.
+
+.. [#f3] La pista: Los grupos de noticias de Internet que no están
+ directamente relacionados con tu trabajo son excelentes maneras de
+ desahogar tus frustraciones con otras personas. Escribe mensajes
+ insultantes con una mueca de desprecio solo para entrar en un humor de
+ vez en cuando, y te sentirás limpio. Eso sí, no te cagues demasiado
+ cerca de casa.
+
+6) ¿Por qué a mí?
+-----------------
+
+Dado que tu principal responsabilidad parece ser asumir la culpa de los
+errores de otras personas y hacer dolorosamente obvio para todos los
+demás que eres incompetente, la pregunta obvia es: ¿por qué hacerlo en
+primer lugar?
+
+Pase lo que pase, **tendrás** una sensación inmensa de logro personal por
+estar “a cargo”. No importa el hecho de que realmente estés liderando al
+tratar de mantenerte al día con todos los demás y correr detrás de ellos
+lo más rápido que puedes. Todo el mundo seguirá pensando que eres la
+persona a cargo.
+
+Es un gran trabajo si puedes descifrarlo.
diff --git a/Documentation/translations/sp_SP/process/programming-language.rst b/Documentation/translations/sp_SP/process/programming-language.rst
new file mode 100644
index 000000000000..301f525372d8
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/programming-language.rst
@@ -0,0 +1,53 @@
+.. include:: ../disclaimer-sp.rst
+
+:Original: :ref:`Documentation/process/programming-language.rst <programming_language>`
+:Translator: Carlos Bilbao <carlos.bilbao@amd.com>
+
+.. _sp_programming_language:
+
+Lenguaje de programación
+========================
+
+El kernel está escrito en el lenguaje de programación C [sp-c-language]_.
+Más concretamente, el kernel normalmente se compila con ``gcc`` [sp-gcc]_
+bajo ``-std=gnu11`` [sp-gcc-c-dialect-options]_: el dialecto GNU de ISO C11.
+``clang`` [sp-clang]_ también es compatible, consulte los documentos en
+:ref:`Building Linux with Clang/LLVM <kbuild_llvm>`.
+
+Este dialecto contiene muchas extensiones del lenguaje [sp-gnu-extensions]_,
+y muchos de ellos se usan dentro del kernel de forma habitual.
+
+Hay algo de soporte para compilar el núcleo con ``icc`` [sp-icc]_ para varias
+de las arquitecturas, aunque en el momento de escribir este texto, eso no
+está terminado y requiere parches de terceros.
+
+Atributos
+---------
+
+Una de las comunes extensiones utilizadas en todo el kernel son los atributos
+[sp-gcc-attribute-syntax]_. Los atributos permiten introducir semántica
+definida por la implementación a las entidades del lenguaje (como variables,
+funciones o tipos) sin tener que hacer cambios sintácticos significativos
+al idioma (por ejemplo, agregar una nueva palabra clave) [sp-n2049]_.
+
+En algunos casos, los atributos son opcionales (es decir, hay compiladores
+que no los admiten pero de todos modos deben producir el código adecuado,
+incluso si es más lento o no realiza tantas comprobaciones/diagnósticos en
+tiempo de compilación).
+
+El kernel define pseudo-palabras clave (por ejemplo, ``__pure``) en lugar
+de usar directamente la sintaxis del atributo GNU (por ejemplo,
+``__attribute__((__pure__))``) con el fin de detectar cuáles se pueden
+utilizar y/o acortar el código.
+
+Por favor consulte ``include/linux/compiler_attributes.h`` para obtener
+más información.
+
+.. [sp-c-language] http://www.open-std.org/jtc1/sc22/wg14/www/standards
+.. [sp-gcc] https://gcc.gnu.org
+.. [sp-clang] https://clang.llvm.org
+.. [sp-icc] https://software.intel.com/en-us/c-compilers
+.. [sp-gcc-c-dialect-options] https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html
+.. [sp-gnu-extensions] https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html
+.. [sp-gcc-attribute-syntax] https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html
+.. [sp-n2049] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2049.pdf
diff --git a/Documentation/translations/sp_SP/process/researcher-guidelines.rst b/Documentation/translations/sp_SP/process/researcher-guidelines.rst
new file mode 100644
index 000000000000..462b3290b7b8
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/researcher-guidelines.rst
@@ -0,0 +1,150 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+:Original: :ref:`Documentation/process/researcher-guidelines.rst`
+:Translator: Avadhut Naik <avadhut.naik@amd.com>
+
+Directrices para Investigadores
+++++++++++++++++++++++++++++++++
+
+La comunidad del kernel de Linux da la bienvenida a la investigación
+transparente sobre el kernel de Linux, las actividades involucradas
+en su producción, otros subproductos de su desarrollo. Linux se
+beneficia mucho de este tipo de investigación, y la mayoría de los
+aspectos de Linux son impulsados por investigación en una forma u otra.
+
+La comunidad agradece mucho si los investigadores pueden compartir
+los hallazgos preliminares antes de hacer públicos sus resultados,
+especialmente si tal investigación involucra seguridad. Involucrarse
+temprano ayuda a mejorar la calidad de investigación y la capacidad
+de Linux para mejorar a partir de ella. En cualquier caso, se recomienda
+compartir copias de acceso abierto de la investigación publicada con
+la comunidad.
+
+Este documento busca clarificar lo que la comunidad del kernel de Linux
+considera practicas aceptables y no aceptables al llevar a cabo
+investigación de este tipo. Por lo menos, dicha investigación y
+actividades afines deben seguir las reglas estándar de ética de la
+investigación. Para más información sobre la ética de la investigación
+en general, ética en la tecnología y la investigación de las comunidades
+de desarrolladores en particular, ver:
+
+
+* `Historia de la Ética en la Investigación <https://www.unlv.edu/research/ORI-HSR/history-ethics>`_
+* `Ética de la IEEE <https://www.ieee.org/about/ethics/index.html>`_
+* `Perspectivas de Desarrolladores e Investigadores sobre la Ética de los Experimentos en Proyectos de Código Abierto <https://arxiv.org/pdf/2112.13217.pdf>`_
+
+La comunidad del kernel de Linux espera que todos los que interactúan con
+el proyecto están participando en buena fe para mejorar Linux. La
+investigación sobre cualquier artefacto disponible públicamente (incluido,
+pero no limitado a código fuente) producido por la comunidad del kernel
+de Linux es bienvenida, aunque la investigación sobre los desarrolladores
+debe ser claramente opcional.
+
+La investigación pasiva que se basa completamente en fuentes disponibles
+públicamente, incluidas las publicaciones en listas de correo públicas y
+las contribuciones a los repositorios públicos, es claramente permitida.
+Aunque, como con cualquier investigación, todavía se debe seguir la ética
+estándar.
+
+La investigación activa sobre el comportamiento de los desarrolladores,
+sin embargo, debe hacerse con el acuerdo explícito y la divulgación
+completa a los desarrolladores individuales involucrados. No se puede
+interactuar / experimentar con los desarrolladores sin consentimiento;
+esto también es ética de investigación estándar.
+
+Para ayudar a aclarar: enviar parches a los desarrolladores es interactuar
+con ellos, pero ya han dado su consentimiento para recibir contribuciones
+en buena fe. No se ha dado consentimiento para enviar parches intencionalmente
+defectuosos / vulnerables o contribuir con la información engañosa a las
+discusiones. Dicha comunicación puede ser perjudicial al desarrollador (por
+ejemplo, agotar el tiempo, el esfuerzo, y la moral) y perjudicial para el
+proyecto al erosionar la confianza de toda la comunidad de desarrolladores en
+el colaborador (y la organización del colaborador en conjunto), socavando
+los esfuerzos para proporcionar reacciones constructivas a los colaboradores
+y poniendo a los usuarios finales en riesgo de fallas de software.
+
+La participación en el desarrollo de Linux en sí mismo por parte de
+investigadores, como con cualquiera, es bienvenida y alentada. La
+investigación del código de Linux es una práctica común, especialmente
+cuando se trata de desarrollar o ejecutar herramientas de análisis que
+producen resultados procesables.
+
+Cuando se interactúa con la comunidad de desarrolladores, enviar un
+parche ha sido tradicionalmente la mejor manera para hacer un impacto.
+Linux ya tiene muchos errores conocidos – lo que es mucho más útil es
+tener soluciones verificadas. Antes de contribuir, lea cuidadosamente
+la documentación adecuada.
+
+* Documentation/process/development-process.rst
+* Documentation/process/submitting-patches.rst
+* Documentation/admin-guide/reporting-issues.rst
+* Documentation/process/security-bugs.rst
+
+Entonces envíe un parche (incluyendo un registro de confirmación con
+todos los detalles enumerados abajo) y haga un seguimiento de cualquier
+comentario de otros desarrolladores.
+
+* ¿Cuál es el problema específico que se ha encontrado?
+* ¿Como podría llegar al problema en un sistema en ejecución?
+* ¿Qué efecto tendría encontrar el problema en el sistema?
+* ¿Como se encontró el problema? Incluya específicamente detalles sobre
+ cualquier prueba, programas de análisis estáticos o dinámicos, y cualquier
+ otra herramienta o método utilizado para realizar el trabajo.
+* ¿En qué versión de Linux se encontró el problema? Se prefiere usar la
+ versión más reciente o una rama reciente de linux-next (ver
+ Documentation/process/howto.rst).
+* ¿Que se cambió para solucionar el problema y por qué se cree es correcto?
+* ¿Como se probó el cambio para la complicación y el tiempo de ejecución?
+* ¿Qué confirmación previa corrige este cambio? Esto debería ir en un “Fixes:”
+ etiqueta como se describe en la documentación.
+* ¿Quién más ha revisado este parche? Esto debería ir con la adecuada “Reviewed-by”
+ etiqueta; Vea abajo.
+
+Por ejemplo (en inglés, pues es en las listas)::
+
+ From: Author <author@email>
+ Subject: [PATCH] drivers/foo_bar: Add missing kfree()
+
+ The error path in foo_bar driver does not correctly free the allocated
+ struct foo_bar_info. This can happen if the attached foo_bar device
+ rejects the initialization packets sent during foo_bar_probe(). This
+ would result in a 64 byte slab memory leak once per device attach,
+ wasting memory resources over time.
+
+ This flaw was found using an experimental static analysis tool we are
+ developing, LeakMagic[1], which reported the following warning when
+ analyzing the v5.15 kernel release:
+
+ path/to/foo_bar.c:187: missing kfree() call?
+
+ Add the missing kfree() to the error path. No other references to
+ this memory exist outside the probe function, so this is the only
+ place it can be freed.
+
+ x86_64 and arm64 defconfig builds with CONFIG_FOO_BAR=y using GCC
+ 11.2 show no new warnings, and LeakMagic no longer warns about this
+ code path. As we don't have a FooBar device to test with, no runtime
+ testing was able to be performed.
+
+ [1] https://url/to/leakmagic/details
+
+ Reported-by: Researcher <researcher@email>
+ Fixes: aaaabbbbccccdddd ("Introduce support for FooBar")
+ Signed-off-by: Author <author@email>
+ Reviewed-by: Reviewer <reviewer@email>
+
+Si usted es un colaborador por primera vez, se recomienda que el parche en
+si sea examinado por otros en privado antes de ser publicado en listas
+públicas. (Esto es necesario si se le ha dicho explícitamente que sus parches
+necesitan una revisión interna más cuidadosa.) Se espera que estas personas
+tengan su etiqueta “Reviewed-by” incluida en el parche resultante. Encontrar
+otro desarrollador con conocimiento de las contribuciones a Linux, especialmente
+dentro de su propia organización, y tener su ayuda con las revisiones antes de
+enviarlas a las listas de correo publico tiende a mejorar significativamente la
+calidad de los parches resultantes, y reduce así la carga de otros desarrolladores.
+
+Si no se puede encontrar a nadie para revisar internamente los parches y necesita
+ayuda para encontrar a esa persona, o si tiene alguna otra pregunta relacionada
+con este documento y las expectativas de la comunidad de desarrolladores, por
+favor contacte con la lista de correo privada Technical Advisory Board:
+<tech-board@lists.linux-foundation.org>.
diff --git a/Documentation/translations/sp_SP/process/security-bugs.rst b/Documentation/translations/sp_SP/process/security-bugs.rst
new file mode 100644
index 000000000000..d07c7e579b52
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/security-bugs.rst
@@ -0,0 +1,103 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-sp.rst
+
+:Original: Documentation/process/security-bugs.rst
+:Translator: Avadhut Naik <avadhut.naik@amd.com>
+
+Errores de seguridad
+====================
+
+Los desarrolladores del kernel de Linux se toman la seguridad muy en
+serio. Como tal, nos gustaría saber cuándo se encuentra un error de
+seguridad para que pueda ser corregido y divulgado lo más rápido posible.
+Por favor, informe sobre los errores de seguridad al equipo de seguridad
+del kernel de Linux.
+
+Contacto
+--------
+
+El equipo de seguridad del kernel de Linux puede ser contactado por correo
+electrónico en <security@kernel.org>. Esta es una lista privada de
+oficiales de seguridad que ayudarán a verificar el informe del error y
+desarrollarán y publicarán una corrección. Si ya tiene una corrección, por
+favor, inclúyala con su informe, ya que eso puede acelerar considerablemente
+el proceso. Es posible que el equipo de seguridad traiga ayuda adicional
+de mantenedores del área para comprender y corregir la vulnerabilidad de
+seguridad.
+
+Como ocurre con cualquier error, cuanta más información se proporcione,
+más fácil será diagnosticarlo y corregirlo. Por favor, revise el
+procedimiento descrito en 'Documentation/admin-guide/reporting-issues.rst'
+si no tiene claro que información es útil. Cualquier código de explotación
+es muy útil y no será divulgado sin el consentimiento del "reportero" (el
+que envia el error) a menos que ya se haya hecho público.
+
+Por favor, envíe correos electrónicos en texto plano sin archivos
+adjuntos cuando sea posible. Es mucho más difícil tener una discusión
+citada en contexto sobre un tema complejo si todos los detalles están
+ocultos en archivos adjuntos. Piense en ello como un
+:doc:`envío de parche regular <submitting-patches>` (incluso si no tiene
+un parche todavía) describa el problema y el impacto, enumere los pasos
+de reproducción, y sígalo con una solución propuesta, todo en texto plano.
+
+
+Divulgación e información embargada
+-----------------------------------
+
+La lista de seguridad no es un canal de divulgación. Para eso, ver
+Coordinación debajo. Una vez que se ha desarrollado una solución robusta,
+comienza el proceso de lanzamiento. Las soluciones para errores conocidos
+públicamente se lanzan inmediatamente.
+
+Aunque nuestra preferencia es lanzar soluciones para errores no divulgados
+públicamente tan pronto como estén disponibles, esto puede postponerse a
+petición del reportero o una parte afectada por hasta 7 días calendario
+desde el inicio del proceso de lanzamiento, con una extensión excepcional
+a 14 días de calendario si se acuerda que la criticalidad del error requiere
+más tiempo. La única razón válida para aplazar la publicación de una
+solución es para acomodar la logística de QA y los despliegues a gran
+escala que requieren coordinación de lanzamiento.
+
+Si bien la información embargada puede compartirse con personas de
+confianza para desarrollar una solución, dicha información no se publicará
+junto con la solución o en cualquier otro canal de divulgación sin el
+permiso del reportero. Esto incluye, pero no se limita al informe original
+del error y las discusiones de seguimiento (si las hay), exploits,
+información sobre CVE o la identidad del reportero.
+
+En otras palabras, nuestro único interés es solucionar los errores. Toda
+otra información presentada a la lista de seguridad y cualquier discusión
+de seguimiento del informe se tratan confidencialmente incluso después de
+que se haya levantado el embargo, en perpetuidad.
+
+Coordinación con otros grupos
+-----------------------------
+
+El equipo de seguridad del kernel recomienda encarecidamente que los
+reporteros de posibles problemas de seguridad NUNCA contacten la lista
+de correo “linux-distros” hasta DESPUES de discutirlo con el equipo de
+seguridad del kernel. No Cc: ambas listas a la vez. Puede ponerse en
+contacto con la lista de correo linux-distros después de que se haya
+acordado una solución y comprenda completamente los requisitos que al
+hacerlo le impondrá a usted y la comunidad del kernel.
+
+Las diferentes listas tienen diferentes objetivos y las reglas de
+linux-distros no contribuyen en realidad a solucionar ningún problema de
+seguridad potencial.
+
+Asignación de CVE
+-----------------
+
+El equipo de seguridad no asigna CVEs, ni los requerimos para informes o
+correcciones, ya que esto puede complicar innecesariamente el proceso y
+puede retrasar el manejo de errores. Si un reportero desea que se le
+asigne un identificador CVE, debe buscar uno por sí mismo, por ejemplo,
+poniéndose en contacto directamente con MITRE. Sin embargo, en ningún
+caso se retrasará la inclusión de un parche para esperar a que llegue un
+identificador CVE.
+
+Acuerdos de no divulgación
+--------------------------
+
+El equipo de seguridad del kernel de Linux no es un organismo formal y,
+por lo tanto, no puede firmar cualquier acuerdo de no divulgación.
diff --git a/Documentation/translations/sp_SP/process/submit-checklist.rst b/Documentation/translations/sp_SP/process/submit-checklist.rst
new file mode 100644
index 000000000000..0d6651f9d871
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/submit-checklist.rst
@@ -0,0 +1,133 @@
+.. include:: ../disclaimer-sp.rst
+
+:Original: Documentation/process/submit-checklist.rst
+:Translator: Avadhut Naik <avadhut.naik@amd.com>
+
+.. _sp_submitchecklist:
+
+Lista de comprobación para enviar parches del kernel de Linux
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Aquí hay algunas cosas básicas que los desarrolladores deben hacer si
+quieren que sus envíos de parches del kernel sean aceptados más
+rápidamente.
+
+Todo esto está más allá de la documentación que se proporciona en
+:ref:`Documentation/translations/sp_SP/process/submitting-patches.rst <sp_submittingpatches>`
+y en otros lugares con respecto al envío de parches del kernel de Linux.
+
+1) Si utiliza una funcionalidad, #include el archivo que define/declara
+ esa funcionalidad. No dependa de otros archivos de encabezado que
+ extraigan los que utiliza.
+
+2) Compile limpiamente:
+
+ a) Con las opciones ``CONFIG`` aplicables o modificadas ``=y``, ``=m``,
+ y ``=n``. Sin advertencias/errores del compilador ``gcc``, ni
+ advertencias/errores del linker.
+
+ b) Aprobar ``allnoconfig``, ``allmodconfig``
+
+ c) Compila correctamente cuando se usa ``O=builddir``
+
+ d) Cualquier documentación o cambios se compilan correctamente sin
+ nuevas advertencias/errores. Utilice ``make htmldocs`` o
+ ``make pdfdocs`` para comprobar la compilación y corregir cualquier
+ problema.
+
+3) Se compila en varias arquitecturas de CPU mediante herramientas de
+ compilación cruzada locales o alguna otra granja de compilación.
+
+4) ppc64 es una buena arquitectura para verificar la compilación cruzada
+ por que tiende a usar ``unsigned long`` para cantidades de 64-bits.
+
+5) Verifique su parche para el estilo general según se detalla en
+ :ref:`Documentation/translations/sp_SP/process/coding-style.rst <sp_codingstyle>`.
+ Verifique las infracciones triviales con el verificador de estilo de
+ parches antes de la entrega (``scripts/checkpatch.pl``).
+ Debería ser capaz de justificar todas las infracciones que permanezcan
+ en su parche.
+
+6) Cualquier opción ``CONFIG`` nueva o modificada no altera el menú de
+ configuración y se desactiva por defecto, a menos que cumpla con los
+ criterios de excepción documentados en
+ ``Documentation/kbuild/kconfig-language.rst`` Atributos del menú: valor por defecto.
+
+7) Todas las nuevas opciones de ``Kconfig`` tienen texto de ayuda.
+
+8) Ha sido revisado cuidadosamente con respecto a las combinaciones
+ relevantes de ``Kconfig``. Esto es muy difícil de hacer correctamente
+ con las pruebas -- la concentración mental da resultados aquí.
+
+9) Verifique limpiamente con sparse.
+
+10) Use ``make checkstack`` y solucione cualquier problema que encuentre.
+
+ .. note::
+
+ ``checkstack`` no señala los problemas explícitamente, pero
+ cualquier función que use más de 512 bytes en la pila es
+ candidata para el cambio.
+
+11) Incluya :ref:`kernel-doc <kernel_doc>` para documentar las API
+ globales del kernel. (No es necesario para funciones estáticas, pero
+ también está bien.) Utilice ``make htmldocs`` o ``make pdfdocs``
+ para comprobar el :ref:`kernel-doc <kernel_doc>` y solucionar
+ cualquier problema.
+
+12) Ha sido probado con ``CONFIG_PREEMPT``, ``CONFIG_DEBUG_PREEMPT``,
+ ``CONFIG_DEBUG_SLAB``, ``CONFIG_DEBUG_PAGEALLOC``, ``CONFIG_DEBUG_MUTEXES``,
+ ``CONFIG_DEBUG_SPINLOCK``, ``CONFIG_DEBUG_ATOMIC_SLEEP``
+ ``CONFIG_PROVE_RCU`` y ``CONFIG_DEBUG_OBJECTS_RCU_HEAD`` todos
+ habilitados simultáneamente.
+
+13) Ha sido probado en tiempo de compilación y ejecución con y sin
+ ``CONFIG_SMP`` y ``CONFIG_PREEMPT``.
+
+14) Todas las rutas de código se han ejercido con todas las
+ características de lockdep habilitadas.
+
+15) Todas las nuevas entradas de ``/proc`` están documentadas en
+ ``Documentation/``.
+
+16) Todos los nuevos parámetros de arranque del kernel están documentados
+ en ``Documentation/admin-guide/kernel-parameters.rst``.
+
+17) Todos los nuevos parámetros del módulo están documentados con
+ ``MODULE_PARM_DESC()``.
+
+18) Todas las nuevas interfaces de espacio de usuario están documentadas
+ en ``Documentation/ABI/``. Consulte ``Documentation/ABI/README`` para
+ obtener más información. Los parches que cambian las interfaces del
+ espacio de usuario deben ser CCed a linux-api@vger.kernel.org.
+
+19) Se ha comprobado con la inyección de al menos errores de asignación
+ de slab y página. Consulte ``Documentation/fault-injection/``.
+
+ Si el nuevo código es sustancial, la adición de la inyección de
+ errores específica del subsistema podría ser apropiada.
+
+20) El nuevo código añadido ha sido compilado con ``gcc -W`` (use
+ ``make KCFLAGS=-W``). Esto generara mucho ruido per es buena para
+ encontrar errores como "warning: comparison between signed and unsigned".
+
+21) Se prueba después de que se haya fusionado en el conjunto de
+ parches -mm para asegurarse de que siga funcionando con todos los
+ demás parches en cola y varios cambios en VM, VFS y otros subsistemas.
+
+22) Todas las barreras de memoria {p.ej., ``barrier()``, ``rmb()``,
+ ``wmb()``} necesitan un comentario en el código fuente que explique
+ la lógica de lo que están haciendo y por qué.
+
+23) Si se añaden algún ioctl en el parche, actualice también
+ ``Documentation/userspace-api/ioctl/ioctl-number.rst``.
+
+24) Si su código fuente modificado depende o utiliza cualquiera de las
+ API o características del kernel que están relacionadas con los
+ siguientes símbolos ``Kconfig`` entonces pruebe varias compilaciones
+ con los símbolos ``Kconfig`` relacionados deshabilitados y/o ``=m``
+ (si esa opción esta disponible) [no todos estos al mismo tiempo, solo
+ varias/aleatorias combinaciones de ellos]:
+
+ ``CONFIG_SMP``, ``CONFIG_SYSFS``, ``CONFIG_PROC_FS``, ``CONFIG_INPUT``, ``CONFIG_PCI``, ``CONFIG_BLOCK``, ``CONFIG_PM``, ``CONFIG_MAGIC_SYSRQ``
+ ``CONFIG_NET``, ``CONFIG_INET=n`` (pero luego con ``CONFIG_NET=y``).
diff --git a/Documentation/translations/sp_SP/process/submitting-patches.rst b/Documentation/translations/sp_SP/process/submitting-patches.rst
new file mode 100644
index 000000000000..c2757d9ab216
--- /dev/null
+++ b/Documentation/translations/sp_SP/process/submitting-patches.rst
@@ -0,0 +1,894 @@
+.. include:: ../disclaimer-sp.rst
+
+:Original: :ref:`Documentation/process/submitting-patches.rst <submittingpatches>`
+:Translator: Carlos Bilbao <carlos.bilbao@amd.com>
+
+.. _sp_submittingpatches:
+
+Envío de parches: la guía esencial para incluir su código en el kernel
+=======================================================================
+
+Para una persona o empresa que desee enviar un cambio al kernel Linux,
+el proceso puede en ocasiones resultar desalentador si no se está
+familiarizado con "el sistema". Este texto es una colección de sugerencias
+que pueden aumentar considerablemente las posibilidades de que se acepte su
+cambio.
+
+Este documento contiene una gran cantidad de sugerencias en un formato
+relativamente conciso. Para obtener información detallada sobre cómo
+funciona el proceso de desarrollo del kernel, consulte
+Documentation/process/development-process.rst. Además, lea
+Documentation/process/submit-checklist.rst para obtener una lista de
+elementos a verificar antes de enviar código. Para los parches de
+"binding" del árbol de dispositivos, lea
+Documentation/devicetree/bindings/submitting-patches.rst.
+
+Esta documentación asume que está usando ``git`` para preparar sus parches.
+Si no está familiarizado con ``git``, le recomendamos que aprenda a
+usarlo, le hará la vida como desarrollador del kernel y en general mucho
+más sencilla.
+
+Algunos subsistemas y árboles de mantenimiento cuentan con información
+adicional sobre su flujo de trabajo y expectativas, consulte
+:ref:`Documentation/process/maintainer-handbooks.rst <maintainer_handbooks_main>`.
+
+Obtenga el código fuente actual
+--------------------------------
+
+Si no tiene a mano un repositorio con el código fuente actual del kernel,
+use ``git`` para obtener uno. Querrá comenzar con el repositorio principal,
+que se puede descargar con::
+
+ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
+
+Tenga en cuenta, sin embargo, que es posible que no desee desarrollar con
+el árbol principal directamente. La mayoría de los maintainers de
+subsistemas usan sus propios árboles de código fuente y quieren ver parches
+preparados para esos árboles. Revise el campo **T:** para el subsistema
+en el archivo MAINTAINERS para encontrar dicho árbol, o simplemente
+pregunte al maintainer si el árbol no está listado allí.
+
+.. _sp_describe_changes:
+
+Describa sus cambios
+---------------------
+
+Describa su problema. Sea su parche una corrección de un error de una
+línea o 5000 líneas para una nuevo "feature", debe haber un problema
+subyacente que le motivó a hacer ese trabajo. Convenza al revisor de que
+hay un problema que merece la pena solucionar y de que tiene sentido que
+lea más allá del primer párrafo.
+
+Describa el impacto relativo al usuario. Cosas que estropeen el kernel y
+los bloqueos son bastante convincentes, pero no todos los errores son tan
+evidentes. Incluso si se detectó un problema durante la revisión del
+código, describa el impacto que cree pueda tener en los usuarios. Tenga en
+cuenta que la mayoría de instalaciones de Linux ejecutan kernels desde
+árboles estables secundarios o árboles específicos de proveedor/producto
+que seleccionan ("cherry-pick") solo parches específicos de upstream, así
+que incluya cualquier cosa que pueda ayudar a dirigir su cambio
+aguas abajo: circunstancias que producen cierta situación, extractos de
+dmesg, descripciones del error fatal, regresiones de rendimiento, picos de
+latencia, bloqueos, etc.
+
+Cuantifique optimizaciones y beneficios/perdidas. Si asegura mejoras en
+rendimiento, consumo de memoria, huella del stack o tamaño de binario,
+incluya números que lo respalden. Pero también describa costes no obvios.
+Las optimizaciones generalmente no son gratuitas, sino un equilibrio entre
+CPU, memoria y legibilidad; o, cuando se trata de heurísticas, entre
+diferentes cargas de trabajo. Describa las desventajas esperadas de su
+optimización para que el revisor pueda comparar las perdidas con los
+beneficios.
+
+Una vez establecido el problema, describa lo que realmente está haciendo
+al respecto en detalles técnicos. Es importante describir el cambio en
+lenguaje sencillo para que el revisor verifique que el código se está
+comportando como se pretende.
+
+El maintainer le agradecerá que escriba la descripción de su parche en un
+formato que se pueda incorporar fácilmente en la gestión del código fuente
+del sistema, ``git``, como un "commit log" (registros de los commits).
+Consulte :ref:`sp_the_canonical_patch_format`.
+
+Resuelva solo un problema por parche. Si su descripción comienza a ser muy
+larga, eso es una señal de que probablemente necesite dividir su parche.
+Lea :ref:`split_changes`.
+
+Cuando envíe o vuelva a enviar un parche o una serie de parches, incluya la
+descripción completa del parche y justificación del mismo. No se limite a
+decir que esa es la versión N del parche (serie). No espere que el
+maintainer del subsistema referencie versiones de parches anteriores o use
+referencias URL para encontrar la descripción del parche y colocarla en el
+parche. Es decir, el parche (serie) y su descripción deben ser
+independientes. Esto beneficia tanto a los maintainers como a los
+revisores. Algunos revisores probablemente ni siquiera recibieran versiones
+anteriores del parche.
+
+Describa sus cambios en la forma imperativa, por ejemplo, "hacer que xyzzy
+haga frotz" en lugar de "[Este parche] hace que xyzzy haga frotz" o "[Yo]
+Cambié xyzzy para que haga frotz", como si estuviera dando órdenes al
+código fuente para cambiar su comportamiento.
+
+Si desea hacer referencia a un commit específico, no se limite a hacer
+referencia al ID SHA-1 del commit. Incluya también el resumen de una línea
+del commit, para que sea más fácil para los revisores saber de qué se
+trata.
+Ejemplo::
+
+ Commit e21d2170f36602ae2708 ("video: quitar platform_set_drvdata()
+ innecesario") eliminó innecesario platform_set_drvdata(), pero dejó la
+ variable "dev" sin usar, bórrese.
+
+También debe asegurarse de utilizar al menos los primeros doce caracteres
+del identificador SHA-1. El repositorio del kernel contiene muchos *muchos*
+objetos, por lo que las colisiones con identificaciones más cortas son una
+posibilidad real. Tenga en cuenta que, aunque no hay colisión con su
+identificación de seis caracteres ahora, esa condición puede cambiar dentro
+de cinco años.
+
+Si las discusiones relacionadas o cualquier otra información relativa al
+cambio se pueden encontrar en la web, agregue las etiquetas 'Link:' que
+apunten a estos. En caso de que su parche corrija un error, por poner un
+ejemplo, agregue una etiqueta con una URL que haga referencia al informe en
+los archivos de las listas de correo o un rastreador de errores; si el
+parche es el resultado de alguna discusión anterior de la lista de correo o
+algo documentado en la web, referencie esto.
+
+Cuando se vincule a archivos de listas de correo, preferiblemente use el
+servicio de archivador de mensajes lore.kernel.org. Para crear la URL del
+enlace, utilice el contenido del encabezado ("header") ``Message-Id`` del
+mensaje sin los corchetes angulares que lo rodean.
+Por ejemplo::
+
+ Link: https://lore.kernel.org/r/30th.anniversary.repost@klaava.Helsinki.FI/
+
+Verifique el enlace para asegurarse de que realmente funciona y apunta al
+mensaje correspondiente.
+
+Sin embargo, intente que su explicación sea comprensible sin recursos
+externos. Además de dar una URL a un archivo o error de la lista de correo,
+resuma los puntos relevantes de la discusión que condujeron al parche tal y
+como se envió.
+
+Si su parche corrige un error en un commit específico, por ejemplo
+encontró un problema usando ``git bisect``, utilice la etiqueta 'Fixes:'
+con los primeros 12 caracteres del ID SHA-1 y el resumen de una línea. No
+divida la etiqueta en varias líneas, las etiquetas están exentas de la
+regla "ajustar a 75 columnas" para simplificar análisis de scripts. Por
+ejemplo::
+
+ Fixes: 54a4f0239f2e ("KVM: MMU: hacer que kvm_mmu_zap_page()
+ devuelva la cantidad de páginas que realmente liberó")
+
+Las siguientes configuraciones de ``git config`` se pueden usar para
+agregar un bonito formato y generar este estilo con los comandos
+``git log`` o ``git show``::
+
+ [core]
+ abbrev = 12
+ [pretty]
+ fixes = Fixes: %h (\"%s\")
+
+Un ejemplo de uso::
+
+ $ git log -1 --pretty=fixes 54a4f0239f2e
+ Fixes: 54a4f0239f2e ("KVM: MMU: hacer que kvm_mmu_zap_page() devuelva la cantidad de páginas que realmente liberó")
+
+.. _sp_split_changes:
+
+Separe sus cambios
+-------------------
+
+Separe cada **cambio lógico** en un parche separado.
+
+Por ejemplo, si sus cambios incluyen correcciones de errores y mejoras en
+el rendimiento de un controlador, separe esos cambios en dos o más parches.
+Si sus cambios incluyen una actualización de la API y una nueva controlador
+que usa esta nueva API, sepárelos en dos parches.
+
+Por otro lado, si realiza un solo cambio en numerosos archivos, agrupe esos
+cambios en un solo parche. Por lo tanto, un solo cambio lógico estará
+contenido en un solo parche.
+
+El punto a recordar es que cada parche debe realizar un cambio que puede
+ser verificado por los revisores fácilmente. Cada parche debe ser
+justificable por sus propios méritos.
+
+Si un parche depende de otro parche para que un cambio sea completo, eso
+está bien. Simplemente incluya que **"este parche depende del parche X"**
+en la descripción de su parche.
+
+Cuando divida su cambio en una serie de parches, tenga especial cuidado en
+asegurarse de que el kernel se compila y ejecuta correctamente después de
+cada parche en la serie. Los desarrolladores que usan ``git bisect``
+para rastrear un problema pueden terminar dividiendo su serie de parches en
+cualquier punto; no le agradecerán si introdujo errores a la mitad.
+
+Si no puede condensar su conjunto de parches en un conjunto más pequeño de
+parches, solo publique, más o menos 15 a la vez, y espere la revisión e
+integración.
+
+
+Revise el estilo en sus cambios
+--------------------------------
+
+Revise su parche para ver si hay violaciones de estilo básico, cuyos
+detalles pueden ser encontrados en Documentation/process/coding-style.rst.
+No hacerlo simplemente desperdicia el tiempo de los revisores y su parche
+será rechazado, probablemente sin siquiera ser leído.
+
+Una excepción importante es cuando se mueve código de un archivo a otro.
+En tal caso, en absoluto debe modificar el código movido en el mismo parche
+en que lo mueve. Esto divide claramente el acto de mover el código y sus
+cambios. Esto ayuda mucho a la revisión de la diferencias reales y permite
+que las herramientas rastreen mejor el historial del código en sí.
+
+Verifique sus parches con el verificador de estilo de parches antes de
+enviarlos (scripts/checkpatch.pl). Tenga en cuenta, sin embargo, que el
+verificador de estilo debe ser visto como una guía, no como un reemplazo
+del juicio humano. Si su código es mejor con una violación entonces
+probablemente sea mejor dejarlo estar.
+
+El verificador informa a tres niveles:
+ - ERROR: cosas que es muy probable que estén mal
+ - WARNING: Advertencia. Cosas que requieren una revisión cuidadosa
+ - CHECK: Revisar. Cosas que requieren pensarlo
+
+Debe poder justificar todas las violaciones que permanezcan en su parche.
+
+
+Seleccione los destinatarios de su parche
+------------------------------------------
+
+Siempre debe incluir en copia a los apropiados maintainers del subsistema
+en cualquier parche con código que mantengan; revise a través del archivo
+MAINTAINERS y el historial de revisión del código fuente para ver quiénes
+son esos maintainers. El script scripts/get_maintainer.pl puede ser muy
+útil en este paso (pase rutas a sus parches como argumentos para
+scripts/get_maintainer.pl). Si no puede encontrar un maintainer del
+subsistema en el que está trabajando, Andrew Morton
+(akpm@linux-foundation.org) sirve como maintainer de último recurso.
+
+Normalmente, también debe elegir al menos una lista de correo para recibir
+una copia de su conjunto de parches. linux-kernel@vger.kernel.org debe
+usarse de forma predeterminada para todos los parches, pero el volumen en
+esta lista ha hecho que muchos desarrolladores se desconecten. Busque en el
+archivo MAINTAINERS una lista específica de los subsistemas; su parche
+probablemente recibirá más atención allí. Sin embargo, no envíe spam a
+listas no relacionadas.
+
+Muchas listas relacionadas con el kernel están alojadas en vger.kernel.org;
+puedes encontrar un listado de estas en
+http://vger.kernel.org/vger-lists.html. Existen listas relacionadas con el
+kernel alojadas en otros lugares, no obstante.
+
+¡No envíe más de 15 parches a la vez a las listas de correo de vger!
+
+Linus Torvalds es el árbitro final de todos los cambios aceptados en el
+kernel de Linux. Su dirección de correo electrónico es
+<torvalds@linux-foundation.org>. Recibe muchos correos electrónicos y, en
+este momento, muy pocos parches pasan por Linus directamente, por lo que
+normalmente debe hacer todo lo posible para -evitar- enviarle un correo
+electrónico.
+
+Si tiene un parche que corrige un error de seguridad explotable, envíe ese
+parche a security@kernel.org. Para errores graves, se debe mantener un
+poco de discreción y permitir que los distribuidores entreguen el parche a
+los usuarios; en esos casos, obviamente, el parche no debe enviarse a
+ninguna lista pública. Revise también
+Documentation/process/security-bugs.rst.
+
+Los parches que corrigen un error grave en un kernel en uso deben dirigirse
+hacia los maintainers estables poniendo una línea como esta::
+
+ CC: stable@vger.kernel.org
+
+en el área de sign-off de su parche (es decir, NO un destinatario de correo
+electrónico). También debe leer
+Documentation/process/stable-kernel-rules.rst además de este documento.
+
+Si los cambios afectan las interfaces del kernel para el usuario, envíe al
+maintainer de las MAN-PAGES (como se indica en el archivo MAINTAINERS) un
+parche de páginas de manual, o al menos una notificación del cambio, para
+que alguna información se abra paso en las páginas del manual. Los cambios
+de la API del espacio de usuario también deben copiarse en
+linux-api@vger.kernel.org.
+
+
+Sin MIME, enlaces, compresión o archivos adjuntos. Solo texto plano
+--------------------------------------------------------------------
+
+Linus y otros desarrolladores del kernel deben poder leer y comentar sobre
+los cambios que está enviando. Es importante para un desarrollador kernel
+poder "citar" sus cambios, utilizando herramientas estándar de correo
+electrónico, de modo que puedan comentar sobre partes específicas de su
+código.
+
+Por este motivo, todos los parches deben enviarse por correo electrónico
+"inline". La forma más sencilla de hacerlo es con ``git send-email``, que
+es muy recomendable. Un tutorial interactivo para ``git send-email`` está
+disponible en https://git-send-email.io.
+
+Si elige no usar ``git send-email``:
+
+.. warning::
+
+ Tenga cuidado con el ajuste de palabras de su editor que corrompe su
+ parche, si elige cortar y pegar su parche.
+
+No adjunte el parche como un archivo adjunto MIME, comprimido o no. Muchas
+populares aplicaciones de correo electrónico no siempre transmiten un MIME
+archivo adjunto como texto sin formato, por lo que es imposible comentar
+en su código. Linus también necesita un poco más de tiempo para procesar un
+archivo adjunto MIME, disminuyendo la probabilidad de que se acepte su
+cambio adjunto en MIME.
+
+Excepción: si su proveedor de correo está destrozando parches, entonces
+alguien puede pedir que los vuelva a enviar usando MIME.
+
+Consulte Documentation/process/email-clients.rst para obtener sugerencias
+sobre cómo configurar su cliente de correo electrónico para que envíe sus
+parches intactos.
+
+Responda a los comentarios de revisión
+---------------------------------------
+
+Es casi seguro que su parche recibirá comentarios de los revisores sobre
+maneras en que se pueda mejorar el parche, en forma de respuesta a su
+correo electrónico. Debe responder a esos comentarios; ignorar a los
+revisores es una buena manera de ser ignorado de vuelta. Simplemente puede
+responder a sus correos electrónicos para contestar a sus comentarios.
+Revisiones a los comentarios o preguntas que no conduzcan a un cambio de
+código deben casi con certeza generar un comentario o una entrada en el
+"changelog" para que el próximo revisor entienda lo que está pasando.
+
+Asegúrese de decirles a los revisores qué cambios está haciendo y de
+agradecerles que dediquen su tiempo. La revisión del código es un proceso
+agotador y lento, y los revisores a veces se ponen de mal humor. Sin
+embargo, incluso en ese caso, responda cortésmente y aborde los problemas
+que hayan señalado. Al enviar un siguiente versión, agregue un
+``patch changelog`` (registro de cambios en los parches) a la carta de
+presentación ("cover letter") o a parches individuales explicando la
+diferencia con la presentación anterior (ver
+:ref:`sp_the_canonical_patch_format`).
+
+Consulte Documentation/process/email-clients.rst para obtener
+recomendaciones sobre clientes de correo electrónico y normas de etiqueta
+en la lista de correo.
+
+.. _sp_resend_reminders:
+
+No se desanime o impaciente
+---------------------------
+
+Después de haber entregado su cambio, sea paciente y espere. Los revisores
+son personas ocupadas y es posible que no lleguen a su parche de inmediato.
+
+Érase una vez, los parches solían desaparecer en el vacío sin comentarios,
+pero el proceso de desarrollo funciona mejor que eso ahora. Debería
+recibir comentarios dentro de una semana más o menos; si eso no sucede,
+asegúrese de que ha enviado sus parches al lugar correcto. Espere un mínimo
+de una semana antes de volver a enviar o hacer ping a los revisores,
+posiblemente más durante periodos de mucho trabajo ocupados como "merge
+windows".
+
+También está bien volver a enviar el parche o la serie de parches después
+de un par de semanas con la palabra "RESEND" (reenviar) añadida a la línea
+de asunto::
+
+ [PATCH Vx RESEND] sub/sys: Resumen condensado de parche
+
+No incluya "RESEND" cuando envíe una versión modificada de su parche o
+serie de parches: "RESEND" solo se aplica al reenvío de un parche o serie
+de parches que no hayan sido modificados de ninguna manera con respecto a
+la presentación anterior.
+
+
+Incluya PATCH en el asunto
+--------------------------
+
+Debido al alto tráfico de correo electrónico a Linus y al kernel de Linux,
+es común prefijar su línea de asunto con [PATCH]. Esto le permite a Linus
+y otros desarrolladores del kernel distinguir más fácilmente los parches de
+otras discusiones por correo electrónico.
+
+``git send-email`` lo hará automáticamente.
+
+
+Firme su trabajo: el Certificado de Origen del Desarrollador
+------------------------------------------------------------
+
+Para mejorar el seguimiento de quién hizo qué, especialmente con parches
+que pueden filtrarse hasta su destino final a través de varias capas de
+maintainers, hemos introducido un procedimiento de "sign-off" (aprobación)
+en parches que se envían por correo electrónico.
+
+La aprobación es una simple línea al final de la explicación del parche,
+que certifica que usted lo escribió o que tiene derecho a enviarlo como un
+parche de código abierto. Las reglas son bastante simples: si usted puede
+certificar lo siguiente:
+
+Certificado de Origen del Desarrollador 1.1
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Al hacer una contribución a este proyecto, certifico que:
+
+ (a) La contribución fue creada en su totalidad o en parte por mí y
+ tengo derecho a enviarlo bajo la licencia de código abierto
+ indicada en el documento; o
+
+ (b) La contribución se basa en trabajo previo que, hasta donde yo
+ soy consciente, está cubierto por una licencia de código
+ abierto apropiada y tengo el derecho bajo esa licencia de
+ presentar tal trabajo con modificaciones, ya sean creadas en su
+ totalidad o en parte por mí, bajo la misma licencia de código
+ (salvo que sea permitido presentar bajo una licencia diferente),
+ tal y como se indica en el documento; o
+
+ (c) La contribución me fue proporcionada directamente por alguna
+ otra persona que certificó (a), (b) o (c) y no he modificado
+ esto.
+
+ (d) Entiendo y acepto que este proyecto y la contribución
+ son públicos y que un registro de la contribución (incluyendo
+ toda la información personal que envío con él, incluida mi
+ firma) es mantenida indefinidamente y puede ser redistribuida
+ de manera consistente con este proyecto o la(s) licencia(s) de
+ código abierto involucradas.
+
+entonces simplemente incluya una línea que rece::
+
+ Signed-off-by: Random J Developer <random@developer.example.org>
+
+usando su nombre real (lamentablemente, no pseudónimos ni contribuciones
+anónimas). Esto se hará por usted automáticamente si usa ``git commit -s``.
+Las reversiones de código también deben incluir "Signed-off-by".
+``git revert -s`` hace eso por usted.
+
+Algunas personas también ponen etiquetas adicionales al final. Simplemente
+serán ignoradas por ahora, pero puede hacer esto para marcar procedimientos
+internos de su empresa o simplemente señalar algún detalle especial sobre
+la firma.
+
+Cualquier otro SoB (Signed-off-by:) después del SoB del autor es de
+personas que manipulen y transporten el parche, pero no participaron en su
+desarrollo. Las cadenas de SoB deben reflejar la ruta **real** del parche
+de cómo se propagó a los maintainers y, en última instancia, a Linus, con
+la primera entrada de SoB que señala la autoría principal de un solo autor.
+
+
+Cuándo usar Acked-by:, Cc: y Co-developed-by por:
+-------------------------------------------------
+
+La etiqueta Signed-off-by: indica que el firmante estuvo involucrado en el
+desarrollo del parche, o que él/ella se encontraba en el camino de entrega
+del parche.
+
+Si una persona no estuvo directamente involucrada en la preparación o
+administración de un parche pero desea expresar y registrar su aprobación,
+entonces puede pedir que se agregue una línea Acked-by: al registro de
+cambios del parche.
+
+Acked-by: a menudo lo usa el maintainer del código afectado cuando ese
+maintainer no contribuyó ni envió el parche.
+
+Acked-by: no es tan formal como Signed-off-by:. Es una manera de marcar que
+el "acker" ha revisado al menos ese parche y ha indicado su aceptación. Por
+los merge de parches a veces convertirán manualmente el "sí, me parece bien"
+de un acker en un Acked-by: (pero tenga en cuenta que por lo general es
+mejor pedir un acuse de recibo explícito).
+
+Acked-by: no necesariamente indica el reconocimiento de todo el parche.
+Por ejemplo, si un parche afecta a varios subsistemas y tiene un
+Acked-by: de un maintainer del subsistema, entonces esto generalmente
+indica el reconocimiento de solo la parte que afecta el código de ese
+maintainer. Buen juicio debe ejercitarse aquí. En caso de duda, la gente
+debe consultar la discusión original en los archivos de la lista de correo.
+
+Si una persona ha tenido la oportunidad de comentar un parche, pero no lo
+ha hecho, puede incluir opcionalmente una etiqueta ``Cc:`` al parche.
+Esta es la única etiqueta que se puede agregar sin una acción explícita por
+parte de la persona a la que se nombre - pero debe indicar que esta persona
+fue copiada en el parche. Esta etiqueta documenta que las partes
+potencialmente interesadas han sido incluidas en la discusión.
+
+Co-developed-by: establece que el parche fue co-creado por múltiples
+desarrolladores; se utiliza para dar atribución a los coautores (además del
+autor atribuido por la etiqueta From:) cuando varias personas trabajan en
+un solo parche. Ya que Co-developed-by: denota autoría, cada
+Co-developed-by: debe ser inmediatamente seguido de Signed-off-by: del
+coautor asociado. Se mantiene el procedimiento estándar, es decir, el orden
+de las etiquetas Signed-off-by: debe reflejar el historial cronológico del
+parche en la medida de lo posible, independientemente de si el autor se
+atribuye a través de From: o Co-developed-by:. Cabe destacar que el último
+Signed-off-by: siempre debe ser del desarrollador que envía el parche.
+
+Tenga en cuenta que la etiqueta From: es opcional cuando el autor From: es
+también la persona (y correo electrónico) enumerados en la línea From: del
+encabezado del correo electrónico.
+
+Ejemplo de un parche enviado por el From: autor::
+
+ <changelog>
+
+ Co-developed-by: Primer coautor <primer@coauthor.example.org>
+ Signed-off-by: Primer coautor <primer@coauthor.example.org>
+ Co-developed-by: Segundo coautor <segundo@coautor.ejemplo.org>
+ Signed-off-by: Segundo coautor <segundo@coautor.ejemplo.org>
+ Signed-off-by: Autor del From <from@author.example.org>
+
+Ejemplo de un parche enviado por un Co-developed-by: autor::
+
+ From: Autor del From <from@author.example.org>
+
+ <changelog>
+
+ Co-developed-by: Co-Autor aleatorio <aleatorio@coauthor.example.org>
+ Signed-off-by: Coautor aleatorio <aleatorio@coauthor.example.org>
+ Signed-off-by: Autor del From <from@author.example.org>
+ Co-developed-by: Coautor que envió <sub@coauthor.example.org>
+ Signed-off-by: Coautor que envía <sub@coauthor.example.org>
+
+Uso de Reported-by:, Tested-by:, Reviewed-by:, Suggested-by: y Fixes:
+----------------------------------------------------------------------
+
+La etiqueta Reported-by (Reportado-por) otorga crédito a las personas que
+encuentran errores y los reportan. Por favor, tenga en cuenta que si se
+informó de un error en privado, debe pedir primero permiso antes de usar la
+etiqueta Reported-by. La etiqueta está destinada a errores; por favor no la
+use para acreditar peticiones de características.
+
+Una etiqueta Tested-by: indica que el parche se probó con éxito (en algún
+entorno) por la persona nombrada. Esta etiqueta informa a los maintainers
+de que se han realizado algunas pruebas, proporciona un medio para ubicar
+"testers" (gente que pruebe) otros parches futuros y asegura el crédito
+para los testers.
+
+Reviewed-by: en cambio, indica que el parche ha sido revisado y encontrado
+aceptable de acuerdo con la Declaración del Revisor:
+
+Declaración de Supervisión del Revisor
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Al ofrecer mi etiqueta Reviewed-by:, afirmo que:
+
+(a) He llevado a cabo una revisión técnica de este parche para
+evaluar su idoneidad y preparación para su inclusión en
+el kernel principal.
+
+(b) Cualquier problema, inquietud o pregunta relacionada con el parche
+han sido comunicados al remitente. Estoy satisfecho
+con la respuesta del remitente a mis comentarios.
+
+(c) Si bien puede haber cosas que podrían mejorarse con esta
+entrega, creo que es, en este momento, (1) una
+modificación valiosa al kernel, y (2) libre de conocidas
+cuestiones que argumentarían en contra de su inclusión.
+
+(d) Si bien he revisado el parche y creo que es correcto,
+no hago (a menos que se indique explícitamente en otro lugar) ninguna
+garantía o avales de que logrará su definido
+propósito o función en cualquier situación dada.
+
+Una etiqueta Reviewed-by es una declaración de opinión de que el parche es
+una modificación apropiada al kernel sin que haya ningún problema grave
+a nivel técnico. Cualquier revisor interesado (que haya hecho el trabajo)
+puede ofrecer una etiqueta Reviewed-by para un parche. Esta etiqueta sirve
+para dar crédito a revisores e informar a los maintainers del grado de
+revisión que se ha hecho en el parche. Las etiquetas Reviewed-by, cuando
+las otorgan revisores conocidos por entender del tema y realizar
+revisiones exhaustivas, normalmente aumentan la probabilidad de que su
+parche entre en el kernel.
+
+Las etiquetas Tested-by y Reviewed-by, una vez recibidas en la lista de
+correo por el tester o revisor, deben ser incluidas por el autor de los
+parches pertinentes al enviar próximas versiones. Sin embargo, si el parche
+ha cambiado sustancialmente en la siguiente versión, es posible que estas
+etiquetas ya no sean aplicables y, por lo tanto, deben eliminarse. Por lo
+general, se debe mencionar la eliminación de las etiquetas Tested-by o
+Reviewed-by de alguien en el registro de cambios del parche (después del
+separador '---').
+
+Una etiqueta Suggested-by: indica que la idea del parche es sugerida por la
+persona nombrada y asegura el crédito a la persona por la idea. Tenga en
+cuenta que esto no debe agregarse sin el permiso del "reporter",
+especialmente si la idea no fue publicada en un foro público. Dicho esto,
+si diligentemente acreditamos a los reporters de ideas, con suerte, se
+sentirán inspirados para ayudarnos nuevamente en el futuro.
+
+Una etiqueta Fixes: indica que el parche corrige un problema en un commit
+anterior. Esto se utiliza para facilitar descubrir dónde se originó un
+error, lo que puede ayudar a revisar una corrección de errores. Esta
+etiqueta también ayuda al equipo del kernel estable a determinar qué
+versiones estables del kernel deberían recibir su corrección. Este es el
+método preferido para indicar un error corregido por el parche. Revise
+:ref:`describe_changes` para más detalles.
+
+Nota: Adjuntar una etiqueta Fixes: no subvierte las reglas estables del
+proceso del kernel ni el requisito de CC: stable@vger.kernel.org en todos
+los parches candidatos de ramas estables. Para obtener más información, lea
+Documentation/process/stable-kernel-rules.rst.
+
+.. _sp_the_canonical_patch_format:
+
+Formato de parche canónico
+---------------------------
+
+Esta sección describe cómo debe darse formato al propio parche. Tenga en
+cuenta que, si tiene sus parches almacenados en un repositorio ``git``, el
+parche con formato adecuado se puede obtener con ``git format-patch``. Las
+herramientas no pueden crear el texto necesario, sin embargo, así que lea
+las instrucciones a continuación de todos modos.
+
+La línea de asunto del parche canónico es::
+
+ Asunto: [PATCH 001/123] subsistema: frase de resumen
+
+El cuerpo del mensaje del parche canónico contiene lo siguiente:
+
+ - Una línea ``from`` que especifica el autor del parche, seguida de una
+ línea vacía (solo es necesario si la persona que envía el parche no es
+ el autor).
+
+ - El cuerpo de la explicación, línea envuelta en 75 columnas, que se
+ copiara en el registro de cambios permanente para describir este parche.
+
+ - Una línea vacía.
+
+ - Las líneas ``Signed-off-by:``, descritas anteriormente, que
+ también vaya en el registro de cambios.
+
+ - Una línea de marcador que contiene simplemente ``---``.
+
+ - Cualquier comentario adicional que no sea adecuado para el registro de
+ cambios.
+
+ - El parche real (output de ``diff``).
+
+El formato de la línea de asunto hace que sea muy fácil ordenar los correos
+electrónicos alfabéticamente por línea de asunto - prácticamente cualquier
+lector de correo electrónico permite esto, ya que debido a que el número de
+secuencia se rellena con ceros, el orden numérico y alfabético es el mismo.
+
+El ``subsistema`` en el asunto del correo electrónico debe identificar qué
+área o subsistema del kernel está siendo parcheado.
+
+La ``frase de resumen`` en el Asunto del correo electrónico debe describir
+de forma concisa el parche que contiene ese correo electrónico. La
+``frase resumen`` no debe ser un nombre de archivo. No use la mismo ``frase
+resumen`` para cada parche en una serie completa de parches (donde una
+`` serie de parches`` (patch series) es una secuencia ordenada de múltiples
+parches relacionados).
+
+Tenga en cuenta que la ``frase de resumen`` de su correo electrónico se
+convierte en un identificador global único para ese parche. Se propaga por
+hasta el registro de cambios de ``git``. La ``frase resumida`` se puede
+usar más adelante en discusiones de desarrolladores que se refieran al
+parche. La gente querrá buscar en Google la ``frase de resumen`` para leer
+la discusión al respecto del parche. También será lo único que la gente
+podrá ver rápidamente cuando, dos o tres meses después, estén pasando por
+quizás miles de parches usando herramientas como ``gitk`` o ``git log
+--oneline``.
+
+Por estas razones, el ``resumen`` no debe tener más de 70-75 caracteres, y
+debe describir tanto lo que cambia el parche como por qué el parche podría
+ser necesario. Es un reto ser tanto sucinto como descriptivo, pero eso es
+lo que un resumen bien escrito debería hacer.
+
+La ``frase de resumen`` puede estar precedida por etiquetas encerradas en
+corchetes: "Asunto: [PATCH <etiqueta>...] <frase de resumen>". Las
+etiquetas no se consideran parte de la frase de resumen, pero describen
+cómo debería ser tratado el parche. Las etiquetas comunes pueden incluir un
+descriptor de versión si las múltiples versiones del parche se han enviado
+en respuesta a comentarios (es decir, "v1, v2, v3") o "RFC" para indicar
+una solicitud de comentarios.
+
+Si hay cuatro parches en una serie de parches, los parches individuales
+pueden enumerarse así: 1/4, 2/4, 3/4, 4/4. Esto asegura que los
+desarrolladores entiendan el orden en que se deben aplicar los parches y
+que han revisado o aplicado todos los parches de la serie de parches.
+
+Aquí hay algunos buenos ejemplos de Asuntos::
+
+ Asunto: [PATCH 2/5] ext2: mejorar la escalabilidad de la búsqueda de mapas de bits
+ Asunto: [PATCH v2 27/01] x86: corregir el seguimiento de eflags
+ Asunto: [PATCH v2] sub/sys: resumen conciso del parche
+ Asunto: [PATCH v2 M/N] sub/sys: resumen conciso del parche
+
+La línea ``from`` debe ser la primera línea en el cuerpo del mensaje,
+y tiene la forma::
+
+ From: Autor del parche <autor@ejemplo.com>
+
+La línea ``From`` especifica quién será acreditado como el autor del parche
+en el registro de cambios permanente. Si falta la línea ``from``, entonces
+la línea ``From:`` del encabezado del correo electrónico se usará para
+determinar el autor del parche en el registro de cambios.
+
+La explicación estará incluida en el commit del changelog permanente, por
+lo que debería tener sentido para un lector competente que hace mucho tiempo
+ha olvidado los detalles de la discusión que podrían haber llevado a
+este parche. Incluidos los síntomas del fallo que el parche trate
+(mensajes de registro del kernel, mensajes de oops, etc.) son especialmente
+útiles para personas que podrían estar buscando en los registros de
+commits en busca de la aplicación del parche. El texto debe estar escrito
+con tal detalle que cuando se lea semanas, meses o incluso años después,
+pueda dar al lector la información necesaria y detalles para comprender el
+razonamiento de **por qué** se creó el parche.
+
+Si un parche corrige una falla de compilación, puede que no sea necesario
+incluir _todos_ los errores de compilación; pero lo suficiente como para
+que sea probable que alguien que busque el parche puede encontrarlo. Como
+en la ``frase de resumen``, es importante ser tanto sucinto como
+descriptivo.
+
+La línea marcadora ``---`` cumple el propósito esencial de marcar para
+herramientas de manejo de parches donde termina el mensaje de registro de
+cambios.
+
+Un buen uso de los comentarios adicionales después del marcador ``---`` es
+para ``diffstat``, para mostrar qué archivos han cambiado, y el número de
+líneas insertadas y eliminadas por archivo. Un ``diffstat`` es
+especialmente útil en parches más grandes. Si va a incluir un ``diffstat``
+después del marcador ``---``, utilice las opciones ``diffstat``
+``-p 1 -w 70`` para que los nombres de archivo se enumeran desde la parte
+superior del árbol de fuentes del kernel y no use demasiado espacio
+horizontal (que encaje fácilmente en 80 columnas, tal vez con alguna
+indentación). (``git`` genera diffstats apropiados por defecto).
+
+Otros comentarios relevantes solo en el momento o para el maintainer, pero
+no adecuados para el registro de cambios permanente, también debe ir aquí.
+Un buen ejemplo de tales comentarios podría ser ``registros de cambios de
+parches`` que describen qué ha cambiado entre la versión v1 y v2 del
+parche.
+
+Por favor, ponga esta información **después** de la línea ``---`` que
+separa el registro de cambios del resto del parche. La información de la
+versión no forma parte del registro de cambios que se incluye con el árbol
+git. Es información adicional para los revisores. Si se coloca encima de la
+etiquetas de commit, necesita interacción manual para eliminarlo. Si esta
+debajo de la línea de separación, se quita automáticamente al aplicar el
+parche::
+
+ <mensaje de commit>
+ ...
+ Signed-off-by: Autor <autor@correo>
+ ---
+ V2 -> V3: función auxiliar redundante eliminada
+ V1 -> V2: estilo de código limpio y comentarios de revisión abordados
+
+ ruta/al/archivo | 5+++--
+ ...
+
+Revise más detalles sobre el formato de parche adecuado en las siguientes
+referencias
+
+.. _sp_backtraces:
+
+Retrocesos en mensajes de confirmación
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Los "backtraces" (deshacer el camino) ayuda a documentar la cadena de
+llamadas que conducen a un problema. Sin embargo, no todos los rastreos son
+útiles. Por ejemplo, las tempranas cadenas de llamadas de inicio son únicas
+y obvias. Sin embargo, al copiar la salida completa de dmesg textualmente,
+incluye información que distrae, como marcas de tiempo, listas de módulos,
+registro y volcados de pila.
+
+Por lo tanto, los backtraces más útiles deben contener los datos
+relevantes de la información vertida, lo que hace que sea más fácil
+centrarse en el verdadero tema. Este es un ejemplo de un backtrace bien
+recortado::
+
+ error de acceso de MSR no verificado: WRMSR a 0xd51 (intentó escribir 0x0000000000000064)
+ en rIP: 0xffffffffae059994 (native_write_msr+0x4/0x20)
+ Rastreo de llamadas:
+ mba_wrmsr
+ update_domains
+ rdtgroup_mkdir
+
+.. _sp_explicit_in_reply_to:
+
+In-Reply-To explicitos en las cabeceras
+---------------------------------------
+
+Puede ser útil agregar manualmente encabezados In-Reply-To: a un parche
+(por ejemplo, al usar ``git send-email``) para asociar el parche con una
+discusión anterior relevante, por ejemplo para vincular una corrección de
+errores al correo electrónico con el informe de errores. Sin embargo, para
+una serie de parches múltiples, generalmente es mejor evitar usar
+In-Reply-To: para vincular a versiones anteriores de la serie. De esta
+forma, varias versiones del parche no se convierten en un inmanejable
+bosque de referencias en clientes de correo electrónico. Si un enlace es
+útil, puede usar el redirector https://lore.kernel.org/ (por ejemplo, en
+el texto de la carta de introducción del correo electrónico) para vincular
+a una versión anterior de la serie de parches.
+
+
+Proporcionar información de árbol base
+--------------------------------------
+
+Cuando otros desarrolladores reciben sus parches y comienzan el proceso de
+revisión, a menudo es útil para ellos saber en qué parte del historial del
+árbol deben colocar su trabajo. Esto es particularmente útil para CI
+automatizado de procesos que intentan ejecutar una serie de pruebas para
+establecer la calidad de su envío antes de que el maintainer comience la
+revisión.
+
+Si está utilizando ``git format-patch`` para generar sus parches, puede
+incluir automáticamente la información del árbol base en su envío usando el
+parámetro ``--base``. La forma más fácil y conveniente de usar esta opción
+es con "topical branches" (ramas de temas)::
+
+ $ git checkout -t -b my-topical-branch master
+ Branch 'my-topical-branch' set up to track local branch 'master'.
+ Switched to a new branch 'my-topical-branch'
+
+ [realice sus cambios y ediciones]
+
+ $ git format-patch --base=auto --cover-letter -o outgoing/ master
+ outgoing/0000-cover-letter.patch
+ outgoing/0001-First-Commit.patch
+ outgoing/...
+
+Cuando abra ``outgoing/0000-cover-letter.patch`` para editar, tenga en
+cuenta que tendrá el tráiler ``base-commit:`` al final, que proporciona al
+revisor y a las herramientas de CI suficiente información para realizar
+correctamente ``git am`` sin preocuparse por los conflictos::
+
+ $ git checkout -b patch-review [base-commit-id]
+ Switched to a new branch 'patch-review'
+ $ git am patches.mbox
+ Applying: First Commit
+ Applying: ...
+
+Consulte ``man git-format-patch`` para obtener más información al respecto
+de esta opción.
+
+.. Note::
+
+ La función ``--base`` se introdujo en la versión 2.9.0 de git.
+
+Si no está utilizando git para dar forma a sus parches, aún puede incluir
+el mismo tráiler ``base-commit`` para indicar el hash de confirmación del
+árbol en que se basa su trabajo. Debe agregarlo en la carta de presentación
+o en el primer parche de la serie y debe colocarse ya sea bajo la línea
+``---`` o en la parte inferior de todos los demás contenido, justo antes de
+su firma del correo electrónico.
+
+
+Referencias
+-----------
+
+"The perfect patch" (tpp) por Andrew Morton.
+ <https://www.ozlabs.org/~akpm/stuff/tpp.txt>
+
+"Linux kernel patch submission format" por Jeff Garzik.
+ <https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html>
+
+"How to piss off a kernel subsystem maintainer" por Greg Kroah-Hartman.
+ <http://www.kroah.com/log/linux/maintainer.html>
+
+ <http://www.kroah.com/log/linux/maintainer-02.html>
+
+ <http://www.kroah.com/log/linux/maintainer-03.html>
+
+ <http://www.kroah.com/log/linux/maintainer-04.html>
+
+ <http://www.kroah.com/log/linux/maintainer-05.html>
+
+ <http://www.kroah.com/log/linux/maintainer-06.html>
+
+NO!!!! Gente, no mas bombas enormes de parches a linux-kernel@vger.kernel.org!
+ <https://lore.kernel.org/r/20050711.125305.08322243.davem@davemloft.net>
+
+Kernel Documentation/process/coding-style.rst
+
+Email de Linus Torvalds sobre la forma canónica de los parches:
+ <https://lore.kernel.org/r/Pine.LNX.4.58.0504071023190.28951@ppc970.osdl.org>
+
+"On submitting kernel patches" por Andi Kleen
+ Algunas estrategias para conseguir incluir cambios complicados o
+ controvertidos.
+
+ http://halobates.de/on-submitting-patches.pdf
diff --git a/Documentation/translations/sp_SP/wrappers/memory-barriers.rst b/Documentation/translations/sp_SP/wrappers/memory-barriers.rst
new file mode 100644
index 000000000000..50715b7d51b9
--- /dev/null
+++ b/Documentation/translations/sp_SP/wrappers/memory-barriers.rst
@@ -0,0 +1,19 @@
+.. SPDX-License-Identifier: GPL-2.0
+ This is a simple wrapper to bring memory-barriers.txt (Spanish
+ translation) into the RST world until such a time as that file can be
+ converted directly.
+
+====================================
+Barreras de Memoria del kernel Linux
+====================================
+
+.. raw:: latex
+
+ \footnotesize
+
+.. include:: ../memory-barriers.txt
+ :literal:
+
+.. raw:: latex
+
+ \normalsize
diff --git a/Documentation/translations/zh_CN/IRQ.txt b/Documentation/translations/zh_CN/IRQ.txt
deleted file mode 100644
index 956026d5cf82..000000000000
--- a/Documentation/translations/zh_CN/IRQ.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-Chinese translated version of Documentation/IRQ.txt
-
-If you have any comment or update to the content, please contact the
-original document maintainer directly. However, if you have a problem
-communicating in English you can also ask the Chinese maintainer for
-help. Contact the Chinese maintainer if this translation is outdated
-or if there is a problem with the translation.
-
-Maintainer: Eric W. Biederman <ebiederman@xmission.com>
-Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
----------------------------------------------------------------------
-Documentation/IRQ.txt 的中文翻译
-
-如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
-交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
-译存在问题,请联系中文版维护者。
-英文版维护者: Eric W. Biederman <ebiederman@xmission.com>
-中文版维护者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
-中文版翻译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
-中文版校译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
-
-
-以下为正文
----------------------------------------------------------------------
-何为 IRQ?
-
-一个 IRQ 是来自某个设备的一个中断请求。目前,它们可以来自一个硬件引脚,
-或来自一个数据包。多个设备可能连接到同个硬件引脚,从而共享一个 IRQ。
-
-一个 IRQ 编号是用于告知硬件中断源的内核标识。通常情况下,这是一个
-全局 irq_desc 数组的索引,但是除了在 linux/interrupt.h 中的实现,
-具体的细节是体系结构特定的。
-
-一个 IRQ 编号是设备上某个可能的中断源的枚举。通常情况下,枚举的编号是
-该引脚在系统内中断控制器的所有输入引脚中的编号。对于 ISA 总线中的情况,
-枚举的是在两个 i8259 中断控制器中 16 个输入引脚。
-
-架构可以对 IRQ 编号指定额外的含义,在硬件涉及任何手工配置的情况下,
-是被提倡的。ISA 的 IRQ 是一个分配这类额外含义的典型例子。
diff --git a/Documentation/translations/zh_CN/PCI/acpi-info.rst b/Documentation/translations/zh_CN/PCI/acpi-info.rst
new file mode 100644
index 000000000000..a35f39dcd858
--- /dev/null
+++ b/Documentation/translations/zh_CN/PCI/acpi-info.rst
@@ -0,0 +1,139 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/PCI/acpi-info.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+=====================
+PCI主桥的ACPI注意事项
+=====================
+
+一般的规则是,ACPI命名空间应该描述操作系统可能使用的所有东西,除非有其他方法让操作系
+统找到它[1, 2]。
+
+例如,没有标准的硬件机制来枚举PCI主桥,所以ACPI命名空间必须描述每个主桥、访问它
+下面的PCI配置空间的方法、主桥转发到PCI的地址空间窗口(使用_CRS)以及传统的INTx
+中断的路由(使用_PRT)。
+
+在主桥下面的PCI设备,通常不需要通过ACPI描述。操作系统可以通过标准的PCI枚举机制来
+发现它们,使用配置访问来发现和识别设备,并读取和测量它们的BAR。然而,如果ACPI为它们
+提供电源管理或热插拔功能,或者如果设备有由平台中断控制器连接的INTx中断,需要一个_PRT
+来描述这些连接,这种情况下ACPI可以描述PCI设备。
+
+ACPI资源描述是通过ACPI命名空间中设备的_CRS对象完成的[2]。_CRS就像一个通用的PCI BAR:
+操作系统可以读取_CRS并找出正在消耗的资源,即使它没有该设备的驱动程序[3]。这一点很重要,
+因为它意味着一个旧的操作系统可以正确地工作,即使是在操作系统不知道的新设备的系统上。新设
+备可能什么都不做,但操作系统至少可以确保没有资源与它们冲突。
+
+像MCFG、HPET、ECDT等静态表,不是保留地址空间的机制。静态表是在操作系统在启动初期且在它
+能够解析ACPI命名空间之前需要知道的东西。如果定义了一个新的表,即使旧的操作系统忽略了这
+个表,它也需要正常运行。_CRS允许这样做,因为它是通用的,可以被旧的操作系统解析;而静态表
+则不允许。
+
+如果操作系统要管理一个通过ACPI描述的不可发现的设备,该设备将有一个特定的_HID/_CID,以
+告诉操作系统与之绑定的驱动程序,并且_CRS告诉操作系统和驱动程序该设备的寄存器在哪里。
+
+PCI主桥是PNP0A03或PNP0A08设备。它们的_CRS应该描述它们所消耗的所有地址空间。这包括它
+们转发到PCI总线上的所有窗口,以及不转发到PCI的主桥本身的寄存器。主桥的寄存器包括次要/下
+级总线寄存器,决定了桥下面的总线范围,窗口寄存器描述了桥洞,等等。这些都是设备相关的,非
+架构相关的东西,所以PNP0A03/PNP0A08驱动可以管理它们的唯一方法是通过_PRS/_CRS/_SRS,
+它包含了特定于设备的细节。主桥寄存器也包括ECAM空间,因为它是由主桥消耗的。
+
+ACPI定义了一个Consumer/Producer位来区分桥寄存器(“Consumer”下文译作消费者)和
+桥洞(“Producer”下文译作生产者)[4, 5],但是早期的BIOS没有正确使用这个位。其结果
+是,目前的ACPI规范只为扩展地址空间描述符定义了消费者/生产者;在旧的QWord/Word/Word地
+址空间描述符中,该位应该被忽略。因此,操作系统必须假定所有的QWord/Word/Word描述符都是
+窗口。
+
+在增加扩展地址空间描述符之前,消费者/生产者的失败意味着没有办法描述PNP0A03/PNP0A08设
+备本身的桥寄存器。解决办法是在PNP0C02捕捉器中描述桥寄存器(包括ECAM空间)[6]。
+除了ECAM之外,桥寄存器空间反正是特定于设备的,所以通用的PNP0A03/PNP0A08驱动程
+序(pci_root.c)没有必要了解它。
+
+新的架构应该能够在PNP0A03设备中使用“消费者”扩展地址空间描述符,用于桥寄存器,包括
+ECAM,尽管对[6]的严格解释可能禁止这样做。旧的x86和ia64内核假定所有的地址空间描述
+符,包括“消费者”扩展地址空间的描述符,都是窗口,所以在这些架构上以这种方式描述桥寄
+存器是不安全的。
+
+PNP0C02“主板”设备基本上是万能的。除了“不要将这些资源用于其他用途”之外,没有其他的编
+程模型。因此,PNP0C02 _CRS应该声明ACPI命名空间中(1)没有被_CRS声明的任何其他设备对
+象的地址空间,(2)不应该被OS分配给其他东西。
+
+除非有一个标准的固件接口用于配置访问,例如ia64 SAL接口[7],否则PCIe规范要求使用增强
+型配置访问方法(ECAM)。主桥消耗ECAM内存地址空间并将内存访问转换为PCI配置访问。该规范
+定义了ECAM地址空间的布局和功能;只有地址空间的基础是特定于设备的。ACPI操作系统从静态
+MCFG表或PNP0A03设备中的_CBA方法中了解基础地址。
+
+MCFG表必须描述非热插拔主桥的ECAM空间[8]。由于MCFG是一个静态表,不能通过热插拔更新,
+PNP0A03设备中的_CBA方法描述了可热插拔主桥的ECAM空间[9]。请注意,对于MCFG和_CBA,
+基址总是对应于总线0,即使桥器下面的总线范围(通过_CRS报告)不从0开始。
+
+
+[1] ACPI 6.2, sec 6.1:
+ 对于任何在非枚举类型的总线上的设备(例如,ISA总线),OSPM会枚举设备的标识符,ACPI
+ 系统固件必须为每个设备提供一个_HID对象...以使OSPM能够做到这一点。
+
+[2] ACPI 6.2, sec 3.7:
+ 操作系统枚举主板设备时,只需通过读取ACPI命名空间来寻找具有硬件ID的设备。
+
+ ACPI枚举的每个设备都包括ACPI命名空间中ACPI定义的对象,该对象报告设备可能占用的硬
+ 件资源[_PRS],报告设备当前使用的资源[_CRS]的对象,以及配置这些资源的对象[_SRS]。
+ 这些信息被即插即用操作系统(OSPM)用来配置设备。
+
+[3] ACPI 6.2, sec 6.2:
+ OSPM使用设备配置对象来配置通过ACPI列举的设备的硬件资源。设备配置对象提供了关于当前
+ 和可能的资源需求的信息,共享资源之间的关系,以及配置硬件资源的方法。
+
+ 当OSPM枚举一个设备时,它调用_PRS来确定该设备的资源需求。它也可以调用_CRS来找到该设
+ 备的当前资源设置。利用这些信息,即插即用系统决定设备应该消耗什么资源,并通过调用设备
+ 的_SRS控制方法来设置这些资源。
+
+ 在ACPI中,设备可以消耗资源(例如,传统的键盘),提供资源(例如,一个专有的PCI桥),
+ 或者两者都做。除非另有规定,设备的资源被假定为来自设备层次结构中设备上方最近的匹配资
+ 源。
+
+[4] ACPI 6.2, sec 6.4.3.5.1, 2, 3, 4:
+ QWord/DWord/Word 地址空间描述符 (.1, .2, .3)
+ 常规标志: Bit [0] 被忽略。
+
+ 扩展地址空间描述符 (.4)
+ 常规标志: Bit [0] 消费者/生产者:
+
+ * 1 – 这个设备消费这个资源
+ * 0 – 该设备生产和消费该资源
+
+[5] ACPI 6.2, sec 19.6.43:
+ ResourceUsage指定内存范围是由这个设备(ResourceConsumer)消费还是传递给子设备
+ (ResourceProducer)。如果没有指定,那么就假定是ResourceConsumer。
+
+[6] PCI Firmware 3.2, sec 4.1.2:
+ 如果操作系统不能原生的懂得保留MMCFG区域,MMCFG区域必须由固件保留。在MCFG表中或通
+ 过_CBA方法(见第4.1.3节)报告的地址范围必须通过声明主板资源来保留。对于大多数系统,
+ 主板资源将出现在ACPI命名空间的根部(在_SB下),在一个节点的_HID为EISAID(PNP0C0
+ 2),在这种情况下的资源不应该要求在根PCI总线的_CRS。这些资源可以选择在Int15 E820
+ 或EFIGetMemoryMap中作为保留内存返回,但必须始终通过ACPI作为主板资源报告。
+
+[7] PCI Express 4.0, sec 7.2.2:
+ 对于PC兼容的系统,或者没有实现允许访问配置空间的处理器架构特定固件接口标准的系统,需
+ 要使用本节中定义的ECAM。
+
+[8] PCI Firmware 3.2, sec 4.1.2:
+ MCFG表是一个ACPI表,用于沟通的基础地址对应的非热的可移动的PCI段组范围内的PCI段组在
+ 启动时提供给操作系统。这对PC兼容系统来说是必需的。
+
+ MCFG表仅用于沟通在启动时系统可用的PCI段组对应的基址。
+
+[9] PCI Firmware 3.2, sec 4.1.3:
+ _CBA (Memory mapped Configuration Base Address) 控制方法是一个可选的ACPI对
+ 象,用于返回热插拔主桥的64位内存映射的配置基址。_CBA 返回的基址是与处理器相关的地址。
+ _CBA 控制方法被评估为一个整数。
+
+ 这个控制方法出现在主桥对象下。当_CBA方法出现在一个活动的主桥对象下时,操作系统会评
+ 估这个结构,以确定内存映射的配置基址,对应于_CRS方法中指定的总线编号范围的PCI段组。
+ 一个包含_CBA方法的ACPI命名空间对象也必须包含一个相应的_SEG方法。
diff --git a/Documentation/translations/zh_CN/PCI/index.rst b/Documentation/translations/zh_CN/PCI/index.rst
new file mode 100644
index 000000000000..cbeb33c34a98
--- /dev/null
+++ b/Documentation/translations/zh_CN/PCI/index.rst
@@ -0,0 +1,34 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/PCI/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+===================
+Linux PCI总线子系统
+===================
+
+.. toctree::
+ :maxdepth: 2
+ :numbered:
+
+ pci
+ pciebus-howto
+ pci-iov-howto
+ msi-howto
+ sysfs-pci
+ acpi-info
+
+
+Todolist:
+
+* pci-error-recovery
+* pcieaer-howto
+* endpoint/index
+* boot-interrupts
diff --git a/Documentation/translations/zh_CN/PCI/msi-howto.rst b/Documentation/translations/zh_CN/PCI/msi-howto.rst
new file mode 100644
index 000000000000..1b9b5ea790d8
--- /dev/null
+++ b/Documentation/translations/zh_CN/PCI/msi-howto.rst
@@ -0,0 +1,244 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: <isonum.txt>
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/PCI/msi-howto.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+
+===========
+MSI驱动指南
+===========
+
+:作者: Tom L Nguyen; Martine Silbermann; Matthew Wilcox
+
+:版权: 2003, 2008 Intel Corporation
+
+关于本指南
+==========
+
+本指南介绍了消息标记中断(MSI)的基本知识,使用MSI相对于传统中断机制的优势,如何
+改变你的驱动程序以使用MSI或MSI-X,以及在设备不支持MSI时可以尝试的一些基本诊断方法。
+
+
+什么是MSI?
+==========
+
+信息信号中断是指从设备写到一个特殊的地址,导致CPU接收到一个中断。
+
+MSI能力首次在PCI 2.2中规定,后来在PCI 3.0中得到增强,允许对每个中断进行单独屏蔽。
+MSI-X功能也随着PCI 3.0被引入。它比MSI支持每个设备更多的中断,并允许独立配置中断。
+
+设备可以同时支持MSI和MSI-X,但一次只能启用一个。
+
+
+为什么用MSI?
+============
+
+有三个原因可以说明为什么使用MSI比传统的基于针脚的中断有优势。
+
+基于针脚的PCI中断通常在几个设备之间共享。为了支持这一点,内核必须调用每个与中断相
+关的中断处理程序,这导致了整个系统性能的降低。MSI从不共享,所以这个问题不会出现。
+
+当一个设备将数据写入内存,然后引发一个基于引脚的中断时,有可能在所有的数据到达内存
+之前,中断就已经到达了(这在PCI-PCI桥后面的设备中变得更有可能)。为了确保所有的数
+据已经到达内存中,中断处理程序必须在引发中断的设备上读取一个寄存器。PCI事务排序规
+则要求所有的数据在返回寄存器的值之前到达内存。使用MSI可以避免这个问题,因为中断产
+生的写入不能通过数据写入,所以当中断发生时,驱动程序知道所有的数据已经到达内存中。
+
+PCI设备每个功能只能支持一个基于引脚的中断。通常情况下,驱动程序必须查询设备以找出
+发生了什么事件,这就减慢了对常见情况的中断处理。有了MSI,设备可以支持更多的中断,
+允许每个中断被专门用于不同的目的。一种可能的设计是给不经常发生的情况(如错误)提供
+自己的中断,这使得驱动程序可以更有效地处理正常的中断处理路径。其他可能的设计包括给
+网卡的每个数据包队列或存储控制器的每个端口提供一个中断。
+
+
+如何使用MSI
+===========
+
+PCI设备被初始化为使用基于引脚的中断。设备驱动程序必须将设备设置为使用MSI或MSI-X。
+并非所有的机器都能正确地支持MSI,对于这些机器,下面描述的API将简单地失败,设备将
+继续使用基于引脚的中断。
+
+加入内核对MSI的支持
+-------------------
+
+为了支持MSI或MSI-X,内核在构建时必须启用CONFIG_PCI_MSI选项。这个选项只在某些架
+构上可用,而且它可能取决于其他一些选项的设置。例如,在x86上,你必须同时启用X86_UP_APIC
+或SMP,才能看到CONFIG_PCI_MSI选项。
+
+使用MSI
+-------
+
+大部分沉重的工作是在PCI层为驱动程序完成的。驱动程序只需要请求PCI层为这个设备设置
+MSI功能。
+
+要自动使用MSI或MSI-X中断向量,请使用以下函数::
+
+ int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
+ unsigned int max_vecs, unsigned int flags);
+
+它为一个PCI设备分配最多至max_vecs的中断向量。它返回分配的向量数量或一个负的错误。
+如果设备对最小数量的向量有要求,驱动程序可以传递一个min_vecs参数,设置为这个限制,
+如果PCI核不能满足最小数量的向量,将返回-ENOSPC。
+
+flags参数用来指定设备和驱动程序可以使用哪种类型的中断(PCI_IRQ_LEGACY, PCI_IRQ_MSI,
+PCI_IRQ_MSIX)。一个方便的短语(PCI_IRQ_ALL_TYPES)也可以用来要求任何可能的中断类型。
+如果PCI_IRQ_AFFINITY标志被设置,pci_alloc_irq_vectors()将把中断分散到可用的CPU上。
+
+要获得传递给require_irq()和free_irq()的Linux IRQ号码和向量,请使用以下函数::
+
+ int pci_irq_vector(struct pci_dev *dev, unsigned int nr);
+
+在删除设备之前,应使用以下功能释放任何已分配的资源::
+
+ void pci_free_irq_vectors(struct pci_dev *dev);
+
+如果一个设备同时支持MSI-X和MSI功能,这个API将优先使用MSI-X,而不是MSI。MSI-X支
+持1到2048之间的任何数量的中断。相比之下,MSI被限制为最多32个中断(而且必须是2的幂)。
+此外,MSI中断向量必须连续分配,所以系统可能无法为MSI分配像MSI-X那样多的向量。在一
+些平台上,MSI中断必须全部针对同一组CPU,而MSI-X中断可以全部针对不同的CPU。
+
+如果一个设备既不支持MSI-X,也不支持MSI,它就会退回到一个传统的IRQ向量。
+
+MSI或MSI-X中断的典型用法是分配尽可能多的向量,可能达到设备支持的极限。如果nvec大于
+设备支持的数量,它将自动被限制在支持的限度内,所以没有必要事先查询支持的向量的数量。::
+
+ nvec = pci_alloc_irq_vectors(pdev, 1, nvec, PCI_IRQ_ALL_TYPES)
+ if (nvec < 0)
+ goto out_err;
+
+如果一个驱动程序不能或不愿意处理可变数量的MSI中断,它可以要求一个特定数量的中断,将该
+数量作为“min_vecs“和“max_vecs“参数传递给pci_alloc_irq_vectors()函数。::
+
+ ret = pci_alloc_irq_vectors(pdev, nvec, nvec, PCI_IRQ_ALL_TYPES);
+ if (ret < 0)
+ goto out_err;
+
+上述请求类型的最臭名昭著的例子是为一个设备启用单一的MSI模式。它可以通过传递两个1作为
+'min_vecs'和'max_vecs'来实现::
+
+ ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+ if (ret < 0)
+ goto out_err;
+
+一些设备可能不支持使用传统的线路中断,在这种情况下,驱动程序可以指定只接受MSI或MSI-X。::
+
+ nvec = pci_alloc_irq_vectors(pdev, 1, nvec, PCI_IRQ_MSI | PCI_IRQ_MSIX);
+ if (nvec < 0)
+ goto out_err;
+
+传统API
+-----------
+
+以下用于启用和禁用MSI或MSI-X中断的旧API不应该在新代码中使用::
+
+ pci_enable_msi() /* deprecated */
+ pci_disable_msi() /* deprecated */
+ pci_enable_msix_range() /* deprecated */
+ pci_enable_msix_exact() /* deprecated */
+ pci_disable_msix() /* deprecated */
+
+此外,还有一些API来提供支持的MSI或MSI-X向量的数量:pci_msi_vec_count()和
+pci_msix_vec_count()。一般来说,应该避免使用这些方法,而是让pci_alloc_irq_vectors()
+来限制向量的数量。如果你对向量的数量有合法的特殊用例,我们可能要重新审视这个决定,
+并增加一个pci_nr_irq_vectors()助手,透明地处理MSI和MSI-X。
+
+使用MSI时需要考虑的因素
+-----------------------
+
+自旋锁
+~~~~~~
+
+大多数设备驱动程序都有一个每的自旋锁,在中断处理程序中被占用。对于基于引脚的中断
+或单一的MSI,没有必要禁用中断(Linux保证同一中断不会被重新输入)。如果一个设备
+使用多个中断,驱动程序必须在锁被持有的时候禁用中断。如果设备发出一个不同的中断,
+驱动程序将死锁,试图递归地获取自旋锁。这种死锁可以通过使用spin_lock_irqsave()
+或spin_lock_irq()来避免,它们可以禁用本地中断并获取锁(见《不可靠的锁定指南》)。
+
+如何判断一个设备上是否启用了MSI/MSI-X
+-------------------------------------
+
+使用“lspci -v“(以root身份)可能会显示一些具有“MSI“、“Message Signalled Interrupts“
+或“MSI-X“功能的设备。这些功能中的每一个都有一个“启用“标志,后面是“+“(启用)
+或“-“(禁用)。
+
+
+MSI特性
+=======
+
+众所周知,一些PCI芯片组或设备不支持MSI。PCI协议栈提供了三种禁用MSI的方法:
+
+1. 全局的
+2. 在一个特定的桥后面的所有设备上
+3. 在单一设备上
+
+全局禁用MSI
+-----------
+
+一些主控芯片组根本无法正确支持MSI。如果我们幸运的话,制造商知道这一点,并在
+ACPI FADT表中指明了它。在这种情况下,Linux会自动禁用MSI。有些板卡在表中没
+有包括这一信息,因此我们必须自己检测它们。完整的列表可以在drivers/pci/quirks.c
+中的quirk_disable_all_msi()函数附近找到。
+
+如果你有一块有MSI问题的板子,你可以在内核命令行中传递pci=nomsi来禁用所有设
+备上的MSI。你最好把问题报告给linux-pci@vger.kernel.org,包括完整的
+“lspci -v“,这样我们就可以把这些怪癖添加到内核中。
+
+禁用桥下的MSI
+-------------
+
+一些PCI桥接器不能在总线之间正确地路由MSI。在这种情况下,必须在桥接器后面的所
+有设备上禁用MSI。
+
+一些桥接器允许你通过改变PCI配置空间的一些位来启用MSI(特别是Hypertransport
+芯片组,如nVidia nForce和Serverworks HT2000)。与主机芯片组一样,Linux大
+多知道它们,如果可以的话,会自动启用MSI。如果你有一个Linux不知道的网桥,你可以
+用你知道的任何方法在配置空间中启用MSI,然后通过以下方式在该网桥上启用MSI::
+
+ echo 1 > /sys/bus/pci/devices/$bridge/msi_bus
+
+其中$bridge是你所启用的桥的PCI地址(例如0000:00:0e.0)。
+
+要禁用MSI,请回显0而不是1。改变这个值应该谨慎进行,因为它可能会破坏这个桥下面所
+有设备的中断处理。
+
+同样,请通知 linux-pci@vger.kernel.org 任何需要特殊处理的桥。
+
+在单一设备上关闭MSIs
+--------------------
+
+众所周知,有些设备的MSI实现是有问题的。通常情况下,这是在单个设备驱动程序中处理的,
+但偶尔也有必要用一个古怪的方法来处理。一些驱动程序有一个选项可以禁用MSI的使用。虽然
+这对驱动程序的作者来说是一个方便的变通办法,但这不是一个好的做法,不应该被模仿。
+
+寻找设备上MSI被禁用的原因
+-------------------------
+
+从以上三个部分,你可以看到有许多原因导致MSI没有在某个设备上被启用。你的第一步应该是
+仔细检查你的dmesg以确定你的机器是否启用了MSI。你还应该检查你的.config以确定你已经
+启用了CONFIG_PCI_MSI。
+
+然后,“lspci -t“给出一个设备上面的网列表。读取 ``/sys/bus/pci/devices/*/msi_bus``
+将告诉你MSI是否被启用(1)或禁用(0)。如果在任何属于PCI根和设备之间的桥的msi_bus
+文件中发现0,说明MSI被禁用。
+
+也需要检查设备驱动程序,看它是否支持MSI。例如,它可能包含对带有PCI_IRQ_MSI或
+PCI_IRQ_MSIX标志的pci_alloc_irq_vectors()的调用。
+
+
+MSI(-X) APIs设备驱动程序列表
+============================
+
+PCI/MSI子系统有一个专门的C文件,用于其导出的设备驱动程序APIs - `drivers/pci/msi/api.c` 。
+以下是导出的函数:
+
+该API在以下内核代码中:
+
+drivers/pci/msi/api.c
diff --git a/Documentation/translations/zh_CN/PCI/pci-iov-howto.rst b/Documentation/translations/zh_CN/PCI/pci-iov-howto.rst
new file mode 100644
index 000000000000..fb023ea1374d
--- /dev/null
+++ b/Documentation/translations/zh_CN/PCI/pci-iov-howto.rst
@@ -0,0 +1,169 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: <isonum.txt>
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/PCI/pci-iov-howto.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+
+.. _cn_pci-iov-howto:
+
+==========================
+PCI Express I/O 虚拟化指南
+==========================
+
+:版权: |copy| 2009 Intel Corporation
+:作者: - Yu Zhao <yu.zhao@intel.com>
+ - Donald Dutile <ddutile@redhat.com>
+
+概述
+====
+
+什么是SR-IOV
+------------
+
+单根I/O虚拟化(SR-IOV)是一种PCI Express扩展功能,它使一个物理设备显示为多个
+虚拟设备。物理设备被称为物理功能(PF),而虚拟设备被称为虚拟功能(VF)。VF的分
+配可以由PF通过封装在该功能中的寄存器动态控制。默认情况下,该功能未被启用,PF表
+现为传统的PCIe设备。一旦开启,每个VF的PCI配置空间都可以通过自己的总线、设备和
+功能编号(路由ID)来访问。而且每个VF也有PCI内存空间,用于映射其寄存器集。VF设
+备驱动程序对寄存器集进行操作,这样它就可以发挥功能,并作为一个真正的现有PCI设备
+出现。
+
+使用指南
+========
+
+我怎样才能启用SR-IOV功能
+------------------------
+
+有多种方法可用于SR-IOV的启用。在第一种方法中,设备驱动(PF驱动)将通过SR-IOV
+核心提供的API控制功能的启用和禁用。如果硬件具有SR-IOV能力,加载其PF驱动器将启
+用它和与PF相关的所有VF。一些PF驱动需要设置一个模块参数,以确定要启用的VF的数量。
+在第二种方法中,对sysfs文件sriov_numvfs的写入将启用和禁用与PCIe PF相关的VF。
+这种方法实现了每个PF的VF启用/禁用值,而第一种方法则适用于同一设备的所有PF。此外,
+PCI SRIOV核心支持确保启用/禁用操作是有效的,以减少同一检查在多个驱动程序中的重
+复,例如,如果启用VF,检查numvfs == 0,确保numvfs <= totalvfs。
+第二种方法是对新的/未来的VF设备的推荐方法。
+
+我怎样才能使用虚拟功能
+----------------------
+
+在内核中,VF被视为热插拔的PCI设备,所以它们应该能够以与真正的PCI设备相同的方式
+工作。VF需要的设备驱动与普通PCI设备的驱动相同。
+
+开发者指南
+==========
+
+SR-IOV API
+----------
+
+用来开启SR-IOV功能:
+
+(a) 对于第一种方法,在驱动程序中::
+
+ int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn);
+
+nr_virtfn'是要启用的VF的编号。
+
+(b) 对于第二种方法,从sysfs::
+
+ echo 'nr_virtfn' > \
+ /sys/bus/pci/devices/<DOMAIN:BUS:DEVICE.FUNCTION>/sriov_numvfs
+
+用来关闭SR-IOV功能:
+
+(a) 对于第一种方法,在驱动程序中::
+
+ void pci_disable_sriov(struct pci_dev *dev);
+
+(b) 对于第二种方法,从sysfs::
+
+ echo 0 > \
+ /sys/bus/pci/devices/<DOMAIN:BUS:DEVICE.FUNCTION>/sriov_numvfs
+
+要想通过主机上的兼容驱动启用自动探测VF,在启用SR-IOV功能之前运行下面的命令。这
+是默认的行为。
+::
+
+ echo 1 > \
+ /sys/bus/pci/devices/<DOMAIN:BUS:DEVICE.FUNCTION>/sriov_drivers_autoprobe
+
+要禁止主机上的兼容驱动自动探测VF,请在启用SR-IOV功能之前运行以下命令。更新这个
+入口不会影响已经被探测的VF。
+::
+
+ echo 0 > \
+ /sys/bus/pci/devices/<DOMAIN:BUS:DEVICE.FUNCTION>/sriov_drivers_autoprobe
+
+用例
+----
+
+下面的代码演示了SR-IOV API的用法
+::
+
+ static int dev_probe(struct pci_dev *dev, const struct pci_device_id *id)
+ {
+ pci_enable_sriov(dev, NR_VIRTFN);
+
+ ...
+
+ return 0;
+ }
+
+ static void dev_remove(struct pci_dev *dev)
+ {
+ pci_disable_sriov(dev);
+
+ ...
+ }
+
+ static int dev_suspend(struct device *dev)
+ {
+ ...
+
+ return 0;
+ }
+
+ static int dev_resume(struct device *dev)
+ {
+ ...
+
+ return 0;
+ }
+
+ static void dev_shutdown(struct pci_dev *dev)
+ {
+ ...
+ }
+
+ static int dev_sriov_configure(struct pci_dev *dev, int numvfs)
+ {
+ if (numvfs > 0) {
+ ...
+ pci_enable_sriov(dev, numvfs);
+ ...
+ return numvfs;
+ }
+ if (numvfs == 0) {
+ ....
+ pci_disable_sriov(dev);
+ ...
+ return 0;
+ }
+ }
+
+ static struct pci_driver dev_driver = {
+ .name = "SR-IOV Physical Function driver",
+ .id_table = dev_id_table,
+ .probe = dev_probe,
+ .remove = dev_remove,
+ .driver.pm = &dev_pm_ops
+ .shutdown = dev_shutdown,
+ .sriov_configure = dev_sriov_configure,
+ };
diff --git a/Documentation/translations/zh_CN/PCI/pci.rst b/Documentation/translations/zh_CN/PCI/pci.rst
new file mode 100644
index 000000000000..83c2a41d38d3
--- /dev/null
+++ b/Documentation/translations/zh_CN/PCI/pci.rst
@@ -0,0 +1,514 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/PCI/pci.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+
+.. _cn_PCI_pci.rst:
+
+===================
+如何写Linux PCI驱动
+===================
+
+:作者: - Martin Mares <mj@ucw.cz>
+ - Grant Grundler <grundler@parisc-linux.org>
+
+PCI的世界是巨大的,而且充满了(大多数是不愉快的)惊喜。由于每个CPU架构实现了不同
+的芯片组,并且PCI设备有不同的要求(呃,“特性”),结果是Linux内核中的PCI支持并不
+像人们希望的那样简单。这篇短文试图向所有潜在的驱动程序作者介绍PCI设备驱动程序的
+Linux APIs。
+
+更完整的资源是Jonathan Corbet、Alessandro Rubini和Greg Kroah-Hartman的
+《Linux设备驱动程序》第三版。LDD3可以免费获得(在知识共享许可下),网址是:
+https://lwn.net/Kernel/LDD3/。
+
+
+
+然而,请记住,所有的文档都会受到“维护不及时”的影响。如果事情没有按照这里描述的那
+样进行,请参考源代码。
+
+请将有关Linux PCI API的问题/评论/补丁发送到“Linux PCI”
+<linux-pci@atrey.karlin.mff.cuni.cz> 邮件列表。
+
+
+PCI驱动的结构体
+===============
+PCI驱动通过pci_register_driver()在系统中“发现”PCI设备。实际上,它是反过来的。
+当PCI通用代码发现一个新设备时,具有匹配“描述”的驱动程序将被通知。下面是这方面的细
+节。
+
+pci_register_driver()将大部分探测设备的工作留给了PCI层,并支持设备的在线插入/移
+除[从而在一个驱动中支持可热插拔的PCI、CardBus和Express-Card]。 pci_register_driver()
+调用需要传入一个函数指针表,从而决定了驱动的高层结构体。
+
+一旦驱动探测到一个PCI设备并取得了所有权,驱动通常需要执行以下初始化:
+
+ - 启用设备
+ - 请求MMIO/IOP资源
+ - 设置DMA掩码大小(对于流式和一致的DMA)
+ - 分配和初始化共享控制数据(pci_allocate_coherent())
+ - 访问设备配置空间(如果需要)
+ - 注册IRQ处理程序(request_irq())
+ - 初始化非PCI(即芯片的LAN/SCSI/等部分)
+ - 启用DMA/处理引擎
+
+当使用完设备后,也许需要卸载模块,驱动需要采取以下步骤:
+
+ - 禁用设备产生的IRQ
+ - 释放IRQ(free_irq())
+ - 停止所有DMA活动
+ - 释放DMA缓冲区(包括一致性和数据流式)
+ - 从其他子系统(例如scsi或netdev)上取消注册
+ - 释放MMIO/IOP资源
+ - 禁用设备
+
+这些主题中的大部分都在下面的章节中有所涉及。其余的内容请参考LDD3或<linux/pci.h> 。
+
+如果没有配置PCI子系统(没有设置 ``CONFIG_PCI`` ),下面描述的大多数PCI函数被定
+义为内联函数,要么完全为空,要么只是返回一个适当的错误代码,以避免在驱动程序中出现
+大量的 ``ifdef`` 。
+
+
+调用pci_register_driver()
+=========================
+
+PCI设备驱动程序在初始化过程中调用 ``pci_register_driver()`` ,并提供一个指向
+描述驱动程序的结构体的指针( ``struct pci_driver`` ):
+
+该API在以下内核代码中:
+
+include/linux/pci.h
+pci_driver
+
+ID表是一个由 ``struct pci_device_id`` 结构体成员组成的数组,以一个全零的成员
+结束。一般来说,带有静态常数的定义是首选。
+
+该API在以下内核代码中:
+
+include/linux/mod_devicetable.h
+pci_device_id
+
+大多数驱动程序只需要 ``PCI_DEVICE()`` 或 ``PCI_DEVICE_CLASS()`` 来设置一个
+pci_device_id表。
+
+新的 ``PCI ID`` 可以在运行时被添加到设备驱动的 ``pci_ids`` 表中,如下所示::
+
+ echo "vendor device subvendor subdevice class class_mask driver_data" > \
+ /sys/bus/pci/drivers/{driver}/new_id
+
+所有字段都以十六进制值传递(没有前置0x)。供应商和设备字段是强制性的,其他字段是可
+选的。用户只需要传递必要的可选字段:
+
+ - subvendor和subdevice字段默认为PCI_ANY_ID (FFFFFFF)。
+ - class和classmask字段默认为0
+ - driver_data默认为0UL。
+ - override_only字段默认为0。
+
+请注意, ``driver_data`` 必须与驱动程序中定义的任何一个 ``pci_device_id`` 条
+目所使用的值相匹配。如果所有的 ``pci_device_id`` 成员都有一个非零的driver_data
+值,这使得driver_data字段是强制性的。
+
+一旦添加,驱动程序探测程序将被调用,以探测其(新更新的) ``pci_ids`` 列表中列出的
+任何无人认领的PCI设备。
+
+当驱动退出时,它只是调用 ``pci_unregister_driver()`` ,PCI层会自动调用驱动处理
+的所有设备的移除钩子。
+
+
+驱动程序功能/数据的“属性”
+-------------------------
+
+请在适当的地方标记初始化和清理函数(相应的宏在<linux/init.h>中定义):
+
+ ====== ==============================================
+ __init 初始化代码。在驱动程序初始化后被抛弃。
+ __exit 退出代码。对于非模块化的驱动程序来说是忽略的。
+ ====== ==============================================
+
+关于何时/何地使用上述属性的提示:
+
+ - module_init()/module_exit()函数(以及所有仅由这些函数调用的初始化函数)应该被标记
+
+ - 为__init/__exit。
+
+ - 不要标记pci_driver结构体。
+
+ - 如果你不确定应该使用哪种标记,请不要标记一个函数。不标记函数比标记错误的函数更好。
+
+
+如何手动搜索PCI设备
+===================
+
+PCI驱动最好有一个非常好的理由不使用 ``pci_register_driver()`` 接口来搜索PCI设备。
+PCI设备被多个驱动程序控制的主要原因是一个PCI设备实现了几个不同的HW服务。例如,组合的
+串行/并行端口/软盘控制器。
+
+可以使用以下结构体进行手动搜索:
+
+通过供应商和设备ID进行搜索::
+
+ struct pci_dev *dev = NULL;
+ while (dev = pci_get_device(VENDOR_ID, DEVICE_ID, dev))
+ configure_device(dev);
+
+按类别ID搜索(以类似的方式迭代)::
+
+ pci_get_class(CLASS_ID, dev)
+
+通过供应商/设备和子系统供应商/设备ID进行搜索::
+
+ pci_get_subsys(VENDOR_ID,DEVICE_ID, SUBSYS_VENDOR_ID, SUBSYS_DEVICE_ID, dev).
+
+你可以使用常数 ``PCI_ANY_ID`` 作为 ``VENDOR_ID`` 或 ``DEVICE_ID`` 的通
+配符替代。例如,这允许搜索来自一个特定供应商的任何设备。
+
+这些函数是热拔插安全的。它们会增加它们所返回的 ``pci_dev`` 的参考计数。你最终
+必须通过调用 ``pci_dev_put()`` 来减少这些设备上的参考计数(可能在模块卸载时)。
+
+
+设备初始化步骤
+==============
+
+正如介绍中所指出的,大多数PCI驱动需要以下步骤进行设备初始化:
+
+ - 启用设备
+ - 请求MMIO/IOP资源
+ - 设置DMA掩码大小(对于流式和一致的DMA)
+ - 分配和初始化共享控制数据(pci_allocate_coherent())
+ - 访问设备配置空间(如果需要)
+ - 注册IRQ处理程序(request_irq())
+ - 初始化non-PCI(即芯片的LAN/SCSI/等部分)
+ - 启用DMA/处理引擎
+
+驱动程序可以在任何时候访问PCI配置空间寄存器。(嗯,几乎如此。当运行BIST时,配置
+空间可以消失......但这只会导致PCI总线主控中止,读取配置将返回垃圾值)。)
+
+
+启用PCI设备
+-----------
+在接触任何设备寄存器之前,驱动程序需要通过调用 ``pci_enable_device()`` 启用
+PCI设备。这将:
+
+ - 唤醒处于暂停状态的设备。
+ - 分配设备的I/O和内存区域(如果BIOS没有这样做)。
+ - 分配一个IRQ(如果BIOS没有)。
+
+.. note::
+ pci_enable_device() 可能失败,检查返回值。
+
+.. warning::
+ OS BUG:在启用这些资源之前,我们没有检查资源分配情况。如果我们在调用
+ 之前调用pci_request_resources(),这个顺序会更合理。目前,当两个设备被分配
+ 了相同的范围时,设备驱动无法检测到这个错误。这不是一个常见的问题,不太可能很快
+ 得到修复。
+
+ 这个问题之前已经讨论过了,但从2.6.19开始没有改变:
+ https://lore.kernel.org/r/20060302180025.GC28895@flint.arm.linux.org.uk/
+
+
+pci_set_master()将通过设置PCI_COMMAND寄存器中的总线主控位来启用DMA。
+``pci_clear_master()`` 将通过清除总线主控位来禁用DMA,它还修复了延迟计时器的
+值,如果它被BIOS设置成假的。
+
+如果PCI设备可以使用 ``PCI Memory-Write-Invalidate`` 事务,请调用 ``pci_set_mwi()`` 。
+这将启用 ``Mem-Wr-Inval`` 的 ``PCI_COMMAND`` 位,也确保缓存行大小寄存器被正确设置。检
+查 ``pci_set_mwi()`` 的返回值,因为不是所有的架构或芯片组都支持 ``Memory-Write-Invalidate`` 。
+另外,如果 ``Mem-Wr-Inval`` 是好的,但不是必须的,可以调用 ``pci_try_set_mwi()`` ,让
+系统尽最大努力来启用 ``Mem-Wr-Inval`` 。
+
+
+请求MMIO/IOP资源
+----------------
+内存(MMIO)和I/O端口地址不应该直接从PCI设备配置空间中读取。使用 ``pci_dev`` 结构体
+中的值,因为PCI “总线地址”可能已经被arch/chip-set特定的内核支持重新映射为“主机物理”
+地址。
+
+参见io_mapping函数,了解如何访问设备寄存器或设备内存。
+
+设备驱动需要调用 ``pci_request_region()`` 来确认没有其他设备已经在使用相同的地址
+资源。反之,驱动应该在调用 ``pci_disable_device()`` 之后调用 ``pci_release_region()`` 。
+这个想法是为了防止两个设备在同一地址范围内发生冲突。
+
+.. tip::
+ 见上面的操作系统BUG注释。目前(2.6.19),驱动程序只能在调用pci_enable_device()
+ 后确定MMIO和IO端口资源的可用性。
+
+``pci_request_region()`` 的通用风格是 ``request_mem_region()`` (用于MMIO
+范围)和 ``request_region()`` (用于IO端口范围)。对于那些不被 "正常 "PCI BAR描
+述的地址资源,使用这些方法。
+
+也请看下面的 ``pci_request_selected_regions()`` 。
+
+
+设置DMA掩码大小
+---------------
+.. note::
+ 如果下面有什么不明白的地方,请参考使用通用设备的动态DMA映射。本节只是提醒大家,
+ 驱动程序需要说明设备的DMA功能,并不是DMA接口的权威来源。
+
+虽然所有的驱动程序都应该明确指出PCI总线主控的DMA功能(如32位或64位),但对于流式
+数据来说,具有超过32位总线主站功能的设备需要驱动程序通过调用带有适当参数的
+``dma_set_mask()`` 来“注册”这种功能。一般来说,在系统RAM高于4G物理地址的情
+况下,这允许更有效的DMA。
+
+所有PCI-X和PCIe兼容设备的驱动程序必须调用 ``dma_set_mask()`` ,因为它们
+是64位DMA设备。
+
+同样,如果设备可以通过调用 ``dma_set_coherent_mask()`` 直接寻址到
+4G物理地址以上的系统RAM中的“一致性内存”,那么驱动程序也必须“注册”这种功能。同
+样,这包括所有PCI-X和PCIe兼容设备的驱动程序。许多64位“PCI”设备(在PCI-X之前)
+和一些PCI-X设备对有效载荷(“流式”)数据具有64位DMA功能,但对控制(“一致性”)数
+据则没有。
+
+
+设置共享控制数据
+----------------
+一旦DMA掩码设置完毕,驱动程序就可以分配“一致的”(又称共享的)内存。参见使用通
+用设备的动态DMA映射,了解DMA API的完整描述。本节只是提醒大家,需要在设备上启
+用DMA之前完成。
+
+
+初始化设备寄存器
+----------------
+一些驱动程序需要对特定的“功能”字段进行编程,或对其他“供应商专用”寄存器进行初始
+化或重置。例如,清除挂起的中断。
+
+
+注册IRQ处理函数
+---------------
+虽然调用 ``request_irq()`` 是这里描述的最后一步,但这往往只是初始化设备的另
+一个中间步骤。这一步通常可以推迟到设备被打开使用时进行。
+
+所有IRQ线的中断处理程序都应该用 ``IRQF_SHARED`` 注册,并使用devid将IRQ映射
+到设备(记住,所有的PCI IRQ线都可以共享)。
+
+``request_irq()`` 将把一个中断处理程序和设备句柄与一个中断号联系起来。历史上,
+中断号码代表从PCI设备到中断控制器的IRQ线。在MSI和MSI-X中(更多内容见下文),中
+断号是CPU的一个“向量”。
+
+``request_irq()`` 也启用中断。在注册中断处理程序之前,请确保设备是静止的,并且
+没有任何中断等待。
+
+MSI和MSI-X是PCI功能。两者都是“消息信号中断”,通过向本地APIC的DMA写入来向CPU发
+送中断。MSI和MSI-X的根本区别在于如何分配多个“向量”。MSI需要连续的向量块,而
+MSI-X可以分配几个单独的向量。
+
+在调用 ``request_irq()`` 之前,可以通过调用 ``pci_alloc_irq_vectors()``
+的PCI_IRQ_MSI和/或PCI_IRQ_MSIX标志来启用MSI功能。这将导致PCI支持将CPU向量数
+据编程到PCI设备功能寄存器中。许多架构、芯片组或BIOS不支持MSI或MSI-X,调用
+``pci_alloc_irq_vectors`` 时只使用PCI_IRQ_MSI和PCI_IRQ_MSIX标志会失败,
+所以尽量也要指定 ``PCI_IRQ_LEGACY`` 。
+
+对MSI/MSI-X和传统INTx有不同中断处理程序的驱动程序应该在调用
+``pci_alloc_irq_vectors`` 后根据 ``pci_dev``结构体中的 ``msi_enabled``
+和 ``msix_enabled`` 标志选择正确的处理程序。
+
+使用MSI有(至少)两个真正好的理由:
+
+1) 根据定义,MSI是一个排他性的中断向量。这意味着中断处理程序不需要验证其设备是
+ 否引起了中断。
+
+2) MSI避免了DMA/IRQ竞争条件。到主机内存的DMA被保证在MSI交付时对主机CPU是可
+ 见的。这对数据一致性和避
+
+3) 免控制数据过期都很重要。这个保证允许驱动程序省略MMIO读取,以刷新DMA流。
+
+参见drivers/infiniband/hw/mthca/或drivers/net/tg3.c了解MSI/MSI-X的使
+用实例。
+
+
+PCI设备关闭
+===========
+
+当一个PCI设备驱动程序被卸载时,需要执行以下大部分步骤:
+
+ - 禁用设备产生的IRQ
+ - 释放IRQ(free_irq())
+ - 停止所有DMA活动
+ - 释放DMA缓冲区(包括流式和一致的)
+ - 从其他子系统(例如scsi或netdev)上取消注册
+ - 禁用设备对MMIO/IO端口地址的响应
+ - 释放MMIO/IO端口资源
+
+
+停止设备上的IRQ
+---------------
+如何做到这一点是针对芯片/设备的。如果不这样做,如果(也只有在)IRQ与另一个设备
+共享,就会出现“尖叫中断”的可能性。
+
+当共享的IRQ处理程序被“解钩”时,使用同一IRQ线的其余设备仍然需要启用该IRQ。因此,
+如果“脱钩”的设备断言IRQ线,假设它是其余设备中的一个断言IRQ线,系统将作出反应。
+由于其他设备都不会处理这个IRQ,系统将“挂起”,直到它决定这个IRQ不会被处理并屏蔽
+这个IRQ(100,000次之后)。一旦共享的IRQ被屏蔽,其余设备将停止正常工作。这不是
+一个好事情。
+
+这是使用MSI或MSI-X的另一个原因,如果它可用的话。MSI和MSI-X被定义为独占中断,
+因此不容易受到“尖叫中断”问题的影响。
+
+释放IRQ
+-------
+一旦设备被静止(不再有IRQ),就可以调用free_irq()。这个函数将在任何待处理
+的IRQ被处理后返回控制,从该IRQ上“解钩”驱动程序的IRQ处理程序,最后如果没有人
+使用该IRQ,则释放它。
+
+
+停止所有DMA活动
+---------------
+在试图取消分配DMA控制数据之前,停止所有的DMA操作是非常重要的。如果不这样做,
+可能会导致内存损坏、挂起,在某些芯片组上还会导致硬崩溃。
+
+在停止IRQ后停止DMA可以避免IRQ处理程序可能重新启动DMA引擎的竞争。
+
+虽然这个步骤听起来很明显,也很琐碎,但过去有几个“成熟”的驱动程序没有做好这个
+步骤。
+
+
+释放DMA缓冲区
+-------------
+一旦DMA被停止,首先要清理流式DMA。即取消数据缓冲区的映射,如果有的话,将缓
+冲区返回给“上游”所有者。
+
+然后清理包含控制数据的“一致的”缓冲区。
+
+关于取消映射接口的细节,请参见Documentation/core-api/dma-api.rst。
+
+
+从其他子系统取消注册
+--------------------
+大多数低级别的PCI设备驱动程序支持其他一些子系统,如USB、ALSA、SCSI、NetDev、
+Infiniband等。请确保你的驱动程序没有从其他子系统中丢失资源。如果发生这种情况,
+典型的症状是当子系统试图调用已经卸载的驱动程序时,会出现Oops(恐慌)。
+
+
+禁止设备对MMIO/IO端口地址做出响应
+---------------------------------
+io_unmap() MMIO或IO端口资源,然后调用pci_disable_device()。
+这与pci_enable_device()对称相反。
+在调用pci_disable_device()后不要访问设备寄存器。
+
+
+释放MMIO/IO端口资源
+-------------------
+调用pci_release_region()来标记MMIO或IO端口范围为可用。
+如果不这样做,通常会导致无法重新加载驱动程序。
+
+
+
+
+如何访问PCI配置空间
+===================
+
+你可以使用 `pci_(read|write)_config_(byte|word|dword)` 来访问由
+`struct pci_dev *` 表示的设备的配置空间。所有这些函数在成功时返回0,或者返回一个
+错误代码( `PCIBIOS_...` ),这个错误代码可以通过pcibios_strerror翻译成文本字
+符串。大多数驱动程序希望对有效的PCI设备的访问不会失败。
+
+如果你没有可用的pci_dev结构体,你可以调用
+`pci_bus_(read|write)_config_(byte|word|dword)` 来访问一个给定的设备和该总
+线上的功能。
+
+如果你访问配置头的标准部分的字段,请使用<linux/pci.h>中声明的位置和位的符号名称。
+
+如果你需要访问扩展的PCI功能寄存器,只要为特定的功能调用pci_find_capability(),
+它就会为你找到相应的寄存器块。
+
+
+其它有趣的函数
+==============
+
+============================= =================================================
+pci_get_domain_bus_and_slot() 找到与给定的域、总线和槽以及编号相对应的pci_dev。
+ 如果找到该设备,它的引用计数就会增加。
+pci_set_power_state() 设置PCI电源管理状态(0=D0 ... 3=D3
+pci_find_capability() 在设备的功能列表中找到指定的功能
+pci_resource_start() 返回一个给定的PCI区域的总线起始地址
+pci_resource_end() 返回给定PCI区域的总线末端地址
+pci_resource_len() 返回一个PCI区域的字节长度
+pci_set_drvdata() 为一个pci_dev设置私有驱动数据指针
+pci_get_drvdata() 返回一个pci_dev的私有驱动数据指针
+pci_set_mwi() 启用设备内存写无效
+pci_clear_mwi() 关闭设备内存写无效
+============================= =================================================
+
+
+杂项提示
+========
+
+当向用户显示PCI设备名称时(例如,当驱动程序想告诉用户它找到了什么卡时),请使
+用pci_name(pci_dev)。
+
+始终通过对pci_dev结构体的指针来引用PCI设备。所有的PCI层函数都使用这个标识,
+它是唯一合理的标识。除了非常特殊的目的,不要使用总线/插槽/功能号————在有多个
+主总线的系统上,它们的语义可能相当复杂。
+
+不要试图在你的驱动程序中开启快速寻址周期写入功能。总线上的所有设备都需要有这样
+的功能,所以这需要由平台和通用代码来处理,而不是由单个驱动程序来处理。
+
+
+供应商和设备标识
+================
+
+不要在include/linux/pci_ids.h中添加新的设备或供应商ID,除非它们是在多个驱
+动程序中共享。如果有需要的话,你可以在你的驱动程序中添加私有定义,或者直接使用
+普通的十六进制常量。
+
+设备ID是任意的十六进制数字(厂商控制),通常只在一个地方使用,即pci_device_id
+表。
+
+请务必提交新的供应商/设备ID到https://pci-ids.ucw.cz/。在
+https://github.com/pciutils/pciids,有一个pci.ids文件的镜像。
+
+
+过时的函数
+==========
+
+当你试图将一个旧的驱动程序移植到新的PCI接口时,你可能会遇到几个函数。它们不再存
+在于内核中,因为它们与热插拔或PCI域或具有健全的锁不兼容。
+
+================= ===================================
+pci_find_device() 被pci_get_device()取代
+pci_find_subsys() 被pci_get_subsys()取代
+pci_find_slot() 被pci_get_domain_bus_and_slot()取代
+pci_get_slot() 被pci_get_domain_bus_and_slot()取代
+================= ===================================
+
+另一种方法是传统的PCI设备驱动,即走PCI设备列表。这仍然是可能的,但不鼓励这样做。
+
+
+MMIO空间和“写通知”
+==================
+
+将驱动程序从使用I/O端口空间转换为使用MMIO空间,通常需要一些额外的改变。具体来说,
+需要处理“写通知”。许多驱动程序(如tg3,acenic,sym53c8xx_2)已经做了这个。I/O
+端口空间保证写事务在CPU继续之前到达PCI设备。对MMIO空间的写入允许CPU在事务到达PCI
+设备之前继续。HW weenies称这为“写通知”,因为在事务到达目的地之前,写的完成被“通知”
+给CPU。
+
+因此,对时间敏感的代码应该添加readl(),CPU在做其他工作之前应该等待。经典的“位脉冲”
+序列对I/O端口空间很有效::
+
+ for (i = 8; --i; val >>= 1) {
+ outb(val & 1, ioport_reg); /* 置位 */
+ udelay(10);
+ }
+
+对MMIO空间来说,同样的顺序应该是::
+
+ for (i = 8; --i; val >>= 1) {
+ writeb(val & 1, mmio_reg); /* 置位 */
+ readb(safe_mmio_reg); /* 刷新写通知 */
+ udelay(10);
+ }
+
+重要的是, ``safe_mmio_reg`` 不能有任何干扰设备正确操作的副作用。
+
+另一种需要注意的情况是在重置PCI设备时。使用PCI配置空间读数来刷新writeel()。如果预期
+PCI设备不响应readl(),这将在所有平台上优雅地处理PCI主控器的中止。大多数x86平台将允许
+MMIO读取主控中止(又称“软失败”),并返回垃圾(例如~0)。但许多RISC平台会崩溃(又称“硬失败”)。
diff --git a/Documentation/translations/zh_CN/PCI/pciebus-howto.rst b/Documentation/translations/zh_CN/PCI/pciebus-howto.rst
new file mode 100644
index 000000000000..65c4301f12cd
--- /dev/null
+++ b/Documentation/translations/zh_CN/PCI/pciebus-howto.rst
@@ -0,0 +1,192 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: <isonum.txt>
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/PCI/pciebus-howto.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+
+.. _cn_pciebus-howto:
+
+===========================
+PCI Express端口总线驱动指南
+===========================
+
+:作者: Tom L Nguyen tom.l.nguyen@intel.com 11/03/2004
+:版权: |copy| 2004 Intel Corporation
+
+关于本指南
+==========
+
+本指南介绍了PCI Express端口总线驱动程序的基本知识,并提供了如何使服务驱
+动程序在PCI Express端口总线驱动程序中注册/取消注册的介绍。
+
+
+什么是PCI Express端口总线驱动程序
+=================================
+
+一个PCI Express端口是一个逻辑的PCI-PCI桥结构。有两种类型的PCI Express端
+口:根端口和交换端口。根端口从PCI Express根综合体发起一个PCI Express链接,
+交换端口将PCI Express链接连接到内部逻辑PCI总线。交换机端口,其二级总线代表
+交换机的内部路由逻辑,被称为交换机的上行端口。交换机的下行端口是从交换机的内部
+路由总线桥接到代表来自PCI Express交换机的下游PCI Express链接的总线。
+
+一个PCI Express端口可以提供多达四个不同的功能,在本文中被称为服务,这取决于
+其端口类型。PCI Express端口的服务包括本地热拔插支持(HP)、电源管理事件支持(PME)、
+高级错误报告支持(AER)和虚拟通道支持(VC)。这些服务可以由一个复杂的驱动程序
+处理,也可以单独分布并由相应的服务驱动程序处理。
+
+为什么要使用PCI Express端口总线驱动程序?
+=========================================
+
+在现有的Linux内核中,Linux设备驱动模型允许一个物理设备只由一个驱动处理。
+PCI Express端口是一个具有多个不同服务的PCI-PCI桥设备。为了保持一个干净和简
+单的解决方案,每个服务都可以有自己的软件服务驱动。在这种情况下,几个服务驱动将
+竞争一个PCI-PCI桥设备。例如,如果PCI Express根端口的本机热拔插服务驱动程序
+首先被加载,它就会要求一个PCI-PCI桥根端口。因此,内核不会为该根端口加载其他服
+务驱动。换句话说,使用当前的驱动模型,不可能让多个服务驱动同时加载并运行在
+PCI-PCI桥设备上。
+
+为了使多个服务驱动程序同时运行,需要有一个PCI Express端口总线驱动程序,它管
+理所有填充的PCI Express端口,并根据需要将所有提供的服务请求分配给相应的服务
+驱动程序。下面列出了使用PCI Express端口总线驱动程序的一些关键优势:
+
+ - 允许在一个PCI-PCI桥接端口设备上同时运行多个服务驱动。
+
+ - 允许以独立的分阶段方式实施服务驱动程序。
+
+ - 允许一个服务驱动程序在多个PCI-PCI桥接端口设备上运行。
+
+ - 管理和分配PCI-PCI桥接端口设备的资源给要求的服务驱动程序。
+
+配置PCI Express端口总线驱动程序与服务驱动程序
+=============================================
+
+将PCI Express端口总线驱动支持纳入内核
+-------------------------------------
+
+包括PCI Express端口总线驱动程序取决于内核配置中是否包含PCI Express支持。当内核
+中的PCI Express支持被启用时,内核将自动包含PCI Express端口总线驱动程序作为内核
+驱动程序。
+
+启用服务驱动支持
+----------------
+
+PCI设备驱动是基于Linux设备驱动模型实现的。所有的服务驱动都是PCI设备驱动。如上所述,
+一旦内核加载了PCI Express端口总线驱动程序,就不可能再加载任何服务驱动程序。为了满
+足PCI Express端口总线驱动程序模型,需要对现有的服务驱动程序进行一些最小的改变,其
+对现有的服务驱动程序的功能没有影响。
+
+服务驱动程序需要使用下面所示的两个API,将其服务注册到PCI Express端口总线驱动程
+序中(见第5.2.1和5.2.2节)。在调用这些API之前,服务驱动程序必须初始化头文件
+/include/linux/pcieport_if.h中的pcie_port_service_driver数据结构。如果不这
+样做,将导致身份不匹配,从而使PCI Express端口总线驱动程序无法加载服务驱动程序。
+
+pcie_port_service_register
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+::
+
+ int pcie_port_service_register(struct pcie_port_service_driver *new)
+
+这个API取代了Linux驱动模型的 pci_register_driver API。一个服务驱动应该总是在模
+块启动时调用 pcie_port_service_register。请注意,在服务驱动被加载后,诸如
+pci_enable_device(dev) 和 pci_set_master(dev) 的调用不再需要,因为这些调用由
+PCI端口总线驱动执行。
+
+pcie_port_service_unregister
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+::
+
+ void pcie_port_service_unregister(struct pcie_port_service_driver *new)
+
+pcie_port_service_unregister取代了Linux驱动模型的pci_unregister_driver。当一
+个模块退出时,它总是被服务驱动调用。
+
+示例代码
+~~~~~~~~
+
+下面是服务驱动代码示例,用于初始化端口服务的驱动程序数据结构。
+::
+
+ static struct pcie_port_service_id service_id[] = { {
+ .vendor = PCI_ANY_ID,
+ .device = PCI_ANY_ID,
+ .port_type = PCIE_RC_PORT,
+ .service_type = PCIE_PORT_SERVICE_AER,
+ }, { /* end: all zeroes */ }
+ };
+
+ static struct pcie_port_service_driver root_aerdrv = {
+ .name = (char *)device_name,
+ .id_table = &service_id[0],
+
+ .probe = aerdrv_load,
+ .remove = aerdrv_unload,
+
+ .suspend = aerdrv_suspend,
+ .resume = aerdrv_resume,
+ };
+
+下面是一个注册/取消注册服务驱动的示例代码。
+::
+
+ static int __init aerdrv_service_init(void)
+ {
+ int retval = 0;
+
+ retval = pcie_port_service_register(&root_aerdrv);
+ if (!retval) {
+ /*
+ * FIX ME
+ */
+ }
+ return retval;
+ }
+
+ static void __exit aerdrv_service_exit(void)
+ {
+ pcie_port_service_unregister(&root_aerdrv);
+ }
+
+ module_init(aerdrv_service_init);
+ module_exit(aerdrv_service_exit);
+
+可能的资源冲突
+==============
+
+由于PCI-PCI桥接端口设备的所有服务驱动被允许同时运行,下面列出了一些可能的资源冲突和
+建议的解决方案。
+
+MSI 和 MSI-X 向量资源
+---------------------
+
+一旦设备上的MSI或MSI-X中断被启用,它就会一直保持这种模式,直到它们再次被禁用。由于同
+一个PCI-PCI桥接端口的服务驱动程序共享同一个物理设备,如果一个单独的服务驱动程序启用或
+禁用MSI/MSI-X模式,可能会导致不可预知的行为。
+
+为了避免这种情况,所有的服务驱动程序都不允许在其设备上切换中断模式。PCI Express端口
+总线驱动程序负责确定中断模式,这对服务驱动程序来说应该是透明的。服务驱动程序只需要知道
+分配给结构体pcie_device的字段irq的向量IRQ,当PCI Express端口总线驱动程序探测每
+个服务驱动程序时,它被传入。服务驱动应该使用(struct pcie_device*)dev->irq来调用
+request_irq/free_irq。此外,中断模式被存储在struct pcie_device的interrupt_mode
+字段中。
+
+PCI内存/IO映射的区域
+--------------------
+
+PCI Express电源管理(PME)、高级错误报告(AER)、热插拔(HP)和虚拟通道(VC)的服务
+驱动程序访问PCI Express端口的PCI配置空间。在所有情况下,访问的寄存器是相互独立的。这
+个补丁假定所有的服务驱动程序都会表现良好,不会覆盖其他服务驱动程序的配置设置。
+
+PCI配置寄存器
+-------------
+
+每个服务驱动都在自己的功能结构体上运行PCI配置操作,除了PCI Express功能结构体,其中根控制
+寄存器和设备控制寄存器是在PME和AER之间共享。这个补丁假定所有的服务驱动都会表现良好,不会
+覆盖其他服务驱动的配置设置。
diff --git a/Documentation/translations/zh_CN/PCI/sysfs-pci.rst b/Documentation/translations/zh_CN/PCI/sysfs-pci.rst
new file mode 100644
index 000000000000..0d75c2e99d52
--- /dev/null
+++ b/Documentation/translations/zh_CN/PCI/sysfs-pci.rst
@@ -0,0 +1,126 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/PCI/sysfs-pci.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+
+========================
+通过sysfs访问PCI设备资源
+========================
+
+sysfs,通常挂载在/sys,在支持它的平台上提供对PCI资源的访问。例如,一个特定的总线可能看起
+来像这样::
+
+ /sys/devices/pci0000:17
+ |-- 0000:17:00.0
+ | |-- class
+ | |-- config
+ | |-- device
+ | |-- enable
+ | |-- irq
+ | |-- local_cpus
+ | |-- remove
+ | |-- resource
+ | |-- resource0
+ | |-- resource1
+ | |-- resource2
+ | |-- revision
+ | |-- rom
+ | |-- subsystem_device
+ | |-- subsystem_vendor
+ | `-- vendor
+ `-- ...
+
+最上面的元素描述了PCI域和总线号码。在这种情况下,域号是0000,总线号是17(两个值都是十六进制)。
+这个总线在0号插槽中包含一个单一功能的设备。为了方便起见,我们复制了域和总线的编号。在设备目录
+下有几个文件,每个文件都有自己的功能。
+
+ =================== =====================================================
+ 文件 功能
+ =================== =====================================================
+ class PCI级别 (ascii, ro)
+ config PCI配置空间 (binary, rw)
+ device PCI设备 (ascii, ro)
+ enable 设备是否被启用 (ascii, rw)
+ irq IRQ编号 (ascii, ro)
+ local_cpus 临近CPU掩码(cpumask, ro)
+ remove 从内核的列表中删除设备 (ascii, wo)
+ resource PCI资源主机地址 (ascii, ro)
+ resource0..N PCI资源N,如果存在的话 (binary, mmap, rw\ [1]_)
+ resource0_wc..N_wc PCI WC映射资源N,如果可预取的话 (binary, mmap)
+ revision PCI修订版 (ascii, ro)
+ rom PCI ROM资源,如果存在的话 (binary, ro)
+ subsystem_device PCI子系统设备 (ascii, ro)
+ subsystem_vendor PCI子系统供应商 (ascii, ro)
+ vendor PCI供应商 (ascii, ro)
+ =================== =====================================================
+
+::
+
+ ro - 只读文件
+ rw - 文件是可读和可写的
+ wo - 只写文件
+ mmap - 文件是可移动的
+ ascii - 文件包含ascii文本
+ binary - 文件包含二进制数据
+ cpumask - 文件包含一个cpumask类型的
+
+.. [1] rw 仅适用于 IORESOURCE_IO(I/O 端口)区域
+
+只读文件是信息性的,对它们的写入将被忽略,但 "rom "文件除外。可写文件可以用来在设备上执
+行操作(例如,改变配置空间,分离设备)。 mmapable文件可以通过偏移量为0的文件的mmap获得,
+可以用来从用户空间进行实际的设备编程。注意,有些平台不支持某些资源的mmapping,所以一定要
+检查任何尝试的mmap的返回值。其中最值得注意的是I/O端口资源,它也提供读/写访问。
+
+enable "文件提供了一个计数器,表明设备已经被启用了多少次。如果'enable'文件目前返回'4',
+而一个'1'被呼入它,它将返回'5'。向它呼入一个'0'会减少计数。不过,即使它返回到0,一些初始
+化可能也不会被逆转。
+
+rom "文件很特别,因为它提供了对设备ROM文件的只读访问,如果有的话。然而,它在默认情况下是
+禁用的,所以应用程序应该在尝试读取调用之前将字符串 "1 "写入该文件以启用它,并在访问之后将
+"0 "写入该文件以禁用它。请注意,设备必须被启用,才能成功返回数据。如果驱动没有被绑定到设备
+上,可以使用上面提到的 "enable "文件将其启用。
+
+remove "文件是用来移除PCI设备的,通过向该文件写入一个非零的整数。这并不涉及任何形式的热插
+拔功能,例如关闭设备的电源。该设备被从内核的PCI设备列表中移除,它的sysfs目录被移除,并且该
+设备将被从任何连接到它的驱动程序中移除。移除PCI根总线是不允许的。
+
+通过sysfs访问原有资源
+---------------------
+
+如果底层平台支持的话,传统的I/O端口和ISA内存资源也会在sysfs中提供。它们位于PCI类的层次结构
+中,例如::
+
+ /sys/class/pci_bus/0000:17/
+ |-- bridge -> ../../../devices/pci0000:17
+ |-- cpuaffinity
+ |-- legacy_io
+ `-- legacy_mem
+
+legacy_io文件是一个读/写文件,可以被应用程序用来做传统的端口I/O。应用程序应该打开该文件,寻
+找所需的端口(例如0x3e8),并进行1、2或4字节的读或写。legacy_mem文件应该被mmapped,其偏移
+量与所需的内存偏移量相对应,例如0xa0000用于VGA帧缓冲器。然后,应用程序可以简单地解除引用返回
+的指针(当然是在检查了错误之后)来访问遗留内存空间。
+
+支持新平台上的PCI访问
+---------------------
+
+为了支持上述的PCI资源映射,Linux平台代码最好定义ARCH_GENERIC_PCI_MMAP_RESOURCE并使用该
+功能的通用实现。为了支持通过/proc/bus/pci中的文件实现mmap()的历史接口,平台也可以设置
+HAVE_PCI_MMAP。
+
+另外,设置了 HAVE_PCI_MMAP 的平台可以提供他们自己的 pci_mmap_page_range() 实现,而不是定
+义 ARCH_GENERIC_PCI_MMAP_RESOURCE。
+
+支持PCI资源的写组合映射的平台必须定义arch_can_pci_mmap_wc(),当写组合被允许时,在运行时应
+评估为非零。支持I/O资源映射的平台同样定义arch_can_pci_mmap_io()。
+
+遗留资源由HAVE_PCI_LEGACY定义保护。希望支持遗留功能的平台应该定义它并提供 pci_legacy_read,
+pci_legacy_write 和 pci_mmap_legacy_page_range 函数。
diff --git a/Documentation/translations/zh_CN/SecurityBugs b/Documentation/translations/zh_CN/SecurityBugs
deleted file mode 100644
index 2d0fffd122ce..000000000000
--- a/Documentation/translations/zh_CN/SecurityBugs
+++ /dev/null
@@ -1,50 +0,0 @@
-Chinese translated version of Documentation/admin-guide/security-bugs.rst
-
-If you have any comment or update to the content, please contact the
-original document maintainer directly. However, if you have a problem
-communicating in English you can also ask the Chinese maintainer for
-help. Contact the Chinese maintainer if this translation is outdated
-or if there is a problem with the translation.
-
-Chinese maintainer: Harry Wei <harryxiyou@gmail.com>
----------------------------------------------------------------------
-Documentation/admin-guide/security-bugs.rst 的中文翻译
-
-如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
-交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
-译存在问题,请联系中文版维护者。
-
-中文版维护者: 贾威威 Harry Wei <harryxiyou@gmail.com>
-中文版翻译者: 贾威威 Harry Wei <harryxiyou@gmail.com>
-中文版校译者: 贾威威 Harry Wei <harryxiyou@gmail.com>
-
-
-以下为正文
----------------------------------------------------------------------
-Linux内核开发者认为安全非常重要。因此,我们想要知道当一个有关于
-安全的漏洞被发现的时候,并且它可能会被尽快的修复或者公开。请把这个安全
-漏洞报告给Linux内核安全团队。
-
-1) 联系
-
-linux内核安全团队可以通过email<security@kernel.org>来联系。这是
-一组独立的安全工作人员,可以帮助改善漏洞报告并且公布和取消一个修复。安
-全团队有可能会从部分的维护者那里引进额外的帮助来了解并且修复安全漏洞。
-当遇到任何漏洞,所能提供的信息越多就越能诊断和修复。如果你不清楚什么
-是有帮助的信息,那就请重温一下admin-guide/reporting-bugs.rst文件中的概述过程。任
-何攻击性的代码都是非常有用的,未经报告者的同意不会被取消,除非它已经
-被公布于众。
-
-2) 公开
-
-Linux内核安全团队的宗旨就是和漏洞提交者一起处理漏洞的解决方案直
-到公开。我们喜欢尽快地完全公开漏洞。当一个漏洞或者修复还没有被完全地理
-解,解决方案没有通过测试或者供应商协调,可以合理地延迟公开。然而,我们
-期望这些延迟尽可能的短些,是可数的几天,而不是几个星期或者几个月。公开
-日期是通过安全团队和漏洞提供者以及供应商洽谈后的结果。公开时间表是从很
-短(特殊的,它已经被公众所知道)到几个星期。作为一个基本的默认政策,我
-们所期望通知公众的日期是7天的安排。
-
-3) 保密协议
-
-Linux内核安全团队不是一个正式的团体,因此不能加入任何的保密协议。
diff --git a/Documentation/translations/zh_CN/accounting/delay-accounting.rst b/Documentation/translations/zh_CN/accounting/delay-accounting.rst
new file mode 100644
index 000000000000..7b8693ccf80a
--- /dev/null
+++ b/Documentation/translations/zh_CN/accounting/delay-accounting.rst
@@ -0,0 +1,112 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/accounting/delay-accounting.rst
+
+:Translator: Yang Yang <yang.yang29@zte.com.cn>
+
+========
+延时计数
+========
+
+任务在等待某些内核资源可用时,会造成延时。例如一个可运行的任务可能会等待
+一个空闲CPU来运行。
+
+基于每任务的延时计数功能度量由以下情况造成的任务延时:
+
+a) 等待一个CPU(任务为可运行)
+b) 完成由该任务发起的块I/O同步请求
+c) 页面交换
+d) 内存回收
+e) 抖动
+f) 直接规整
+g) 写保护复制
+
+并将这些统计信息通过taskstats接口提供给用户空间。
+
+这些延时信息为适当的调整任务CPU优先级、io优先级、rss限制提供反馈。重要任务
+长期延时,表示可能需要提高其相关优先级。
+
+通过使用taskstats接口,本功能还可提供一个线程组(对应传统Unix进程)所有任务
+(或线程)的总延时统计信息。此类汇总往往是需要的,由内核来完成更加高效。
+
+用户空间的实体,特别是资源管理程序,可将延时统计信息汇总到任意组中。为实现
+这一点,任务的延时统计信息在其生命周期内和退出时皆可获取,从而确保可进行
+连续、完整的监控。
+
+接口
+----
+
+延时计数使用taskstats接口,该接口由本目录另一个单独的文档详细描述。Taskstats
+向用户态返回一个通用数据结构,对应每pid或每tgid的统计信息。延时计数功能填写
+该数据结构的特定字段。见
+
+ include/uapi/linux/taskstats.h
+
+其描述了延时计数相关字段。系统通常以计数器形式返回 CPU、同步块 I/O、交换、内存
+回收、页缓存抖动、直接规整、写保护复制等的累积延时。
+
+取任务某计数器两个连续读数的差值,将得到任务在该时间间隔内等待对应资源的总延时。
+
+当任务退出时,内核会将包含每任务的统计信息发送给用户空间,而无需额外的命令。
+若其为线程组最后一个退出的任务,内核还会发送每tgid的统计信息。更多详细信息见
+taskstats接口的描述。
+
+tools/accounting目录中的用户空间程序getdelays.c提供了一些简单的命令,用以显示
+延时统计信息。其也是使用taskstats接口的示例。
+
+用法
+----
+
+使用以下配置编译内核::
+
+ CONFIG_TASK_DELAY_ACCT=y
+ CONFIG_TASKSTATS=y
+
+延时计数在启动时默认关闭。
+若需开启,在启动参数中增加::
+
+ delayacct
+
+本文后续的说明基于延时计数已开启。也可在系统运行时,使用sysctl的
+kernel.task_delayacct进行开关。注意,只有在启用延时计数后启动的
+任务才会有相关信息。
+
+系统启动后,使用类似getdelays.c的工具获取任务或线程组(tgid)的延时信息。
+
+getdelays命令的一般格式::
+
+ getdelays [-dilv] [-t tgid] [-p pid]
+
+获取pid为10的任务从系统启动后的延时信息::
+
+ # ./getdelays -d -p 10
+ (输出信息和下例相似)
+
+获取所有tgid为5的任务从系统启动后的总延时信息::
+
+ # ./getdelays -d -t 5
+ print delayacct stats ON
+ TGID 5
+
+
+ CPU count real total virtual total delay total delay average
+ 8 7000000 6872122 3382277 0.423ms
+ IO count delay total delay average
+ 0 0 0.000ms
+ SWAP count delay total delay average
+ 0 0 0.000ms
+ RECLAIM count delay total delay average
+ 0 0 0.000ms
+ THRASHING count delay total delay average
+ 0 0 0.000ms
+ COMPACT count delay total delay average
+ 0 0 0.000ms
+ WPCOPY count delay total delay average
+ 0 0 0ms
+
+获取pid为1的IO计数,它只和-p一起使用::
+ # ./getdelays -i -p 1
+ printing IO accounting
+ linuxrc: read=65536, write=0, cancelled_write=0
+
+上面的命令与-v一起使用,可以获取更多调试信息。
diff --git a/Documentation/translations/zh_CN/accounting/index.rst b/Documentation/translations/zh_CN/accounting/index.rst
new file mode 100644
index 000000000000..a34952e12a27
--- /dev/null
+++ b/Documentation/translations/zh_CN/accounting/index.rst
@@ -0,0 +1,25 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/accounting/index.rst
+:Translator: Yang Yang <yang.yang29@zte.com.cn>
+
+.. _cn_accounting_index.rst:
+
+
+====
+计数
+====
+
+.. toctree::
+ :maxdepth: 1
+
+ delay-accounting
+ psi
+ taskstats
+
+Todolist:
+
+ cgroupstats
+ taskstats-struct
diff --git a/Documentation/translations/zh_CN/accounting/psi.rst b/Documentation/translations/zh_CN/accounting/psi.rst
new file mode 100644
index 000000000000..a0ddb7bd257c
--- /dev/null
+++ b/Documentation/translations/zh_CN/accounting/psi.rst
@@ -0,0 +1,155 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/accounting/psi.rst
+:Translator: Yang Yang <yang.yang29@zte.com.cn>
+
+.. _cn_psi.rst:
+
+
+=================
+PSI——压力阻塞信息
+=================
+
+:日期: April, 2018
+:作者: Johannes Weiner <hannes@cmpxchg.org>
+
+当CPU、memory或IO设备处于竞争状态,业务负载会遭受时延毛刺、吞吐量降低,
+及面临OOM的风险。
+
+如果没有一种准确的方法度量系统竞争程度,则有两种后果:一种是用户过于节制,
+未充分利用系统资源;另一种是过度使用,经常性面临业务中断的风险。
+
+psi特性能够识别和量化资源竞争导致的业务中断,及其对复杂负载乃至整个系统在
+时间上的影响。
+
+准确度量因资源不足造成的生产力损失,有助于用户基于硬件调整业务负载,或基
+于业务负载配置硬件。
+
+psi能够实时的提供相关信息,因此系统可基于psi实现动态的负载管理。如实施
+卸载、迁移、策略性的停止或杀死低优先级或可重启的批处理任务。
+
+psi帮助用户实现硬件资源利用率的最大化。同时无需牺牲业务负载健康度,也无需
+面临OOM等造成业务中断的风险。
+
+压力接口
+========
+
+压力信息可通过/proc/pressure/ --cpu、memory、io文件分别获取。
+
+CPU相关信息格式如下:
+
+ some avg10=0.00 avg60=0.00 avg300=0.00 total=0
+
+内存和IO相关信息如下:
+
+ some avg10=0.00 avg60=0.00 avg300=0.00 total=0
+ full avg10=0.00 avg60=0.00 avg300=0.00 total=0
+
+some行代表至少有一个任务阻塞于特定资源的时间占比。
+
+full行代表所有非idle任务同时阻塞于特定资源的时间占比。在这种状态下CPU资源
+完全被浪费,相对于正常运行,业务负载由于耗费更多时间等待而受到严重影响。
+
+由于此情况严重影响系统性能,因此清楚的识别本情况并与some行所代表的情况区分开,
+将有助于分析及提升系统性能。这就是full独立于some行的原因。
+
+avg代表阻塞时间占比(百分比),为最近10秒、60秒、300秒内的均值。这样我们
+既可观察到短期事件的影响,也可看到中等及长时间内的趋势。total代表总阻塞
+时间(单位微秒),可用于观察时延毛刺,这种毛刺可能在均值中无法体现。
+
+监控压力门限
+============
+
+用户可注册触发器,通过poll()监控资源压力是否超过门限。
+
+触发器定义:指定时间窗口期内累积阻塞时间的最大值。比如可定义500ms内积累
+100ms阻塞,即触发一次唤醒事件。
+
+触发器注册方法:用户打开代表特定资源的psi接口文件,写入门限、时间窗口的值。
+所打开的文件描述符用于等待事件,可使用select()、poll()、epoll()。
+写入信息的格式如下:
+
+ <some|full> <stall amount in us> <time window in us>
+
+示例:向/proc/pressure/memory写入"some 150000 1000000"将新增触发器,将在
+1秒内至少一个任务阻塞于内存的总时间超过150ms时触发。向/proc/pressure/io写入
+"full 50000 1000000"将新增触发器,将在1秒内所有任务都阻塞于io的总时间超过50ms时触发。
+
+触发器可针对多个psi度量值设置,同一个psi度量值可设置多个触发器。每个触发器需要
+单独的文件描述符用于轮询,以区分于其他触发器。所以即使对于同一个psi接口文件,
+每个触发器也需要单独的调用open()。
+
+监控器在被监控资源进入阻塞状态时启动,在系统退出阻塞状态后停用。系统进入阻塞
+状态后,监控psi增长的频率为每监控窗口刷新10次。
+
+内核接受的窗口为500ms~10s,所以监控间隔为50ms~1s。设置窗口下限目的是为了
+防止过于频繁的轮询。设置窗口上限的目的是因为窗口过长则无意义,此时查看
+psi接口提供的均值即可。
+
+监控器在激活后,至少在跟踪窗口期间将保持活动状态。以避免随着系统进入和退出
+阻塞状态,监控器过于频繁的进入和退出活动状态。
+
+用户态通知在监控窗口内会受到速率限制。当对应的文件描述符关闭,触发器会自动注销。
+
+用户态监控器使用示例
+====================
+
+::
+
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <stdio.h>
+ #include <poll.h>
+ #include <string.h>
+ #include <unistd.h>
+
+ /* 监控内存部分阻塞,监控时间窗口为1秒、阻塞门限为150毫秒。*/
+ int main() {
+ const char trig[] = "some 150000 1000000";
+ struct pollfd fds;
+ int n;
+
+ fds.fd = open("/proc/pressure/memory", O_RDWR | O_NONBLOCK);
+ if (fds.fd < 0) {
+ printf("/proc/pressure/memory open error: %s\n",
+ strerror(errno));
+ return 1;
+ }
+ fds.events = POLLPRI;
+
+ if (write(fds.fd, trig, strlen(trig) + 1) < 0) {
+ printf("/proc/pressure/memory write error: %s\n",
+ strerror(errno));
+ return 1;
+ }
+
+ printf("waiting for events...\n");
+ while (1) {
+ n = poll(&fds, 1, -1);
+ if (n < 0) {
+ printf("poll error: %s\n", strerror(errno));
+ return 1;
+ }
+ if (fds.revents & POLLERR) {
+ printf("got POLLERR, event source is gone\n");
+ return 0;
+ }
+ if (fds.revents & POLLPRI) {
+ printf("event triggered!\n");
+ } else {
+ printf("unknown event received: 0x%x\n", fds.revents);
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+
+Cgroup2接口
+===========
+
+对于CONFIG_CGROUP=y及挂载了cgroup2文件系统的系统,能够获取cgroups内任务的psi。
+此场景下cgroupfs挂载点的子目录包含cpu.pressure、memory.pressure、io.pressure文件,
+内容格式与/proc/pressure/下的文件相同。
+
+可设置基于cgroup的psi监控器,方法与系统级psi监控器相同。
diff --git a/Documentation/translations/zh_CN/accounting/taskstats.rst b/Documentation/translations/zh_CN/accounting/taskstats.rst
new file mode 100644
index 000000000000..307ac5ce0e4b
--- /dev/null
+++ b/Documentation/translations/zh_CN/accounting/taskstats.rst
@@ -0,0 +1,145 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/accounting/taskstats.rst
+
+:Translator: Yang Yang <yang.yang29@zte.com.cn>
+
+================
+每任务的统计接口
+================
+
+Taskstats是一个基于netlink的接口,用于从内核向用户空间发送每任务及每进程的
+统计信息。
+
+Taskstats设计目的:
+
+- 在任务生命周期内和退出时高效的提供统计信息
+- 统一不同计数子系统的接口
+- 支持未来计数系统的扩展
+
+术语
+----
+
+“pid”、“tid”、“任务”互换使用,用于描述由struct task_struct定义的标准
+Linux任务。“每pid的统计数据”等价于“每任务的统计数据”。
+
+“tgid”、“进程”、“线程组”互换使用,用于描述共享mm_struct的任务集,
+也就是传统的Unix进程。尽管使用了tgid这个词,即使一个任务是线程组组长,
+对它的处理也没有什么不同。只要一个进程还有任何归属它的任务,它就被认为
+活着。
+
+用法
+----
+
+为了在任务生命周期内获得统计信息,用户空间需打开一个单播的netlink套接字
+(NETLINK_GENERIC族)然后发送指定pid或tgid的命令。响应消息中包含单个
+任务的统计信息(若指定了pid)或进程所有任务汇总的统计信息(若指定了tgid)。
+
+为了在任务退出时获取统计信息,用户空间的监听者发送一个指定cpu掩码的注册命令。
+cpu掩码内的cpu上有任务退出时,每pid的统计信息将发送给注册成功的监听者。使用
+cpu掩码可以限制一个监听者收到的数据,并有助于对netlink接口进行流量控制,后文
+将进行更详细的解释。
+
+如果正在退出的任务是线程组中最后一个退出的线程,额外一条包含每tgid统计信息的
+记录也将发送给用户空间。后者包含线程组中所有线程(包括过去和现在)的每pid统计
+信息总和。
+
+getdelays.c是一个简单的示例,用以演示如何使用taskstats接口获取延迟统计信息。
+用户可注册cpu掩码、发送命令和处理响应、监听每tid/tgid退出数据、将收到的数据
+写入文件、通过增大接收缓冲区进行基本的流量控制。
+
+接口
+----
+
+内核用户接口封装在include/linux/taskstats.h。
+
+为避免本文档随着接口的演进而过期,本文仅给出当前版本的概要。当本文与taskstats.h
+不一致时,以taskstats.h为准。
+
+struct taskstats是每pid和每tgid数据共用的计数结构体。它是版本化的,可在内核新增
+计数子系统时进行扩展。taskstats.h中定义了各字段及语义。
+
+用户、内核空间的数据交换是属于NETLINK_GENERIC族的netlink消息,使用netlink属性
+接口。消息格式如下::
+
+ +----------+- - -+-------------+-------------------+
+ | nlmsghdr | Pad | genlmsghdr | taskstats payload |
+ +----------+- - -+-------------+-------------------+
+
+Taskstats载荷有三种类型:
+
+1. 命令:由用户发送给内核。获取指定pid/tgid数据的命令包含一个类型为
+TASKSTATS_CMD_ATTR_PID/TGID的属性,该属性包含u32的pid或tgid载荷。
+pid/tgid指示用户空间要统计的任务/进程。
+
+注册/注销获取指定cpu集上退出数据的命令包含一个类型为
+TASKSTATS_CMD_ATTR_REGISTER/DEREGISTER_CPUMASK的属性,该属性包含cpu掩码载荷。
+cpu掩码是以ascii码表示,用逗号分隔的cpu范围。例如若需监听1,2,3,5,7,8号cpu的
+退出数据,cpu掩码表示为"1-3,5,7-8"。若用户空间在关闭监听套接字前忘了注销监听
+的cpu集,随着时间的推移,内核会清理此监听集。但是,出于提效的目的,建议明确
+执行注销。
+
+2. 命令的应答:内核发出应答用户空间的命令。载荷有三类属性:
+
+a) TASKSTATS_TYPE_AGGR_PID/TGID: 本属性不包含载荷,用以指示其后为被统计对象
+的pig/tgid。
+
+b) TASKSTATS_TYPE_PID/TGID:本属性的载荷为pig/tgid,其统计信息将被返回。
+
+c) TASKSTATS_TYPE_STATS:本属性的载荷为一个struct taskstats实例。每pid和
+每tgid统计信息共用该结构体。
+
+3. 内核会在任务退出时发送新消息。其载荷包含一系列以下类型的属性:
+
+a) TASKSTATS_TYPE_AGGR_PID:指示其后两个属性为pid+stats。
+b) TASKSTATS_TYPE_PID:包含退出任务的pid。
+c) TASKSTATS_TYPE_STATS:包含退出任务的每pid统计信息
+d) TASKSTATS_TYPE_AGGR_TGID:指示其后两个属性为tgid+stats。
+e) TASKSTATS_TYPE_TGID:包含任务所属进程的tgid
+f) TASKSTATS_TYPE_STATS:包含退出任务所属进程的每tgid统计信息
+
+每tgid的统计
+------------
+
+除了每任务的统计信息,taskstats还提供每进程的统计信息,因为资源管理通常以进程
+粒度完成,并且仅在用户空间聚合任务统计信息效率低下且可能不准确(缺乏原子性)。
+
+然而,除了每任务统计信息,在内核中维护每进程统计信息存在额外的时间和空间开销。
+为解决此问题,taskstats代码将退出任务的统计信息累积到进程范围的数据结构中。
+当进程最后一个任务退出时,累积的进程级数据也会发送到用户空间(与每任务数据一起)。
+
+当用户查询每tgid数据时,内核将指定线程组中所有活动线程的统计信息相加,并添加到
+该线程组的累积总数(含之前退出的线程)。
+
+扩展taskstats
+-------------
+
+有两种方法可在未来修改内核扩展taskstats接口,以导出更多的每任务/进程统计信息:
+
+1. 在现有struct taskstats末尾增加字段。该结构体中的版本号确保了向后兼容性。
+用户空间将仅使用与其版本对应的结构体字段。
+
+2. 定义单独的统计结构体并使用netlink属性接口返回对应的数据。由于用户空间独立
+处理每个netlink属性,所以总是可以忽略其不理解类型的属性(因为使用了旧版本接口)。
+
+在1.和2.之间进行选择,属于权衡灵活性和开销的问题。若仅需增加少数字段,那么1.是
+首选方法,因为内核和用户空间无需承担处理新netlink属性的开销。但若新字段过多的
+扩展现有结构体,导致不同的用户空间计数程序不必要的接收大型结构体,而对结构体
+字段并不感兴趣,那么2.是值得的。
+
+Taskstats的流量控制
+-------------------
+
+当退出任务数速率变大,监听者可能跟不上内核发送每tid/tgid退出数据的速率,而导致
+数据丢失。taskstats结构体变大、cpu数量上升,都会导致这种可能性增加。
+
+为避免统计信息丢失,用户空间应执行以下操作中至少一项:
+
+- 增大监听者用于接收退出数据的netlink套接字接收缓存区。
+
+- 创建更多的监听者,减少每个监听者监听的cpu数量。极端情况下可为每个cpu创建
+ 一个监听者。用户还可考虑将监听者的cpu亲和性设置为监听cpu的子集,特别是当他们
+ 仅监听一个cpu。
+
+尽管采取了这些措施,若用户空间仍收到指示接收缓存区溢出的ENOBUFS错误消息,
+则应采取其他措施处理数据丢失。
diff --git a/Documentation/translations/zh_CN/admin-guide/README.rst b/Documentation/translations/zh_CN/admin-guide/README.rst
new file mode 100644
index 000000000000..e679cbc3c89d
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/README.rst
@@ -0,0 +1,291 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/admin-guide/README.rst
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+Linux内核6.x版本 <http://kernel.org/>
+=========================================
+
+以下是Linux版本6的发行注记。仔细阅读它们,
+它们会告诉你这些都是什么,解释如何安装内核,以及遇到问题时该如何做。
+
+什么是Linux?
+---------------
+
+ Linux是Unix操作系统的克隆版本,由Linus Torvalds在一个松散的网络黑客
+ (Hacker,无贬义)团队的帮助下从头开始编写。它旨在实现兼容POSIX和
+ 单一UNIX规范。
+
+ 它具有在现代成熟的Unix中应当具有的所有功能,包括真正的多任务处理、虚拟内存、
+ 共享库、按需加载、共享的写时拷贝(COW)可执行文件、恰当的内存管理以及包括
+ IPv4和IPv6在内的复合网络栈。
+
+ Linux在GNU通用公共许可证,版本2(GNU GPLv2)下分发,详见随附的COPYING文件。
+
+它能在什么样的硬件上运行?
+-----------------------------
+
+ 虽然Linux最初是为32位的x86 PC机(386或更高版本)开发的,但今天它也能运行在
+ (至少)Compaq Alpha AXP、Sun SPARC与UltraSPARC、Motorola 68000、PowerPC、
+ PowerPC64、ARM、Hitachi SuperH、Cell、IBM S/390、MIPS、HP PA-RISC、Intel
+ IA-64、DEC VAX、AMD x86-64 Xtensa和ARC架构上。
+
+ Linux很容易移植到大多数通用的32位或64位体系架构,只要它们有一个分页内存管理
+ 单元(PMMU)和一个移植的GNU C编译器(gcc;GNU Compiler Collection,GCC的一
+ 部分)。Linux也被移植到许多没有PMMU的体系架构中,尽管功能显然受到了一定的
+ 限制。
+ Linux也被移植到了其自己上。现在可以将内核作为用户空间应用程序运行——这被
+ 称为用户模式Linux(UML)。
+
+文档
+-----
+因特网上和书籍上都有大量的电子文档,既有Linux专属文档,也有与一般UNIX问题相关
+的文档。我建议在任何Linux FTP站点上查找LDP(Linux文档项目)书籍的文档子目录。
+本自述文件并不是关于系统的文档:有更好的可用资源。
+
+ - 因特网上和书籍上都有大量的(电子)文档,既有Linux专属文档,也有与普通
+ UNIX问题相关的文档。我建议在任何有LDP(Linux文档项目)书籍的Linux FTP
+ 站点上查找文档子目录。本自述文件并不是关于系统的文档:有更好的可用资源。
+
+ - 文档/子目录中有各种自述文件:例如,这些文件通常包含一些特定驱动程序的
+ 内核安装说明。请阅读
+ :ref:`Documentation/process/changes.rst <changes>` 文件,它包含了升级内核
+ 可能会导致的问题的相关信息。
+
+安装内核源代码
+---------------
+
+ - 如果您要安装完整的源代码,请把内核tar档案包放在您有权限的目录中(例如您
+ 的主目录)并将其解包::
+
+ xz -cd linux-6.x.tar.xz | tar xvf -
+
+ 将“X”替换成最新内核的版本号。
+
+ 【不要】使用 /usr/src/linux 目录!这里有一组库头文件使用的内核头文件
+ (通常是不完整的)。它们应该与库匹配,而不是被内核的变化搞得一团糟。
+
+ - 您还可以通过打补丁在6.x版本之间升级。补丁以xz格式分发。要通过打补丁进行
+ 安装,请获取所有较新的补丁文件,进入内核源代码(linux-6.x)的目录并
+ 执行::
+
+ xz -cd ../patch-6.x.xz | patch -p1
+
+ 请【按顺序】替换所有大于当前源代码树版本的“x”,这样就可以了。您可能想要
+ 删除备份文件(文件名类似xxx~ 或 xxx.orig),并确保没有失败的补丁(文件名
+ 类似xxx# 或 xxx.rej)。如果有,不是你就是我犯了错误。
+
+ 与6.x内核的补丁不同,6.x.y内核(也称为稳定版内核)的补丁不是增量的,而是
+ 直接应用于基本的6.x内核。例如,如果您的基本内核是6.0,并且希望应用6.0.3
+ 补丁,则不应先应用6.0.1和6.0.2的补丁。类似地,如果您运行的是6.0.2内核,
+ 并且希望跳转到6.0.3,那么在应用6.0.3补丁之前,必须首先撤销6.0.2补丁
+ (即patch -R)。更多关于这方面的内容,请阅读
+ :ref:`Documentation/process/applying-patches.rst <applying_patches>` 。
+
+ 或者,脚本 patch-kernel 可以用来自动化这个过程。它能确定当前内核版本并
+ 应用找到的所有补丁::
+
+ linux/scripts/patch-kernel linux
+
+ 上面命令中的第一个参数是内核源代码的位置。补丁是在当前目录应用的,但是
+ 可以将另一个目录指定为第二个参数。
+
+ - 确保没有过时的 .o 文件和依赖项::
+
+ cd linux
+ make mrproper
+
+ 现在您应该已经正确安装了源代码。
+
+软件要求
+---------
+
+ 编译和运行6.x内核需要各种软件包的最新版本。请参考
+ :ref:`Documentation/process/changes.rst <changes>`
+ 来了解最低版本要求以及如何升级软件包。请注意,使用过旧版本的这些包可能会
+ 导致很难追踪的间接错误,因此不要以为在生成或操作过程中出现明显问题时可以
+ 只更新包。
+
+为内核建立目录
+---------------
+
+ 编译内核时,默认情况下所有输出文件都将与内核源代码放在一起。使用
+ ``make O=output/dir`` 选项可以为输出文件(包括 .config)指定备用位置。
+ 例如::
+
+ kernel source code: /usr/src/linux-6.x
+ build directory: /home/name/build/kernel
+
+ 要配置和构建内核,请使用::
+
+ cd /usr/src/linux-6.x
+ make O=/home/name/build/kernel menuconfig
+ make O=/home/name/build/kernel
+ sudo make O=/home/name/build/kernel modules_install install
+
+ 请注意:如果使用了 ``O=output/dir`` 选项,那么它必须用于make的所有调用。
+
+配置内核
+---------
+
+ 即使只升级一个小版本,也不要跳过此步骤。每个版本中都会添加新的配置选项,
+ 如果配置文件没有按预定设置,就会出现奇怪的问题。如果您想以最少的工作量
+ 将现有配置升级到新版本,请使用 ``make oldconfig`` ,它只会询问您新配置
+ 选项的答案。
+
+ - 其他配置命令包括::
+
+ "make config" 纯文本界面。
+
+ "make menuconfig" 基于文本的彩色菜单、选项列表和对话框。
+
+ "make nconfig" 增强的基于文本的彩色菜单。
+
+ "make xconfig" 基于Qt的配置工具。
+
+ "make gconfig" 基于GTK+的配置工具。
+
+ "make oldconfig" 基于现有的 ./.config 文件选择所有选项,并询问
+ 新配置选项。
+
+ "make olddefconfig"
+ 类似上一个,但不询问直接将新选项设置为默认值。
+
+ "make defconfig" 根据体系架构,使用arch/$arch/defconfig或
+ arch/$arch/configs/${PLATFORM}_defconfig中的
+ 默认选项值创建./.config文件。
+
+ "make ${PLATFORM}_defconfig"
+ 使用arch/$arch/configs/${PLATFORM}_defconfig中
+ 的默认选项值创建一个./.config文件。
+ 用“make help”来获取您体系架构中所有可用平台的列表。
+
+ "make allyesconfig"
+ 通过尽可能将选项值设置为“y”,创建一个
+ ./.config文件。
+
+ "make allmodconfig"
+ 通过尽可能将选项值设置为“m”,创建一个
+ ./.config文件。
+
+ "make allnoconfig" 通过尽可能将选项值设置为“n”,创建一个
+ ./.config文件。
+
+ "make randconfig" 通过随机设置选项值来创建./.config文件。
+
+ "make localmodconfig" 基于当前配置和加载的模块(lsmod)创建配置。禁用
+ 已加载的模块不需要的任何模块选项。
+
+ 要为另一台计算机创建localmodconfig,请将该计算机
+ 的lsmod存储到一个文件中,并将其作为lsmod参数传入。
+
+ 此外,通过在参数LMC_KEEP中指定模块的路径,可以将
+ 模块保留在某些文件夹或kconfig文件中。
+
+ target$ lsmod > /tmp/mylsmod
+ target$ scp /tmp/mylsmod host:/tmp
+
+ host$ make LSMOD=/tmp/mylsmod \
+ LMC_KEEP="drivers/usb:drivers/gpu:fs" \
+ localmodconfig
+
+ 上述方法在交叉编译时也适用。
+
+ "make localyesconfig" 与localmodconfig类似,只是它会将所有模块选项转换
+ 为内置(=y)。你可以同时通过LMC_KEEP保留模块。
+
+ "make kvm_guest.config"
+ 为kvm客户机内核支持启用其他选项。
+
+ "make xen.config" 为xen dom0客户机内核支持启用其他选项。
+
+ "make tinyconfig" 配置尽可能小的内核。
+
+ 更多关于使用Linux内核配置工具的信息,见文档
+ Documentation/kbuild/kconfig.rst。
+
+ - ``make config`` 注意事项:
+
+ - 包含不必要的驱动程序会使内核变大,并且在某些情况下会导致问题:
+ 探测不存在的控制器卡可能会混淆其他控制器。
+
+ - 如果存在协处理器,则编译了数学仿真的内核仍将使用协处理器:在
+ 这种情况下,数学仿真永远不会被使用。内核会稍微大一点,但不管
+ 是否有数学协处理器,都可以在不同的机器上工作。
+
+ - “kernel hacking”配置细节通常会导致更大或更慢的内核(或两者
+ 兼而有之),甚至可以通过配置一些例程来主动尝试破坏坏代码以发现
+ 内核问题,从而降低内核的稳定性(kmalloc())。因此,您可能应该
+ 用于研究“开发”、“实验”或“调试”特性相关问题。
+
+编译内核
+---------
+
+ - 确保您至少有gcc 5.1可用。
+ 有关更多信息,请参阅 :ref:`Documentation/process/changes.rst <changes>` 。
+
+ - 执行 ``make`` 来创建压缩内核映像。如果您安装了lilo以适配内核makefile,
+ 那么也可以进行 ``make install`` ,但是您可能需要先检查特定的lilo设置。
+
+ 实际安装必须以root身份执行,但任何正常构建都不需要。
+ 无须徒然使用root身份。
+
+ - 如果您将内核的任何部分配置为模块,那么还必须执行 ``make modules_install`` 。
+
+ - 详细的内核编译/生成输出:
+
+ 通常,内核构建系统在相当安静的模式下运行(但不是完全安静)。但是有时您或
+ 其他内核开发人员需要看到编译、链接或其他命令的执行过程。为此,可使用
+ “verbose(详细)”构建模式。
+ 向 ``make`` 命令传递 ``V=1`` 来实现,例如::
+
+ make V=1 all
+
+ 如需构建系统也给出内个目标重建的愿意,请使用 ``V=2`` 。默认为 ``V=0`` 。
+
+ - 准备一个备份内核以防出错。对于开发版本尤其如此,因为每个新版本都包含
+ 尚未调试的新代码。也要确保保留与该内核对应的模块的备份。如果要安装
+ 与工作内核版本号相同的新内核,请在进行 ``make modules_install`` 安装
+ 之前备份modules目录。
+
+ 或者,在编译之前,使用内核配置选项“LOCALVERSION”向常规内核版本附加
+ 一个唯一的后缀。LOCALVERSION可以在“General Setup”菜单中设置。
+
+ - 为了引导新内核,您需要将内核映像(例如编译后的
+ .../linux/arch/x86/boot/bzImage)复制到常规可引导内核的位置。
+
+ - 不再支持在没有LILO等启动装载程序帮助的情况下直接从软盘引导内核。
+
+ 如果从硬盘引导Linux,很可能使用LILO,它使用/etc/lilo.conf文件中
+ 指定的内核映像文件。内核映像文件通常是/vmlinuz、/boot/vmlinuz、
+ /bzImage或/boot/bzImage。使用新内核前,请保存旧映像的副本,并复制
+ 新映像覆盖旧映像。然后您【必须重新运行LILO】来更新加载映射!否则,
+ 将无法启动新的内核映像。
+
+ 重新安装LILO通常需要运行/sbin/LILO。您可能希望编辑/etc/lilo.conf
+ 文件为旧内核映像指定一个条目(例如/vmlinux.old)防止新的不能正常
+ 工作。有关更多信息,请参阅LILO文档。
+
+ 重新安装LILO之后,您应该就已经准备好了。关闭系统,重新启动,尽情
+ 享受吧!
+
+ 如果需要更改内核映像中的默认根设备、视频模式等,请在适当的地方使用
+ 启动装载程序的引导选项。无需重新编译内核即可更改这些参数。
+
+ - 使用新内核重新启动并享受它吧。
+
+若遇到问题
+-----------
+
+如果您发现了一些可能由于内核缺陷所导致的问题,请参阅:
+Documentation/translations/zh_CN/admin-guide/reporting-issues.rst 。
+
+想要理解内核错误报告,请参阅:
+Documentation/translations/zh_CN/admin-guide/bug-hunting.rst 。
+
+更多用GDB调试内核的信息,请参阅:
+Documentation/translations/zh_CN/dev-tools/gdb-kernel-debugging.rst
+和 Documentation/dev-tools/kgdb.rst 。
diff --git a/Documentation/translations/zh_CN/admin-guide/bootconfig.rst b/Documentation/translations/zh_CN/admin-guide/bootconfig.rst
new file mode 100644
index 000000000000..072d17f5f199
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/bootconfig.rst
@@ -0,0 +1,293 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/admin-guide/bootconfig.rst
+
+:译者: 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+========
+引导配置
+========
+
+:作者: Masami Hiramatsu <mhiramat@kernel.org>
+
+概述
+====
+
+引导配置扩展了现有的内核命令行,以一种更有效率的方式在引导内核时进一步支持
+键值数据。这允许管理员传递一份结构化关键字的配置文件。
+
+配置文件语法
+============
+
+引导配置文件的语法采用非常简单的键值结构。每个关键字由点连接的单词组成,键
+和值由 ``=`` 连接。值以分号( ``;`` )或换行符( ``\n`` )结尾。数组值中每
+个元素由逗号( ``,`` )分隔。::
+
+ KEY[.WORD[...]] = VALUE[, VALUE2[...]][;]
+
+与内核命令行语法不同,逗号和 ``=`` 周围允许有空格。
+
+关键字只允许包含字母、数字、连字符( ``-`` )和下划线( ``_`` )。值可包含
+可打印字符和空格,但分号( ``;`` )、换行符( ``\n`` )、逗号( ``,`` )、
+井号( ``#`` )和右大括号( ``}`` )等分隔符除外。
+
+如果你需要在值中使用这些分隔符,可以用双引号( ``"VALUE"`` )或单引号
+( ``'VALUE'`` )括起来。注意,引号无法转义。
+
+键的值可以为空或不存在。这些键用于检查该键是否存在(类似布尔值)。
+
+键值语法
+--------
+
+引导配置文件语法允许用户通过大括号合并键名部分相同的关键字。例如::
+
+ foo.bar.baz = value1
+ foo.bar.qux.quux = value2
+
+也可以写成::
+
+ foo.bar {
+ baz = value1
+ qux.quux = value2
+ }
+
+或者更紧凑一些,写成::
+
+ foo.bar { baz = value1; qux.quux = value2 }
+
+在这两种样式中,引导解析时相同的关键字都会自动合并。因此可以追加类似的树或
+键值。
+
+相同关键字的值
+--------------
+
+禁止两个或多个值或数组共享同一个关键字。例如::
+
+ foo = bar, baz
+ foo = qux # !错误! 我们不可以重定义相同的关键字
+
+如果你想要更新值,必须显式使用覆盖操作符 ``:=`` 。例如::
+
+ foo = bar, baz
+ foo := qux
+
+这样 ``foo`` 关键字的值就变成了 ``qux`` 。这对于通过添加(部分)自定义引导
+配置来覆盖默认值非常有用,免于解析默认引导配置。
+
+如果你想对现有关键字追加值作为数组成员,可以使用 ``+=`` 操作符。例如::
+
+ foo = bar, baz
+ foo += qux
+
+这样, ``foo`` 关键字就同时拥有了 ``bar`` , ``baz`` 和 ``qux`` 。
+
+此外,父关键字下可同时存在值和子关键字。
+例如,下列配置是可行的。::
+
+ foo = value1
+ foo.bar = value2
+ foo := value3 # 这会更新foo的值。
+
+注意,裸值不能直接放进结构化关键字中,必须在大括号外定义它。例如::
+
+ foo {
+ bar = value1
+ bar {
+ baz = value2
+ qux = value3
+ }
+ }
+
+同时,关键字下值节点的顺序是固定的。如果值和子关键字同时存在,值永远是该关
+键字的第一个子节点。因此如果用户先指定子关键字,如::
+
+ foo.bar = value1
+ foo = value2
+
+则在程序(和/proc/bootconfig)中,它会按如下显示::
+
+ foo = value2
+ foo.bar = value1
+
+注释
+----
+
+配置语法接受shell脚本风格的注释。注释以井号( ``#`` )开始,到换行符
+( ``\n`` )结束。
+
+::
+
+ # comment line
+ foo = value # value is set to foo.
+ bar = 1, # 1st element
+ 2, # 2nd element
+ 3 # 3rd element
+
+会被解析为::
+
+ foo = value
+ bar = 1, 2, 3
+
+注意你不能把注释放在值和分隔符( ``,`` 或 ``;`` )之间。如下配置语法是错误的::
+
+ key = 1 # comment
+ ,2
+
+
+/proc/bootconfig
+================
+
+/proc/bootconfig是引导配置的用户空间接口。与/proc/cmdline不同,此文件内容以
+键值列表样式显示。
+每个键值对一行,样式如下::
+
+ KEY[.WORDS...] = "[VALUE]"[,"VALUE2"...]
+
+
+用引导配置引导内核
+==================
+
+用引导配置引导内核有两种方法:将引导配置附加到initrd镜像或直接嵌入内核中。
+
+*initrd: initial RAM disk,初始内存磁盘*
+
+将引导配置附加到initrd
+----------------------
+
+由于默认情况下引导配置文件是用initrd加载的,因此它将被添加到initrd(initramfs)
+镜像文件的末尾,其中包含填充、大小、校验值和12字节幻数,如下所示::
+
+ [initrd][bootconfig][padding][size(le32)][checksum(le32)][#BOOTCONFIG\n]
+
+大小和校验值为小端序存放的32位无符号值。
+
+当引导配置被加到initrd镜像时,整个文件大小会对齐到4字节。空字符( ``\0`` )
+会填补对齐空隙。因此 ``size`` 就是引导配置文件的长度+填充的字节。
+
+Linux内核在内存中解码initrd镜像的最后部分以获取引导配置数据。由于这种“背负式”
+的方法,只要引导加载器传递了正确的initrd文件大小,就无需更改或更新引导加载器
+和内核镜像本身。如果引导加载器意外传递了更长的大小,内核将无法找到引导配置数
+据。
+
+Linux内核在tools/bootconfig下提供了 ``bootconfig`` 命令来完成此操作,管理员
+可以用它从initrd镜像中删除或追加配置文件。你可以用以下命令来构建它::
+
+ # make -C tools/bootconfig
+
+要向initrd镜像添加你的引导配置文件,请按如下命令操作(旧数据会自动移除)::
+
+ # tools/bootconfig/bootconfig -a your-config /boot/initrd.img-X.Y.Z
+
+要从镜像中移除配置,可以使用-d选项::
+
+ # tools/bootconfig/bootconfig -d /boot/initrd.img-X.Y.Z
+
+然后在内核命令行上添加 ``bootconfig`` 告诉内核去initrd文件末尾寻找内核配置。
+
+将引导配置嵌入内核
+------------------
+
+如果你不能使用initrd,也可以通过Kconfig选项将引导配置文件嵌入内核中。在此情
+况下,你需要用以下选项重新编译内核::
+
+ CONFIG_BOOT_CONFIG_EMBED=y
+ CONFIG_BOOT_CONFIG_EMBED_FILE="/引导配置/文件/的/路径"
+
+``CONFIG_BOOT_CONFIG_EMBED_FILE`` 需要从源码树或对象树开始的引导配置文件的
+绝对/相对路径。内核会将其嵌入作为默认引导配置。
+
+与将引导配置附加到initrd一样,你也需要在内核命令行上添加 ``bootconfig`` 告诉
+内核去启用内嵌的引导配置。
+
+注意,即使你已经设置了此选项,仍可用附加到initrd的其他引导配置覆盖内嵌的引导
+配置。
+
+通过引导配置传递内核参数
+========================
+
+除了内核命令行,引导配置也可以用于传递内核参数。所有 ``kernel`` 关键字下的键
+值对都将直接传递给内核命令行。此外, ``init`` 下的键值对将通过命令行传递给
+init进程。参数按以下顺序与用户给定的内核命令行字符串相连,因此命令行参数可以
+覆盖引导配置参数(这取决于子系统如何处理参数,但通常前面的参数将被后面的参数
+覆盖)::
+
+ [bootconfig params][cmdline params] -- [bootconfig init params][cmdline init params]
+
+如果引导配置文件给出的kernel/init参数是::
+
+ kernel {
+ root = 01234567-89ab-cdef-0123-456789abcd
+ }
+ init {
+ splash
+ }
+
+这将被复制到内核命令行字符串中,如下所示::
+
+ root="01234567-89ab-cdef-0123-456789abcd" -- splash
+
+如果用户给出的其他命令行是::
+
+ ro bootconfig -- quiet
+
+则最后的内核命令行如下::
+
+ root="01234567-89ab-cdef-0123-456789abcd" ro bootconfig -- splash quiet
+
+
+配置文件的限制
+==============
+
+当前最大的配置大小是32KB,关键字总数(不是键值条目)必须少于1024个节点。
+注意:这不是条目数而是节点数,条目必须消耗超过2个节点(一个关键字和一个值)。
+所以从理论上讲最多512个键值对。如果关键字平均包含3个单词,则可有256个键值对。
+在大多数情况下,配置项的数量将少于100个条目,小于8KB,因此这应该足够了。如果
+节点数超过1024,解析器将返回错误,即使文件大小小于32KB。(请注意,此最大尺寸
+不包括填充的空字符。)
+无论如何,因为 ``bootconfig`` 命令在附加启动配置到initrd映像时会验证它,用户
+可以在引导之前注意到它。
+
+
+引导配置API
+===========
+
+用户可以查询或遍历键值对,也可以查找(前缀)根关键字节点,并在查找该节点下的
+键值。
+
+如果您有一个关键字字符串,则可以直接使用 xbc_find_value() 查询该键的值。如果
+你想知道引导配置里有哪些关键字,可以使用 xbc_for_each_key_value() 迭代键值对。
+请注意,您需要使用 xbc_array_for_each_value() 访问数组的值,例如::
+
+ vnode = NULL;
+ xbc_find_value("key.word", &vnode);
+ if (vnode && xbc_node_is_array(vnode))
+ xbc_array_for_each_value(vnode, value) {
+ printk("%s ", value);
+ }
+
+如果您想查找具有前缀字符串的键,可以使用 xbc_find_node() 通过前缀字符串查找
+节点,然后用 xbc_node_for_each_key_value() 迭代前缀节点下的键。
+
+但最典型的用法是获取前缀下的命名值或前缀下的命名数组,例如::
+
+ root = xbc_find_node("key.prefix");
+ value = xbc_node_find_value(root, "option", &vnode);
+ ...
+ xbc_node_for_each_array_value(root, "array-option", value, anode) {
+ ...
+ }
+
+这将访问值“key.prefix.option”的值和“key.prefix.array-option”的数组。
+
+锁是不需要的,因为在初始化之后配置只读。如果需要修改,必须复制所有数据和关键字。
+
+
+函数与结构体
+============
+
+相关定义的kernel-doc参见:
+
+ - include/linux/bootconfig.h
+ - lib/bootconfig.c
diff --git a/Documentation/translations/zh_CN/admin-guide/bug-bisect.rst b/Documentation/translations/zh_CN/admin-guide/bug-bisect.rst
new file mode 100644
index 000000000000..662eb5b46e84
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/bug-bisect.rst
@@ -0,0 +1,81 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: :doc:`../../../admin-guide/bug-bisect`
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+二分(bisect)缺陷
++++++++++++++++++++
+
+(英文版)最后更新:2016年10月28日
+
+引言
+=====
+
+始终尝试由来自kernel.org的源代码构建的最新内核。如果您没有信心这样做,请将
+错误报告给您的发行版供应商,而不是内核开发人员。
+
+找到缺陷(bug)并不总是那么容易,不过仍然得去找。如果你找不到它,不要放弃。
+尽可能多的向相关维护人员报告您发现的信息。请参阅MAINTAINERS文件以了解您所
+关注的子系统的维护人员。
+
+在提交错误报告之前,请阅读“Documentation/admin-guide/reporting-issues.rst”。
+
+设备未出现(Devices not appearing)
+====================================
+
+这通常是由udev/systemd引起的。在将其归咎于内核之前先检查一下。
+
+查找导致缺陷的补丁
+===================
+
+使用 ``git`` 提供的工具可以很容易地找到缺陷,只要缺陷是可复现的。
+
+操作步骤:
+
+- 从git源代码构建内核
+- 以此开始二分 [#f1]_::
+
+ $ git bisect start
+
+- 标记损坏的变更集::
+
+ $ git bisect bad [commit]
+
+- 标记正常工作的变更集::
+
+ $ git bisect good [commit]
+
+- 重新构建内核并测试
+- 使用以下任一与git bisect进行交互::
+
+ $ git bisect good
+
+ 或::
+
+ $ git bisect bad
+
+ 这取决于您测试的变更集上是否有缺陷
+- 在一些交互之后,git bisect将给出可能导致缺陷的变更集。
+
+- 例如,如果您知道当前版本有问题,而4.8版本是正常的,则可以执行以下操作::
+
+ $ git bisect start
+ $ git bisect bad # Current version is bad
+ $ git bisect good v4.8
+
+
+.. [#f1] 您可以(可选地)在开始git bisect的时候提供good或bad参数
+ ``git bisect start [BAD] [GOOD]``
+
+如需进一步参考,请阅读:
+
+- ``git-bisect`` 的手册页
+- `Fighting regressions with git bisect(用git bisect解决回归)
+ <https://www.kernel.org/pub/software/scm/git/docs/git-bisect-lk2009.html>`_
+- `Fully automated bisecting with "git bisect run"(使用git bisect run
+ 来全自动二分) <https://lwn.net/Articles/317154>`_
+- `Using Git bisect to figure out when brokenness was introduced
+ (使用Git二分来找出何时引入了错误) <http://webchick.net/node/99>`_
diff --git a/Documentation/translations/zh_CN/admin-guide/bug-hunting.rst b/Documentation/translations/zh_CN/admin-guide/bug-hunting.rst
new file mode 100644
index 000000000000..decb9b26d2f1
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/bug-hunting.rst
@@ -0,0 +1,340 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: :doc:`../../../admin-guide/bug-hunting`
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+追踪缺陷
+=========
+
+内核错误报告通常附带如下堆栈转储::
+
+ ------------[ cut here ]------------
+ WARNING: CPU: 1 PID: 28102 at kernel/module.c:1108 module_put+0x57/0x70
+ Modules linked in: dvb_usb_gp8psk(-) dvb_usb dvb_core nvidia_drm(PO) nvidia_modeset(PO) snd_hda_codec_hdmi snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd soundcore nvidia(PO) [last unloaded: rc_core]
+ CPU: 1 PID: 28102 Comm: rmmod Tainted: P WC O 4.8.4-build.1 #1
+ Hardware name: MSI MS-7309/MS-7309, BIOS V1.12 02/23/2009
+ 00000000 c12ba080 00000000 00000000 c103ed6a c1616014 00000001 00006dc6
+ c1615862 00000454 c109e8a7 c109e8a7 00000009 ffffffff 00000000 f13f6a10
+ f5f5a600 c103ee33 00000009 00000000 00000000 c109e8a7 f80ca4d0 c109f617
+ Call Trace:
+ [<c12ba080>] ? dump_stack+0x44/0x64
+ [<c103ed6a>] ? __warn+0xfa/0x120
+ [<c109e8a7>] ? module_put+0x57/0x70
+ [<c109e8a7>] ? module_put+0x57/0x70
+ [<c103ee33>] ? warn_slowpath_null+0x23/0x30
+ [<c109e8a7>] ? module_put+0x57/0x70
+ [<f80ca4d0>] ? gp8psk_fe_set_frontend+0x460/0x460 [dvb_usb_gp8psk]
+ [<c109f617>] ? symbol_put_addr+0x27/0x50
+ [<f80bc9ca>] ? dvb_usb_adapter_frontend_exit+0x3a/0x70 [dvb_usb]
+ [<f80bb3bf>] ? dvb_usb_exit+0x2f/0xd0 [dvb_usb]
+ [<c13d03bc>] ? usb_disable_endpoint+0x7c/0xb0
+ [<f80bb48a>] ? dvb_usb_device_exit+0x2a/0x50 [dvb_usb]
+ [<c13d2882>] ? usb_unbind_interface+0x62/0x250
+ [<c136b514>] ? __pm_runtime_idle+0x44/0x70
+ [<c13620d8>] ? __device_release_driver+0x78/0x120
+ [<c1362907>] ? driver_detach+0x87/0x90
+ [<c1361c48>] ? bus_remove_driver+0x38/0x90
+ [<c13d1c18>] ? usb_deregister+0x58/0xb0
+ [<c109fbb0>] ? SyS_delete_module+0x130/0x1f0
+ [<c1055654>] ? task_work_run+0x64/0x80
+ [<c1000fa5>] ? exit_to_usermode_loop+0x85/0x90
+ [<c10013f0>] ? do_fast_syscall_32+0x80/0x130
+ [<c1549f43>] ? sysenter_past_esp+0x40/0x6a
+ ---[ end trace 6ebc60ef3981792f ]---
+
+这样的堆栈跟踪提供了足够的信息来识别内核源代码中发生错误的那一行。根据问题的
+严重性,它还可能包含 **“Oops”** 一词,比如::
+
+ BUG: unable to handle kernel NULL pointer dereference at (null)
+ IP: [<c06969d4>] iret_exc+0x7d0/0xa59
+ *pdpt = 000000002258a001 *pde = 0000000000000000
+ Oops: 0002 [#1] PREEMPT SMP
+ ...
+
+尽管有 **Oops** 或其他类型的堆栈跟踪,但通常需要找到出问题的行来识别和处理缺
+陷。在本章中,我们将参考“Oops”来了解需要分析的各种堆栈跟踪。
+
+如果内核是用 ``CONFIG_DEBUG_INFO`` 编译的,那么可以使用文件:
+`scripts/decode_stacktrace.sh` 。
+
+链接的模块
+-----------
+
+受到污染或正在加载/卸载的模块用“(…)”标记,污染标志在
+`Documentation/admin-guide/tainted-kernels.rst` 文件中进行了描述,“正在被加
+载”用“+”标注,“正在被卸载”用“-”标注。
+
+
+Oops消息在哪?
+---------------
+
+通常,Oops文本由klogd从内核缓冲区读取,然后交给 ``syslogd`` ,后者将其写入
+syslog文件,通常是 ``/var/log/messages`` (取决于 ``/etc/syslog.conf`` )。
+在使用systemd的系统上,它也可以由 ``journald`` 守护进程存储,并通过运行
+``journalctl`` 命令进行访问。
+
+有时 ``klogd`` 会挂掉,这种情况下您可以运行 ``dmesg > file`` 从内核缓冲区
+读取数据并保存它。或者您可以 ``cat /proc/kmsg > file`` ,但是您必须适时
+中断以停止传输,因为 ``kmsg`` 是一个“永无止境的文件”。
+
+如果机器严重崩溃,无法输入命令或磁盘不可用,那还有三个选项:
+
+(1) 手动复制屏幕上的文本,并在机器重新启动后输入。很难受,但这是突然崩溃下
+ 唯一的选择。或者你可以用数码相机拍下屏幕——虽然不那么好,但总比什么都没
+ 有好。如果消息滚动超出控制台顶部,使用更高分辨率(例如 ``vga=791`` )
+ 引导启动将允许您阅读更多文本。(警告:这需要 ``vesafb`` ,因此对“早期”
+ 的Oppses没有帮助)
+
+(2) 从串口终端启动(参见
+ :ref:`Documentation/admin-guide/serial-console.rst <serial_console>` ),
+ 在另一台机器上运行调制解调器然后用你喜欢的通信程序捕获输出。
+ Minicom运行良好。
+
+(3) 使用Kdump(参阅 Documentation/admin-guide/kdump/kdump.rst ),使用
+ Documentation/admin-guide/kdump/gdbmacros.txt 中的dmesg gdbmacro从旧内存
+ 中提取内核环形缓冲区。
+
+找到缺陷位置
+-------------
+
+如果你能指出缺陷在内核源代码中的位置,则报告缺陷的效果会非常好。这有两种方法。
+通常来说使用 ``gdb`` 会比较容易,不过内核需要用调试信息来预编译。
+
+gdb
+^^^^
+
+GNU 调试器(GNU debugger, ``gdb`` )是从 ``vmlinux`` 文件中找出OOPS的确切
+文件和行号的最佳方法。
+
+在使用 ``CONFIG_DEBUG_INFO`` 编译的内核上使用gdb效果最好。可通过运行以下命令
+进行设置::
+
+ $ ./scripts/config -d COMPILE_TEST -e DEBUG_KERNEL -e DEBUG_INFO
+
+在用 ``CONFIG_DEBUG_INFO`` 编译的内核上,你可以直接从OOPS复制EIP值::
+
+ EIP: 0060:[<c021e50e>] Not tainted VLI
+
+并使用GDB来将其翻译成可读形式::
+
+ $ gdb vmlinux
+ (gdb) l *0xc021e50e
+
+如果没有启用 ``CONFIG_DEBUG_INFO`` ,则使用OOPS的函数偏移::
+
+ EIP is at vt_ioctl+0xda8/0x1482
+
+并在启用 ``CONFIG_DEBUG_INFO`` 的情况下重新编译内核::
+
+ $ ./scripts/config -d COMPILE_TEST -e DEBUG_KERNEL -e DEBUG_INFO
+ $ make vmlinux
+ $ gdb vmlinux
+ (gdb) l *vt_ioctl+0xda8
+ 0x1888 is in vt_ioctl (drivers/tty/vt/vt_ioctl.c:293).
+ 288 {
+ 289 struct vc_data *vc = NULL;
+ 290 int ret = 0;
+ 291
+ 292 console_lock();
+ 293 if (VT_BUSY(vc_num))
+ 294 ret = -EBUSY;
+ 295 else if (vc_num)
+ 296 vc = vc_deallocate(vc_num);
+ 297 console_unlock();
+
+或者若您想要更详细的显示::
+
+ (gdb) p vt_ioctl
+ $1 = {int (struct tty_struct *, unsigned int, unsigned long)} 0xae0 <vt_ioctl>
+ (gdb) l *0xae0+0xda8
+
+您也可以使用对象文件作为替代::
+
+ $ make drivers/tty/
+ $ gdb drivers/tty/vt/vt_ioctl.o
+ (gdb) l *vt_ioctl+0xda8
+
+如果你有调用跟踪,类似::
+
+ Call Trace:
+ [<ffffffff8802c8e9>] :jbd:log_wait_commit+0xa3/0xf5
+ [<ffffffff810482d9>] autoremove_wake_function+0x0/0x2e
+ [<ffffffff8802770b>] :jbd:journal_stop+0x1be/0x1ee
+ ...
+
+这表明问题可能在 :jbd: 模块中。您可以在gdb中加载该模块并列出相关代码::
+
+ $ gdb fs/jbd/jbd.ko
+ (gdb) l *log_wait_commit+0xa3
+
+.. note::
+
+ 您还可以对堆栈跟踪处的任何函数调用执行相同的操作,例如::
+
+ [<f80bc9ca>] ? dvb_usb_adapter_frontend_exit+0x3a/0x70 [dvb_usb]
+
+ 上述调用发生的位置可以通过以下方式看到::
+
+ $ gdb drivers/media/usb/dvb-usb/dvb-usb.o
+ (gdb) l *dvb_usb_adapter_frontend_exit+0x3a
+
+objdump
+^^^^^^^^
+
+要调试内核,请使用objdump并从崩溃输出中查找十六进制偏移,以找到有效的代码/汇
+编行。如果没有调试符号,您将看到所示例程的汇编程序代码,但是如果内核有调试
+符号,C代码也将可见(调试符号可以在内核配置菜单的hacking项中启用)。例如::
+
+ $ objdump -r -S -l --disassemble net/dccp/ipv4.o
+
+.. note::
+
+ 您需要处于内核树的顶层以便此获得您的C文件。
+
+如果您无法访问源代码,仍然可以使用以下方法调试一些崩溃转储(如Dave Miller的
+示例崩溃转储输出所示)::
+
+ EIP is at +0x14/0x4c0
+ ...
+ Code: 44 24 04 e8 6f 05 00 00 e9 e8 fe ff ff 8d 76 00 8d bc 27 00 00
+ 00 00 55 57 56 53 81 ec bc 00 00 00 8b ac 24 d0 00 00 00 8b 5d 08
+ <8b> 83 3c 01 00 00 89 44 24 14 8b 45 28 85 c0 89 44 24 18 0f 85
+
+ Put the bytes into a "foo.s" file like this:
+
+ .text
+ .globl foo
+ foo:
+ .byte .... /* bytes from Code: part of OOPS dump */
+
+ Compile it with "gcc -c -o foo.o foo.s" then look at the output of
+ "objdump --disassemble foo.o".
+
+ Output:
+
+ ip_queue_xmit:
+ push %ebp
+ push %edi
+ push %esi
+ push %ebx
+ sub $0xbc, %esp
+ mov 0xd0(%esp), %ebp ! %ebp = arg0 (skb)
+ mov 0x8(%ebp), %ebx ! %ebx = skb->sk
+ mov 0x13c(%ebx), %eax ! %eax = inet_sk(sk)->opt
+
+`scripts/decodecode` 文件可以用来自动完成大部分工作,这取决于正在调试的CPU
+体系结构。
+
+报告缺陷
+---------
+
+一旦你通过定位缺陷找到了其发生的地方,你可以尝试自己修复它或者向上游报告它。
+
+为了向上游报告,您应该找出用于开发受影响代码的邮件列表。这可以使用 ``get_maintainer.pl`` 。
+
+
+例如,您在gspca的sonixj.c文件中发现一个缺陷,则可以通过以下方法找到它的维护者::
+
+ $ ./scripts/get_maintainer.pl -f drivers/media/usb/gspca/sonixj.c
+ Hans Verkuil <hverkuil@xs4all.nl> (odd fixer:GSPCA USB WEBCAM DRIVER,commit_signer:1/1=100%)
+ Mauro Carvalho Chehab <mchehab@kernel.org> (maintainer:MEDIA INPUT INFRASTRUCTURE (V4L/DVB),commit_signer:1/1=100%)
+ Tejun Heo <tj@kernel.org> (commit_signer:1/1=100%)
+ Bhaktipriya Shridhar <bhaktipriya96@gmail.com> (commit_signer:1/1=100%,authored:1/1=100%,added_lines:4/4=100%,removed_lines:9/9=100%)
+ linux-media@vger.kernel.org (open list:GSPCA USB WEBCAM DRIVER)
+ linux-kernel@vger.kernel.org (open list)
+
+请注意它将指出:
+
+- 最后接触源代码的开发人员(如果这是在git树中完成的)。在上面的例子中是Tejun
+ 和Bhaktipriya(在这个特定的案例中,没有人真正参与这个文件的开发);
+- 驱动维护人员(Hans Verkuil);
+- 子系统维护人员(Mauro Carvalho Chehab);
+- 驱动程序和/或子系统邮件列表(linux-media@vger.kernel.org);
+- Linux内核邮件列表(linux-kernel@vger.kernel.org)。
+
+通常,修复缺陷的最快方法是将它报告给用于开发相关代码的邮件列表(linux-media
+ML),抄送驱动程序维护者(Hans)。
+
+如果你完全不知道该把报告寄给谁,且 ``get_maintainer.pl`` 也没有提供任何有用
+的信息,请发送到linux-kernel@vger.kernel.org。
+
+感谢您的帮助,这使Linux尽可能稳定:-)
+
+修复缺陷
+---------
+
+如果你懂得编程,你不仅可以通过报告错误来帮助我们,还可以提供一个解决方案。
+毕竟,开源就是分享你的工作,你不想因为你的天才而被认可吗?
+
+如果你决定这样做,请在制定解决方案后将其提交到上游。
+
+请务必阅读
+:ref:`Documentation/process/submitting-patches.rst <submittingpatches>` ,
+以帮助您的代码被接受。
+
+
+---------------------------------------------------------------------------
+
+用 ``klogd`` 进行Oops跟踪的注意事项
+------------------------------------
+
+为了帮助Linus和其他内核开发人员, ``klogd`` 对保护故障的处理提供了大量支持。
+为了完整支持地址解析,至少应该使用 ``sysklogd`` 包的1.3-pl3版本。
+
+当发生保护故障时, ``klogd`` 守护进程会自动将内核日志消息中的重要地址转换为
+它们的等效符号。然后通过 ``klogd`` 使用的任何报告机制来转发这个已翻译的内核
+消息。保护错误消息可以直接从消息文件中剪切出来并转发给内核开发人员。
+
+``klogd`` 执行两种类型的地址解析,静态翻译和动态翻译。静态翻译使用System.map
+文件。为了进行静态转换, ``klogd`` 守护进程必须能够在守护进程初始化时找到系
+统映射文件。有关 ``klogd`` 如何搜索映射文件的信息,请参见klogd手册页。
+
+当使用内核可加载模块时,动态地址转换非常重要。由于内核模块的内存是从内核的
+动态内存池中分配的,因此无论是模块的开头还是模块中的函数和符号都没有固定的
+位置。
+
+内核支持系统调用,允许程序确定加载哪些模块及其在内存中的位置。klogd守护进程
+使用这些系统调用构建了一个符号表,可用于调试可加载内核模块中发生的保护错误。
+
+klogd至少会提供产生保护故障的模块的名称。如果可加载模块的开发人员选择从模块
+导出符号信息,则可能会有其他可用的符号信息。
+
+由于内核模块环境可以是动态的,因此当模块环境发生变化时,必须有一种通知
+``klogd`` 守护进程的机制。有一些可用的命令行选项允许klogd向当前正在执行的守
+护进程发出信号示意应该刷新符号信息。有关更多信息,请参阅 ``klogd`` 手册页。
+
+sysklogd发行版附带了一个补丁,它修改了 ``modules-2.0.0`` 包,以便在加载或
+卸载模块时自动向klogd发送信号。应用此补丁基本上可无缝支持调试内核可加载模块
+发生的保护故障。
+
+以下是 ``klogd`` 处理的可加载模块中的保护故障示例::
+
+ Aug 29 09:51:01 blizard kernel: Unable to handle kernel paging request at virtual address f15e97cc
+ Aug 29 09:51:01 blizard kernel: current->tss.cr3 = 0062d000, %cr3 = 0062d000
+ Aug 29 09:51:01 blizard kernel: *pde = 00000000
+ Aug 29 09:51:01 blizard kernel: Oops: 0002
+ Aug 29 09:51:01 blizard kernel: CPU: 0
+ Aug 29 09:51:01 blizard kernel: EIP: 0010:[oops:_oops+16/3868]
+ Aug 29 09:51:01 blizard kernel: EFLAGS: 00010212
+ Aug 29 09:51:01 blizard kernel: eax: 315e97cc ebx: 003a6f80 ecx: 001be77b edx: 00237c0c
+ Aug 29 09:51:01 blizard kernel: esi: 00000000 edi: bffffdb3 ebp: 00589f90 esp: 00589f8c
+ Aug 29 09:51:01 blizard kernel: ds: 0018 es: 0018 fs: 002b gs: 002b ss: 0018
+ Aug 29 09:51:01 blizard kernel: Process oops_test (pid: 3374, process nr: 21, stackpage=00589000)
+ Aug 29 09:51:01 blizard kernel: Stack: 315e97cc 00589f98 0100b0b4 bffffed4 0012e38e 00240c64 003a6f80 00000001
+ Aug 29 09:51:01 blizard kernel: 00000000 00237810 bfffff00 0010a7fa 00000003 00000001 00000000 bfffff00
+ Aug 29 09:51:01 blizard kernel: bffffdb3 bffffed4 ffffffda 0000002b 0007002b 0000002b 0000002b 00000036
+ Aug 29 09:51:01 blizard kernel: Call Trace: [oops:_oops_ioctl+48/80] [_sys_ioctl+254/272] [_system_call+82/128]
+ Aug 29 09:51:01 blizard kernel: Code: c7 00 05 00 00 00 eb 08 90 90 90 90 90 90 90 90 89 ec 5d c3
+
+---------------------------------------------------------------------------
+
+::
+
+ Dr. G.W. Wettstein Oncology Research Div. Computing Facility
+ Roger Maris Cancer Center INTERNET: greg@wind.rmcc.com
+ 820 4th St. N.
+ Fargo, ND 58122
+ Phone: 701-234-7556
diff --git a/Documentation/translations/zh_CN/admin-guide/clearing-warn-once.rst b/Documentation/translations/zh_CN/admin-guide/clearing-warn-once.rst
new file mode 100644
index 000000000000..659264d5f994
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/clearing-warn-once.rst
@@ -0,0 +1,9 @@
+清除 WARN_ONCE
+--------------
+
+WARN_ONCE / WARN_ON_ONCE / printk_once 仅仅打印一次消息.
+
+echo 1 > /sys/kernel/debug/clear_warn_once
+
+可以清除这种状态并且再次允许打印一次告警信息,这对于运行测试集后重现问题
+很有用。
diff --git a/Documentation/translations/zh_CN/admin-guide/cpu-load.rst b/Documentation/translations/zh_CN/admin-guide/cpu-load.rst
new file mode 100644
index 000000000000..a73400a054ff
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/cpu-load.rst
@@ -0,0 +1,105 @@
+========
+CPU 负载
+========
+
+Linux通过``/proc/stat``和``/proc/uptime``导出各种信息,用户空间工具
+如top(1)使用这些信息计算系统花费在某个特定状态的平均时间。
+例如:
+
+ $ iostat
+ Linux 2.6.18.3-exp (linmac) 02/20/2007
+
+ avg-cpu: %user %nice %system %iowait %steal %idle
+ 10.01 0.00 2.92 5.44 0.00 81.63
+
+ ...
+
+这里系统认为在默认采样周期內有10.01%的时间工作在用户空间,2.92%的时
+间用在系统空间,总体上有81.63%的时间是空闲的。
+
+大多数情况下``/proc/stat``的信息几乎真实反映了系统信息,然而,由于内
+核采集这些数据的方式/时间的特点,有时这些信息根本不可靠。
+
+那么这些信息是如何被搜集的呢?每当时间中断触发时,内核查看此刻运行的
+进程类型,并增加与此类型/状态进程对应的计数器的值。这种方法的问题是
+在两次时间中断之间系统(进程)能够在多种状态之间切换多次,而计数器只
+增加最后一种状态下的计数。
+
+举例
+---
+
+假设系统有一个进程以如下方式周期性地占用cpu::
+
+ 两个时钟中断之间的时间线
+ |-----------------------|
+ ^ ^
+ |_ 开始运行 |
+ |_ 开始睡眠
+ (很快会被唤醒)
+
+在上面的情况下,根据``/proc/stat``的信息(由于当系统处于空闲状态时,
+时间中断经常会发生)系统的负载将会是0
+
+大家能够想象内核的这种行为会发生在许多情况下,这将导致``/proc/stat``
+中存在相当古怪的信息::
+
+ /* gcc -o hog smallhog.c */
+ #include <time.h>
+ #include <limits.h>
+ #include <signal.h>
+ #include <sys/time.h>
+ #define HIST 10
+
+ static volatile sig_atomic_t stop;
+
+ static void sighandler (int signr)
+ {
+ (void) signr;
+ stop = 1;
+ }
+ static unsigned long hog (unsigned long niters)
+ {
+ stop = 0;
+ while (!stop && --niters);
+ return niters;
+ }
+ int main (void)
+ {
+ int i;
+ struct itimerval it = { .it_interval = { .tv_sec = 0, .tv_usec = 1 },
+ .it_value = { .tv_sec = 0, .tv_usec = 1 } };
+ sigset_t set;
+ unsigned long v[HIST];
+ double tmp = 0.0;
+ unsigned long n;
+ signal (SIGALRM, &sighandler);
+ setitimer (ITIMER_REAL, &it, NULL);
+
+ hog (ULONG_MAX);
+ for (i = 0; i < HIST; ++i) v[i] = ULONG_MAX - hog (ULONG_MAX);
+ for (i = 0; i < HIST; ++i) tmp += v[i];
+ tmp /= HIST;
+ n = tmp - (tmp / 3.0);
+
+ sigemptyset (&set);
+ sigaddset (&set, SIGALRM);
+
+ for (;;) {
+ hog (n);
+ sigwait (&set, &i);
+ }
+ return 0;
+ }
+
+
+参考
+---
+
+- https://lore.kernel.org/r/loom.20070212T063225-663@post.gmane.org
+- Documentation/filesystems/proc.rst (1.8)
+
+
+谢谢
+---
+
+Con Kolivas, Pavel Machek
diff --git a/Documentation/translations/zh_CN/admin-guide/cputopology.rst b/Documentation/translations/zh_CN/admin-guide/cputopology.rst
new file mode 100644
index 000000000000..544d42f8f3fa
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/cputopology.rst
@@ -0,0 +1,96 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/admin-guide/cputopology.rst
+
+:翻译:
+
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+==========================
+如何通过sysfs将CPU拓扑导出
+==========================
+
+CPU拓扑信息通过sysfs导出。显示的项(属性)和某些架构的/proc/cpuinfo输出相似。它们位于
+/sys/devices/system/cpu/cpuX/topology/。请阅读ABI文件:
+Documentation/ABI/stable/sysfs-devices-system-cpu。
+
+drivers/base/topology.c是体系结构中性的,它导出了这些属性。然而,die、cluster、book、
+draw这些层次结构相关的文件仅在体系结构提供了下文描述的宏的条件下被创建。
+
+对于支持这个特性的体系结构,它必须在include/asm-XXX/topology.h中定义这些宏中的一部分::
+
+ #define topology_physical_package_id(cpu)
+ #define topology_die_id(cpu)
+ #define topology_cluster_id(cpu)
+ #define topology_core_id(cpu)
+ #define topology_book_id(cpu)
+ #define topology_drawer_id(cpu)
+ #define topology_sibling_cpumask(cpu)
+ #define topology_core_cpumask(cpu)
+ #define topology_cluster_cpumask(cpu)
+ #define topology_die_cpumask(cpu)
+ #define topology_book_cpumask(cpu)
+ #define topology_drawer_cpumask(cpu)
+
+``**_id macros`` 的类型是int。
+``**_cpumask macros`` 的类型是 ``(const) struct cpumask *`` 。后者和恰当的
+``**_siblings`` sysfs属性对应(除了topology_sibling_cpumask(),它和thread_siblings
+对应)。
+
+为了在所有体系结构上保持一致,include/linux/topology.h提供了上述所有宏的默认定义,以防
+它们未在include/asm-XXX/topology.h中定义:
+
+1) topology_physical_package_id: -1
+2) topology_die_id: -1
+3) topology_cluster_id: -1
+4) topology_core_id: 0
+5) topology_book_id: -1
+6) topology_drawer_id: -1
+7) topology_sibling_cpumask: 仅入参CPU
+8) topology_core_cpumask: 仅入参CPU
+9) topology_cluster_cpumask: 仅入参CPU
+10) topology_die_cpumask: 仅入参CPU
+11) topology_book_cpumask: 仅入参CPU
+12) topology_drawer_cpumask: 仅入参CPU
+
+此外,CPU拓扑信息由/sys/devices/system/cpu提供,包含下述文件。输出对应的内部数据源放在
+方括号("[]")中。
+
+ =========== ==================================================================
+ kernel_max: 内核配置允许的最大CPU下标值。[NR_CPUS-1]
+
+ offline: 由于热插拔移除或者超过内核允许的CPU上限(上文描述的kernel_max)
+ 导致未上线的CPU。[~cpu_online_mask + cpus >= NR_CPUS]
+
+ online: 在线的CPU,可供调度使用。[cpu_online_mask]
+
+ possible: 已被分配资源的CPU,如果它们CPU实际存在,可以上线。
+ [cpu_possible_mask]
+
+ present: 被系统识别实际存在的CPU。[cpu_present_mask]
+ =========== ==================================================================
+
+上述输出的格式和cpulist_parse()兼容[参见 <linux/cpumask.h>]。下面给些例子。
+
+在本例中,系统中有64个CPU,但是CPU 32-63超过了kernel_max值,因为NR_CPUS配置项是32,
+取值范围被限制为0..31。此外注意CPU2和4-31未上线,但是可以上线,因为它们同时存在于
+present和possible::
+
+ kernel_max: 31
+ offline: 2,4-31,32-63
+ online: 0-1,3
+ possible: 0-31
+ present: 0-31
+
+在本例中,NR_CPUS配置项是128,但内核启动时设置possible_cpus=144。系统中有4个CPU,
+CPU2被手动设置下线(也是唯一一个可以上线的CPU)::
+
+ kernel_max: 127
+ offline: 2,4-127,128-143
+ online: 0-1,3
+ possible: 0-127
+ present: 0-3
+
+阅读Documentation/core-api/cpu_hotplug.rst可了解开机参数possible_cpus=NUM,同时还
+可以了解各种cpumask的信息。
diff --git a/Documentation/translations/zh_CN/admin-guide/index.rst b/Documentation/translations/zh_CN/admin-guide/index.rst
new file mode 100644
index 000000000000..ac2960da33e6
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/index.rst
@@ -0,0 +1,133 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: :doc:`../../../admin-guide/index`
+:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+
+
+Linux 内核用户和管理员指南
+==========================
+
+下面是一组随时间添加到内核中的面向用户的文档的集合。到目前为止,还没有一个
+整体的顺序或组织 - 这些材料不是一个单一的,连贯的文件!幸运的话,情况会随着
+时间的推移而迅速改善。
+
+这个初始部分包含总体信息,包括描述内核的README, 关于内核参数的文档等。
+
+.. toctree::
+ :maxdepth: 1
+
+ README
+
+Todolist:
+
+* kernel-parameters
+* devices
+* sysctl/index
+
+本节介绍CPU漏洞及其缓解措施。
+
+Todolist:
+
+* hw-vuln/index
+
+下面的一组文档,针对的是试图跟踪问题和bug的用户。
+
+.. toctree::
+ :maxdepth: 1
+
+ reporting-issues
+ reporting-regressions
+ security-bugs
+ bug-hunting
+ bug-bisect
+ tainted-kernels
+ init
+
+Todolist:
+
+* ramoops
+* dynamic-debug-howto
+* kdump/index
+* perf/index
+
+这是应用程序开发人员感兴趣的章节的开始。可以在这里找到涵盖内核ABI各个
+方面的文档。
+
+Todolist:
+
+* sysfs-rules
+
+本手册的其余部分包括各种指南,介绍如何根据您的喜好配置内核的特定行为。
+
+
+.. toctree::
+ :maxdepth: 1
+
+ bootconfig
+ clearing-warn-once
+ cpu-load
+ cputopology
+ lockup-watchdogs
+ unicode
+ sysrq
+ mm/index
+
+Todolist:
+
+* acpi/index
+* aoe/index
+* auxdisplay/index
+* bcache
+* binderfs
+* binfmt-misc
+* blockdev/index
+* braille-console
+* btmrvl
+* cgroup-v1/index
+* cgroup-v2
+* cifs/index
+* dell_rbu
+* device-mapper/index
+* edid
+* efi-stub
+* ext4
+* nfs/index
+* gpio/index
+* highuid
+* hw_random
+* initrd
+* iostats
+* java
+* jfs
+* kernel-per-CPU-kthreads
+* laptops/index
+* lcd-panel-cgram
+* ldm
+* LSM/index
+* md
+* media/index
+* module-signing
+* mono
+* namespaces/index
+* numastat
+* parport
+* perf-security
+* pm/index
+* pnp
+* rapidio
+* ras
+* rtc
+* serial-console
+* svga
+* thunderbolt
+* ufs
+* vga-softcursor
+* video-output
+* xfs
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
diff --git a/Documentation/translations/zh_CN/admin-guide/init.rst b/Documentation/translations/zh_CN/admin-guide/init.rst
new file mode 100644
index 000000000000..fbaf6d97f86c
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/init.rst
@@ -0,0 +1,54 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: :doc:`../../../admin-guide/init`
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+解释“No working init found.”启动挂起消息
+=========================================
+
+:作者:
+
+ Andreas Mohr <andi at lisas period de>
+
+ Cristian Souza <cristianmsbr at gmail period com>
+
+本文档提供了加载初始化二进制(init binary)失败的一些高层级原因(大致按执行
+顺序列出)。
+
+1) **无法挂载根文件系统Unable to mount root FS** :请设置“debug”内核参数(在
+ 引导加载程序bootloader配置文件或CONFIG_CMDLINE)以获取更详细的内核消息。
+
+2) **初始化二进制不存在于根文件系统上init binary doesn't exist on rootfs** :
+ 确保您的根文件系统类型正确(并且 ``root=`` 内核参数指向正确的分区);拥有
+ 所需的驱动程序,例如SCSI或USB等存储硬件;文件系统(ext3、jffs2等)是内建的
+ (或者作为模块由initrd预加载)。
+
+3) **控制台设备损坏Broken console device** : ``console= setup`` 中可能存在
+ 冲突 --> 初始控制台不可用(initial console unavailable)。例如,由于串行
+ IRQ问题(如缺少基于中断的配置)导致的某些串行控制台不可靠。尝试使用不同的
+ ``console= device`` 或像 ``netconsole=`` 。
+
+4) **二进制存在但依赖项不可用Binary exists but dependencies not available** :
+ 例如初始化二进制的必需库依赖项,像 ``/lib/ld-linux.so.2`` 丢失或损坏。使用
+ ``readelf -d <INIT>|grep NEEDED`` 找出需要哪些库。
+
+5) **无法加载二进制Binary cannot be loaded** :请确保二进制的体系结构与您的
+ 硬件匹配。例如i386不匹配x86_64,或者尝试在ARM硬件上加载x86。如果您尝试在
+ 此处加载非二进制文件(shell脚本?),您应该确保脚本在其工作头(shebang
+ header)行 ``#!/...`` 中指定能正常工作的解释器(包括其库依赖项)。在处理
+ 脚本之前,最好先测试一个简单的非脚本二进制文件,比如 ``/bin/sh`` ,并确认
+ 它能成功执行。要了解更多信息,请将代码添加到 ``init/main.c`` 以显示
+ kernel_execve()的返回值。
+
+当您发现新的失败原因时,请扩展本解释(毕竟加载初始化二进制是一个 **关键** 且
+艰难的过渡步骤,需要尽可能无痛地进行),然后向LKML提交一个补丁。
+
+待办事项:
+
+- 通过一个可以存储 ``kernel_execve()`` 结果值的结构体数组实现各种
+ ``run_init_process()`` 调用,并在失败时通过迭代 **所有** 结果来记录一切
+ (非常重要的可用性修复)。
+- 试着使实现本身在一般情况下更有帮助,例如在受影响的地方提供额外的错误消息。
diff --git a/Documentation/translations/zh_CN/admin-guide/lockup-watchdogs.rst b/Documentation/translations/zh_CN/admin-guide/lockup-watchdogs.rst
new file mode 100644
index 000000000000..55ed3f4af442
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/lockup-watchdogs.rst
@@ -0,0 +1,66 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/admin-guide/lockup-watchdogs.rst
+:Translator: Hailong Liu <liu.hailong6@zte.com.cn>
+
+.. _cn_lockup-watchdogs:
+
+
+=================================================
+Softlockup与hardlockup检测机制(又名:nmi_watchdog)
+=================================================
+
+Linux中内核实现了一种用以检测系统发生softlockup和hardlockup的看门狗机制。
+
+Softlockup是一种会引发系统在内核态中一直循环超过20秒(详见下面“实现”小节)导致
+其他任务没有机会得到运行的BUG。一旦检测到'softlockup'发生,默认情况下系统会打
+印当前堆栈跟踪信息并进入锁定状态。也可配置使其在检测到'softlockup'后进入panic
+状态;通过sysctl命令设置“kernel.softlockup_panic”、使用内核启动参数
+“softlockup_panic”(详见Documentation/admin-guide/kernel-parameters.rst)以及使
+能内核编译选项“BOOTPARAM_SOFTLOCKUP_PANIC”都可实现这种配置。
+
+而'hardlockup'是一种会引发系统在内核态一直循环超过10秒钟(详见"实现"小节)导致其
+他中断没有机会运行的缺陷。与'softlockup'情况类似,除了使用sysctl命令设置
+'hardlockup_panic'、使能内核选项“BOOTPARAM_HARDLOCKUP_PANIC”以及使用内核参数
+"nmi_watchdog"(详见:”Documentation/admin-guide/kernel-parameters.rst“)外,一旦检
+测到'hardlockup'默认情况下系统打印当前堆栈跟踪信息,然后进入锁定状态。
+
+这个panic选项也可以与panic_timeout结合使用(这个panic_timeout是通过稍具迷惑性的
+sysctl命令"kernel.panic"来设置),使系统在panic指定时间后自动重启。
+
+实现
+====
+
+Softlockup和hardlockup分别建立在hrtimer(高精度定时器)和perf两个子系统上而实现。
+这也就意味着理论上任何架构只要实现了这两个子系统就支持这两种检测机制。
+
+Hrtimer用于周期性产生中断并唤醒watchdog线程;NMI perf事件则以”watchdog_thresh“
+(编译时默认初始化为10秒,也可通过”watchdog_thresh“这个sysctl接口来进行配置修改)
+为间隔周期产生以检测 hardlockups。如果一个CPU在这个时间段内没有检测到hrtimer中
+断发生,'hardlockup 检测器'(即NMI perf事件处理函数)将会视系统配置而选择产生内核
+警告或者直接panic。
+
+而watchdog线程本质上是一个高优先级内核线程,每调度一次就对时间戳进行一次更新。
+如果时间戳在2*watchdog_thresh(这个是softlockup的触发门限)这段时间都未更新,那么
+"softlocup 检测器"(内部hrtimer定时器回调函数)会将相关的调试信息打印到系统日志中,
+然后如果系统配置了进入panic流程则进入panic,否则内核继续执行。
+
+Hrtimer定时器的周期是2*watchdog_thresh/5,也就是说在hardlockup被触发前hrtimer有
+2~3次机会产生时钟中断。
+
+如上所述,内核相当于为系统管理员提供了一个可调节hrtimer定时器和perf事件周期长度
+的调节旋钮。如何通过这个旋钮为特定使用场景配置一个合理的周期值要对lockups检测的
+响应速度和lockups检测开销这二者之间进行权衡。
+
+默认情况下所有在线cpu上都会运行一个watchdog线程。不过在内核配置了”NO_HZ_FULL“的
+情况下watchdog线程默认只会运行在管家(housekeeping)cpu上,而”nohz_full“启动参数指
+定的cpu上则不会有watchdog线程运行。试想,如果我们允许watchdog线程在”nohz_full“指
+定的cpu上运行,这些cpu上必须得运行时钟定时器来激发watchdog线程调度;这样一来就会
+使”nohz_full“保护用户程序免受内核干扰的功能失效。当然,副作用就是”nohz_full“指定
+的cpu即使在内核产生了lockup问题我们也无法检测到。不过,至少我们可以允许watchdog
+线程在管家(non-tickless)核上继续运行以便我们能继续正常的监测这些cpus上的lockups
+事件。
+
+不论哪种情况都可以通过sysctl命令kernel.watchdog_cpumask来对没有运行watchdog线程
+的cpu集合进行调节。对于nohz_full而言,如果nohz_full cpu上有异常挂住的情况,通过
+这种方式打开这些cpu上的watchdog进行调试可能会有所作用。
diff --git a/Documentation/translations/zh_CN/admin-guide/mm/damon/index.rst b/Documentation/translations/zh_CN/admin-guide/mm/damon/index.rst
new file mode 100644
index 000000000000..6f8676a50b38
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/mm/damon/index.rst
@@ -0,0 +1,29 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../../disclaimer-zh_CN.rst
+
+:Original: Documentation/admin-guide/mm/damon/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+============
+监测数据访问
+============
+
+:doc:`DAMON </mm/damon/index>` 允许轻量级的数据访问监测。使用DAMON,
+用户可以分析他们系统的内存访问模式,并优化它们。
+
+.. toctree::
+ :maxdepth: 2
+
+ start
+ usage
+ reclaim
+ lru_sort
+
+
+
+
diff --git a/Documentation/translations/zh_CN/admin-guide/mm/damon/lru_sort.rst b/Documentation/translations/zh_CN/admin-guide/mm/damon/lru_sort.rst
new file mode 100644
index 000000000000..03d33c710604
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/mm/damon/lru_sort.rst
@@ -0,0 +1,263 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../../disclaimer-zh_CN.rst
+
+:Original: Documentation/admin-guide/mm/damon/lru_sort.rst
+
+:翻译:
+
+ 臧雷刚 Leigang Zang <zangleigang@hisilicon.com>
+
+:校译:
+
+==================
+基于DAMON的LRU排序
+==================
+
+基于DAMON的LRU排序是一个静态的内核模块,旨在用于以主动的、轻量级的数据访问模型
+为基础的页面优先级处理的LRU链表上,以使得LRU上的数据访问模型更为可信。
+
+哪里需要主动的LRU排序
+=====================
+
+在一个大型系统中,以页为粒度的访问检测会有比较显著的开销,LRU通常不会主动去排序,
+而是对部分特殊事件进行部分的、响应式的排序,例如:特殊的用户请求,系统调用或者
+内存压力。这导致,在有些场景下,LRU不能够完美的作为一个可信的数据访问模型,比如
+在内存压力下对目标内存进行回收。
+
+因为DAMON能够尽可能准确的识别数据访问模型,同时只引起用户指定范围的开销,主动的
+执行DAMON_LRU_SORT让LRU变得更为可信是有益的,而且这只需要较少和可控的开销。
+
+这是如何工作的
+==============
+
+DAMON_LRU_SORT使用DAMON寻找热页(范围内的页面访问频率高于用户指定的阈值)和冷页
+(范围内的页面在超过用户指定的时间无访问),并提高热页和降低冷页在LRU中的优先级。
+为了避免在排序过程占用更多的CPU计算资源,可以设置一个CPU占用时间的约束值。在约
+束下,分别提升或者降低更多的热页和冷页。系统管理员也可以配置三个内存水位以控制
+在何种条件下自动激活或者停止这种机制。
+
+冷热阈值和CPU约束的默认值是比较保守的。这意味着,在默认参数下,模块可以广泛且无
+负作用的使用在常见环境中,同时在只消耗一小部分CPU时间的情况下,给有内存压力的系
+统提供一定水平的冷热识别。
+
+接口:模块参数
+==============
+
+使用此特性,你首先需要确认你的系统中运行的内核在编译时启用了
+``CONFIG_DAMON_LRU_SORT=y``.
+
+为了让系统管理员打开或者关闭并且调节指定的系统,DAMON_LRU_SORT设计了模块参数。
+这意味着,你可以添加 ``damon_lru_sort.<parameter>=<value>`` 到内核的启动命令行
+参数,或者在 ``/sys/modules/damon_lru_sort/parameters/<parameter>`` 写入正确的
+值。
+
+下边是每个参数的描述
+
+enabled
+-------
+
+打开或者关闭DAMON_LRU_SORT.
+
+你可以通过设置这个参数为 ``Y`` 来打开DAMON_LRU_SORT。设置为 ``N`` 关闭
+DAMON_LRU_SORT。注意,在基于水位的激活的情况下,DAMON_LRU_SORT有可能不会真正去
+监测或者做LRU排序。对这种情况,参考下方关于水位的描述。
+
+commit_inputs
+-------------
+
+让DAMON_LRU_SORT再次读取输入参数,除了 ``enabled`` 。
+
+在DAMON_LRU_SORT运行时,新的输入参数默认不会被应用。一旦这个参数被设置为 ``Y``
+,DAMON_LRU_SORT会再次读取除了 ``enabled`` 之外的参数。读取完成后,这个参数会被
+设置为 ``N`` 。如果在读取时发现有无效参数,DAMON_LRU_SORT会被关闭。
+
+hot_thres_access_freq
+---------------------
+
+热点内存区域的访问频率阈值,千分比。
+
+如果一个内存区域的访问频率大于等于这个值,DAMON_LRU_SORT把这个区域看作热区,并
+在LRU上把这个区域标记为已访问,因些在内存压力下这部分内存不会被回收。默认为50%。
+
+cold_min_age
+------------
+
+用于识别冷内存区域的时间阈值,单位是微秒。
+
+如果一个内存区域在这个时间内未被访问过,DAMON_LRU_SORT把这个区域看作冷区,并在
+LRU上把这个区域标记为未访问,因此在内存压力下这些内存会首先被回收。默认值为120
+秒。
+
+quota_ms
+--------
+
+尝试LRU链表排序的时间限制,单位是毫秒。
+
+DAMON_LRU_SORT在一个时间窗口内(quota_reset_interval_ms)内最多尝试这么长时间来
+对LRU进行排序。这个可以用来作为CPU计算资源的约束。如果值为0,则表示无限制。
+
+默认10毫秒。
+
+quota_reset_interval_ms
+-----------------------
+
+配额计时重置周期,毫秒。
+
+配额计时重置周期。即,在quota_reset_interval_ms毫秒内,DAMON_LRU_SORT对LRU进行
+排序不会超过quota_ms或者quota_sz。
+
+默认1秒。
+
+wmarks_interval
+---------------
+
+水位的检查周期,单位是微秒。
+
+当DAMON_LRU_SORT使能但是由于水位而不活跃时检查水位前最小的等待时间。默认值5秒。
+
+wmarks_high
+-----------
+
+空闲内存高水位,千分比。
+
+如果空闲内存水位高于这个值,DAMON_LRU_SORT停止工作,不做任何事,除了周期性的检
+查水位。默认200(20%)。
+
+wmarks_mid
+----------
+
+空闲内存中间水位,千分比。
+
+如果空闲内存水位在这个值与低水位之间,DAMON_LRU_SORT开始工作,开始检测并对LRU链
+表进行排序。默认150(15%)。
+
+wmarks_low
+----------
+
+空闲内存低水位,千分比。
+
+如果空闲内存小于这个值,DAMON_LRU_SORT不再工作,不做任何事,除了周期性的检查水
+线。默认50(5%)。
+
+sample_interval
+---------------
+
+监测的采样周期,微秒。
+
+DAMON对冷内存监测的采样周期。更多细节请参考DAMON文档 (:doc:`usage`) 。默认5
+毫秒。
+
+aggr_interval
+-------------
+
+监测的收集周期,微秒。
+
+DAMON对冷内存进行收集的时间周期。更多细节请参考DAMON文档 (:doc:`usage`) 。默认
+100毫秒。
+
+min_nr_regions
+--------------
+
+最小监测区域数量。
+
+对冷内存区域监测的最小数量。这个值可以作为监测质量的下限。不过,这个值设置的过
+大会增加开销。更多细节请参考DAMON文档 (:doc:`usage`) 。默认值为10。
+
+max_nr_regions
+--------------
+
+最大监测区域数量。
+
+对冷内存区域监测的最大数量。这个值可以作为监测质量的上限。然而,这个值设置的过
+低会导致监测结果变差。更多细节请参考DAMON文档 (:doc:`usage`) 。默认值为1000。
+
+monitor_region_start
+--------------------
+
+目标内存区域的起始物理地址。
+
+DAMON_LRU_SORT要处理的目标内存区域的起始物理地址。默认,使用系统最大内存。
+
+monitor_region_end
+------------------
+
+目标内存区域的结束物理地址。
+
+DAMON_LRU_SORT要处理的目标内存区域的结束物理地址。默认,使用系统最大内存。
+
+kdamond_pid
+-----------
+
+DAMON线程的PID。
+
+如果DAMON_LRU_SORT是使能的,这个表示任务线程的PID。其它情况为-1。
+
+nr_lru_sort_tried_hot_regions
+-----------------------------
+
+被尝试进行LRU排序的热内存区域的数量。
+
+bytes_lru_sort_tried_hot_regions
+--------------------------------
+
+被尝试进行LRU排序的热内存区域的大小(字节)。
+
+nr_lru_sorted_hot_regions
+-------------------------
+
+成功进行LRU排序的热内存区域的数量。
+
+bytes_lru_sorted_hot_regions
+----------------------------
+
+成功进行LRU排序的热内存区域的大小(字节)。
+
+nr_hot_quota_exceeds
+--------------------
+
+热区域时间约束超过限制的次数。
+
+nr_lru_sort_tried_cold_regions
+------------------------------
+
+被尝试进行LRU排序的冷内存区域的数量。
+
+bytes_lru_sort_tried_cold_regions
+---------------------------------
+
+被尝试进行LRU排序的冷内存区域的大小(字节)。
+
+nr_lru_sorted_cold_regions
+--------------------------
+
+成功进行LRU排序的冷内存区域的数量。
+
+bytes_lru_sorted_cold_regions
+-----------------------------
+
+成功进行LRU排序的冷内存区域的大小(字节)。
+
+nr_cold_quota_exceeds
+---------------------
+
+冷区域时间约束超过限制的次数。
+
+Example
+=======
+
+如下是一个运行时的命令示例,使DAMON_LRU_SORT查找访问频率超过50%的区域并对其进行
+LRU的优先级的提升,同时降低那些超过120秒无人访问的内存区域的优先级。优先级的处
+理被限制在最多1%的CPU以避免DAMON_LRU_SORT消费过多CPU时间。在系统空闲内存超过50%
+时DAMON_LRU_SORT停止工作,并在低于40%时重新开始工作。如果DAMON_RECLAIM没有取得
+进展且空闲内存低于20%,再次让DAMON_LRU_SORT停止工作,以此回退到以LRU链表为基础
+以页面为单位的内存回收上。 ::
+
+ # cd /sys/modules/damon_lru_sort/parameters
+ # echo 500 > hot_thres_access_freq
+ # echo 120000000 > cold_min_age
+ # echo 10 > quota_ms
+ # echo 1000 > quota_reset_interval_ms
+ # echo 500 > wmarks_high
+ # echo 400 > wmarks_mid
+ # echo 200 > wmarks_low
+ # echo Y > enabled
diff --git a/Documentation/translations/zh_CN/admin-guide/mm/damon/reclaim.rst b/Documentation/translations/zh_CN/admin-guide/mm/damon/reclaim.rst
new file mode 100644
index 000000000000..d14ba32f7788
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/mm/damon/reclaim.rst
@@ -0,0 +1,228 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../../disclaimer-zh_CN.rst
+
+:Original: Documentation/admin-guide/mm/damon/reclaim.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+===============
+基于DAMON的回收
+===============
+
+基于DAMON的回收(DAMON_RECLAIM)是一个静态的内核模块,旨在用于轻度内存压力下的主动和轻
+量级的回收。它的目的不是取代基于LRU列表的页面回收,而是有选择地用于不同程度的内存压力和要
+求。
+
+哪些地方需要主动回收?
+======================
+
+在一般的内存超量使用(over-committed systems,虚拟化相关术语)的系统上,主动回收冷页
+有助于节省内存和减少延迟高峰,这些延迟是由直接回收进程或kswapd的CPU消耗引起的,同时只产
+生最小的性能下降 [1]_ [2]_ 。
+
+基于空闲页报告 [3]_ 的内存过度承诺的虚拟化系统就是很好的例子。在这样的系统中,客户机
+向主机报告他们的空闲内存,而主机则将报告的内存重新分配给其他客户。因此,系统的内存得到了充
+分的利用。然而,客户可能不那么节省内存,主要是因为一些内核子系统和用户空间应用程序被设计为
+使用尽可能多的内存。然后,客户机可能只向主机报告少量的内存是空闲的,导致系统的内存利用率下降。
+在客户中运行主动回收可以缓解这个问题。
+
+它是如何工作的?
+================
+
+DAMON_RECLAIM找到在特定时间内没有被访问的内存区域并分页。为了避免它在分页操作中消耗过多
+的CPU,可以配置一个速度限制。在这个速度限制下,它首先分页出那些没有被访问过的内存区域。系
+统管理员还可以配置在什么情况下这个方案应该自动激活和停用三个内存压力水位。
+
+接口: 模块参数
+==============
+
+要使用这个功能,你首先要确保你的系统运行在一个以 ``CONFIG_DAMON_RECLAIM=y`` 构建的内
+核上。
+
+为了让系统管理员启用或禁用它,并为给定的系统进行调整,DAMON_RECLAIM利用了模块参数。也就
+是说,你可以把 ``damon_reclaim.<parameter>=<value>`` 放在内核启动命令行上,或者把
+适当的值写入 ``/sys/module/damon_reclaim/parameters/<parameter>`` 文件。
+
+下面是每个参数的描述。
+
+enabled
+-------
+
+启用或禁用DAMON_RECLAIM。
+
+你可以通过把这个参数的值设置为 ``Y`` 来启用DAMON_RCLAIM,把它设置为 ``N`` 可以禁用
+DAMON_RECLAIM。注意,由于基于水位的激活条件,DAMON_RECLAIM不能进行真正的监测和回收。
+这一点请参考下面关于水位参数的描述。
+
+min_age
+-------
+
+识别冷内存区域的时间阈值,单位是微秒。
+
+如果一个内存区域在这个时间或更长的时间内没有被访问,DAMON_RECLAIM会将该区域识别为冷的,
+并回收它。
+
+默认为120秒。
+
+quota_ms
+--------
+
+回收的时间限制,以毫秒为单位。
+
+DAMON_RECLAIM 试图在一个时间窗口(quota_reset_interval_ms)内只使用到这个时间,以
+尝试回收冷页。这可以用来限制DAMON_RECLAIM的CPU消耗。如果该值为零,则该限制被禁用。
+
+默认为10ms。
+
+quota_sz
+--------
+
+回收的内存大小限制,单位为字节。
+
+DAMON_RECLAIM 收取在一个时间窗口(quota_reset_interval_ms)内试图回收的内存量,并
+使其不超过这个限制。这可以用来限制CPU和IO的消耗。如果该值为零,则限制被禁用。
+
+默认情况下是128 MiB。
+
+quota_reset_interval_ms
+-----------------------
+
+时间/大小配额收取重置间隔,单位为毫秒。
+
+时间(quota_ms)和大小(quota_sz)的配额的目标重置间隔。也就是说,DAMON_RECLAIM在
+尝试回收‘不’超过quota_ms毫秒或quota_sz字节的内存。
+
+默认为1秒。
+
+wmarks_interval
+---------------
+
+当DAMON_RECLAIM被启用但由于其水位规则而不活跃时,在检查水位之前的最小等待时间。
+
+wmarks_high
+-----------
+
+高水位的可用内存率(每千字节)。
+
+如果系统的可用内存(以每千字节为单位)高于这个数值,DAMON_RECLAIM就会变得不活跃,所以
+它什么也不做,只是定期检查水位。
+
+wmarks_mid
+----------
+
+中间水位的可用内存率(每千字节)。
+
+如果系统的空闲内存(以每千字节为单位)在这个和低水位线之间,DAMON_RECLAIM就会被激活,
+因此开始监测和回收。
+
+wmarks_low
+----------
+
+低水位的可用内存率(每千字节)。
+
+如果系统的空闲内存(以每千字节为单位)低于这个数值,DAMON_RECLAIM就会变得不活跃,所以
+它除了定期检查水位外什么都不做。在这种情况下,系统会退回到基于LRU列表的页面粒度回收逻辑。
+
+sample_interval
+---------------
+
+监测的采样间隔,单位是微秒。
+
+DAMON用于监测冷内存的采样间隔。更多细节请参考DAMON文档 (:doc:`usage`) 。
+
+aggr_interval
+-------------
+
+监测的聚集间隔,单位是微秒。
+
+DAMON对冷内存监测的聚集间隔。更多细节请参考DAMON文档 (:doc:`usage`)。
+
+min_nr_regions
+--------------
+
+监测区域的最小数量。
+
+DAMON用于冷内存监测的最小监测区域数。这可以用来设置监测质量的下限。但是,设
+置的太高可能会导致监测开销的增加。更多细节请参考DAMON文档 (:doc:`usage`) 。
+
+max_nr_regions
+--------------
+
+监测区域的最大数量。
+
+DAMON用于冷内存监测的最大监测区域数。这可以用来设置监测开销的上限值。但是,
+设置得太低可能会导致监测质量不好。更多细节请参考DAMON文档 (:doc:`usage`) 。
+
+monitor_region_start
+--------------------
+
+目标内存区域的物理地址起点。
+
+DAMON_RECLAIM将对其进行工作的内存区域的起始物理地址。也就是说,DAMON_RECLAIM
+将在这个区域中找到冷的内存区域并进行回收。默认情况下,该区域使用最大系统内存区。
+
+monitor_region_end
+------------------
+
+目标内存区域的结束物理地址。
+
+DAMON_RECLAIM将对其进行工作的内存区域的末端物理地址。也就是说,DAMON_RECLAIM将
+在这个区域内找到冷的内存区域并进行回收。默认情况下,该区域使用最大系统内存区。
+
+kdamond_pid
+-----------
+
+DAMON线程的PID。
+
+如果DAMON_RECLAIM被启用,这将成为工作线程的PID。否则,为-1。
+
+nr_reclaim_tried_regions
+------------------------
+
+试图通过DAMON_RECLAIM回收的内存区域的数量。
+
+bytes_reclaim_tried_regions
+---------------------------
+
+试图通过DAMON_RECLAIM回收的内存区域的总字节数。
+
+nr_reclaimed_regions
+--------------------
+
+通过DAMON_RECLAIM成功回收的内存区域的数量。
+
+bytes_reclaimed_regions
+-----------------------
+
+通过DAMON_RECLAIM成功回收的内存区域的总字节数。
+
+nr_quota_exceeds
+----------------
+
+超过时间/空间配额限制的次数。
+
+例子
+====
+
+下面的运行示例命令使DAMON_RECLAIM找到30秒或更长时间没有访问的内存区域并“回收”?
+为了避免DAMON_RECLAIM在分页操作中消耗过多的CPU时间,回收被限制在每秒1GiB以内。
+它还要求DAMON_RECLAIM在系统的可用内存率超过50%时不做任何事情,但如果它低于40%时
+就开始真正的工作。如果DAMON_RECLAIM没有取得进展,因此空闲内存率低于20%,它会要求
+DAMON_RECLAIM再次什么都不做,这样我们就可以退回到基于LRU列表的页面粒度回收了::
+
+ # cd /sys/module/damon_reclaim/parameters
+ # echo 30000000 > min_age
+ # echo $((1 * 1024 * 1024 * 1024)) > quota_sz
+ # echo 1000 > quota_reset_interval_ms
+ # echo 500 > wmarks_high
+ # echo 400 > wmarks_mid
+ # echo 200 > wmarks_low
+ # echo Y > enabled
+
+.. [1] https://research.google/pubs/pub48551/
+.. [2] https://lwn.net/Articles/787611/
+.. [3] https://www.kernel.org/doc/html/latest/mm/free_page_reporting.html
diff --git a/Documentation/translations/zh_CN/admin-guide/mm/damon/start.rst b/Documentation/translations/zh_CN/admin-guide/mm/damon/start.rst
new file mode 100644
index 000000000000..bf21ff84f396
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/mm/damon/start.rst
@@ -0,0 +1,124 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../../disclaimer-zh_CN.rst
+
+:Original: Documentation/admin-guide/mm/damon/start.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+========
+入门指南
+========
+
+本文通过演示DAMON的默认用户空间工具,简要地介绍了如何使用DAMON。请注意,为了简洁
+起见,本文档只描述了它的部分功能。更多细节请参考该工具的使用文档。
+`doc <https://github.com/awslabs/damo/blob/next/USAGE.md>`_ .
+
+
+前提条件
+========
+
+内核
+----
+
+首先,你要确保你当前系统中跑的内核构建时选定了这个功能选项 ``CONFIG_DAMON_*=y``.
+
+
+用户空间工具
+------------
+
+在演示中,我们将使用DAMON的默认用户空间工具,称为DAMON Operator(DAMO)。它可以在
+https://github.com/awslabs/damo找到。下面的例子假设DAMO在你的$PATH上。当然,但
+这并不是强制性的。
+
+因为DAMO使用了DAMON的sysfs接口(详情请参考:doc:`usage`),你应该确保
+:doc:`sysfs </filesystems/sysfs>` 被挂载。
+
+记录数据访问模式
+================
+
+下面的命令记录了一个程序的内存访问模式,并将监测结果保存到文件中。 ::
+
+ $ git clone https://github.com/sjp38/masim
+ $ cd masim; make; ./masim ./configs/zigzag.cfg &
+ $ sudo damo record -o damon.data $(pidof masim)
+
+命令的前两行下载了一个人工内存访问生成器程序并在后台运行。生成器将重复地逐一访问两个
+100 MiB大小的内存区域。你可以用你的真实工作负载来代替它。最后一行要求 ``damo`` 将
+访问模式记录在 ``damon.data`` 文件中。
+
+
+将记录的模式可视化
+==================
+
+你可以在heatmap中直观地看到这种模式,显示哪个内存区域(X轴)何时被访问(Y轴)以及访
+问的频率(数字)。::
+
+ $ sudo damo report heats --heatmap stdout
+ 22222222222222222222222222222222222222211111111111111111111111111111111111111100
+ 44444444444444444444444444444444444444434444444444444444444444444444444444443200
+ 44444444444444444444444444444444444444433444444444444444444444444444444444444200
+ 33333333333333333333333333333333333333344555555555555555555555555555555555555200
+ 33333333333333333333333333333333333344444444444444444444444444444444444444444200
+ 22222222222222222222222222222222222223355555555555555555555555555555555555555200
+ 00000000000000000000000000000000000000288888888888888888888888888888888888888400
+ 00000000000000000000000000000000000000288888888888888888888888888888888888888400
+ 33333333333333333333333333333333333333355555555555555555555555555555555555555200
+ 88888888888888888888888888888888888888600000000000000000000000000000000000000000
+ 88888888888888888888888888888888888888600000000000000000000000000000000000000000
+ 33333333333333333333333333333333333333444444444444444444444444444444444444443200
+ 00000000000000000000000000000000000000288888888888888888888888888888888888888400
+ [...]
+ # access_frequency: 0 1 2 3 4 5 6 7 8 9
+ # x-axis: space (139728247021568-139728453431248: 196.848 MiB)
+ # y-axis: time (15256597248362-15326899978162: 1 m 10.303 s)
+ # resolution: 80x40 (2.461 MiB and 1.758 s for each character)
+
+你也可以直观地看到工作集的大小分布,按大小排序。::
+
+ $ sudo damo report wss --range 0 101 10
+ # <percentile> <wss>
+ # target_id 18446632103789443072
+ # avr: 107.708 MiB
+ 0 0 B | |
+ 10 95.328 MiB |**************************** |
+ 20 95.332 MiB |**************************** |
+ 30 95.340 MiB |**************************** |
+ 40 95.387 MiB |**************************** |
+ 50 95.387 MiB |**************************** |
+ 60 95.398 MiB |**************************** |
+ 70 95.398 MiB |**************************** |
+ 80 95.504 MiB |**************************** |
+ 90 190.703 MiB |********************************************************* |
+ 100 196.875 MiB |***********************************************************|
+
+在上述命令中使用 ``--sortby`` 选项,可以显示工作集的大小是如何按时间顺序变化的。::
+
+ $ sudo damo report wss --range 0 101 10 --sortby time
+ # <percentile> <wss>
+ # target_id 18446632103789443072
+ # avr: 107.708 MiB
+ 0 3.051 MiB | |
+ 10 190.703 MiB |***********************************************************|
+ 20 95.336 MiB |***************************** |
+ 30 95.328 MiB |***************************** |
+ 40 95.387 MiB |***************************** |
+ 50 95.332 MiB |***************************** |
+ 60 95.320 MiB |***************************** |
+ 70 95.398 MiB |***************************** |
+ 80 95.398 MiB |***************************** |
+ 90 95.340 MiB |***************************** |
+ 100 95.398 MiB |***************************** |
+
+
+数据访问模式感知的内存管理
+==========================
+
+以下三个命令使每一个大小>=4K的内存区域在你的工作负载中没有被访问>=60秒,就会被换掉。 ::
+
+ $ echo "#min-size max-size min-acc max-acc min-age max-age action" > test_scheme
+ $ echo "4K max 0 0 60s max pageout" >> test_scheme
+ $ damo schemes -c test_scheme <pid of your workload>
diff --git a/Documentation/translations/zh_CN/admin-guide/mm/damon/usage.rst b/Documentation/translations/zh_CN/admin-guide/mm/damon/usage.rst
new file mode 100644
index 000000000000..17b9949d9b43
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/mm/damon/usage.rst
@@ -0,0 +1,591 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../../disclaimer-zh_CN.rst
+
+:Original: Documentation/admin-guide/mm/damon/usage.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+========
+详细用法
+========
+
+DAMON 为不同的用户提供了下面这些接口。
+
+- *DAMON用户空间工具。*
+ `这 <https://github.com/awslabs/damo>`_ 为有这特权的人, 如系统管理员,希望有一个刚好
+ 可以工作的人性化界面。
+ 使用它,用户可以以人性化的方式使用DAMON的主要功能。不过,它可能不会为特殊情况进行高度调整。
+ 它同时支持虚拟和物理地址空间的监测。更多细节,请参考它的 `使用文档
+ <https://github.com/awslabs/damo/blob/next/USAGE.md>`_。
+- *sysfs接口。*
+ :ref:`这 <sysfs_interface>` 是为那些希望更高级的使用DAMON的特权用户空间程序员准备的。
+ 使用它,用户可以通过读取和写入特殊的sysfs文件来使用DAMON的主要功能。因此,你可以编写和使
+ 用你个性化的DAMON sysfs包装程序,代替你读/写sysfs文件。 `DAMON用户空间工具
+ <https://github.com/awslabs/damo>`_ 就是这种程序的一个例子 它同时支持虚拟和物理地址
+ 空间的监测。注意,这个界面只提供简单的监测结果 :ref:`统计 <damos_stats>`。对于详细的监测
+ 结果,DAMON提供了一个:ref:`跟踪点 <tracepoint>`。
+- *debugfs interface.*
+ :ref:`这 <debugfs_interface>` 几乎与:ref:`sysfs interface <sysfs_interface>` 接
+ 口相同。这将在下一个LTS内核发布后被移除,所以用户应该转移到
+ :ref:`sysfs interface <sysfs_interface>`。
+- *内核空间编程接口。*
+ :doc:`这 </mm/damon/api>` 这是为内核空间程序员准备的。使用它,用户可以通过为你编写内
+ 核空间的DAMON应用程序,最灵活有效地利用DAMON的每一个功能。你甚至可以为各种地址空间扩展DAMON。
+ 详细情况请参考接口 :doc:`文件 </mm/damon/api>`。
+
+sysfs接口
+=========
+DAMON的sysfs接口是在定义 ``CONFIG_DAMON_SYSFS`` 时建立的。它在其sysfs目录下创建多
+个目录和文件, ``<sysfs>/kernel/mm/damon/`` 。你可以通过对该目录下的文件进行写入和
+读取来控制DAMON。
+
+对于一个简短的例子,用户可以监测一个给定工作负载的虚拟地址空间,如下所示::
+
+ # cd /sys/kernel/mm/damon/admin/
+ # echo 1 > kdamonds/nr_kdamonds && echo 1 > kdamonds/0/contexts/nr_contexts
+ # echo vaddr > kdamonds/0/contexts/0/operations
+ # echo 1 > kdamonds/0/contexts/0/targets/nr_targets
+ # echo $(pidof <workload>) > kdamonds/0/contexts/0/targets/0/pid_target
+ # echo on > kdamonds/0/state
+
+文件层次结构
+------------
+
+DAMON sysfs接口的文件层次结构如下图所示。在下图中,父子关系用缩进表示,每个目录有
+``/`` 后缀,每个目录中的文件用逗号(",")分开。 ::
+
+ /sys/kernel/mm/damon/admin
+ │ kdamonds/nr_kdamonds
+ │ │ 0/state,pid
+ │ │ │ contexts/nr_contexts
+ │ │ │ │ 0/operations
+ │ │ │ │ │ monitoring_attrs/
+ │ │ │ │ │ │ intervals/sample_us,aggr_us,update_us
+ │ │ │ │ │ │ nr_regions/min,max
+ │ │ │ │ │ targets/nr_targets
+ │ │ │ │ │ │ 0/pid_target
+ │ │ │ │ │ │ │ regions/nr_regions
+ │ │ │ │ │ │ │ │ 0/start,end
+ │ │ │ │ │ │ │ │ ...
+ │ │ │ │ │ │ ...
+ │ │ │ │ │ schemes/nr_schemes
+ │ │ │ │ │ │ 0/action
+ │ │ │ │ │ │ │ access_pattern/
+ │ │ │ │ │ │ │ │ sz/min,max
+ │ │ │ │ │ │ │ │ nr_accesses/min,max
+ │ │ │ │ │ │ │ │ age/min,max
+ │ │ │ │ │ │ │ quotas/ms,bytes,reset_interval_ms
+ │ │ │ │ │ │ │ │ weights/sz_permil,nr_accesses_permil,age_permil
+ │ │ │ │ │ │ │ watermarks/metric,interval_us,high,mid,low
+ │ │ │ │ │ │ │ stats/nr_tried,sz_tried,nr_applied,sz_applied,qt_exceeds
+ │ │ │ │ │ │ │ tried_regions/
+ │ │ │ │ │ │ │ │ 0/start,end,nr_accesses,age
+ │ │ │ │ │ │ │ │ ...
+ │ │ │ │ │ │ ...
+ │ │ │ │ ...
+ │ │ ...
+
+根
+--
+
+DAMON sysfs接口的根是 ``<sysfs>/kernel/mm/damon/`` ,它有一个名为 ``admin`` 的
+目录。该目录包含特权用户空间程序控制DAMON的文件。拥有根权限的用户空间工具或deamons可以
+使用这个目录。
+
+kdamonds/
+---------
+
+与监测相关的信息包括请求规格和结果被称为DAMON上下文。DAMON用一个叫做kdamond的内核线程
+执行每个上下文,多个kdamonds可以并行运行。
+
+在 ``admin`` 目录下,有一个目录,即``kdamonds``,它有控制kdamonds的文件存在。在开始
+时,这个目录只有一个文件,``nr_kdamonds``。向该文件写入一个数字(``N``),就会创建名为
+``0`` 到 ``N-1`` 的子目录数量。每个目录代表每个kdamond。
+
+kdamonds/<N>/
+-------------
+
+在每个kdamond目录中,存在两个文件(``state`` 和 ``pid`` )和一个目录( ``contexts`` )。
+
+读取 ``state`` 时,如果kdamond当前正在运行,则返回 ``on`` ,如果没有运行则返回 ``off`` 。
+写入 ``on`` 或 ``off`` 使kdamond处于状态。向 ``state`` 文件写 ``update_schemes_stats`` ,
+更新kdamond的每个基于DAMON的操作方案的统计文件的内容。关于统计信息的细节,请参考
+:ref:`stats section <sysfs_schemes_stats>`. 将 ``update_schemes_tried_regions`` 写到
+``state`` 文件,为kdamond的每个基于DAMON的操作方案,更新基于DAMON的操作方案动作的尝试区域目录。
+将`clear_schemes_tried_regions`写入`state`文件,清除kdamond的每个基于DAMON的操作方案的动作
+尝试区域目录。 关于基于DAMON的操作方案动作尝试区域目录的细节,请参考:ref:tried_regions 部分
+<sysfs_schemes_tried_regions>`。
+
+如果状态为 ``on``,读取 ``pid`` 显示kdamond线程的pid。
+
+``contexts`` 目录包含控制这个kdamond要执行的监测上下文的文件。
+
+kdamonds/<N>/contexts/
+----------------------
+
+在开始时,这个目录只有一个文件,即 ``nr_contexts`` 。向该文件写入一个数字( ``N`` ),就会创
+建名为``0`` 到 ``N-1`` 的子目录数量。每个目录代表每个监测背景。目前,每个kdamond只支持
+一个上下文,所以只有 ``0`` 或 ``1`` 可以被写入文件。
+
+contexts/<N>/
+-------------
+
+在每个上下文目录中,存在一个文件(``operations``)和三个目录(``monitoring_attrs``,
+``targets``, 和 ``schemes``)。
+
+DAMON支持多种类型的监测操作,包括对虚拟地址空间和物理地址空间的监测。你可以通过向文件
+中写入以下关键词之一,并从文件中读取,来设置和获取DAMON将为上下文使用何种类型的监测操作。
+
+ - vaddr: 监测特定进程的虚拟地址空间
+ - paddr: 监视系统的物理地址空间
+
+contexts/<N>/monitoring_attrs/
+------------------------------
+
+用于指定监测属性的文件,包括所需的监测质量和效率,都在 ``monitoring_attrs`` 目录中。
+具体来说,这个目录下有两个目录,即 ``intervals`` 和 ``nr_regions`` 。
+
+在 ``intervals`` 目录下,存在DAMON的采样间隔(``sample_us``)、聚集间隔(``aggr_us``)
+和更新间隔(``update_us``)三个文件。你可以通过写入和读出这些文件来设置和获取微秒级的值。
+
+在 ``nr_regions`` 目录下,有两个文件分别用于DAMON监测区域的下限和上限(``min`` 和 ``max`` ),
+这两个文件控制着监测的开销。你可以通过向这些文件的写入和读出来设置和获取这些值。
+
+关于间隔和监测区域范围的更多细节,请参考设计文件 (:doc:`/mm/damon/design`)。
+
+contexts/<N>/targets/
+---------------------
+
+在开始时,这个目录只有一个文件 ``nr_targets`` 。向该文件写入一个数字(``N``),就可以创建
+名为 ``0`` 到 ``N-1`` 的子目录的数量。每个目录代表每个监测目标。
+
+targets/<N>/
+------------
+
+在每个目标目录中,存在一个文件(``pid_target``)和一个目录(``regions``)。
+
+如果你把 ``vaddr`` 写到 ``contexts/<N>/operations`` 中,每个目标应该是一个进程。你
+可以通过将进程的pid写到 ``pid_target`` 文件中来指定DAMON的进程。
+
+targets/<N>/regions
+-------------------
+
+当使用 ``vaddr`` 监测操作集时( ``vaddr`` 被写入 ``contexts/<N>/operations`` 文
+件),DAMON自动设置和更新监测目标区域,这样就可以覆盖目标进程的整个内存映射。然而,用户可
+能希望将初始监测区域设置为特定的地址范围。
+
+相反,当使用 ``paddr`` 监测操作集时,DAMON不会自动设置和更新监测目标区域( ``paddr``
+被写入 ``contexts/<N>/operations`` 中)。因此,在这种情况下,用户应该自己设置监测目标
+区域。
+
+在这种情况下,用户可以按照自己的意愿明确设置初始监测目标区域,将适当的值写入该目录下的文件。
+
+开始时,这个目录只有一个文件, ``nr_regions`` 。向该文件写入一个数字(``N``),就可以创
+建名为 ``0`` 到 ``N-1`` 的子目录。每个目录代表每个初始监测目标区域。
+
+regions/<N>/
+------------
+
+在每个区域目录中,你会发现两个文件( ``start`` 和 ``end`` )。你可以通过向文件写入
+和从文件中读出,分别设置和获得初始监测目标区域的起始和结束地址。
+
+每个区域不应该与其他区域重叠。 目录“N”的“结束”应等于或小于目录“N+1”的“开始”。
+
+contexts/<N>/schemes/
+---------------------
+
+对于一版的基于DAMON的数据访问感知的内存管理优化,用户通常希望系统对特定访问模式的内存区
+域应用内存管理操作。DAMON从用户那里接收这种形式化的操作方案,并将这些方案应用于目标内存
+区域。用户可以通过读取和写入这个目录下的文件来获得和设置这些方案。
+
+在开始时,这个目录只有一个文件,``nr_schemes``。向该文件写入一个数字(``N``),就可以
+创建名为``0``到``N-1``的子目录的数量。每个目录代表每个基于DAMON的操作方案。
+
+schemes/<N>/
+------------
+
+在每个方案目录中,存在五个目录(``access_pattern``、``quotas``、``watermarks``、
+``stats`` 和 ``tried_regions``)和一个文件(``action``)。
+
+``action`` 文件用于设置和获取你想应用于具有特定访问模式的内存区域的动作。可以写入文件
+和从文件中读取的关键词及其含义如下。
+
+ - ``willneed``: 对有 ``MADV_WILLNEED`` 的区域调用 ``madvise()`` 。
+ - ``cold``: 对具有 ``MADV_COLD`` 的区域调用 ``madvise()`` 。
+ - ``pageout``: 为具有 ``MADV_PAGEOUT`` 的区域调用 ``madvise()`` 。
+ - ``hugepage``: 为带有 ``MADV_HUGEPAGE`` 的区域调用 ``madvise()`` 。
+ - ``nohugepage``: 为带有 ``MADV_NOHUGEPAGE`` 的区域调用 ``madvise()``。
+ - ``lru_prio``: 在其LRU列表上对区域进行优先排序。
+ - ``lru_deprio``: 对区域的LRU列表进行降低优先处理。
+ - ``stat``: 什么都不做,只计算统计数据
+
+schemes/<N>/access_pattern/
+---------------------------
+
+每个基于DAMON的操作方案的目标访问模式由三个范围构成,包括以字节为单位的区域大小、每个
+聚合区间的监测访问次数和区域年龄的聚合区间数。
+
+在 ``access_pattern`` 目录下,存在三个目录( ``sz``, ``nr_accesses``, 和 ``age`` ),
+每个目录有两个文件(``min`` 和 ``max`` )。你可以通过向 ``sz``, ``nr_accesses``, 和
+``age`` 目录下的 ``min`` 和 ``max`` 文件分别写入和读取来设置和获取给定方案的访问模式。
+
+schemes/<N>/quotas/
+-------------------
+
+每个 ``动作`` 的最佳 ``目标访问模式`` 取决于工作负载,所以不容易找到。更糟糕的是,将某些动作
+的方案设置得过于激进会造成严重的开销。为了避免这种开销,用户可以为每个方案限制时间和大小配额。
+具体来说,用户可以要求DAMON尽量只使用特定的时间(``时间配额``)来应用动作,并且在给定的时间间
+隔(``重置间隔``)内,只对具有目标访问模式的内存区域应用动作,而不使用特定数量(``大小配额``)。
+
+当预计超过配额限制时,DAMON会根据 ``目标访问模式`` 的大小、访问频率和年龄,对找到的内存区域
+进行优先排序。为了进行个性化的优先排序,用户可以为这三个属性设置权重。
+
+在 ``quotas`` 目录下,存在三个文件(``ms``, ``bytes``, ``reset_interval_ms``)和一个
+目录(``weights``),其中有三个文件(``sz_permil``, ``nr_accesses_permil``, 和
+``age_permil``)。
+
+你可以设置以毫秒为单位的 ``时间配额`` ,以字节为单位的 ``大小配额`` ,以及以毫秒为单位的 ``重
+置间隔`` ,分别向这三个文件写入数值。你还可以通过向 ``weights`` 目录下的三个文件写入数值来设
+置大小、访问频率和年龄的优先权,单位为千分之一。
+
+schemes/<N>/watermarks/
+-----------------------
+
+为了便于根据系统状态激活和停用每个方案,DAMON提供了一个称为水位的功能。该功能接收五个值,称为
+``度量`` 、``间隔`` 、``高`` 、``中`` 、``低`` 。``度量值`` 是指可以测量的系统度量值,如
+自由内存比率。如果系统的度量值 ``高`` 于memoent的高值或 ``低`` 于低值,则该方案被停用。如果
+该值低于 ``中`` ,则该方案被激活。
+
+在水位目录下,存在五个文件(``metric``, ``interval_us``,``high``, ``mid``, and ``low``)
+用于设置每个值。你可以通过向这些文件的写入来分别设置和获取这五个值。
+
+可以写入 ``metric`` 文件的关键词和含义如下。
+
+ - none: 忽略水位
+ - free_mem_rate: 系统的自由内存率(千分比)。
+
+``interval`` 应以微秒为单位写入。
+
+schemes/<N>/stats/
+------------------
+
+DAMON统计每个方案被尝试应用的区域的总数量和字节数,每个方案被成功应用的区域的两个数字,以及
+超过配额限制的总数量。这些统计数据可用于在线分析或调整方案。
+
+可以通过读取 ``stats`` 目录下的文件(``nr_tried``, ``sz_tried``, ``nr_applied``,
+``sz_applied``, 和 ``qt_exceeds``))分别检索这些统计数据。这些文件不是实时更新的,所以
+你应该要求DAMON sysfs接口通过在相关的 ``kdamonds/<N>/state`` 文件中写入一个特殊的关键字
+``update_schemes_stats`` 来更新统计信息的文件内容。
+
+schemes/<N>/tried_regions/
+--------------------------
+
+当一个特殊的关键字 ``update_schemes_tried_regions`` 被写入相关的 ``kdamonds/<N>/state``
+文件时,DAMON会在这个目录下创建从 ``0`` 开始命名的整数目录。每个目录包含的文件暴露了关于每个
+内存区域的详细信息,在下一个 :ref:`聚集区间 <sysfs_monitoring_attrs>`,相应的方案的 ``动作``
+已经尝试在这个目录下应用。这些信息包括地址范围、``nr_accesses`` 以及区域的 ``年龄`` 。
+
+当另一个特殊的关键字 ``clear_schemes_tried_regions`` 被写入相关的 ``kdamonds/<N>/state``
+文件时,这些目录将被删除。
+
+tried_regions/<N>/
+------------------
+
+在每个区域目录中,你会发现四个文件(``start``, ``end``, ``nr_accesses``, and ``age``)。
+读取这些文件将显示相应的基于DAMON的操作方案 ``动作`` 试图应用的区域的开始和结束地址、``nr_accesses``
+和 ``年龄`` 。
+
+用例
+~~~~
+
+下面的命令应用了一个方案:”如果一个大小为[4KiB, 8KiB]的内存区域在[10, 20]的聚合时间间隔内
+显示出每一个聚合时间间隔[0, 5]的访问量,请分页该区域。对于分页,每秒最多只能使用10ms,而且每
+秒分页不能超过1GiB。在这一限制下,首先分页出具有较长年龄的内存区域。另外,每5秒钟检查一次系统
+的可用内存率,当可用内存率低于50%时开始监测和分页,但如果可用内存率大于60%,或低于30%,则停
+止监测。“ ::
+
+ # cd <sysfs>/kernel/mm/damon/admin
+ # # populate directories
+ # echo 1 > kdamonds/nr_kdamonds; echo 1 > kdamonds/0/contexts/nr_contexts;
+ # echo 1 > kdamonds/0/contexts/0/schemes/nr_schemes
+ # cd kdamonds/0/contexts/0/schemes/0
+ # # set the basic access pattern and the action
+ # echo 4096 > access_pattern/sz/min
+ # echo 8192 > access_pattern/sz/max
+ # echo 0 > access_pattern/nr_accesses/min
+ # echo 5 > access_pattern/nr_accesses/max
+ # echo 10 > access_pattern/age/min
+ # echo 20 > access_pattern/age/max
+ # echo pageout > action
+ # # set quotas
+ # echo 10 > quotas/ms
+ # echo $((1024*1024*1024)) > quotas/bytes
+ # echo 1000 > quotas/reset_interval_ms
+ # # set watermark
+ # echo free_mem_rate > watermarks/metric
+ # echo 5000000 > watermarks/interval_us
+ # echo 600 > watermarks/high
+ # echo 500 > watermarks/mid
+ # echo 300 > watermarks/low
+
+请注意,我们强烈建议使用用户空间的工具,如 `damo <https://github.com/awslabs/damo>`_ ,
+而不是像上面那样手动读写文件。以上只是一个例子。
+
+debugfs接口
+===========
+
+.. note::
+
+ DAMON debugfs接口将在下一个LTS内核发布后被移除,所以用户应该转移到
+ :ref:`sysfs接口<sysfs_interface>`。
+
+DAMON导出了八个文件, ``attrs``, ``target_ids``, ``init_regions``,
+``schemes``, ``monitor_on``, ``kdamond_pid``, ``mk_contexts`` 和
+``rm_contexts`` under its debugfs directory, ``<debugfs>/damon/``.
+
+
+属性
+----
+
+用户可以通过读取和写入 ``attrs`` 文件获得和设置 ``采样间隔`` 、 ``聚集间隔`` 、 ``更新间隔``
+以及监测目标区域的最小/最大数量。要详细了解监测属性,请参考 `:doc:/mm/damon/design` 。例如,
+下面的命令将这些值设置为5ms、100ms、1000ms、10和1000,然后再次检查::
+
+ # cd <debugfs>/damon
+ # echo 5000 100000 1000000 10 1000 > attrs
+ # cat attrs
+ 5000 100000 1000000 10 1000
+
+
+目标ID
+------
+
+一些类型的地址空间支持多个监测目标。例如,虚拟内存地址空间的监测可以有多个进程作为监测目标。用户
+可以通过写入目标的相关id值来设置目标,并通过读取 ``target_ids`` 文件来获得当前目标的id。在监
+测虚拟地址空间的情况下,这些值应该是监测目标进程的pid。例如,下面的命令将pid为42和4242的进程设
+为监测目标,并再次检查::
+
+ # cd <debugfs>/damon
+ # echo 42 4242 > target_ids
+ # cat target_ids
+ 42 4242
+
+用户还可以通过在文件中写入一个特殊的关键字 "paddr\n" 来监测系统的物理内存地址空间。因为物理地
+址空间监测不支持多个目标,读取文件会显示一个假值,即 ``42`` ,如下图所示::
+
+ # cd <debugfs>/damon
+ # echo paddr > target_ids
+ # cat target_ids
+ 42
+
+请注意,设置目标ID并不启动监测。
+
+
+初始监测目标区域
+----------------
+
+在虚拟地址空间监测的情况下,DAMON自动设置和更新监测的目标区域,这样就可以覆盖目标进程的整个
+内存映射。然而,用户可能希望将监测区域限制在特定的地址范围内,如堆、栈或特定的文件映射区域。
+或者,一些用户可以知道他们工作负载的初始访问模式,因此希望为“自适应区域调整”设置最佳初始区域。
+
+相比之下,DAMON在物理内存监测的情况下不会自动设置和更新监测目标区域。因此,用户应该自己设置
+监测目标区域。
+
+在这种情况下,用户可以通过在 ``init_regions`` 文件中写入适当的值,明确地设置他们想要的初
+始监测目标区域。输入应该是一个由三个整数组成的队列,用空格隔开,代表一个区域的形式如下::
+
+ <target idx> <start address> <end address>
+
+目标idx应该是 ``target_ids`` 文件中目标的索引,从 ``0`` 开始,区域应该按照地址顺序传递。
+例如,下面的命令将设置几个地址范围, ``1-100`` 和 ``100-200`` 作为pid 42的初始监测目标
+区域,这是 ``target_ids`` 中的第一个(索引 ``0`` ),另外几个地址范围, ``20-40`` 和
+``50-100`` 作为pid 4242的地址,这是 ``target_ids`` 中的第二个(索引 ``1`` )::
+
+ # cd <debugfs>/damon
+ # cat target_ids
+ 42 4242
+ # echo "0 1 100 \
+ 0 100 200 \
+ 1 20 40 \
+ 1 50 100" > init_regions
+
+请注意,这只是设置了初始的监测目标区域。在虚拟内存监测的情况下,DAMON会在一个 ``更新间隔``
+后自动更新区域的边界。因此,在这种情况下,如果用户不希望更新的话,应该把 ``更新间隔`` 设
+置得足够大。
+
+
+方案
+----
+
+对于通常的基于DAMON的数据访问感知的内存管理优化,用户只是希望系统对特定访问模式的内存区域应用内
+存管理操作。DAMON从用户那里接收这种形式化的操作方案,并将这些方案应用到目标进程中。
+
+用户可以通过读取和写入 ``scheme`` debugfs文件来获得和设置这些方案。读取该文件还可以显示每个
+方案的统计数据。在文件中,每一个方案都应该在每一行中以下列形式表示出来::
+
+ <target access pattern> <action> <quota> <watermarks>
+
+你可以通过简单地在文件中写入一个空字符串来禁用方案。
+
+目标访问模式
+~~~~~~~~~~~~
+
+``<目标访问模式>`` 是由三个范围构成的,形式如下::
+
+ min-size max-size min-acc max-acc min-age max-age
+
+具体来说,区域大小的字节数( `min-size` 和 `max-size` ),访问频率的每聚合区间的监测访问次
+数( `min-acc` 和 `max-acc` ),区域年龄的聚合区间数( `min-age` 和 `max-age` )都被指定。
+请注意,这些范围是封闭区间。
+
+动作
+~~~~
+
+``<action>`` 是一个预定义的内存管理动作的整数,DAMON将应用于具有目标访问模式的区域。支持
+的数字和它们的含义如下::
+
+ - 0: Call ``madvise()`` for the region with ``MADV_WILLNEED``
+ - 1: Call ``madvise()`` for the region with ``MADV_COLD``
+ - 2: Call ``madvise()`` for the region with ``MADV_PAGEOUT``
+ - 3: Call ``madvise()`` for the region with ``MADV_HUGEPAGE``
+ - 4: Call ``madvise()`` for the region with ``MADV_NOHUGEPAGE``
+ - 5: Do nothing but count the statistics
+
+配额
+~~~~
+
+每个 ``动作`` 的最佳 ``目标访问模式`` 取决于工作负载,所以不容易找到。更糟糕的是,将某个
+动作的方案设置得过于激进会导致严重的开销。为了避免这种开销,用户可以通过下面表格中的 ``<quota>``
+来限制方案的时间和大小配额::
+
+ <ms> <sz> <reset interval> <priority weights>
+
+这使得DAMON在 ``<reset interval>`` 毫秒内,尽量只用 ``<ms>`` 毫秒的时间对 ``目标访
+问模式`` 的内存区域应用动作,并在 ``<reset interval>`` 内只对最多<sz>字节的内存区域应
+用动作。将 ``<ms>`` 和 ``<sz>`` 都设置为零,可以禁用配额限制。
+
+当预计超过配额限制时,DAMON会根据 ``目标访问模式`` 的大小、访问频率和年龄,对发现的内存
+区域进行优先排序。为了实现个性化的优先级,用户可以在 ``<优先级权重>`` 中设置这三个属性的
+权重,具体形式如下::
+
+ <size weight> <access frequency weight> <age weight>
+
+水位
+~~~~
+
+有些方案需要根据系统特定指标的当前值来运行,如自由内存比率。对于这种情况,用户可以为该条
+件指定水位。::
+
+ <metric> <check interval> <high mark> <middle mark> <low mark>
+
+``<metric>`` 是一个预定义的整数,用于要检查的度量。支持的数字和它们的含义如下。
+
+ - 0: 忽视水位
+ - 1: 系统空闲内存率 (千分比)
+
+每隔 ``<检查间隔>`` 微秒检查一次公制的值。
+
+如果该值高于 ``<高标>`` 或低于 ``<低标>`` ,该方案被停用。如果该值低于 ``<中标>`` ,
+该方案将被激活。
+
+统计数据
+~~~~~~~~
+
+它还统计每个方案被尝试应用的区域的总数量和字节数,每个方案被成功应用的区域的两个数量,以
+及超过配额限制的总数量。这些统计数据可用于在线分析或调整方案。
+
+统计数据可以通过读取方案文件来显示。读取该文件将显示你在每一行中输入的每个 ``方案`` ,
+统计的五个数字将被加在每一行的末尾。
+
+例子
+~~~~
+
+下面的命令应用了一个方案:”如果一个大小为[4KiB, 8KiB]的内存区域在[10, 20]的聚合时间
+间隔内显示出每一个聚合时间间隔[0, 5]的访问量,请分页出该区域。对于分页,每秒最多只能使
+用10ms,而且每秒分页不能超过1GiB。在这一限制下,首先分页出具有较长年龄的内存区域。另外,
+每5秒钟检查一次系统的可用内存率,当可用内存率低于50%时开始监测和分页,但如果可用内存率
+大于60%,或低于30%,则停止监测“::
+
+ # cd <debugfs>/damon
+ # scheme="4096 8192 0 5 10 20 2" # target access pattern and action
+ # scheme+=" 10 $((1024*1024*1024)) 1000" # quotas
+ # scheme+=" 0 0 100" # prioritization weights
+ # scheme+=" 1 5000000 600 500 300" # watermarks
+ # echo "$scheme" > schemes
+
+
+开关
+----
+
+除非你明确地启动监测,否则如上所述的文件设置不会产生效果。你可以通过写入和读取 ``monitor_on``
+文件来启动、停止和检查监测的当前状态。写入 ``on`` 该文件可以启动对有属性的目标的监测。写入
+``off`` 该文件则停止这些目标。如果每个目标进程被终止,DAMON也会停止。下面的示例命令开启、关
+闭和检查DAMON的状态::
+
+ # cd <debugfs>/damon
+ # echo on > monitor_on
+ # echo off > monitor_on
+ # cat monitor_on
+ off
+
+请注意,当监测开启时,你不能写到上述的debugfs文件。如果你在DAMON运行时写到这些文件,将会返
+回一个错误代码,如 ``-EBUSY`` 。
+
+
+监测线程PID
+-----------
+
+DAMON通过一个叫做kdamond的内核线程来进行请求监测。你可以通过读取 ``kdamond_pid`` 文件获
+得该线程的 ``pid`` 。当监测被 ``关闭`` 时,读取该文件不会返回任何信息::
+
+ # cd <debugfs>/damon
+ # cat monitor_on
+ off
+ # cat kdamond_pid
+ none
+ # echo on > monitor_on
+ # cat kdamond_pid
+ 18594
+
+
+使用多个监测线程
+----------------
+
+每个监测上下文都会创建一个 ``kdamond`` 线程。你可以使用 ``mk_contexts`` 和 ``rm_contexts``
+文件为多个 ``kdamond`` 需要的用例创建和删除监测上下文。
+
+将新上下文的名称写入 ``mk_contexts`` 文件,在 ``DAMON debugfs`` 目录上创建一个该名称的目录。
+该目录将有该上下文的 ``DAMON debugfs`` 文件::
+
+ # cd <debugfs>/damon
+ # ls foo
+ # ls: cannot access 'foo': No such file or directory
+ # echo foo > mk_contexts
+ # ls foo
+ # attrs init_regions kdamond_pid schemes target_ids
+
+如果不再需要上下文,你可以通过把上下文的名字放到 ``rm_contexts`` 文件中来删除它和相应的目录::
+
+ # echo foo > rm_contexts
+ # ls foo
+ # ls: cannot access 'foo': No such file or directory
+
+注意, ``mk_contexts`` 、 ``rm_contexts`` 和 ``monitor_on`` 文件只在根目录下。
+
+
+监测结果的监测点
+================
+
+DAMON通过一个tracepoint ``damon:damon_aggregated`` 提供监测结果. 当监测开启时,你可
+以记录追踪点事件,并使用追踪点支持工具如perf显示结果。比如说::
+
+ # echo on > monitor_on
+ # perf record -e damon:damon_aggregated &
+ # sleep 5
+ # kill 9 $(pidof perf)
+ # echo off > monitor_on
+ # perf script
diff --git a/Documentation/translations/zh_CN/admin-guide/mm/index.rst b/Documentation/translations/zh_CN/admin-guide/mm/index.rst
new file mode 100644
index 000000000000..a8fd2c4a8796
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/mm/index.rst
@@ -0,0 +1,49 @@
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/admin-guide/mm/index.rst
+
+:翻译:
+
+ 徐鑫 xu xin <xu.xin16@zte.com.cn>
+
+
+========
+内存管理
+========
+
+Linux内存管理子系统,顾名思义,是负责系统中的内存管理。它包括了虚拟内存与请求
+分页的实现,内核内部结构和用户空间程序的内存分配、将文件映射到进程地址空间以
+及许多其他很酷的事情。
+
+Linux内存管理是一个具有许多可配置设置的复杂系统, 且这些设置中的大多数都可以通
+过 ``/proc`` 文件系统获得,并且可以使用 ``sysctl`` 进行查询和调整。这些API接
+口被描述在Documentation/admin-guide/sysctl/vm.rst文件和 `man 5 proc`_ 中。
+
+.. _man 5 proc: http://man7.org/linux/man-pages/man5/proc.5.html
+
+Linux内存管理有它自己的术语,如果你还不熟悉它,请考虑阅读下面参考:
+Documentation/admin-guide/mm/concepts.rst.
+
+在此目录下,我们详细描述了如何与Linux内存管理中的各种机制交互。
+
+.. toctree::
+ :maxdepth: 1
+
+ damon/index
+ ksm
+
+Todolist:
+* concepts
+* cma_debugfs
+* hugetlbpage
+* idle_page_tracking
+* memory-hotplug
+* nommu-mmap
+* numa_memory_policy
+* numaperf
+* pagemap
+* soft-dirty
+* swap_numa
+* transhuge
+* userfaultfd
+* zswap
diff --git a/Documentation/translations/zh_CN/admin-guide/mm/ksm.rst b/Documentation/translations/zh_CN/admin-guide/mm/ksm.rst
new file mode 100644
index 000000000000..0029c4fd2201
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/mm/ksm.rst
@@ -0,0 +1,198 @@
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/admin-guide/mm/ksm.rst
+
+:翻译:
+
+ 徐鑫 xu xin <xu.xin16@zte.com.cn>
+
+
+============
+内核同页合并
+============
+
+
+概述
+====
+
+KSM是一种能节省内存的数据去重功能,由CONFIG_KSM=y启用,并在2.6.32版本时被添
+加到Linux内核。详见 ``mm/ksm.c`` 的实现,以及http://lwn.net/Articles/306704
+和https://lwn.net/Articles/330589
+
+KSM最初目的是为了与KVM(即著名的内核共享内存)一起使用而开发的,通过共享虚拟机
+之间的公共数据,将更多虚拟机放入物理内存。但它对于任何会生成多个相同数据实例的
+应用程序都是很有用的。
+
+KSM的守护进程ksmd会定期扫描那些已注册的用户内存区域,查找内容相同的页面,这些
+页面可以被单个写保护页面替换(如果进程以后想要更新其内容,将自动复制)。使用:
+引用:`sysfs intraface <ksm_sysfs>` 接口来配置KSM守护程序在单个过程中所扫描的页
+数以及两个过程之间的间隔时间。
+
+KSM只合并匿名(私有)页面,从不合并页缓存(文件)页面。KSM的合并页面最初只能被
+锁定在内核内存中,但现在可以就像其他用户页面一样被换出(但当它们被交换回来时共
+享会被破坏: ksmd必须重新发现它们的身份并再次合并)。
+
+以madvise控制KSM
+================
+
+KSM仅在特定的地址空间区域时运行,即应用程序通过使用如下所示的madvise(2)系统调
+用来请求某块地址成为可能的合并候选者的地址空间::
+
+ int madvise(addr, length, MADV_MERGEABLE)
+
+应用程序当然也可以通过调用::
+
+ int madvise(addr, length, MADV_UNMERGEABLE)
+
+来取消该请求,并恢复为非共享页面:此时KSM将去除合并在该范围内的任何合并页。注意:
+这个去除合并的调用可能突然需要的内存量超过实际可用的内存量-那么可能会出现EAGAIN
+失败,但更可能会唤醒OOM killer。
+
+如果KSM未被配置到正在运行的内核中,则madvise MADV_MERGEABLE 和 MADV_UNMERGEABLE
+的调用只会以EINVAL 失败。如果正在运行的内核是用CONFIG_KSM=y方式构建的,那么这些
+调用通常会成功:即使KSM守护程序当前没有运行,MADV_MERGEABLE 仍然会在KSM守护程序
+启动时注册范围,即使该范围不能包含KSM实际可以合并的任何页面,即使MADV_UNMERGEABLE
+应用于从未标记为MADV_MERGEABLE的范围。
+
+如果一块内存区域必须被拆分为至少一个新的MADV_MERGEABLE区域或MADV_UNMERGEABLE区域,
+当该进程将超过 ``vm.max_map_count`` 的设定,则madvise可能返回ENOMEM。(请参阅文档
+Documentation/admin-guide/sysctl/vm.rst)。
+
+与其他madvise调用一样,它们在用户地址空间的映射区域上使用:如果指定的范围包含未
+映射的间隙(尽管在中间的映射区域工作),它们将报告ENOMEM,如果没有足够的内存用于
+内部结构,则可能会因EAGAIN而失败。
+
+KSM守护进程sysfs接口
+====================
+
+KSM守护进程可以由``/sys/kernel/mm/ksm/`` 中的sysfs文件控制,所有人都可以读取,但
+只能由root用户写入。各接口解释如下:
+
+
+pages_to_scan
+ ksmd进程进入睡眠前要扫描的页数。
+ 例如, ``echo 100 > /sys/kernel/mm/ksm/pages_to_scan``
+
+ 默认值:100(该值被选择用于演示目的)
+
+sleep_millisecs
+ ksmd在下次扫描前应休眠多少毫秒
+ 例如, ``echo 20 > /sys/kernel/mm/ksm/sleep_millisecs``
+
+ 默认值:20(该值被选择用于演示目的)
+
+merge_across_nodes
+ 指定是否可以合并来自不同NUMA节点的页面。当设置为0时,ksm仅合并在物理上位
+ 于同一NUMA节点的内存区域中的页面。这降低了访问共享页面的延迟。在有明显的
+ NUMA距离上,具有更多节点的系统可能受益于设置该值为0时的更低延迟。而对于
+ 需要对内存使用量最小化的较小系统来说,设置该值为1(默认设置)则可能会受
+ 益于更大共享页面。在决定使用哪种设置之前,您可能希望比较系统在每种设置下
+ 的性能。 ``merge_across_nodes`` 仅当系统中没有ksm共享页面时,才能被更改设
+ 置:首先将接口`run` 设置为2从而对页进行去合并,然后在修改
+ ``merge_across_nodes`` 后再将‘run’又设置为1,以根据新设置来重新合并。
+
+ 默认值:1(如早期的发布版本一样合并跨站点)
+
+run
+ * 设置为0可停止ksmd运行,但保留合并页面,
+ * 设置为1可运行ksmd,例如, ``echo 1 > /sys/kernel/mm/ksm/run`` ,
+ * 设置为2可停止ksmd运行,并且对所有目前已合并的页进行去合并,但保留可合并
+ 区域以供下次运行。
+
+ 默认值:0(必须设置为1才能激活KSM,除非禁用了CONFIG_SYSFS)
+
+use_zero_pages
+ 指定是否应当特殊处理空页(即那些仅含zero的已分配页)。当该值设置为1时,
+ 空页与内核零页合并,而不是像通常情况下那样空页自身彼此合并。这可以根据
+ 工作负载的不同,在具有着色零页的架构上可以提高性能。启用此设置时应小心,
+ 因为它可能会降低某些工作负载的KSM性能,比如,当待合并的候选页面的校验和
+ 与空页面的校验和恰好匹配的时候。此设置可随时更改,仅对那些更改后再合并
+ 的页面有效。
+
+ 默认值:0(如同早期版本的KSM正常表现)
+
+max_page_sharing
+ 单个KSM页面允许的最大共享站点数。这将强制执行重复数据消除限制,以避免涉
+ 及遍历共享KSM页面的虚拟映射的虚拟内存操作的高延迟。最小值为2,因为新创
+ 建的KSM页面将至少有两个共享者。该值越高,KSM合并内存的速度越快,去重
+ 因子也越高,但是对于任何给定的KSM页面,虚拟映射的最坏情况遍历的速度也会
+ 越慢。减慢了这种遍历速度就意味着在交换、压缩、NUMA平衡和页面迁移期间,
+ 某些虚拟内存操作将有更高的延迟,从而降低这些虚拟内存操作调用者的响应能力。
+ 其他任务如果不涉及执行虚拟映射遍历的VM操作,其任务调度延迟不受此参数的影
+ 响,因为这些遍历本身是调度友好的。
+
+stable_node_chains_prune_millisecs
+ 指定KSM检查特定页面的元数据的频率(即那些达到过时信息数据去重限制标准的
+ 页面)单位是毫秒。较小的毫秒值将以更低的延迟来释放KSM元数据,但它们将使
+ ksmd在扫描期间使用更多CPU。如果还没有一个KSM页面达到 ``max_page_sharing``
+ 标准,那就没有什么用。
+
+KSM与MADV_MERGEABLE的工作有效性体现于 ``/sys/kernel/mm/ksm/`` 路径下的接口:
+
+pages_shared
+ 表示多少共享页正在被使用
+pages_sharing
+ 表示还有多少站点正在共享这些共享页,即节省了多少
+pages_unshared
+ 表示有多少页是唯一的,但被反复检查以进行合并
+pages_volatile
+ 表示有多少页因变化太快而无法放在tree中
+full_scans
+ 表示所有可合并区域已扫描多少次
+stable_node_chains
+ 达到 ``max_page_sharing`` 限制的KSM页数
+stable_node_dups
+ 重复的KSM页数
+
+比值 ``pages_sharing/pages_shared`` 的最大值受限制于 ``max_page_sharing``
+的设定。要想增加该比值,则相应地要增加 ``max_page_sharing`` 的值。
+
+监测KSM的收益
+=============
+
+KSM可以通过合并相同的页面来节省内存,但也会消耗额外的内存,因为它需要生成一些rmap_items
+来保存每个扫描页面的简要rmap信息。其中有些页面可能会被合并,但有些页面在被检查几次
+后可能无法被合并,这些都是无益的内存消耗。
+
+1) 如何确定KSM在全系统范围内是节省内存还是消耗内存?这里有一个简单的近似计算方法供参考::
+
+ general_profit =~ pages_sharing * sizeof(page) - (all_rmap_items) *
+ sizeof(rmap_item);
+
+ 其中all_rmap_items可以通过对 ``pages_sharing`` 、 ``pages_shared`` 、 ``pages_unshared``
+ 和 ``pages_volatile`` 的求和而轻松获得。
+
+2) 单一进程中KSM的收益也可以通过以下近似的计算得到::
+
+ process_profit =~ ksm_merging_pages * sizeof(page) -
+ ksm_rmap_items * sizeof(rmap_item).
+
+ 其中ksm_merging_pages显示在 ``/proc/<pid>/`` 目录下,而ksm_rmap_items
+ 显示在 ``/proc/<pid>/ksm_stat`` 。
+
+从应用的角度来看, ``ksm_rmap_items`` 和 ``ksm_merging_pages`` 的高比例意
+味着不好的madvise-applied策略,所以开发者或管理员必须重新考虑如何改变madvis策
+略。举个例子供参考,一个页面的大小通常是4K,而rmap_item的大小在32位CPU架构上分
+别是32B,在64位CPU架构上是64B。所以如果 ``ksm_rmap_items/ksm_merging_pages``
+的比例在64位CPU上超过64,或者在32位CPU上超过128,那么应用程序的madvise策略应
+该被放弃,因为ksm收益大约为零或负值。
+
+监控KSM事件
+===========
+
+在/proc/vmstat中有一些计数器,可以用来监控KSM事件。KSM可能有助于节省内存,这是
+一种权衡,因为它可能会在KSM COW或复制中的交换上遭受延迟。这些事件可以帮助用户评估
+是否或如何使用KSM。例如,如果cow_ksm增加得太快,用户可以减少madvise(, , MADV_MERGEABLE)
+的范围。
+
+cow_ksm
+ 在每次KSM页面触发写时拷贝(COW)时都会被递增,当用户试图写入KSM页面时,
+ 我们必须做一个拷贝。
+
+ksm_swpin_copy
+ 在换入时,每次KSM页被复制时都会被递增。请注意,KSM页在换入时可能会被复
+ 制,因为do_swap_page()不能做所有的锁,而需要重组一个跨anon_vma的KSM页。
+
+--
+Izik Eidus,
+Hugh Dickins, 2009年11月17日。
diff --git a/Documentation/translations/zh_CN/admin-guide/reporting-issues.rst b/Documentation/translations/zh_CN/admin-guide/reporting-issues.rst
new file mode 100644
index 000000000000..59e51e3539b4
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/reporting-issues.rst
@@ -0,0 +1,1368 @@
+.. SPDX-License-Identifier: (GPL-2.0+ OR CC-BY-4.0)
+.. See the bottom of this file for additional redistribution information.
+
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/admin-guide/reporting-issues.rst
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+
+报告问题
++++++++++
+
+
+简明指南(亦即 太长不看)
+==========================
+
+您面临的是否为同系列稳定版或长期支持内核的普通内核的回归?是否仍然受支持?
+请搜索 `LKML内核邮件列表 <https://lore.kernel.org/lkml/>`_ 和
+`Linux稳定版邮件列表 <https://lore.kernel.org/stable/>`_ 存档中匹配的报告并
+加入讨论。如果找不到匹配的报告,请安装该系列的最新版本。如果它仍然出现问题,
+请报告给稳定版邮件列表(stable@vger.kernel.org)并抄送回归邮件列表
+(regressions@lists.linux.dev);理想情况下,还可以抄送维护者和相关子系统的
+邮件列表。
+
+在所有其他情况下,请尽可能猜测是哪个内核部分导致了问题。查看MAINTAINERS文件,
+了解开发人员希望如何得知问题,大多数情况下,报告问题都是通过电子邮件和抄送
+相关邮件列表进行的。检查报告目的地的存档中是否已有匹配的报告;也请搜索
+`LKML <https://lore.kernel.org/lkml/>`_ 和网络。如果找不到可加入的讨论,请
+安装 `最新的主线内核 <https://kernel.org/>`_ 。如果仍存在问题,请发送报告。
+
+问题已经解决了,但是您希望看到它在一个仍然支持的稳定版或长期支持系列中得到
+解决?请安装其最新版本。如果它出现了问题,那么在主线中搜索修复它的更改,并
+检查是否正在回传(backporting)或者已放弃;如果两者都没有,那么可询问处理
+更改的人员。
+
+**通用提醒** :当安装和测试上述内核时,请确保它是普通的(即:没有补丁,也没
+有使用附加模块)。还要确保它是在一个正常的环境中构建和运行,并且在问题发生
+之前没有被污染(tainted)。
+
+当你同时面临Linux内核的多个问题时,请分别报告。在编写报告时,要涵盖与问题
+相关的所有信息,如使用的内核和发行版。如果碰见回归,请把报告抄送回归邮件列表
+(regressions@lists.linux.dev)。也请试试用二分法找出源头;如果成功找到,请
+在报告中写上它的提交ID并抄送sign-off-by链中的所有人。
+
+一旦报告发出,请回答任何出现的问题,并尽可能地提供帮助。这包括通过不时重新
+测试新版本并发送状态更新来推动进展。
+
+
+如何向内核维护人员报告问题的逐步指南
+=====================================
+
+上面的简明指南概述了如何向Linux内核开发人员报告问题。对于已经熟悉向自由和开
+源软件(FLOSS)项目报告问题的人来说,这可能是他们所需要的全部内容。对于其他
+人,本部分更为详细,并一步一步地描述。为了便于阅读,它仍然尽量简洁,并省略
+了许多细节;这些在逐步指南后的参考章节中进行了描述,该章节更详细地解释了每
+个步骤。
+
+注意:本节涉及的方面比简明指南多,顺序也稍有不同。这符合你的利益,以确保您
+尽早意识到看起来像Linux内核毛病的问题可能实际上是由其他原因引起的。这些步骤
+可以确保你最终不会觉得在这一过程中投入的时间是浪费:
+
+ * 您是否面临硬件或软件供应商提供的Linux内核的问题?那么基本上您最好停止阅读
+ 本文档,转而向您的供应商报告问题,除非您愿意自己安装最新的Linux版本。寻找
+ 和解决问题往往需要后者。
+
+ * 使用您喜爱的网络搜索引擎对现有报告进行粗略搜索;此外,请检查
+ `Linux内核邮件列表(LKML) <https://lore.kernel.org/lkml/>`_ 的存档。如果
+ 找到匹配的报告,请加入讨论而不是发送新报告。
+
+ * 看看你正在处理的问题是否为回归问题、安全问题或非常严重的问题:这些都是需
+ 要在接下来的一些步骤中特别处理的“高优先级问题”。
+
+ * 确保不是内核环境导致了您面临的问题。
+
+ * 创建一个新的备份,并将系统修复和恢复工具放在手边。
+
+ * 确保您的系统不会通过动态构建额外的内核模块来增强其内核,像DKMS这样的解决
+ 方案可能在您不知情的情况下就在本地进行了这样的工作。
+
+ * 当问题发生时,检查您的内核是否被“污染”,因为使内核设置这个标志的事件可能
+ 会导致您面临的问题。
+
+ * 粗略地写下如何重现这个问题。如果您同时处理多个问题,请为每个问题单独写注
+ 释,并确保它们在新启动的系统上独立出现。这是必要的,因为每个问题都需要分
+ 别报告给内核开发人员,除非它们严重纠缠在一起。
+
+ * 如果您正面临稳定版或长期支持版本线的回归(例如从5.10.4更新到5.10.5时出现
+ 故障),请查看后文“报告稳定版和长期支持内核线的回归”小节。
+
+ * 定位可能引起问题的驱动程序或内核子系统。找出其开发人员期望的报告的方式和
+ 位置。注意:大多数情况下不会是 bugzilla.kernel.org,因为问题通常需要通
+ 过邮件发送给维护人员和公共邮件列表。
+
+ * 在缺陷追踪器或问题相关邮件列表的存档中彻底搜索可能与您的问题匹配的报告。
+ 如果你发现了一些相关讨论,请加入讨论而不是发送新的报告。
+
+在完成这些准备之后,你将进入主要部分:
+
+ * 除非您已经在运行最新的“主线”Linux内核,否则最好在报告流程前安装它。在某些
+ 情况下,使用最新的“稳定版”Linux进行测试和报告也是可以接受的替代方案;在
+ 合并窗口期间,这实际上可能是最好的方法,但在开发阶段最好还是暂停几天。无论
+ 你选择什么版本,最好使用“普通”构建。忽略这些建议会大大增加您的报告被拒绝
+ 或忽略的风险。
+
+ * 确保您刚刚安装的内核在运行时不会“污染”自己。
+
+ * 在您刚刚安装的内核中复现这个问题。如果它没有出现,请查看下方只发生在
+ 稳定版和长期支持内核的问题的说明。
+
+ * 优化你的笔记:试着找到并写出最直接的复现问题的方法。确保最终结果包含所有
+ 重要的细节,同时让第一次听说的人容易阅读和理解。如果您在此过程中学到了一
+ 些东西,请考虑再次搜索关于该问题的现有报告。
+
+ * 如果失败涉及“panic”、“Oops”、“warning”或“BUG”,请考虑解码内核日志以查找触
+ 发错误的代码行。
+
+ * 如果您的问题是回归问题,请尽可能缩小引入问题时的范围。
+
+ * 通过详细描述问题来开始编写报告。记得包括以下条目:您为复现而安装的最新内
+ 核版本、使用的Linux发行版以及关于如何复现该问题的说明。如果可能,将内核
+ 构建配置(.config)和 ``dmesg`` 的输出放在网上的某个地方,并链接到它。包
+ 含或上传所有其他可能相关的信息,如Oops的输出/截图或来自 ``lspci`` 的输出
+ 。一旦你写完了这个主要部分,请在上方插入一个正常长度的段落快速概述问题和
+ 影响。再在此之上添加一个简单描述问题的句子,以得到人们的阅读。现在给出一
+ 个更短的描述性标题或主题。然后就可以像MAINTAINERS文件告诉你的那样发送或
+ 提交报告了,除非你在处理一个“高优先级问题”:它们需要按照下面“高优先级问
+ 题的特殊处理”所述特别关照。
+
+ * 等待别人的反应,继续推进事情,直到你能够接受这样或那样的结果。因此,请公
+ 开和及时地回应任何询问。测试提出的修复。积极地测试:至少重新测试每个新主
+ 线版本的首个候选版本(RC),并报告你的结果。如果出现拖延,就友好地提醒一
+ 下。如果你没有得到任何帮助或者未能满意,请试着自己帮助自己。
+
+
+报告稳定版和长期支持内核线的回归
+----------------------------------
+
+如果您发现了稳定版或长期支持内核版本线中的回归问题并按上述流程跳到这里,那么
+请阅读本小节。即例如您在从5.10.4更新到5.10.5时出现了问题(从5.9.15到5.10.5则
+不是)。开发人员希望尽快修复此类回归,因此有一个简化流程来报告它们:
+
+ * 检查内核开发人员是否仍然维护你关心的Linux内核版本线:去 `kernel.org 的首页
+ <https://kernel.org/>`_ ,确保此特定版本线的最新版没有“[EOL]”标记。
+
+ * 检查 `Linux稳定版邮件列表 <https://lore.kernel.org/stable/>`_ 中的现有报告。
+
+ * 从特定的版本线安装最新版本作为纯净内核。确保这个内核没有被污染,并且仍然
+ 存在问题,因为问题可能已经在那里被修复了。如果您第一次发现供应商内核的问题,
+ 请检查已知最新版本的普通构建是否可以正常运行。
+
+ * 向Linux稳定版邮件列表发送一个简短的问题报告(stable@vger.kernel.org)并抄送
+ Linux回归邮件列表(regressions@lists.linux.dev);如果你怀疑是由某子系统
+ 引起的,请抄送其维护人员和子系统邮件列表。大致描述问题,并解释如何复现。
+ 讲清楚首个出现问题的版本和最后一个工作正常的版本。然后等待进一步的指示。
+
+下面的参考章节部分详细解释了这些步骤中的每一步。
+
+
+报告只发生在较旧内核版本线的问题
+----------------------------------
+
+若您尝试了上述的最新主线内核,但未能在那里复现问题,那么本小节适用于您;以下
+流程有助于使问题在仍然支持的稳定版或长期支持版本线,或者定期基于最新稳定版或
+长期支持内核的供应商内核中得到修复。如果是这种情况,请执行以下步骤:
+
+ * 请做好准备,接下来的几个步骤可能无法在旧版本中解决问题:修复可能太大或太
+ 冒险,无法移植到那里。
+
+ * 执行前节“报告稳定版和长期支持内核线的回归”中的前三个步骤。
+
+ * 在Linux内核版本控制系统中搜索修复主线问题的更改,因为它的提交消息可能会
+ 告诉你修复是否已经计划好了支持。如果你没有找到,搜索适当的邮件列表,寻找
+ 讨论此类问题或同行评议可能修复的帖子;然后检查讨论是否认为修复不适合支持。
+ 如果支持根本不被考虑,加入最新的讨论,询问是否有可能。
+
+ * 前面的步骤之一应该会给出一个解决方案。如果仍未能成功,请向可能引起问题的
+ 子系统的维护人员询问建议;抄送特定子系统的邮件列表以及稳定版邮件列表
+
+下面的参考章节部分详细解释了这些步骤中的每一步。
+
+
+参考章节:向内核维护者报告问题
+===============================
+
+上面的详细指南简要地列出了所有主要步骤,这对大多数人来说应该足够了。但有时,
+即使是有经验的用户也可能想知道如何实际执行这些步骤之一。这就是本节的目的,
+因为它将提供关于上述每个步骤的更多细节。请将此作为参考文档:可以从头到尾
+阅读它。但它主要是为了浏览和查找如何实际执行这些步骤的详细信息。
+
+在深入挖掘细节之前,我想先给你一些一般性建议:
+
+ * Linux内核开发人员很清楚这个过程很复杂,比其他的FLOSS项目要求更多。我们很
+ 希望让它更简单。但这需要在不同的地方以及一些基础设施上付诸努力,这些基础
+ 设施需要持续的维护;尚未有人站出来做这些工作,所以目前情况就是这样。
+
+ * 与某些供应商签订的保证或支持合同并不能使您有权要求上游Linux内核社区的开
+ 发人员进行修复:这样的合同完全在Linux内核、其开发社区和本文档的范围之外。
+ 这就是为什么在这种情况下,你不能要求任何契约保证,即使开发人员处理的问
+ 题对供应商有效。如果您想主张您的权利,使用供应商的支持渠道代替。当这样做
+ 的时候,你可能想提出你希望看到这个问题在上游Linux内核中修复;可以这是确
+ 保最终修复将被纳入所有Linux发行版的唯一方法来鼓励他们。
+
+ * 如果您从未向FLOSS项目报告过任何问题,那么您应该考虑阅读 `如何有效地报告
+ 缺陷 <https://www.chiark.greenend.org.uk/~sgtatham/bugs.html>`_ , `如何
+ 以明智的方式提问 <http://www.catb.org/esr/faqs/smart-questions.html>`_ ,
+ 和 `如何提出好问题 <https://jvns.ca/blog/good-questions/>`_ 。
+
+解决这些问题之后,可以在下面找到如何正确地向Linux内核报告问题的详细信息。
+
+
+确保您使用的是上游Linux内核
+----------------------------
+
+ *您是否面临硬件或软件供应商提供的Linux内核的问题?那么基本上您最好停止阅
+ 读本文档,转而向您的供应商报告问题,除非您愿意自己安装最新的Linux版本。
+ 寻找和解决问题往往需要后者。*
+
+与大多数程序员一样,Linux内核开发人员不喜欢花时间处理他们维护的源代码中根本
+不会发生的问题的报告。这只会浪费每个人的时间,尤其是你的时间。不幸的是,当
+涉及到内核时,这样的情况很容易发生,并且常常导致双方气馁。这是因为几乎所有预
+装在设备(台式机、笔记本电脑、智能手机、路由器等)上的Linux内核,以及大多数
+由Linux发行商提供的内核,都与由kernel.org发行的官方Linux内核相距甚远:从Linux
+开发的角度来看,这些供应商提供的内核通常是古老的或者经过了大量修改,通常两点
+兼具。
+
+大多数供应商内核都不适合用来向Linux内核开发人员报告问题:您在其中遇到的问题
+可能已经由Linux内核开发人员在数月或数年前修复;此外,供应商的修改和增强可能
+会导致您面临的问题,即使它们看起来很小或者完全不相关。这就是为什么您应该向
+供应商报告这些内核的问题。它的开发者应该查看报告,如果它是一个上游问题,直接
+于上游修复或将报告转发到那里。在实践中,这有时行不通。因此,您可能需要考虑
+通过自己安装最新的Linux内核内核来绕过供应商。如果如果您选择此方法,那么本指
+南后面的步骤将解释如何在排除了其他可能导致您的问题的原因后执行此操作。
+
+注意前段使用的词语是“大多数”,因为有时候开发人员实际上愿意处理供应商内核出现
+的问题报告。他们是否这么做很大程度上取决于开发人员和相关问题。如果发行版只
+根据最近的Linux版本对内核进行了较小修改,那么机会就比较大;例如对于Debian
+GNU/Linux Sid或Fedora Rawhide所提供的主线内核。一些开发人员还将接受基于最新
+稳定内核的发行版内核问题报告,只要它改动不大;例如Arch Linux、常规Fedora版本
+和openSUSE Turboweed。但是请记住,您最好使用主线Linux,并避免在此流程中使用
+稳定版内核,如“安装一个新的内核进行测试”一节中所详述。
+
+当然,您可以忽略所有这些建议,并向上游Linux开发人员报告旧的或经过大量修改的
+供应商内核的问题。但是注意,这样的报告经常被拒绝或忽视,所以自行小心考虑一下。
+不过这还是比根本不报告问题要好:有时候这样的报告会直接或间接地帮助解决之后的
+问题。
+
+
+搜索现有报告(第一部分)
+-------------------------
+
+ *使用您喜爱的网络搜索引擎对现有报告进行粗略搜索;此外,请检查Linux内核
+ 邮件列表(LKML)的存档。如果找到匹配的报告,请加入讨论而不是发送新报告。*
+
+报告一个别人已经提出的问题,对每个人来说都是浪费时间,尤其是作为报告人的你。
+所以彻底检查是否有人已经报告了这个问题,这对你自己是有利的。在流程中的这一步,
+可以只执行一个粗略的搜索:一旦您知道您的问题需要报告到哪里,稍后的步骤将告诉
+您如何详细搜索。尽管如此,不要仓促完成这一步,它可以节省您的时间和减少麻烦。
+
+只需先用你最喜欢的搜索引擎在互联网上搜索。然后再搜索Linux内核邮件列表(LKML)
+存档。
+
+如果搜索结果实在太多,可以考虑让你的搜索引擎将搜索时间范围限制在过去的一个
+月或一年。而且无论你在哪里搜索,一定要用恰当的搜索关键词;也要变化几次关键
+词。同时,试着从别人的角度看问题:这将帮助你想出其他的关键词。另外,一定不
+要同时使用过多的关键词。记住搜索时要同时尝试包含和不包含内核驱动程序的名称
+或受影响的硬件组件的名称等信息。但其确切的品牌名称(比如说“华硕红魔 Radeon
+RX 5700 XT Gaming OC”)往往帮助不大,因为它太具体了。相反,尝试搜索术语,如
+型号(Radeon 5700 或 Radeon 5000)和核心代号(“Navi”或“Navi10”),以及包含
+和不包含其制造商(“AMD”)。
+
+如果你发现了关于你的问题的现有报告,请加入讨论,因为你可能会提供有价值的额
+外信息。这一点很重要,即使是在修复程序已经准备好或处于最后阶段,因为开发人
+员可能会寻找能够提供额外信息或测试建议修复程序的人。跳到“发布报告后的责任”
+一节,了解有关如何正确参与的细节。
+
+注意,搜索 `bugzilla.kernel.org <https://bugzilla.kernel.org/>`_ 网站可能
+也是一个好主意,因为这可能会提供有价值的见解或找到匹配的报告。如果您发现后者,
+请记住:大多数子系统都希望在不同的位置报告,如下面“你需要将问题报告到何处”
+一节中所述。因此本应处理这个问题的开发人员甚至可能不知道bugzilla的工单。所以
+请检查工单中的问题是否已经按照本文档所述得到报告,如果没有,请考虑这样做。
+
+高优先级的问题?
+-----------------
+
+ *看看你正在处理的问题是否是回归问题、安全问题或非常严重的问题:这些都是
+ 需要在接下来的一些步骤中特别处理的“高优先级问题”。*
+
+Linus Torvalds和主要的Linux内核开发人员希望看到一些问题尽快得到解决,因此在
+报告过程中有一些“高优先级问题”的处理略有不同。有三种情况符合条件:回归、安全
+问题和非常严重的问题。
+
+如果某个应用程序或实际用例在原先的Linux内核上运行良好,但在使用类似配置编译的
+较新版本上效果更差、或者根本不能用,那么你就需要处理回归问题。
+Documentation/admin-guide/reporting-regressions.rst 对此进行了更详细的解释。
+它还提供了很多你可能想知道的关于回归的其他信息;例如,它解释了如何将您的问题
+添加到回归跟踪列表中,以确保它不会被忽略。
+
+什么是安全问题留给您自己判断。在继续之前,请考虑阅读
+Documentation/translations/zh_CN/admin-guide/security-bugs.rst ,
+因为它提供了如何最恰当地处理安全问题的额外细节。
+
+当发生了完全无法接受的糟糕事情时,此问题就是一个“非常严重的问题”。例如,
+Linux内核破坏了它处理的数据或损坏了它运行的硬件。当内核突然显示错误消息
+(“kernel panic”)并停止工作,或者根本没有任何停止信息时,您也在处理一个严重
+的问题。注意:不要混淆“panic”(内核停止自身的致命错误)和“Oops”(可恢复错误),
+因为显示后者之后内核仍然在运行。
+
+
+确保环境健康
+--------------
+
+ *确保不是内核所处环境导致了你所面临的问题。*
+
+看起来很像内核问题的问题有时是由构建或运行时环境引起的。很难完全排除这种问
+题,但你应该尽量减少这种问题:
+
+ * 构建内核时,请使用经过验证的工具,因为编译器或二进制文件中的错误可能会导
+ 致内核出现错误行为。
+
+ * 确保您的计算机组件在其设计规范内运行;这对处理器、内存和主板尤为重要。因
+ 此,当面临潜在的内核问题时,停止低电压或超频。
+
+ * 尽量确保不是硬件故障导致了你的问题。例如,内存损坏会导致大量的问题,这些
+ 问题会表现为看起来像内核问题。
+
+ * 如果你正在处理一个文件系统问题,你可能需要用 ``fsck`` 检查一下文件系统,
+ 因为它可能会以某种方式被损坏,从而导致无法预期的内核行为。
+
+ * 在处理回归问题时,要确保没有在更新内核的同时发生了其他变化。例如,这个问
+ 题可能是由同时更新的其他软件引起的。也有可能是在你第一次重启进入新内核时,
+ 某个硬件巧合地坏了。更新系统 BIOS 或改变 BIOS 设置中的某些内容也会导致
+ 一些看起来很像内核回归的问题。
+
+
+为紧急情况做好准备
+-------------------
+
+ *创建一个全新的备份,并将系统修复和还原工具放在手边*
+
+我得提醒您,您正在和计算机打交道,计算机有时会出现意想不到的事情,尤其是当
+您折腾其操作系统的内核等关键部件时。而这就是你在这个过程中要做的事情。因此,
+一定要创建一个全新的备份;还要确保你手头有修复或重装操作系统的所有工具,
+以及恢复备份所需的一切。
+
+
+确保你的内核不会被增强
+------------------------
+
+ *确保您的系统不会通过动态构建额外的内核模块来增强其内核,像DKMS这样的解
+ 决方案可能在您不知情的情况下就在本地进行了这样的工作。*
+
+如果内核以任何方式得到增强,那么问题报告被忽略或拒绝的风险就会急剧增加。这就
+是为什么您应该删除或禁用像akmods和DKMS这样的机制:这些机制会自动构建额外内核
+模块,例如当您安装新的Linux内核或第一次引导它时。也要记得同时删除他们可能安装
+的任何模块。然后重新启动再继续。
+
+注意,你可能不知道你的系统正在使用这些解决方案之一:当你安装 Nvidia 专有图
+形驱动程序、VirtualBox 或其他需要 Linux 内核以外的模块支持的软件时,它们通
+常会静默设置。这就是为什么你可能需要卸载这些软件的软件包,以摆脱任何第三方
+内核模块。
+
+
+检查“污染”标志
+----------------
+
+ *当问题发生时,检查您的内核是否被“污染”,因为使内核设置这个标志的事件可
+ 能会导致您面临的问题。*
+
+当某些可能会导致看起来完全不相关的后续错误的事情发生时,内核会用“污染
+(taint)”标志标记自己。如果您的内核受到污染,那么您面临的可能是这样的错误。
+因此在投入更多时间到这个过程中之前,尽早排除此情况可能对你有好处。这是这个
+步骤出现在这里的唯一原因,因为这个过程稍后会告诉您安装最新的主线内核;然后
+您将需要再次检查污染标志,因为当它出问题的时候内核报告会关注它。
+
+在正在运行的系统上检查内核是否污染非常容易:如果 ``cat /proc/sys/kernel/tainted``
+返回“0”,那么内核没有被污染,一切正常。在某些情况下无法检查该文件;这就是
+为什么当内核报告内部问题(“kernel bug”)、可恢复错误(“kernel Oops”)或停止
+操作前不可恢复的错误(“kernel panic”)时,它也会提到污染状态。当其中一个错
+误发生时,查看打印的错误消息的顶部,搜索以“CPU:”开头的行。如果发现问题时内
+核未被污染,那么它应该以“Not infected”结束;如果你看到“Tainted:”且后跟一些
+空格和字母,那就被污染了。
+
+如果你的内核被污染了,请阅读 Documentation/translations/zh_CN/admin-guide/tainted-kernels.rst
+以找出原因。设法消除污染因素。通常是由以下三种因素之一引起的:
+
+ 1. 发生了一个可恢复的错误(“kernel Oops”),内核污染了自己,因为内核知道在
+ 此之后它可能会出现奇怪的行为错乱。在这种情况下,检查您的内核或系统日志,
+ 并寻找以下列文字开头的部分::
+
+ Oops: 0000 [#1] SMP
+
+ 如方括号中的“#1”所示,这是自启动以来的第一次Oops。每个Oops和此后发生的
+ 任何其他问题都可能是首个Oops的后续问题,即使这两个问题看起来完全不相关。
+ 通过消除首个Oops的原因并在之后复现该问题,可以排除这种情况。有时仅仅
+ 重新启动就足够了,有时更改配置后重新启动可以消除Oops。但是在这个流程中
+ 不要花费太多时间在这一点上,因为引起Oops的原因可能已经在您稍后将按流程
+ 安装的新Linux内核版本中修复了。
+
+ 2. 您的系统使用的软件安装了自己的内核模块,例如Nvidia的专有图形驱动程序或
+ VirtualBox。当内核从外部源(即使它们是开源的)加载此类模块时,它会污染
+ 自己:它们有时会在不相关的内核区域导致错误,从而可能导致您面临的问题。
+ 因此,当您想要向Linux内核开发人员报告问题时,您必须阻止这些模块加载。
+ 大多数情况下最简单的方法是:临时卸载这些软件,包括它们可能已经安装的任
+ 何模块。之后重新启动。
+
+ 3. 当内核加载驻留在Linux内核源代码staging树中的模块时,它也会污染自身。这
+ 是一个特殊的区域,代码(主要是驱动程序)还没有达到正常Linux内核的质量
+ 标准。当您报告此种模块的问题时,内核受到污染显然是没有问题的;只需确保
+ 问题模块是造成污染的唯一原因。如果问题发生在一个不相关的区域,重新启动
+ 并通过指定 ``foo.blacklist=1`` 作为内核参数临时阻止该模块被加载(用有
+ 问题的模块名替换“foo”)。
+
+
+记录如何重现问题
+------------------
+
+ *粗略地写下如何重现这个问题。如果您同时处理多个问题,请为每个问题单独写
+ 注释,并确保它们在新启动的系统上独立出现。这是必要的,因为每个问题都需
+ 要分别报告给内核开发人员,除非它们严重纠缠在一起。*
+
+如果你同时处理多个问题,必须分别报告每个问题,因为它们可能由不同的开发人员
+处理。在一份报告中描述多种问题,也会让其他人难以将其分开。因此只有在问题严
+重纠缠的情况下,才能将问题合并在一份报告中。
+
+此外,在报告过程中,你必须测试该问题是否发生在其他内核版本上。因此,如果您
+知道如何在一个新启动的系统上快速重现问题,将使您的工作更加轻松。
+
+注意:报告只发生过一次的问题往往是没有结果的,因为它们可能是由于宇宙辐射导
+致的位翻转。所以你应该尝试通过重现问题来排除这种情况,然后再继续。如果你有
+足够的经验来区分由于硬件故障引起的一次性错误和难以重现的罕见内核问题,可以
+忽略这个建议。
+
+
+稳定版或长期支持内核的回归?
+-----------------------------
+
+ *如果您正面临稳定版或长期支持版本线的回归(例如从5.10.4更新到5.10.5时出现
+ 故障),请查看后文“报告稳定版和长期支持内核线的回归”小节。*
+
+稳定版和长期支持内核版本线中的回归是Linux开发人员非常希望解决的问题,这样的
+问题甚至比主线开发分支中的回归更不应出现,因为它们会很快影响到很多人。开发人员
+希望尽快了解此类问题,因此有一个简化流程来报告这些问题。注意,使用更新内核版
+本线的回归(比如从5.9.15切换到5.10.5时出现故障)不符合条件。
+
+
+你需要将问题报告到何处
+------------------------
+
+ *定位可能引起问题的驱动程序或内核子系统。找出其开发人员期望的报告的方式
+ 和位置。注意:大多数情况下不会是bugzilla.kernel.org,因为问题通常需要通
+ 过邮件发送给维护人员和公共邮件列表。*
+
+将报告发送给合适的人是至关重要的,因为Linux内核是一个大项目,大多数开发人员
+只熟悉其中的一小部分。例如,相当多的程序员只关心一个驱动程序,比如一个WiFi
+芯片驱动程序;它的开发人员可能对疏远的或不相关的“子系统”(如TCP堆栈、
+PCIe/PCI子系统、内存管理或文件系统)的内部知识了解很少或完全不了解。
+
+问题在于:Linux内核缺少一个,可以简单地将问题归档并让需要了解它的开发人员了
+解它的,中心化缺陷跟踪器。这就是为什么你必须找到正确的途径来自己报告问题。
+您可以在脚本的帮助下做到这一点(见下文),但它主要针对的是内核开发人员和专
+家。对于其他人来说,MAINTAINERS(维护人员)文件是更好的选择。
+
+如何阅读MAINTAINERS维护者文件
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+为了说明如何使用 :ref:`MAINTAINERS <maintainers>` 文件,让我们假设您的笔记
+本电脑中的WiFi在更新内核后突然出现了错误行为。这种情况下可能是WiFi驱动的问
+题。显然,它也可能由于驱动基于的某些代码,但除非你怀疑有这样的东西会附着在
+驱动程序上。如果真的是其他的问题,驱动程序的开发人员会让合适的人参与进来。
+
+遗憾的是,没有通用且简单的办法来检查哪个代码驱动了特定硬件组件。
+
+在WiFi驱动出现问题的情况下,你可能想查看 ``lspci -k`` 的输出,因为它列出了
+PCI/PCIe总线上的设备和驱动它的内核模块::
+
+ [user@something ~]$ lspci -k
+ [...]
+ 3a:00.0 Network controller: Qualcomm Atheros QCA6174 802.11ac Wireless Network Adapter (rev 32)
+ Subsystem: Bigfoot Networks, Inc. Device 1535
+ Kernel driver in use: ath10k_pci
+ Kernel modules: ath10k_pci
+ [...]
+
+但如果你的WiFi芯片通过USB或其他内部总线连接,这种方法就行不通了。在这种情况
+下,您可能需要检查您的WiFi管理器或 ``ip link`` 的输出。寻找有问题的网络接口
+的名称,它可能类似于“wlp58s0”。此名称可以用来找到驱动它的模块::
+
+ [user@something ~]$ realpath --relative-to=/sys/module//sys/class/net/wlp58s0/device/driver/module
+ ath10k_pci
+
+如果这些技巧不能进一步帮助您,请尝试在网上搜索如何缩小相关驱动程序或子系统
+的范围。如果你不确定是哪一个:试着猜一下,即使你猜得不好,也会有人会帮助你
+的。
+
+一旦您知道了相应的驱动程序或子系统,您就希望在MAINTAINERS文件中搜索它。如果
+是“ath10k_pci”,您不会找到任何东西,因为名称太具体了。有时你需要在网上寻找
+帮助;但在此之前,请尝试使用一个稍短或修改过的名称来搜索MAINTAINERS文件,因
+为这样你可能会发现类似这样的东西::
+
+ QUALCOMM ATHEROS ATH10K WIRELESS DRIVER
+ Mail: A. Some Human <shuman@example.com>
+ Mailing list: ath10k@lists.infradead.org
+ Status: Supported
+ Web-page: https://wireless.wiki.kernel.org/en/users/Drivers/ath10k
+ SCM: git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
+ Files: drivers/net/wireless/ath/ath10k/
+
+注意:如果您阅读在Linux源代码树的根目录中找到的原始维护者文件,则行描述将是
+缩写。例如,“Mail:(邮件)”将是“M:”,“Mailing list:(邮件列表)”将是“L”,
+“Status:(状态)”将是“S:”。此文件顶部有一段解释了这些和其他缩写。
+
+首先查看“Status”状态行。理想情况下,它应该得到“Supported(支持)”或
+“Maintained(维护)”。如果状态为“Obsolete(过时的)”,那么你在使用一些过时的
+方法,需要转换到新的解决方案上。有时候,只有在感到有动力时,才会有人为代码
+提供“Odd Fixes”。如果碰见“Orphan”,你就完全不走运了,因为再也没有人关心代码
+了,只剩下这些选项:准备好与问题共存,自己修复它,或者找一个愿意修复它的程序员。
+
+检查状态后,寻找以“bug:”开头的一行:它将告诉你在哪里可以找到子系统特定的缺
+陷跟踪器来提交你的问题。上面的例子没有此行。大多数部分都是这样,因为 Linux
+内核的开发完全是由邮件驱动的。很少有子系统使用缺陷跟踪器,且其中只有一部分
+依赖于 bugzilla.kernel.org。
+
+在这种以及其他很多情况下,你必须寻找以“Mail:”开头的行。这些行提到了特定代码
+的维护者的名字和电子邮件地址。也可以查找以“Mailing list:”开头的行,它告诉你
+开发代码的公共邮件列表。你的报告之后需要通过邮件发到这些地址。另外,对于所有
+通过电子邮件发送的问题报告,一定要抄送 Linux Kernel Mailing List(LKML)
+<linux-kernel@vger.kernel.org>。在以后通过邮件发送问题报告时,不要遗漏任何
+一个邮件列表!维护者都是大忙人,可能会把一些工作留给子系统特定列表上的其他开
+发者;而 LKML 很重要,因为需要一个可以找到所有问题报告的地方。
+
+
+借助脚本找到维护者
+~~~~~~~~~~~~~~~~~~~~
+
+对于手头有Linux源码的人来说,有第二个可以找到合适的报告地点的选择:脚本
+“scripts/get_maintainer.pl”,它尝试找到所有要联系的人。它会查询MAINTAINERS
+文件,并需要用相关源代码的路径来调用。对于编译成模块的驱动程序,经常可以用
+这样的命令找到::
+
+ $ modinfo ath10k_pci | grep filename | sed 's!/lib/modules/.*/kernel/!!; s!filename:!!; s!\.ko\(\|\.xz\)!!'
+ drivers/net/wireless/ath/ath10k/ath10k_pci.ko
+
+将其中的部分内容传递给脚本::
+
+ $ ./scripts/get_maintainer.pl -f drivers/net/wireless/ath/ath10k*
+ Some Human <shuman@example.com> (supporter:QUALCOMM ATHEROS ATH10K WIRELESS DRIVER)
+ Another S. Human <asomehuman@example.com> (maintainer:NETWORKING DRIVERS)
+ ath10k@lists.infradead.org (open list:QUALCOMM ATHEROS ATH10K WIRELESS DRIVER)
+ linux-wireless@vger.kernel.org (open list:NETWORKING DRIVERS (WIRELESS))
+ netdev@vger.kernel.org (open list:NETWORKING DRIVERS)
+ linux-kernel@vger.kernel.org (open list)
+
+不要把你的报告发给所有的人。发送给维护者,脚本称之为“supporter:”;另外抄送
+代码最相关的邮件列表,以及 Linux 内核邮件列表(LKML)。在此例中,你需要将报
+告发送给 “Some Human <shuman@example.com>” ,并抄送
+“ath10k@lists.infradead.org”和“linux-kernel@vger.kernel.org”。
+
+注意:如果你用 git 克隆了 Linux 源代码,你可能需要用--git 再次调用
+get_maintainer.pl。脚本会查看提交历史,以找到最近哪些人参与了相关代码的编写,
+因为他们可能会提供帮助。但要小心使用这些结果,因为它很容易让你误入歧途。
+例如,这种情况常常会发生在很少被修改的地方(比如老旧的或未维护的驱动程序):
+有时这样的代码会在树级清理期间被根本不关心此驱动程序的开发者修改。
+
+
+搜索现有报告(第二部分)
+--------------------------
+
+ *在缺陷追踪器或问题相关邮件列表的存档中彻底搜索可能与您的问题匹配的报告。
+ 如果找到匹配的报告,请加入讨论而不是发送新报告。*
+
+如前所述:报告一个别人已经提出的问题,对每个人来说都是浪费时间,尤其是作为报告
+人的你。这就是为什么你应该再次搜索现有的报告。现在你已经知道问题需要报告到哪里。
+如果是邮件列表,那么一般在 `lore.kernel.org <https://lore.kernel.org/>`_ 可以
+找到相应存档。
+
+但有些列表运行在其他地方。例如前面步骤中当例子的ath10k WiFi驱动程序就是这种
+情况。但是你通常可以在网上很容易地找到这些列表的档案。例如搜索“archive
+ath10k@lists.infradead.org”,将引导您到ath10k邮件列表的信息页,该页面顶部链接
+到其 `列表存档 <https://lists.infradead.org/pipermail/ath10k/>`_ 。遗憾的是,
+这个列表和其他一些列表缺乏搜索其存档的功能。在这种情况下可以使用常规的互联网
+搜索引擎,并添加类似“site:lists.infadead.org/pipermail/ath10k/”这
+样的搜索条件,这会把结果限制在该链接中的档案。
+
+也请进一步搜索网络、LKML和bugzilla.kernel.org网站。如果你的报告需要发送到缺陷
+跟踪器中,那么您可能还需要检查子系统的邮件列表存档,因为可能有人只在那里报告了它。
+
+有关如何搜索以及在找到匹配报告时如何操作的详细信息,请参阅上面的“搜索现有报告
+(第一部分)”。
+
+不要急着完成报告过程的这一步:花30到60分钟甚至更多的时间可以为你和其他人节省 /
+减少相当多的时间和麻烦。
+
+
+安装一个新的内核进行测试
+--------------------------
+
+ *除非您已经在运行最新的“主线”Linux内核,否则最好在报告流程前安装它。在
+ 某些情况下,使用最新的“稳定版”Linux进行测试和报告也是可以接受的替代方案;
+ 在合并窗口期间,这实际上可能是最好的方法,但在开发阶段最好还是暂停几天。
+ 无论你选择什么版本,最好使用“普通”构建。忽略这些建议会大大增加您的报告
+ 被拒绝或忽略的风险。*
+
+正如第一步的详细解释中所提到的:与大多数程序员一样,与大多数程序员一样,Linux
+内核开发人员不喜欢花时间处理他们维护的源代码中根本不会发生的问题的报告。这只
+会浪费每个人的时间,尤其是你的时间。这就是为什么在报告问题之前,您必须先确认
+问题仍然存在于最新的上游代码中,这符合每个人的利益。您可以忽略此建议,但如前
+所述:这样做会极大地增加问题报告被拒绝或被忽略的风险。
+
+内核“最新上游”的范围通常指:
+
+ * 安装一个主线内核;最新的稳定版内核也可以是一个选择,但大多数时候都最好避免。
+ 长期支持内核(有时称为“LTS内核”)不适合此流程。下一小节将更详细地解释所有
+ 这些。
+
+ * 下一小节描述获取和安装这样一个内核的方法。它还指出了使用预编译内核是可以的,
+ 但普通的内核更好,这意味着:它是直接使用从 `kernel.org <https://kernel.org/>`_
+ 获得的Linux源代码构建并且没有任何方式修改或增强。
+
+
+选择适合测试的版本
+~~~~~~~~~~~~~~~~~~~~
+
+前往 `kernel.org <https://kernel.org/>`_ 来决定使用哪个版本。忽略那个写着
+“Latest release最新版本”的巨大黄色按钮,往下看有一个表格。在表格的顶部,你会
+看到一行以“mainline”开头的字样,大多数情况下它会指向一个版本号类似“5.8-rc2”
+的预发布版本。如果是这样的话,你将需要使用这个主线内核进行测试。不要让“rc”
+吓到你,这些“开发版内核”实际上非常可靠——而且你已经按照上面的指示做了备份,
+不是吗?
+
+大概每九到十周,“mainline”可能会给你指出一个版本号类似“5.7”的正式版本。如果
+碰见这种情况,请考虑暂停报告过程,直到下一个版本的第一个预发布(5.8-rc1)出
+现在 `kernel.org <https://kernel.org/>`_ 上。这是因为 Linux 的开发周期正在
+两周的“合并窗口”内。大部分的改动和所有干扰性的改动都会在这段时间内被合并到
+下一个版本中。在此期间使用主线是比较危险的。内核开发者通常也很忙,可能没有
+多余的时间来处理问题报告。这也是很有可能在合并窗口中应用了许多修改来修复你
+所面临的问题;这就是为什么你很快就得用一个新的内核版本重新测试,就像下面“发
+布报告后的责任”一节中所述的那样。
+
+这就是为什么要等到合并窗口结束后才去做。但是如果你处理的是一些不应该等待的
+东西,则无需这样做。在这种情况下,可以考虑通过 git 获取最新的主线内核(见下
+文),或者使用 kernel.org 上提供的最新稳定版本。如果 mainline 因为某些原因
+不无法正常工作,那么使用它也是可以接受的。总的来说:用它来重现问题也比完全
+不报告问题要好。
+
+最好避免在合并窗口外使用最新的稳定版内核,因为所有修复都必须首先应用于主线。
+这就是为什么检查最新的主线内核是如此重要:你希望看到在旧版本线修复的任何问题
+需要先在主线修复,然后才能得到回传,这可能需要几天或几周。另一个原因是:您
+希望的修复对于回传来说可能太难或太冒险;因此再次报告问题不太可能改变任何事情。
+
+这些方面也部分表明了为什么长期支持内核(有时称为“LTS内核”)不适合报告流程:
+它们与当前代码的距离太远。因此,先去测试主线,然后再按流程走:如果主线没有
+出现问题,流程将指导您如何在旧版本线中修复它。
+
+如何获得新的 Linux 内核
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+你可以使用预编译或自编译的内核进行测试;如果你选择后者,可以使用 git 获取源
+代码,或者下载其 tar 存档包。
+
+**使用预编译的内核** :这往往是最快速、最简单、最安全的方法——尤其是在你不熟
+悉 Linux 内核的情况下。问题是:发行商或附加存储库提供的大多数版本都是从修改
+过的Linux源代码构建的。因此它们不是普通的,通常不适合于测试和问题报告:这些
+更改可能会导致您面临的问题或以某种方式影响问题。
+
+但是如果您使用的是流行的Linux发行版,那么您就很幸运了:对于大部分的发行版,
+您可以在网上找到包含最新主线或稳定版本Linux内核包的存储库。使用这些是完全可
+以的,只要从存储库的描述中确认它们是普通的或者至少接近普通。此外,请确保软件
+包包含kernel.org上提供的最新版本内核。如果这些软件包的时间超过一周,那么它们
+可能就不合适了,因为新的主线和稳定版内核通常至少每周发布一次。
+
+请注意,您以后可能需要手动构建自己的内核:有时这是调试或测试修复程序所必需的,
+如后文所述。还要注意,预编译的内核可能缺少在出现panic、Oops、warning或BUG时
+解码内核打印的消息所需的调试符号;如果您计划解码这些消息,最好自己编译内核
+(有关详细信息,请参阅本小节结尾和“解码失败信息”小节)。
+
+**使用git** :熟悉 git 的开发者和有经验的 Linux 用户通常最好直接从
+`kernel.org 上的官方开发仓库
+<https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/>`_
+中获取最新的 Linux 内核源代码。这些很可能比最新的主线预发布版本更新一些。不
+用担心:它们和正式的预发布版本一样可靠,除非内核的开发周期目前正处于合并窗
+口中。不过即便如此,它们也是相当可靠的。
+
+**常规方法** :不熟悉 git 的人通常最好从 `kernel.org <https://kernel.org/>`_
+下载源码的tar 存档包。
+
+如何实际构建一个内核并不在这里描述,因为许多网站已经解释了必要的步骤。如果
+你是新手,可以考虑按照那些建议使用 ``make localmodconfig`` 来做,它将尝试获
+取你当前内核的配置,然后根据你的系统进行一些调整。这样做并不能使编译出来的
+内核更好,但可以更快地编译。
+
+注意:如果您正在处理来自内核的pannc、Oops、warning或BUG,请在配置内核时尝试
+启用 CONFIG_KALLSYMS 选项。此外,还可以启用 CONFIG_DEBUG_KERNEL 和
+CONFIG_DEBUG_INFO;后者是相关选项,但只有启用前者才能开启。请注意,
+CONFIG_DEBUG_INFO 会需要更多储存空间来构建内核。但这是值得的,因为这些选项将
+允许您稍后精确定位触发问题的确切代码行。下面的“解码失败信息”一节对此进行了更
+详细的解释。
+
+但请记住:始终记录遇到的问题,以防难以重现。发送未解码的报告总比不报告要好。
+
+
+检查“污染”标志
+----------------
+
+ *确保您刚刚安装的内核在运行时不会“污染”自己。*
+
+正如上面已经详细介绍过的:当发生一些可能会导致一些看起来完全不相关的后续错
+误的事情时,内核会设置一个“污染”标志。这就是为什么你需要检查你刚刚安装的内
+核是否有设置此标志。如果有的话,几乎在任何情况下你都需要在报告问题之前先消
+除它。详细的操作方法请看上面的章节。
+
+
+用新内核重现问题
+------------------
+
+ *在您刚刚安装的内核中复现这个问题。如果它没有出现,请查看下方只发生在
+ 稳定版和长期支持内核的问题的说明。*
+
+检查这个问题是否发生在你刚刚安装的新 Linux 内核版本上。如果新内核已经修复了,
+可以考虑使用此版本线,放弃报告问题。但是请记住,只要它没有在 `kernel.org
+<https://kernel.org/>`_ 的稳定版和长期版(以及由这些版本衍生出来的厂商内核)
+中得到修复,其他用户可能仍然会受到它的困扰。如果你喜欢使用其中的一个,或
+者只是想帮助它们的用户,请前往下面的“报告只发生在较旧内核版本线的问题”一节。
+
+
+优化复现问题的描述
+--------------------
+
+ *优化你的笔记:试着找到并写出最直接的复现问题的方法。确保最终结果包含所
+ 有重要的细节,同时让第一次听说的人容易阅读和理解。如果您在此过程中学到
+ 了一些东西,请考虑再次搜索关于该问题的现有报告。*
+
+过于复杂的报告会让别人很难理解。因此请尽量找到一个可以直接描述、易于以书面
+形式理解的再现方法。包含所有重要的细节,但同时也要尽量保持简短。
+
+在这在前面的步骤中,你很可能已经了解了一些关于你所面临的问题的点。利用这些
+知识,再次搜索可以转而加入的现有报告。
+
+
+解码失败信息
+-------------
+
+ *如果失败涉及“panic”、“Oops”、“warning”或“BUG”,请考虑解码内核日志以查找
+ 触发错误的代码行。*
+
+当内核检测到内部问题时,它会记录一些有关已执行代码的信息。这使得在源代码中精
+确定位触发问题的行并显示如何调用它成为可能。但只有在配置内核时启用了
+CONFIG_DEBUG_INFO 和 CONFIG_KALLSYMS选项时,这种方法才起效。如果已启用此选项,
+请考虑解码内核日志中的信息。这将使我们更容易理解是什么导致了“panic”、“Oops”、
+“warning”或“BUG”,从而增加了有人提供修复的几率。
+
+解码可以通过Linux源代码树中的脚本来完成。如果您运行的内核是之前自己编译的,
+这样这样调用它::
+
+ [user@something ~]$ sudo dmesg | ./linux-5.10.5/scripts/decode_stacktrace.sh ./linux-5.10.5/vmlinux
+ /usr/lib/debug/lib/modules/5.10.10-4.1.x86_64/vmlinux /usr/src/kernels/5.10.10-4.1.x86_64/
+
+如果您运行的是打包好的普通内核,则可能需要安装带有调试符号的相应包。然后按以下
+方式调用脚本(如果发行版未打包,则可能需要从Linux源代码获取)::
+
+ [user@something ~]$ sudo dmesg | ./linux-5.10.5/scripts/decode_stacktrace.sh \
+ /usr/lib/debug/lib/modules/5.10.10-4.1.x86_64/vmlinux /usr/src/kernels/5.10.10-4.1.x86_64/
+
+脚本将解码如下的日志行,这些日志行显示内核在发生错误时正在执行的代码的地址::
+
+ [ 68.387301] RIP: 0010:test_module_init+0x5/0xffa [test_module]
+
+解码之后,这些行将变成这样::
+
+ [ 68.387301] RIP: 0010:test_module_init (/home/username/linux-5.10.5/test-module/test-module.c:16) test_module
+
+在本例中,执行的代码是从文件“~/linux-5.10.5/test-module/test-module.c”构建的,
+错误出现在第16行的指令中。
+
+该脚本也会如此解码以“Call trace”开头的部分中提到的地址,该部分显示出现问题的
+函数的路径。此外,脚本还会显示内核正在执行的代码部分的汇编输出。
+
+注意,如果你没法做到这一点,只需跳过这一步,并在报告中说明原因。如果你幸运的
+话,可能无需解码。如果需要的话,也许有人会帮你做这件事情。还要注意,这只是解
+码内核堆栈跟踪的几种方法之一。有时需要采取不同的步骤来检索相关的详细信息。
+别担心,如果您碰到的情况需要这样做,开发人员会告诉您该怎么做。
+
+
+对回归的特别关照
+-----------------
+
+ *如果您的问题是回归问题,请尽可能缩小引入问题时的范围。*
+
+Linux 首席开发者 Linus Torvalds 认为 Linux 内核永远不应恶化,这就是为什么他
+认为回归是不可接受的,并希望看到它们被迅速修复。这就是为什么引入了回归的改
+动导致的问题若无法通过其他方式快速解决,通常会被迅速撤销。因此,报告回归有
+点像“王炸”,会迅速得到修复。但要做到这一点,需要知道导致回归的变化。通常情
+况下,要由报告者来追查罪魁祸首,因为维护者往往没有时间或手头设置不便来自行
+重现它。
+
+有一个叫做“二分”的过程可以来寻找变化,这在
+Documentation/translations/zh_CN/admin-guide/bug-bisect.rst 文档中进行了详细
+的描述,这个过程通常需要你构建十到二十个内核镜像,每次都尝试在构建下一个镜像
+之前重现问题。是的,这需要花费一些时间,但不用担心,它比大多数人想象的要快得多。
+多亏了“binary search二分搜索”,这将引导你在源代码管理系统中找到导致回归的提交。
+一旦你找到它,就在网上搜索其主题、提交ID和缩短的提交ID(提交ID的前12个字符)。
+如果有的话,这将引导您找到关于它的现有报告。
+
+需要注意的是,二分法需要一点窍门,不是每个人都懂得诀窍,也需要相当多的努力,
+不是每个人都愿意投入。尽管如此,还是强烈建议自己进行一次二分。如果你真的
+不能或者不想走这条路,至少要找出是哪个主线内核引入的回归。比如说从 5.5.15
+切换到 5.8.4 的时候出现了一些问题,那么至少可以尝试一下相近的所有的主线版本
+(5.6、5.7 和 5.8)来检查它是什么时候出现的。除非你想在一个稳定版或长期支持
+内核中找到一个回归,否则要避免测试那些编号有三段的版本(5.6.12、5.7.8),因
+为那会使结果难以解释,可能会让你的测试变得无用。一旦你找到了引入回归的主要
+版本,就可以放心地继续报告了。但请记住:在不知道罪魁祸首的情况下,开发人员
+是否能够提供帮助取决于手头的问题。有时他们可能会从报告中确认是什么出现了问
+题,并能修复它;有时他们可能无法提供帮助,除非你进行二分。
+
+当处理回归问题时,请确保你所面临的问题真的是由内核引起的,而不是由其他东西
+引起的,如上文所述。
+
+在整个过程中,请记住:只有当旧内核和新内核的配置相似时,问题才算回归。这可以
+通过 ``make olddefconfig`` 来实现,详细解释参见
+Documentation/admin-guide/reporting-regressions.rst ;它还提供了大量其他您
+可能希望了解的有关回归的信息。
+
+
+撰写并发送报告
+---------------
+
+ *通过详细描述问题来开始编写报告。记得包括以下条目:您为复现而安装的最新
+ 内核版本、使用的Linux发行版以及关于如何复现该问题的说明。如果可能,将内
+ 核构建配置(.config)和 ``dmesg`` 的输出放在网上的某个地方,并链接到它。
+ 包含或上传所有其他可能相关的信息,如Oops的输出/截图或来自 ``lspci``
+ 的输出。一旦你写完了这个主要部分,请在上方插入一个正常长度的段落快速概
+ 述问题和影响。再在此之上添加一个简单描述问题的句子,以得到人们的阅读。
+ 现在给出一个更短的描述性标题或主题。然后就可以像MAINTAINERS文件告诉你的
+ 那样发送或提交报告了,除非你在处理一个“高优先级问题”:它们需要按照下面
+ “高优先级问题的特殊处理”所述特别关照。*
+
+现在你已经准备好了一切,是时候写你的报告了。上文前言中链接的三篇文档对如何
+写报告做了部分解释。这就是为什么本文将只提到一些基本的内容以及 Linux 内核特
+有的东西。
+
+有一点是符合这两类的:你的报告中最关键的部分是标题/主题、第一句话和第一段。
+开发者经常会收到许多邮件。因此,他们往往只是花几秒钟的时间浏览一下邮件,然
+后再决定继续下一封或仔细查看。因此,你报告的开头越好,有人研究并帮助你的机
+会就越大。这就是为什么你应该暂时忽略他们,先写出详细的报告。;-)
+
+每份报告都应提及的事项
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+详细描述你的问题是如何发生在你安装的新纯净内核上的。试着包含你之前写的和优
+化过的分步说明,概述你和其他人如何重现这个问题;在极少数无法重现的情况下,
+尽量描述你做了什么来触发它。
+
+还应包括其他人为了解该问题及其环境而可能需要的所有相关信息。实际需要的东西
+在很大程度上取决于具体问题,但有些事项你总是应该包括在内:
+
+ * ``cat /proc/version`` 的输出,其中包含 Linux 内核版本号和构建时的编译器。
+
+ * 机器正在运行的 Linux 发行版( ``hostnamectl | grep “Operating System“`` )
+
+ * CPU 和操作系统的架构( ``uname -mi`` )
+
+ * 如果您正在处理回归,并进行了二分,请提及导致回归的变更的主题和提交ID。
+
+许多情况下,让读你报告的人多了解两件事也是明智之举:
+
+ * 用于构建 Linux 内核的配置(“.config”文件)
+
+ * 内核的信息,你从 ``dmesg`` 得到的信息写到一个文件里。确保它以像“Linux
+ version 5.8-1 (foobar@example.com) (gcc (GCC) 10.2.1, GNU ld version
+ 2.34) #1 SMP Mon Aug 3 14:54:37 UTC 2020”这样的行开始,如果没有,那么第
+ 一次启动阶段的重要信息已经被丢弃了。在这种情况下,可以考虑使用
+ ``journalctl -b 0 -k`` ;或者你也可以重启,重现这个问题,然后调用
+ ``dmesg`` 。
+
+这两个文件很大,所以直接把它们放到你的报告中是个坏主意。如果你是在缺陷跟踪
+器中提交问题,那么将它们附加到工单中。如果你通过邮件报告问题,不要用附件附
+上它们,因为那会使邮件变得太大,可以按下列之一做:
+
+ * 将文件上传到某个公开的地方(你的网站,公共文件粘贴服务,在
+ `bugzilla.kernel.org <https://bugzilla.kernel.org/>`_ 上创建的工单……),
+ 并在你的报告中放上链接。理想情况下请使用允许这些文件保存很多年的地方,因
+ 为它们可能在很多年后对别人有用;例如 5 年或 10 年后,一个开发者正在修改
+ 一些代码,而这些代码正是为了修复你的问题。
+
+ * 把文件放在一边,然后说明你会在他人回复时再单独发送。只要记得报告发出去后,
+ 真正做到这一点就可以了。;-)
+
+提供这些东西可能是明智的
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+根据问题的不同,你可能需要提供更多的背景数据。这里有一些关于提供什么比较好
+的建议:
+
+ * 如果你处理的是内核的“warning”、“OOPS”或“panic”,请包含它。如果你不能复制
+ 粘贴它,试着用netconsole网络终端远程跟踪或者至少拍一张屏幕的照片。
+
+ * 如果问题可能与你的电脑硬件有关,请说明你使用的是什么系统。例如,如果你的
+ 显卡有问题,请提及它的制造商,显卡的型号,以及使用的芯片。如果是笔记本电
+ 脑,请提及它的型号名称,但尽量确保意义明确。例如“戴尔 XPS 13”就不很明确,
+ 因为它可能是 2012 年的那款,那款除了看起来和现在销售的没有什么不同之外,
+ 两者没有任何共同之处。因此,在这种情况下,要加上准确的型号,例如 2019
+ 年内推出的 XPS 13 型号为“9380”或“7390”。像“联想 Thinkpad T590”这样的名字
+ 也有些含糊不清:这款笔记本有带独立显卡和不带的子型号,所以要尽量找到准确
+ 的型号名称或注明主要部件。
+
+ * 说明正在使用的相关软件。如果你在加载模块时遇到了问题,你要说明正在使用的
+ kmod、systemd 和 udev 的版本。如果其中一个 DRM 驱动出现问题,你要说明
+ libdrm 和 Mesa 的版本;还要说明你的 Wayland 合成器或 X-Server 及其驱动。
+ 如果你有文件系统问题,请注明相应的文件系统实用程序的版本(e2fsprogs,
+ btrfs-progs, xfsprogs……)。
+
+ * 从内核中收集可能有用的额外信息。例如, ``lspci -nn`` 的输出可以帮助别人
+ 识别你使用的硬件。如果你的硬件有问题,你甚至可以给出 ``sudo lspci -vvv``
+ 的结果,因为它提供了组件是如何配置的信息。对于一些问题,可能最好包含
+ ``/proc/cpuinfo`` , ``/proc/ioports`` , ``/proc/iomem`` ,
+ ``/proc/modules`` 或 ``/proc/scsi/scsi`` 等文件的内容。一些子系统还提
+ 供了收集相关信息的工具。 ``alsa-info.sh`` `就是这样一个工具,它是音频/声
+ 音子系统开发者提供的 <https://www.alsa-project.org/wiki/AlsaInfo>`_ 。
+
+这些例子应该会给你一些知识点,让你知道附上什么数据可能是明智的,但你自己也
+要想一想,哪些数据对别人会有帮助。不要太担心忘记一些东西,因为开发人员会要
+求提供他们需要的额外细节。但从一开始就把所有重要的东西都提供出来,会增加别
+人仔细查看的机会。
+
+
+重要部分:报告的开头
+~~~~~~~~~~~~~~~~~~~~~~
+
+现在你已经准备好了报告的详细部分,让我们进入最重要的部分:开头几句。现在到
+报告的最前面,在你刚才写的部分之前加上类似“The detailed description:”(详细
+描述)这样的内容,并在最前面插入两个新行。现在写一个正常长度的段落,大致概
+述这个问题。去掉所有枯燥的细节,把重点放在读者需要知道的关键部分,以让人了
+解这是怎么回事;如果你认为这个缺陷影响了很多用户,就提一下这点来吸引大家关
+注。
+
+做好这一点后,在顶部再插入两行,写一句话的摘要,快速解释报告的内容。之后你
+要更加抽象,为报告写一个更短的主题/标题。
+
+现在你已经写好了这部分,请花点时间来优化它,因为它是你的报告中最重要的部分:
+很多人会先读这部分,然后才会决定是否值得花时间阅读其他部分。
+
+现在就像 :ref:`MAINTAINERS <maintainers>` 维护者文件告诉你的那样发送或提交
+报告,除非它是前面概述的那些“高优先级问题”之一:在这种情况下,请先阅读下一
+小节,然后再发送报告。
+
+高优先级问题的特殊处理
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+高优先级问题的报告需要特殊处理。
+
+**非常严重的缺陷** :确保在主题或工单标题以及第一段中明显标出 severeness
+(非常严重的)。
+
+**回归** :报告的主题应以“[REGRESSION]”开头。
+
+如果您成功用二分法定位了问题,请使用引入回归之更改的标题作为主题的第二部分。
+请在报告中写明“罪魁祸首”的提交ID。如果未能成功二分,请在报告中讲明最后一个
+正常工作的版本(例如5.7)和最先发生问题的版本(例如5.8-rc1)。
+
+通过邮件发送报告时,请抄送Linux回归邮件列表(regressions@lists.linux.dev)。
+如果报告需要提交到某个web追踪器,请继续提交;并在提交后,通过邮件将报告转发
+至回归列表;抄送相关子系统的维护人员和邮件列表。请确保报告是内联转发的,不要
+把它作为附件。另外请在顶部添加一个简短的说明,在那里写上工单的网址。
+
+在邮寄或转发报告时,如果成功二分,需要将“罪魁祸首”的作者添加到收件人中;同时
+抄送signed-off-by链中的每个人,您可以在提交消息的末尾找到。
+
+**安全问题** :对于这种问题,你将必须评估:如果细节被公开披露,是否会对其他
+用户产生短期风险。如果不会,只需按照所述继续报告问题。如果有此风险,你需要
+稍微调整一下报告流程。
+
+ * 如果 MAINTAINERS 文件指示您通过邮件报告问题,请不要抄送任何公共邮件列表。
+
+ * 如果你应该在缺陷跟踪器中提交问题,请确保将工单标记为“私有”或“安全问题”。
+ 如果缺陷跟踪器没有提供保持报告私密性的方法,那就别想了,把你的报告以私人
+ 邮件的形式发送给维护者吧。
+
+在这两种情况下,都一定要将报告发到 MAINTAINERS 文件中“安全联络”部分列出的
+地址。理想的情况是在发送报告的时候直接抄送他们。如果您在缺陷跟踪器中提交了
+报告,请将报告的文本转发到这些地址;但请在报告的顶部加上注释,表明您提交了
+报告,并附上工单链接。
+
+更多信息请参见 Documentation/translations/zh_CN/admin-guide/security-bugs.rst 。
+
+
+发布报告后的责任
+------------------
+
+ *等待别人的反应,继续推进事情,直到你能够接受这样或那样的结果。因此,请
+ 公开和及时地回应任何询问。测试提出的修复。积极地测试:至少重新测试每个
+ 新主线版本的首个候选版本(RC),并报告你的结果。如果出现拖延,就友好地
+ 提醒一下。如果你没有得到任何帮助或者未能满意,请试着自己帮助自己。*
+
+如果你的报告非常优秀,而且你真的很幸运,那么某个开发者可能会立即发现导致问
+题的原因;然后他们可能会写一个补丁来修复、测试它,并直接发送给主线集成,同
+时标记它以便以后回溯到需要它的稳定版和长期支持内核。那么你需要做的就是回复
+一句“Thank you very much”(非常感谢),然后在发布后换上修复好的版本。
+
+但这种理想状况很少发生。这就是为什么你把报告拿出来之后工作才开始。你要做的
+事情要视情况而定,但通常会是下面列出的事情。但在深入研究细节之前,这里有几
+件重要的事情,你需要记住这部分的过程。
+
+
+关于进一步互动的一般建议
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**总是公开回复** :当你在缺陷跟踪器中提交问题时,一定要在那里回复,不要私下
+联系任何开发者。对于邮件报告,在回复您收到的任何邮件时,总是使用“全部回复”
+功能。这包括带有任何你可能想要添加到你的报告中的额外数据的邮件:进入邮件应
+用程序“已发送”文件夹,并在邮件上使用“全部回复”来回复报告。这种方法可以确保
+公共邮件列表和其他所有参与者都能及时了解情况;它还能保持邮件线程的完整性,
+这对于邮件列表将所有相关邮件归为一类是非常重要的。
+
+只有两种情况不适合在缺陷跟踪器或“全部回复”中发表评论:
+
+ * 有人让你私下发东西。
+
+ * 你被告知要发送一些东西,但注意到其中包含需要保密的敏感信息。在这种情况下,
+ 可以私下发送给要求发送的开发者。但要在工单或邮件中注明你是这么做的,这
+ 样其他人就知道你尊重了这个要求。
+
+**在请求解释或帮助之前先研究一下** :在这部分过程中,有人可能会告诉你用尚未
+掌握的技能做一些事情。例如你可能会被要求使用一些你从未听说过的测试工具;或
+者你可能会被要求在 Linux 内核源代码上应用一个补丁来测试它是否有帮助。在某些
+情况下,发个回复询问如何做就可以了。但在走这条路之前,尽量通过在互联网上搜
+索自行找到答案;或者考虑在其他地方询问建议。比如询问朋友,或者到你平时常去
+的聊天室或论坛发帖咨询。
+
+**要有耐心** :如果你真的很幸运,你可能会在几个小时内收到对你的报告的答复。
+但大多数情况下会花费更多的时间,因为维护者分散在全球各地,因此可能在不同的
+时区——在那里他们已经享受着远离键盘的夜晚。
+
+一般来说,内核开发者需要一到五个工作日来回复报告。有时会花费更长的时间,因
+为他们可能正忙于合并窗口、其他工作、参加开发者会议,或者只是在享受一个漫长
+的暑假。
+
+“高优先级的问题”(见上面的解释)例外:维护者应该尽快解决这些问题;这就是为
+什么你应该最多等待一个星期(如果是紧急的事情,则只需两天),然后再发送友好
+的提醒。
+
+有时维护者可能没有及时回复;有时候可能会出现分歧,例如一个问题是否符合回归
+的条件。在这种情况下,在邮件列表上提出你的顾虑,并请求其他人公开或私下回复
+如何继续推进。如果失败了,可能应该让更高级别的维护者介入。如果是 WiFi 驱动,
+那就是无线维护者;如果没有更高级别的维护者,或者其他一切努力都失败了,那
+这可能是一种罕见的、可以让 Linus Torvalds 参与进来的情况。
+
+**主动测试** :每当一个新的主线内核版本的第一个预发布版本(rc1)发布的时候,
+去检查一下这个问题是否得到了解决,或者是否有什么重要的变化。在工单中或在
+回复报告的邮件中提及结果(确保所有参与讨论的人都被抄送)。这将表明你的承诺
+和你愿意帮忙。如果问题持续存在,它也会提醒开发者确保他们不会忘记它。其他一
+些不定期的重新测试(例如用rc3、rc5 和最终版本)也是一个好主意,但只有在相关
+的东西发生变化或者你正在写什么东西的时候才报告你的结果。
+
+这些些常规的事情就不说了,我们来谈谈报告后如何帮助解决问题的细节。
+
+查询和测试请求
+~~~~~~~~~~~~~~~
+
+如果你的报告得到了回复则需履行以下责任:
+
+**检查与你打交道的人** :大多数情况下,会是维护者或特定代码区域的开发人员对
+你的报告做出回应。但由于问题通常是公开报告的,所以回复的可能是任何人——包括
+那些想要帮忙的人,但最后可能会用他们的问题或请求引导你完全偏离轨道。这很少
+发生,但这是快速上网搜搜看你正在与谁互动是明智之举的许多原因之一。通过这样
+做,你也可以知道你的报告是否被正确的人听到,因为如果讨论没有导致满意的问题
+解决方案而淡出,之后可能需要提醒维护者(见下文)。
+
+**查询数据** :通常你会被要求测试一些东西或提供更多细节。尽快提供所要求的信
+息,因为你已经得到了可能会帮助你的人的注意,你等待的时间越长就有越可能失去
+关注;如果你不在数个工作日内提供信息,甚至可能出现这种结果。
+
+**测试请求** :当你被要求测试一个诊断补丁或可能的修复时,也要尽量及时测试。
+但要做得恰当,一定不要急于求成:混淆事情很容易发生,这会给所有人带来许多困
+惑。例如一个常见的错误是以为应用了一个带修复的建议补丁,但事实上并没有。即
+使是有经验的测试人员也会偶尔发生这样的事情,但当有修复的内核和没有修复的内
+核表现得一样时,他们大多时候会注意到。
+
+当没有任何实质性进展时该怎么办
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+有些报告不会得到负有相关责任的 Linux 内核开发者的任何反应;或者围绕这个问题
+的讨论有所发展,但渐渐淡出,没有任何实质内容产出。
+
+在这种情况下,要等两个星期(最好是三个星期)后再发出友好的提醒:也许当你的
+报告到达时,维护者刚刚离开键盘一段时间,或者有更重要的事情要处理。在写提醒
+信的时候,要善意地问一下,是否还需要你这边提供什么来让事情推进下去。如果报
+告是通过邮件发出来的,那就在邮件的第一行回复你的初始邮件(见上文),其中包
+括下方的原始报告的完整引用:这是少数几种情况下,这样的“TOFU”(Text Over,
+Fullquote Under文字在上,完整引用在下)是正确的做法,因为这样所有的收件人都
+会以适当的顺序立即让细节到手头上来。
+
+在提醒之后,再等三周的回复。如果你仍然没有得到适当的反馈,你首先应该重新考
+虑你的方法。你是否可能尝试接触了错误的人?是不是报告也许令人反感或者太混乱,
+以至于人们决定完全远离它?排除这些因素的最好方法是:把报告给一两个熟悉
+FLOSS 问题报告的人看,询问他们的意见。同时征求他们关于如何继续推进的建议。
+这可能意味着:准备一份更好的报告,让这些人在你发出去之前对它进行审查。这样
+的方法完全可以;只需说明这是关于这个问题的第二份改进的报告,并附上第一份报
+告的链接。
+
+如果报告是恰当的,你可以发送第二封提醒信;在其中询问为什么报告没有得到任何
+回复。第二封提醒邮件的好时机是在新 Linux 内核版本的首个预发布版本('rc1')
+发布后不久,因为无论如何你都应该在那个时候重新测试并提供状态更新(见上文)。
+
+如果第二次提醒的结果又在一周内没有任何反应,可以尝试联系上级维护者询问意见:
+即使再忙的维护者在这时候也至少应该发过某种确认。
+
+记住要做好失望的准备:理想状况下维护者最好对每一个问题报告做出回应,但他们
+只有义务解决之前列出的“高优先级问题”。所以,如果你得到的回复是“谢谢你的报告,
+我目前有更重要的问题要处理,在可预见的未来没有时间去研究这个问题”,那请不
+要太沮丧。
+
+也有可能在缺陷跟踪器或列表中进行了一些讨论之后,什么都没有发生,提醒也无助
+于激励大家进行修复。这种情况可能是毁灭性的,但在 Linux 内核开发中确实会发生。
+这些和其他得不到帮助的原因在本文结尾处的“为什么有些问题在被报告后没有得到
+任何回应或者仍然没有修复”中进行了解释。
+
+如果你没有得到任何帮助或问题最终没有得到解决,不要沮丧:Linux 内核是 FLOSS,
+因此你仍然可以自己帮助自己。例如,你可以试着找到其他受影响的人,和他们一
+起合作来解决这个问题。这样的团队可以一起准备一份新的报告,提到团队有多少人,
+为什么你们认为这是应该得到解决的事情。也许你们还可以一起缩小确切原因或引
+入回归的变化,这往往会使修复更容易。而且如果运气好的话,团队中可能会有懂点
+编程的人,也许能写出一个修复方案。
+
+
+
+“报告稳定版和长期支持内核线的回归”的参考
+------------------------------------------
+
+本小节提供了在稳定版和长期支持内核线中面对回归时需要执行的步骤的详细信息。
+
+确保特定版本线仍然受支持
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ *检查内核开发人员是否仍然维护你关心的Linux内核版本线:去 kernel.org 的
+ 首页,确保此特定版本线的最新版没有“[EOL]”标记。*
+
+大多数内核版本线只支持三个月左右,因为延长维护时间会带来相当多的工作。因此,
+每年只会选择一个版本来支持至少两年(通常是六年)。这就是为什么你需要检查
+内核开发者是否还支持你关心的版本线。
+
+注意,如果 `kernel.org <https://kernel.org/>`_ 在首页上列出了两个“稳定”版本,
+你应该考虑切换到较新的版本,而忘掉较旧的版本:对它的支持可能很快就会结束。
+然后,它将被标记为“生命周期结束”(EOL)。达到这个程度的版本线仍然会在
+`kernel.org <https://kernel.org/>`_ 首页上被显示一两周,但不适合用于测试和
+报告。
+
+搜索稳定版邮件列表
+~~~~~~~~~~~~~~~~~~~
+
+ *检查Linux稳定版邮件列表中的现有报告。*
+
+也许你所面临的问题已经被发现,并且已经或即将被修复。因此,请在 `Linux 稳定
+版邮件列表的档案 <https://lore.kernel.org/stable/>`_ 中搜索类似问题的报告。
+如果你找到任何匹配的问题,可以考虑加入讨论,除非修复工作已经完成并计划很快
+得到应用。
+
+用最新版本复现问题
+~~~~~~~~~~~~~~~~~~~
+
+ *从特定的版本线安装最新版本作为纯净内核。确保这个内核没有被污染,并且仍
+ 然存在问题,因为问题可能已经在那里被修复了。*
+
+在投入更多时间到这个过程中之前,你要检查这个问题是否在你关注的版本线的最新
+版本中已经得到了修复。这个内核需要是纯净的,在问题发生之前不应该被污染,正
+如上面已经在测试主线的过程中详细介绍过的一样。
+
+您是否是第一次注意到供应商内核的回归?供应商的更改可能会发生变化。你需要重新
+检查排除来这个问题。当您从5.10.4-vendor.42更新到5.10.5-vendor.43时,记录损坏
+的信息。然后在测试了前一段中所述的最新5.10版本之后,检查Linux 5.10.4的普通版本
+是否也可以正常工作。如果问题在那里出现,那就不符合上游回归的条件,您需要切换
+回主逐步指南来报告问题。
+
+报告回归
+~~~~~~~~~~
+
+ *向Linux稳定版邮件列表发送一个简短的问题报告(stable@vger.kernel.org)并
+ 抄送Linux回归邮件列表(regressions@lists.linux.dev);如果你怀疑是由某
+ 子系统引起的,请抄送其维护人员和子系统邮件列表。大致描述问题,并解释如
+ 何复现。讲清楚首个出现问题的版本和最后一个工作正常的版本。然后等待进一
+ 步的指示。*
+
+当报告在稳定版或长期支持内核线内发生的回归(例如在从5.10.4更新到5.10.5时),
+一份简短的报告足以快速报告问题。因此只需向稳定版和回归邮件列表发送粗略的描述;
+不过如果你怀疑某子系统导致此问题的话,请一并抄送其维护人员和子系统邮件列表,
+这会加快进程。
+
+请注意,如果您能够指明引入问题的确切版本,这将对开发人员有很大帮助。因此
+如果有时间的话,请尝试使用普通内核找到该版本。让我们假设发行版发布Linux内核
+5.10.5到5.10.8的更新时发生了故障。那么按照上面的指示,去检查该版本线中的最新
+内核,比如5.10.9。如果问题出现,请尝试普通5.10.5,以确保供应商应用的补丁不会
+干扰。如果问题没有出现,那么尝试5.10.7,然后直到5.10.8或5.10.6(取决于结果)
+找到第一个引入问题的版本。在报告中写明这一点,并指出5.10.9仍然存在故障。
+
+前一段基本粗略地概述了“二分”方法。一旦报告出来,您可能会被要求做一个正确的
+报告,因为它允许精确地定位导致问题的确切更改(然后很容易被恢复以快速修复问题)。
+因此如果时间允许,考虑立即进行适当的二分。有关如何详细信息,请参阅“对回归的
+特别关照”部分和文档 Documentation/translations/zh_CN/admin-guide/bug-bisect.rst 。
+如果成功二分的话,请将“罪魁祸首”的作者添加到收件人中;同时抄送所有在
+signed-off-by链中的人,您可以在提交消息的末尾找到。
+
+
+“报告仅在旧内核版本线中发生的问题”的参考
+----------------------------------------
+
+本节详细介绍了如果无法用主线内核重现问题,但希望在旧版本线(又称稳定版内核和
+长期支持内核)中修复问题时需要采取的步骤。
+
+有些修复太复杂
+~~~~~~~~~~~~~~~
+
+ *请做好准备,接下来的几个步骤可能无法在旧版本中解决问题:修复可能太大或
+ 太冒险,无法移植到那里。*
+
+即使是微小的、看似明显的代码变化,有时也会带来新的、完全意想不到的问题。稳
+定版和长期支持内核的维护者非常清楚这一点,因此他们只对这些内核进行符合
+Documentation/translations/zh_CN/process/stable-kernel-rules.rst 中所列出的
+规则的修改。
+
+复杂或有风险的修改不符合条件,因此只能应用于主线。其他的修复很容易被回溯到
+最新的稳定版和长期支持内核,但是风险太大,无法集成到旧版内核中。所以要注意
+你所希望的修复可能是那些不会被回溯到你所关心的版本线的修复之一。在这种情况
+下,你将别无选择,要么忍受这个问题,要么切换到一个较新的 Linux 版本,除非你
+想自己把修复补丁应用到你的内核中。
+
+通用准备
+~~~~~~~~~~
+
+ *执行上面“报告仅在旧内核版本线中发生的问题”一节中的前三个步骤。*
+
+您需要执行本指南另一节中已经描述的几个步骤。这些步骤将让您:
+
+ * 检查内核开发人员是否仍然维护您关心的Linux内核版本行。
+
+ * 在Linux稳定邮件列表中搜索退出的报告。
+
+ * 检查最新版本。
+
+
+检查代码历史和搜索现有的讨论
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ *在Linux内核版本控制系统中搜索修复主线问题的更改,因为它的提交消息可能
+ 会告诉你修复是否已经计划好了支持。如果你没有找到,搜索适当的邮件列表,
+ 寻找讨论此类问题或同行评议可能修复的帖子;然后检查讨论是否认为修复不适
+ 合支持。如果支持根本不被考虑,加入最新的讨论,询问是否有可能。*
+
+在许多情况下,你所处理的问题会发生在主线上,但已在主线上得到了解决。修正它
+的提交也需要被回溯才能解决这个问题。这就是为什么你要搜索它或任何相关讨论。
+
+ * 首先尝试在存放 Linux 内核源代码的 Git 仓库中找到修复。你可以通过
+ `kernel.org 上的网页
+ <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/>`_
+ 或 `GitHub 上的镜像 <https://github.com/torvalds/linux>`_ 来实现;如果你
+ 有一个本地克隆,你也可以在命令行用 ``git log --grep=<pattern>`` 来搜索。
+
+ 如果你找到了修复,请查看提交消息的尾部是否包含了类似这样的“稳定版标签”:
+
+ Cc: <stable@vger.kernel.org> # 5.4+
+
+ 像上面这行,开发者标记了安全修复可以回传到 5.4 及以后的版本。大多数情况
+ 下,它会在两周内被应用到那里,但有时需要更长的时间。
+
+ * 如果提交没有告诉你任何东西,或者你找不到修复,请再找找关于这个问题的讨论。
+ 用你最喜欢的搜索引擎搜索网络,以及 `Linux kernel developers mailing
+ list 内核开发者邮件列表 <https://lore.kernel.org/lkml/>`_ 的档案。也可以
+ 阅读上面的 `定位导致问题的内核区域` 一节,然后按照说明找到导致问题的子系
+ 统:它的缺陷跟踪器或邮件列表存档中可能有你要找的答案。
+
+ * 如果你看到了一个计划的修复,请按上所述在版本控制系统中搜索它,因为提交可
+ 能会告诉你是否可以进行回溯。
+
+ * 检查讨论中是否有任何迹象表明,该修复程序可能风险太大,无法回溯到你关心
+ 的版本线。如果是这样的话,你必须忍受这个问题,或者切换到应用了修复的内
+ 核版本线。
+
+ * 如果修复的问题未包含稳定版标签,并且没有讨论过回溯问题,请加入讨论:如
+ 果合适的话,请提及你所面对的问题的版本,以及你希望看到它被修复。
+
+
+请求建议
+~~~~~~~~~
+
+ *前面的步骤之一应该会给出一个解决方案。如果仍未能成功,请向可能引起问题
+ 的子系统的维护人员询问建议;抄送特定子系统的邮件列表以及稳定版邮件列表。*
+
+如果前面的三个步骤都没有让你更接近解决方案,那么只剩下一个选择:请求建议。
+在你发给可能是问题根源的子系统的维护者的邮件中这样做;抄送子系统的邮件列表
+以及稳定版邮件列表(stable@vger.kernel.org)。
+
+
+为什么有些问题在报告后没有任何回应或仍未解决?
+===============================================
+
+当向 Linux 开发者报告问题时,要注意只有“高优先级的问题”(回归、安全问题、严
+重问题)才一定会得到解决。如果维护者或其他人都失败了,Linus Torvalds 他自己
+会确保这一点。他们和其他内核开发者也会解决很多其他问题。但是要知道,有时他
+们也会不能或不愿帮忙;有时甚至没有人发报告给他们。
+
+最好的解释就是那些内核开发者常常是在业余时间为 Linux 内核做出贡献。内核中的
+不少驱动程序都是由这样的程序员编写的,往往只是因为他们想让自己的硬件可以在
+自己喜欢的操作系统上使用。
+
+这些程序员大多数时候会很乐意修复别人报告的问题。但是没有人可以强迫他们这样
+做,因为他们是自愿贡献的。
+
+还有一些情况下,这些开发者真的很想解决一个问题,但却不能解决:有时他们缺乏
+硬件编程文档来解决问题。这种情况往往由于公开的文档太简陋,或者驱动程序是通
+过逆向工程编写的。
+
+业余开发者迟早也会不再关心某驱动。也许他们的测试硬件坏了,被更高级的玩意取
+代了,或者是太老了以至于只能在计算机博物馆里找到。有时开发者根本就不关心他
+们的代码和 Linux 了,因为在他们的生活中一些不同的东西变得更重要了。在某些情
+况下,没有人愿意接手维护者的工作——也没有人可以被强迫,因为对 Linux 内核的贡
+献是自愿的。然而被遗弃的驱动程序仍然存在于内核中:它们对人们仍然有用,删除
+它们可能导致回归。
+
+对于那些为 Linux 内核工作而获得报酬的开发者来说,情况并没有什么不同。这些人
+现在贡献了大部分的变更。但是他们的雇主迟早也会停止关注他们的代码或者让程序
+员专注于其他事情。例如,硬件厂商主要通过销售新硬件来赚钱;因此,他们中的不
+少人并没有投入太多时间和精力来维护他们多年前就停止销售的东西的 Linux 内核驱
+动。企业级 Linux 发行商往往持续维护的时间比较长,但在新版本中往往会把对老旧
+和稀有硬件的支持放在一边,以限制范围。一旦公司抛弃了一些代码,往往由业余贡
+献者接手,但正如上面提到的:他们迟早也会放下代码。
+
+优先级是一些问题没有被修复的另一个原因,因为维护者相当多的时候是被迫设置这
+些优先级的,因为在 Linux 上工作的时间是有限的。对于业余时间或者雇主给予他们
+的开发人员用于上游内核维护工作的时间也是如此。有时维护人员也会被报告淹没,
+即使一个驱动程序几乎完美地工作。为了不被完全缠住,程序员可能别无选择,只能
+对问题报告进行优先级排序而拒绝其中的一些报告。
+
+不过这些都不用太过担心,很多驱动都有积极的维护者,他们对尽可能多的解决问题
+相当感兴趣。
+
+
+结束语
+=======
+
+与其他免费/自由&开源软件(Free/Libre & Open Source Software,FLOSS)相比,
+向 Linux 内核开发者报告问题是很难的:这个文档的长度和复杂性以及字里行间的内
+涵都说明了这一点。但目前就是这样了。这篇文字的主要作者希望通过记录现状来为
+以后改善这种状况打下一些基础。
+
+
+..
+ end-of-content
+..
+ This English version of this document is maintained by Thorsten Leemhuis
+ <linux@leemhuis.info>. If you spot a typo or small mistake, feel free to
+ let him know directly and he'll fix it. For translation problems, please
+ contact with translators. You are free to do the same in a mostly informal
+ way if you want to contribute changes to the text, but for copyright
+ reasons please CC linux-doc@vger.kernel.org and "sign-off" your
+ contribution as Documentation/process/submitting-patches.rst outlines in
+ the section "Sign your work - the Developer's Certificate of Origin".
+..
+ This text is available under GPL-2.0+ or CC-BY-4.0, as stated at the top
+ of the file. If you want to distribute this text under CC-BY-4.0 only,
+ please use "The Linux kernel developers" for author attribution and link
+ this as source:
+ https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/Documentation/admin-guide/reporting-issues.rst
+..
+ Note: Only the content of this RST file as found in the Linux kernel sources
+ is available under CC-BY-4.0, as versions of this text that were processed
+ (for example by the kernel's build system) might contain content taken from
+ files which use a more restrictive license.
diff --git a/Documentation/translations/zh_CN/admin-guide/reporting-regressions.rst b/Documentation/translations/zh_CN/admin-guide/reporting-regressions.rst
new file mode 100644
index 000000000000..c0461ee855bc
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/reporting-regressions.rst
@@ -0,0 +1,370 @@
+.. SPDX-License-Identifier: (GPL-2.0+ OR CC-BY-4.0)
+.. 【重分发信息参见本文件结尾】
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/admin-guide/reporting-regressions.rst
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+
+============
+报告回归问题
+============
+
+“*我们拒绝出现回归*”是Linux内核开发的首要规则;Linux的发起者和领军开发者Linus
+Torvalds立下了此规则并确保它被落实。
+
+本文档描述了这条规则对用户的意义,以及Linux内核开发模型如何确保解决所有被报告
+的回归;关于内核开发者如何处理的方面参见 Documentation/process/handling-regressions.rst 。
+
+
+本文重点(亦即“太长不看”)
+==========================
+
+#. 如果某程序在原先的Linux内核上运行良好,但在较新版本上效果更差、或者根本不
+ 能用,那么你就碰见回归问题了。注意,新内核需要使用类似配置编译;更多相关细
+ 节参见下方。
+
+#. 按照 Documentation/translations/zh_CN/admin-guide/reporting-issues.rst 中
+ 所说的报告你的问题,该文档已经包含了所有关于回归的重要方面,为了方便起见也
+ 复制到了下面。两个重点:在报告主题中使用“[REGRESSION]”开头并抄送或转发到
+ `回归邮件列表 <https://lore.kernel.org/regressions/>`_
+ (regressions@lists.linux.dev)。
+
+#. 可选但是建议:在发送或转发报告时,指明该回归发生的起点,以便Linux内核回归
+ 追踪机器人“regzbot”可以追踪此问题::
+
+ #regzbot introduced v5.13..v5.14-rc1
+
+
+与用户相关的所有Linux内核回归细节
+=================================
+
+
+基本重点
+--------
+
+
+什么是“回归”以及什么是“无回归规则”?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+如果某程序/实例在原先的Linux内核上运行良好,但在较新版本上效果更差、或者根本
+不能用,那么你就碰见回归问题了。“无回归规则”不允许出现这种情况。如果偶然发
+生了,导致问题的开发者应当迅速修复问题。
+
+也就是说,若Linux 5.13中的WiFi驱动程序运行良好,但是在5.14版本上却不能用、速
+度明显变慢或出现错误,那就出现了回归。如果某正常工作的应用程序突然在新内核上
+出现不稳定,这也是回归;这些问题可能是由于procfs、sysfs或Linux提供给用户空间
+软件的许多其他接口之一的变化。但请记住,前述例子中的5.14需要使用类似于5.13的
+配置构建。这可以用 ``make olddefconfig`` 实现,详细解释见下。
+
+注意本节第一句话中的“实例”:即使开发者需要遵循“无回归”规则,但仍可自由地改
+变内核的任何方面,甚至是导出到用户空间的API或ABI,只要别破坏现有的应用程序或
+用例。
+
+还需注意,“无回归”规则只限制内核提供给用户空间的接口。它不适用于内核内部接
+口,比如一些外部开发的驱动程序用来插入钩子到内核的模块API。
+
+如何报告回归?
+~~~~~~~~~~~~~~
+
+只需按照 Documentation/translations/zh_CN/admin-guide/reporting-issues.rst 中
+所说的报告你的问题,该文档已经包含了要点。下面几点概述了一下只在回归中重要的
+方面:
+
+ * 在检查可加入讨论的现有报告时,别忘了搜索 `Linux回归邮件列表
+ <https://lore.kernel.org/regressions/>`_ 和 `regzbot网页界面
+ <https://linux-regtracking.leemhuis.info/regzbot/>`_ 。
+
+ * 在报告主题的开头加上“[REGRESSION]”。
+
+ * 在你的报告中明确最后一个正常工作的内核版本和首个出问题的版本。如若可能,
+ 用二分法尝试找出导致回归的变更,更多细节见下。
+
+ * 记得把报告发到Linux回归邮件列表(regressions@lists.linux.dev)。
+
+ * 如果通过邮件报告回归,请抄送回归列表。
+
+ * 如果你使用某些缺陷追踪器报告回归,请通过邮件转发已提交的报告到回归列表,
+ 并抄送维护者以及出问题的相关子系统的邮件列表。
+
+ 如果是稳定版或长期支持版系列(如v5.15.3…v5.15.5)的回归,请记得抄送
+ `Linux稳定版邮件列表 <https://lore.kernel.org/stable/>`_ (stable@vger.kernel.org)。
+
+ 如果你成功地执行了二分,请抄送肇事提交的信息中所有签了“Signed-off-by:”的人。
+
+在抄送你的报告到列表时,也请记得通知前述的Linux内核回归追踪机器人。只需在邮件
+中包含如下片段::
+
+ #regzbot introduced: v5.13..v5.14-rc1
+
+Regzbot会就将你的邮件视为在某个特定版本区间的回归报告。上例中即linux v5.13仍
+然正常,而Linux 5.14-rc1是首个您遇到问题的版本。如果你执行了二分以查找导致回
+归的提交,请使用指定肇事提交的id代替::
+
+ #regzbot introduced: 1f2e3d4c5d
+
+添加这样的“regzbot命令”对你是有好处的,它会确保报告不会被忽略。如果你省略了
+它,Linux内核的回归跟踪者会把你的回归告诉regzbot,只要你发送了一个副本到回归
+邮件列表。但是回归跟踪者只有一个人,有时不得不休息或甚至偶尔享受可以远离电脑
+的时光(听起来很疯狂)。因此,依赖此人手动将回归添加到 `已追踪且尚未解决的
+Linux内核回归列表 <https://linux-regtracking.leemhuis.info/regzbot/>`_ 和
+regzbot发送的每周回归报告,可能会出现延迟。 这样的延误会导致Linus Torvalds
+在决定“继续开发还是发布新版本?”时忽略严重的回归。
+
+真的修复了所有的回归吗?
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+几乎所有都是,只要引起问题的变更(肇事提交)被可靠定位。也有些回归可以不用这
+样,但通常是必须的。
+
+谁需要找出回归的根本原因?
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+受影响代码区域的开发者应该自行尝试定位问题所在。但仅靠他们的努力往往是不可
+能做到的,很多问题只发生在开发者的无法接触的其他特定外部环境中——例如特定的
+硬件平台、固件、Linux发行版、系统的配置或应用程序。这就是为什么最终往往是报
+告者定位肇事提交;有时用户甚至需要再运行额外测试以查明确切的根本原因。开发
+者应该提供建议和可能的帮助,以使普通用户更容易完成该流程。
+
+如何找到罪魁祸首?
+~~~~~~~~~~~~~~~~~~
+
+如 Documentation/translations/zh_CN/admin-guide/reporting-issues.rst (简要)
+和 Documentation/translations/zh_CN/admin-guide/bug-bisect.rst (详细)中所
+述,执行二分。听起来工作量很大,但大部分情况下很快就能找到罪魁祸首。如果这很
+困难或可靠地重现问题很耗时,请考虑与其他受影响的用户合作,一起缩小搜索范围。
+
+当出现回归时我可以向谁寻求建议?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+发送邮件到回归邮件列表(regressions@lists.linux.dev)同时抄送Linux内核的回归
+跟踪者(regressions@leemhuis.info);如果问题需要保密处理,可以省略列表。
+
+
+关于回归的更多细节
+------------------
+
+
+“无回归规则”的目标是什么?
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+用户应该放心升级内核版本,而不必担心有程序可能崩溃。这符合内核开发者的利益,
+可以使更新有吸引力:他们不希望用户停留在停止维护或超过一年半的稳定/长期Linux
+版本系列上。这也符合所有人的利益,因为 `那些系列可能含有已知的缺陷、安全问题
+或其他后续版本已经修复的问题
+<http://www.kroah.com/log/blog/2018/08/24/what-stable-kernel-should-i-use/>`_ 。
+此外,内核开发者希望使用户测试最新的预发行版或常规发行版变得简单而有吸引力。
+这同样符合所有人的利益,如果新版本出来后很快就有相关报告,会使追踪和修复问题
+更容易。
+
+实际中“无回归”规则真的可行吗?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+这不是句玩笑话,请见Linux创建者和主要开发人员Linus Torvalds在邮件列表中的许
+多发言,其中一些在 Documentation/process/handling-regressions.rst 中被引用。
+
+此规则的例外情况极为罕见;之前当开发者认为某个特定的情况有必要援引例外时,
+基本都被证明错了。
+
+谁来确保“无回归”被落实?
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+照看和支撑树的子系统维护者应该关心这一点——例如,Linus Torvalds之于主线,
+Greg Kroah-Hartman等人之于各种稳定/长期系列。
+
+他们都得到了别人的帮助,以确保回归报告不会被遗漏。其中之一是Thorsten
+Leemhuis,他目前担任Linux内核的“回归跟踪者”;为了做好这项工作,他使用了
+regzbot——Linux内核回归跟踪机器人。所以这就是为什么要抄送或转发你的报告到
+回归邮件列表来通知这些人,已经最好在你的邮件中包含“regzbot命令”来立即追踪它。
+
+回归通常多久能修复?
+~~~~~~~~~~~~~~~~~~~~
+
+开发者应该尽快修复任何被报告的回归,以提供及时为受影响的用户提供解决方案,并
+防止更多用户遇到问题;然而,开发人员需要花足够的时间和注意力确保回归修复不会
+造成额外的损害。
+
+因此,答案取决于各种因素,如回归的影响、存在时长或出现于哪个Linux版本系列。
+但最终,大多数的回归应该在两周内修复。
+
+当问题可以通过升级某些软件解决时,是回归吗?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+基本都是。如果开发人员告诉您其他情况,请咨询上述回归跟踪者。
+
+当新内核变慢或能耗增加,是回归吗?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+是的,但有一些差别。在微型基准测试中变慢5%不太可能被视为回归,除非它也会对
+广泛基准测试的结果产生超过1%的影响。如果有疑问,请寻求建议。
+
+当更新Linux时外部内核模块崩溃了,是回归吗?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+不,因为“无回归”规则仅限于Linux内核提供给用户空间的接口和服务。因此,它不包括
+构建或运行外部开发的内核模块,因为它们在内核空间中运行与挂进内核使用的内部接
+口偶尔会变化。
+
+如何处理安全修复引起的回归?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+在极为罕见的情况下,安全问题无法在不引起回归的情况下修复;这些修复都被放弃了,
+因为它们终究会引起问题。幸运的是这种两难境地基本都可以避免,受影响区域的主要
+开发者以及Linus Torvalds本人通常都会努力在不引入回归的情况下解决安全问题。
+
+如果你仍然面临此种情况,请查看邮件列表档案是否有人尽力避免过回归。如果没有,
+请报告它;如有疑问,请如上所述寻求建议。
+
+当修复回归时不可避免会引入另一个,如何处理?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+很遗憾这种事确实会出现,但幸运的是并不经常出现;如果发生了,受影响代码区的资
+深开发者应当调查该问题以找到避免回归的解决方法,至少避免它们的影响。如果你遇
+到这样的情况,如上所述:检查之前的讨论是否有人已经尽了最大努力,如有疑问请寻
+求建议。
+
+小提示:如果人们在每个开发周期中定期给出主线预发布(即v5.15-rc1或-rc3)以供
+测试,则可以避免这种情况。为了更好地解释,可以设想一个在Linux v5.14和v5.15-rc1
+之间集成的更改,该更改导致了回归,但同时是应用于5.15-rc1的其他改进的强依赖。
+如果有人在5.15发布之前就发现并报告了这个问题,那么所有更改都可以直接撤销,从
+而解决回归问题。而就在几天或几周后,此解决方案变成了不可能,因为一些软件可能
+已经开始依赖于后续更改之一:撤销所有更改将导致上述用户软件出现回归,这是不可
+接受的。
+
+若我所依赖的功能在数月前被移除了,是回归吗?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+是的,但如前节所述,通常很难修复此类回归。因此需要逐案处理。这也是定期测试主
+线预发布对所有人有好处的另一个原因。
+
+如果我似乎是唯一受影响的人,是否仍适用“无回归”规则?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+适用,但仅限于实际使用:Linux开发人员希望能够自由地取消那些只能在阁楼和博物
+馆中找到的硬件的支持。
+
+请注意,有时为了取得进展,不得不出现回归——后者也是防止Linux停滞不前所必需
+的。因此如果回归所影响的用户很少,那么为了他们和其他人更大的利益,还是让事情
+过去吧。尤其是存在某种规避回归的简单方法,例如更新一些软件或者使用专门为此目
+的创建的内核参数。
+
+回归规则是否也适用于staging树中的代码?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+不,参见 `适用于所有staging代码配置选项的帮助文本
+<https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/staging/Kconfig>`_ ,
+其早已声明::
+
+ 请注意:这些驱动正在积极开发中,可能无法正常工作,并可能包含会在不久的
+ 将来发生变化的用户接口。
+
+虽然staging开发人员通常坚持“无回归”的原则,但有时为了取得进展也会违背它。这就
+是为什么当staging树的WiFi驱动被基本推倒重来时,有些用户不得不处理回归(通常可
+以忽略)。
+
+为什么较新版本必须“使用相似配置编译”?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+因为Linux内核开发人员有时会集成已知的会导致回归的变更,但使它们成为可选的,并
+在内核的默认配置下禁用它们。这一技巧允许进步,否则“无回归”规则将导致停滞。
+
+例如,试想一个新的可以阻止恶意软件滥用某个内核的接口的安全特性,同时又需要满足
+另一个很罕见的应用程序。上述的方法可使两方都满意:使用这些应用程序的人可以关闭
+新的安全功能,而其他不会遇到麻烦的人可以启用它。
+
+如何创建与旧内核相似的配置?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+用一个已知良好的内核启动机器,并用 ``make olddefconfig`` 配置新版的Linux。这
+会让内核的构建脚本从正在运行的内核中摘录配置文件(“.config”文件),作为即将编
+译的新版本的基础配置;同时将所有新的配置选项设为默认值,以禁用可能导致回归的
+新功能。
+
+如何报告在预编译的普通内核中发现的回归?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+您需要确保新的内核是用与旧版相似的配置编译(见上文),因为那些构建它们的人可
+能启用了一些已知的与新内核不兼容的特性。如有疑问,请向内核的提供者报告问题并
+寻求建议。
+
+
+用“regzbot”追踪回归的更多信息
+-----------------------------
+
+什么是回归追踪?为啥我需要关心它?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+像“无回归”这样的规则需要有人来确保它们被遵守,否则会被有意/无意打破。历史证
+明了这一点对于Linux内核开发也适用。这就是为什么Linux内核的回归跟踪者Thorsten
+Leemhuis,,和另一些人尽力关注所有的回归直到他们解决。他们从未为此获得报酬,
+因此这项工作是在尽最大努力的基础上完成的。
+
+为什么/如何使用机器人追踪Linux内核回归?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+由于Linux内核开发过程的分布式和松散结构,完全手动跟踪回归已经被证明是相当困难
+的。因此Linux内核的回归跟踪者开发了regzbot来促进这项工作,其长期目标是尽可能为
+所有相关人员自动化回归跟踪。
+
+Regzbot通过监视跟踪的回归报告的回复来工作。此外,它还查找用“Link:”标签引用这
+些报告的补丁;对这些补丁的回复也会被跟踪。结合这些数据,可以很好地了解当前修
+复过程的状态。
+
+如何查看regzbot当前追踪的回归?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+参见 `regzbot在线 <https://linux-regtracking.leemhuis.info/regzbot/>`_ 。
+
+何种问题可以由regzbot追踪?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+该机器人只为了跟踪回归,因此请不要让regzbot涉及常规问题。但是对于Linux内核的
+回归跟踪者来说,让regzbot跟踪严重问题也可以,如有关挂起、损坏数据或内部错误
+(Panic、Oops、BUG()、warning…)的报告。
+
+如何修改被追踪回归的相关信息?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+在直接或间接回复报告邮件时使用“regzbot命令”即可。最简单的方法是:在“已发送”文
+件夹或邮件列表存档中找到报告,然后使用邮件客户端的“全部回复”功能对其进行回复。
+在该邮件中的独立段落中可使用以下命令之一(即使用空行将这些命令中的一个或多个与
+其余邮件文本分隔开)。
+
+ * 更新回归引入起点,例如在执行二分之后::
+
+ #regzbot introduced: 1f2e3d4c5d
+
+ * 设置或更新标题::
+
+ #regzbot title: foo
+
+ * 监视讨论或bugzilla.kernel.org上有关讨论或修复的工单::
+
+ #regzbot monitor: https://lore.kernel.org/r/30th.anniversary.repost@klaava.Helsinki.FI/
+ #regzbot monitor: https://bugzilla.kernel.org/show_bug.cgi?id=123456789
+
+ * 标记一个有更多相关细节的地方,例如有关但主题不同的邮件列表帖子或缺陷追踪器中的工单::
+
+ #regzbot link: https://bugzilla.kernel.org/show_bug.cgi?id=123456789
+
+ * 标记回归已失效::
+
+ #regzbot invalid: wasn't a regression, problem has always existed
+
+Regzbot还支持其他一些主要由开发人员或回归追踪人员使用的命令。命令的更多细节请
+参考 `入门指南 <https://gitlab.com/knurd42/regzbot/-/blob/main/docs/getting_started.md>`_
+和 `参考手册 <https://gitlab.com/knurd42/regzbot/-/blob/main/docs/reference.md>`_ 。
+
+..
+ 正文结束
+..
+ 如本文件开头所述,本文以GPL-2.0+或CC-BY-4.0许可发行。如您想仅在CC-BY-4.0许
+ 可下重分发本文,请用“Linux内核开发者”作为作者,并用如下链接作为来源:
+ https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/Documentation/translations/zh_CN/admin-guide/reporting-regressions.rst
+..
+ 注意:本RST文件内容只有在来自Linux内核源代码时是使用CC-BY-4.0许可的,因为经
+ 过处理的版本(如经内核的构建系统)可能包含来自使用更严格许可证的文件的内容。
diff --git a/Documentation/translations/zh_CN/admin-guide/security-bugs.rst b/Documentation/translations/zh_CN/admin-guide/security-bugs.rst
new file mode 100644
index 000000000000..d6b8f8a4e7f6
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/security-bugs.rst
@@ -0,0 +1,74 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: :doc:`../../../process/security-bugs`
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+安全缺陷
+=========
+
+Linux内核开发人员非常重视安全性。因此我们想知道何时发现了安全漏洞,以便尽快
+修复和披露。请向Linux内核安全团队报告安全漏洞。
+
+联络
+-----
+
+可以通过电子邮件<security@kernel.org>联系Linux内核安全团队。这是一个安全人员
+的私有列表,他们将帮助验证错误报告并开发和发布修复程序。如果您已经有了一个
+修复,请将其包含在您的报告中,这样可以大大加快进程。安全团队可能会从区域维护
+人员那里获得额外的帮助,以理解和修复安全漏洞。
+
+与任何缺陷一样,提供的信息越多,诊断和修复就越容易。如果您不清楚哪些信息有用,
+请查看“Documentation/translations/zh_CN/admin-guide/reporting-issues.rst”中
+概述的步骤。任何利用漏洞的攻击代码都非常有用,未经报告者同意不会对外发布,除
+非已经公开。
+
+请尽可能发送无附件的纯文本电子邮件。如果所有的细节都藏在附件里,那么就很难对
+一个复杂的问题进行上下文引用的讨论。把它想象成一个
+:doc:`常规的补丁提交 <../process/submitting-patches>` (即使你还没有补丁):
+描述问题和影响,列出复现步骤,然后给出一个建议的解决方案,所有这些都是纯文本的。
+
+披露和限制信息
+---------------
+
+安全列表不是公开渠道。为此,请参见下面的协作。
+
+一旦开发出了健壮的补丁,发布过程就开始了。对公开的缺陷的修复会立即发布。
+
+尽管我们倾向于在未公开缺陷的修复可用时即发布补丁,但应报告者或受影响方的请求,
+这可能会被推迟到发布过程开始后的7日内,如果根据缺陷的严重性需要更多的时间,
+则可额外延长到14天。推迟发布修复的唯一有效原因是为了适应QA的逻辑和需要发布
+协调的大规模部署。
+
+虽然可能与受信任的个人共享受限信息以开发修复,但未经报告者许可,此类信息不会
+与修复程序一起发布或发布在任何其他披露渠道上。这包括但不限于原始错误报告和
+后续讨论(如有)、漏洞、CVE信息或报告者的身份。
+
+换句话说,我们唯一感兴趣的是修复缺陷。提交给安全列表的所有其他资料以及对报告
+的任何后续讨论,即使在解除限制之后,也将永久保密。
+
+协调
+------
+
+对敏感缺陷(例如那些可能导致权限提升的缺陷)的修复可能需要与私有邮件列表
+<linux-distros@vs.openwall.org>进行协调,以便分发供应商做好准备,在公开披露
+上游补丁时发布一个已修复的内核。发行版将需要一些时间来测试建议的补丁,通常
+会要求至少几天的限制,而供应商更新发布更倾向于周二至周四。若合适,安全团队
+可以协助这种协调,或者报告者可以从一开始就包括linux发行版。在这种情况下,请
+记住在电子邮件主题行前面加上“[vs]”,如linux发行版wiki中所述:
+<http://oss-security.openwall.org/wiki/mailing-lists/distros#how-to-use-the-lists>。
+
+CVE分配
+--------
+
+安全团队通常不分配CVE,我们也不需要它们来进行报告或修复,因为这会使过程不必
+要的复杂化,并可能耽误缺陷处理。如果报告者希望在公开披露之前分配一个CVE编号,
+他们需要联系上述的私有linux-distros列表。当在提供补丁之前已有这样的CVE编号时,
+如报告者愿意,最好在提交消息中提及它。
+
+保密协议
+---------
+
+Linux内核安全团队不是一个正式的机构实体,因此无法签订任何保密协议。
diff --git a/Documentation/translations/zh_CN/admin-guide/sysrq.rst b/Documentation/translations/zh_CN/admin-guide/sysrq.rst
new file mode 100644
index 000000000000..8276d70f3b40
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/sysrq.rst
@@ -0,0 +1,280 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/admin-guide/sysrq.rst
+
+:翻译:
+
+ 黄军华 Junhua Huang <huang.junhua@zte.com.cn>
+
+:校译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_admin-guide_sysrq:
+
+Linux 魔法系统请求键骇客
+========================
+
+针对 sysrq.c 的文档说明
+
+什么是魔法 SysRq 键?
+~~~~~~~~~~~~~~~~~~~~~
+
+它是一个你可以输入的具有魔法般的组合键。
+无论内核在做什么,内核都会响应 SysRq 键的输入,除非内核完全卡死。
+
+如何使能魔法 SysRq 键?
+~~~~~~~~~~~~~~~~~~~~~~~
+
+在配置内核时,我们需要设置 'Magic SysRq key (CONFIG_MAGIC_SYSRQ)' 为 'Y'。
+当运行一个编译进 sysrq 功能的内核时,/proc/sys/kernel/sysrq 控制着被
+SysRq 键调用的功能许可。这个文件的默认值由 CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE
+配置符号设定,文件本身默认设置为 1。以下是 /proc/sys/kernel/sysrq 中可能的
+值列表:
+
+ - 0 - 完全不使能 SysRq 键
+ - 1 - 使能 SysRq 键的全部功能
+ - >1 - 对于允许的 SysRq 键功能的比特掩码(参见下面更详细的功能描述)::
+
+ 2 = 0x2 - 使能对控制台日志记录级别的控制
+ 4 = 0x4 - 使能对键盘的控制 (SAK, unraw)
+ 8 = 0x8 - 使能对进程的调试导出等
+ 16 = 0x10 - 使能同步命令
+ 32 = 0x20 - 使能重新挂载只读
+ 64 = 0x40 - 使能对进程的信号操作 (term, kill, oom-kill)
+ 128 = 0x80 - 允许重启、断电
+ 256 = 0x100 - 允许让所有实时任务变普通任务
+
+你可以通过如下命令把值设置到这个文件中::
+
+ echo "number" >/proc/sys/kernel/sysrq
+
+这里被写入的 number 可以是 10 进制数,或者是带着 0x 前缀的 16 进制数。
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE 必须是以 16 进制数写入。
+
+注意,``/proc/sys/kernel/sysrq`` 的值只影响通过键盘触发 SySRq 的调用,对于
+通过 ``/proc/sysrq-trigger`` 的任何操作调用都是允许的
+(通过具有系统权限的用户)。
+
+如何使用魔法 SysRq 键?
+~~~~~~~~~~~~~~~~~~~~~~~
+
+在 x86 架构上
+ 你可以按下键盘组合键 :kbd:`ALT-SysRq-<command key>`。
+
+ .. note::
+ 一些键盘可能没有标识 'SySRq' 键。'SySRq' 键也被当做 'Print Screen'键。
+ 同时有些键盘无法处理同时按下这么多键,因此你可以先按下键盘 :kbd:`Alt` 键,
+ 然后按下键盘 :kbd:`SysRq` 键,再释放键盘 :kbd:`SysRq` 键,之后按下键盘上命令键
+ :kbd:`<command key>`,最后释放所有键。
+
+在 SPARC 架构上
+ 你可以按下键盘组合键 :kbd:`ALT-STOP-<command key>` 。
+
+在串行控制台(只针对 PC 类型的标准串口)
+ 你可以发一个 ``BREAK`` ,然后在 5 秒内发送一个命令键,
+ 发送 ``BREAK`` 两次将被翻译为一个正常的 BREAK 操作。
+
+在 PowerPC 架构上
+ 按下键盘组合键 :kbd:`ALT - Print Screen` (或者 :kbd:`F13`) - :kbd:`<命令键>` 。
+ :kbd:`Print Screen` (或者 :kbd:`F13`) - :kbd:`<命令键>` 或许也能实现。
+
+在其他架构上
+ 如果你知道其他架构的组合键,请告诉我,我可以把它们添加到这部分。
+
+在所有架构上
+ 写一个字符到 /proc/sysrq-trigger 文件,例如::
+
+ echo t > /proc/sysrq-trigger
+
+这个命令键 :kbd:`<command key>` 是区分大小写的。
+
+什么是命令键?
+~~~~~~~~~~~~~~
+
+=========== ================================================================
+命令键 功能
+=========== ================================================================
+``b`` 将立即重启系统,不会同步或者卸载磁盘。
+
+``c`` 将执行系统 crash,如果配置了系统 crashdump,将执行 crashdump。
+
+``d`` 显示所有持有的锁。
+
+``e`` 发送 SIGTERM 信号给所有进程,除了 init 进程。
+
+``f`` 将调用 oom killer 杀掉一个过度占用内存的进程,如果什么任务都没杀,
+ 也不会 panic。
+
+``g`` kgdb 使用(内核调试器)。
+
+``h`` 将会显示帮助。(实际上除了这里列举的键,其他的都将显示帮助,
+ 但是 ``h`` 容易记住):-)
+
+``i`` 发送 SIGKILL 给所有进程,除了 init 进程。
+
+``j`` 强制性的 “解冻它” - 用于被 FIFREEZE ioctl 操作冻住的文件系统。
+
+``k`` 安全访问秘钥(SAK)杀掉在当前虚拟控制台的所有程序,注意:参考
+ 下面 SAK 节重要论述。
+
+``l`` 显示所有活动 cpu 的栈回溯。
+
+``m`` 将导出当前内存信息到你的控制台。
+
+``n`` 用于使所有实时任务变成普通任务。
+
+``o`` 将关闭系统(如果配置和支持的话)。
+
+``p`` 将导出当前寄存器和标志位到控制台。
+
+``q`` 将导出每个 cpu 上所有已装备的高精度定时器(不是完整的
+ time_list 文件显示的 timers)和所有时钟事件设备的详细信息。
+
+``r`` 关闭键盘的原始模式,设置为转换模式。
+
+``s`` 将尝试同步所有的已挂载文件系统。
+
+``t`` 将导出当前所有任务列表和它们的信息到控制台。
+
+``u`` 将尝试重新挂载已挂载文件系统为只读。
+
+``v`` 强制恢复帧缓存控制台。
+``v`` 触发 ETM 缓存导出 [ARM 架构特有]
+
+``w`` 导出处于不可中断状态(阻塞)的任务。
+
+``x`` 在 ppc/powerpc 架构上用于 xmon 接口。
+ 在 sparc64 架构上用于显示全局的 PMU(性能监控单元)寄存器。
+ 在 MIPS 架构上导出所有的 tlb 条目。
+
+``y`` 显示全局 cpu 寄存器 [SPARC-64 架构特有]
+
+``z`` 导出 ftrace 缓存信息
+
+``0``-``9`` 设置控制台日志级别,该级别控制什么样的内核信息将被打印到你的
+ 控制台。(比如 ``0`` ,将使得只有紧急信息,像 PANICs or OOPSes
+ 才能到你的控制台。)
+=========== ================================================================
+
+好了,我能用他们做什么呢?
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+嗯,当你的 X 服务端或者 svgalib 程序崩溃,unraw(r) 非原始模式命令键是非常
+方便的。
+
+sak(k)(安全访问秘钥)在你尝试登陆的同时,又想确保当前控制台没有可以获取你的
+密码的特洛伊木马程序运行时是有用的。它会杀掉给定控制台的所有程序,这样你
+就可以确认当前的登陆提示程序是实际来自 init 进程的程序,而不是某些特洛伊
+木马程序。
+
+.. important::
+
+ 在其实际的形式中,在兼容 C2 安全标准的系统上,它不是一个真正的 SAK,
+ 它也不应该误认为此。
+
+似乎其他人发现其可以作为(系统终端联机键)当你想退出一个程序,
+同时不会让你切换控制台的方法。(比如,X 服务端或者 svgalib 程序)
+
+``reboot(b)`` 是个好方法,当你不能关闭机器时,它等同于按下"复位"按钮。
+
+``crash(c)`` 可以用于手动触发一个 crashdump,当系统卡住时。
+注意当 crashdump 机制不可用时,这个只是触发一个内核 crash。
+
+``sync(s)`` 在拔掉可移动介质之前,或者在使用不提供优雅关机的
+救援 shell 之后很方便 -- 它将确保你的数据被安全地写入磁盘。注意,在你看到
+屏幕上出现 "OK" 和 "Done" 之前,同步还没有发生。
+
+``umount(u)`` 可以用来标记文件系统正常卸载,从正在运行的系统角度来看,它们将
+被重新挂载为只读。这个重新挂载动作直到你看到 "OK" 和 "Done" 信息出现在屏幕上
+才算完成。
+
+日志级别 ``0`` - ``9`` 用于当你的控制台被大量的内核信息冲击,你不想看见的时候。
+选择 ``0`` 将禁止除了最紧急的内核信息外的所有的内核信息输出到控制台。(但是如果
+syslogd/klogd 进程是运行的,它们仍将被记录。)
+
+``term(e)`` 和 ``kill(i)`` 用于当你有些有点失控的进程,你无法通过其他方式杀掉
+它们的时候,特别是它正在创建其他进程。
+
+"just thaw ``it(j)`` " 用于当你的系统由于一个 FIFREEZE ioctl 调用而产生的文件
+系统冻结,而导致的不响应时。
+
+有的时候 SysRq 键在使用它之后,看起来像是“卡住”了,我能做些什么?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+这也会发生在我这,我发现轻敲键盘两侧的 shift、alt 和 control 键,然后再次敲击
+一个无效的 SysRq 键序列可以解决问题。(比如,像键盘组合键 :kbd:`alt-sysrq-z` )
+切换到另一个虚拟控制台(键盘操作 :kbd:`ALT+Fn` ),然后再切回来应该也有帮助。
+
+我敲击了 SysRq 键,但像是什么都没发生,发生了什么错误?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+有一些键盘对于 SysRq 键设置了不同的键值,而不是提前定义的 99
+(查看在 ``include/uapi/linux/input-event-codes.h`` 文件中 ``KEY_SYSRQ`` 的定义)
+或者就根本没有 SysRq 键。在这些场景下,执行 ``showkey -s`` 命令来找到一个合适
+的扫描码序列,然后使用 ``setkeycodes <sequence> 99`` 命令映射这个序列值到通用
+的 SysRq 键编码上(比如 ``setkeycodes e05b 99`` )。最好将这个命令放在启动脚本
+中。
+哦,顺便说一句,你十秒钟不输入任何东西就将退出 “showkey”。
+
+我想添加一个 SysRq 键事件到一个模块中,如何去做呢?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+为了注册一个基础函数到这个表中,首先你必须包含 ``include/linux/sysrq.h`` 头
+文件,这个头文件定义了你所需要的所有东西。然后你必须创建一个 ``sysrq_key_op``
+结构体,然后初始化它,使用如下内容,A) 你将使用的这个键的处理函数, B) 一个
+help_msg 字符串,在 SysRq 键打印帮助信息时将打印出来,C) 一个 action_msg 字
+符串,就在你的处理函数调用前打印出来。你的处理函数必须符合在 'sysrq.h' 文件中
+的函数原型。
+
+在 ``sysrq_key_op`` 结构体被创建后,你可以调用内核函数
+``register_sysrq_key(int key, const struct sysrq_key_op *op_p);``,
+该函数在表中的 'key' 对应位置内容是空的情况下,将通过 ``op_p`` 指针注册这个操作
+函数到表中 'key' 对应位置上。在模块卸载的时候,你必须调用
+``unregister_sysrq_key(int key, const struct sysrq_key_op *op_p)`` 函数,该函数
+只有在当前该键对应的处理函数被注册到了 'key' 对应位置时,才会移除 'op_p' 指针
+对应的键值操作函数。这是为了防止在你注册之后,该位置被改写的情况。
+
+魔法 SysRq 键系统的工作原理是将键对应操作函数注册到键的操作查找表,
+该表定义在 'drivers/tty/sysrq.c' 文件中。
+该键表有许多在编译时候就注册进去的操作函数,但是是可变的。
+并且有两个函数作为操作该表的接口被导出::
+
+ register_sysrq_key 和 unregister_sysrq_key.
+
+当然,永远不要在表中留下无效指针,即,当你的模块存在调用 register_sysrq_key()
+函数,它一定要调用 unregister_sysrq_key() 来清除它使用过的 SysRq 键表条目。
+表中的空指针是安全的。:)
+
+如果对于某种原因,在 handle_sysrq 调用的处理函数中,你认为有必要调用
+handle_sysrq 函数时,你必须意识到当前你处于一个锁中(你同时也处于一个中断处理
+函数中,这意味着不能睡眠)。所以这时你必须使用 ``__handle_sysrq_nolock`` 替代。
+
+当我敲击一个 SysRq 组合键时,只有标题打印出现在控制台?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+SysRq 键的输出和所有其他控制台输出一样,受制于控制台日志级别控制。
+这意味着,如果内核以发行版内核中常见的 "quiet" 方式启动,则输出可能不会出现在实际
+的控制台上,即使它会出现在 dmesg 缓存中,也可以通过 dmesg 命令和 ``/proc/kmsg``
+文件的消费访问到。作为一个特例,来自 sysrq 命令的标题行将被传递给所有控制台
+使用者,就好像当前日志级别是最大的一样。如果只发出标题头,则几乎可以肯定内核日志
+级别太低。如果你需要控制台上的输出,那么你将需要临时提高控制台日志级别,通过使用
+键盘组合键 :kbd:`alt-sysrq-8` 或者::
+
+ echo 8 > /proc/sysrq-trigger
+
+在触发了你感兴趣的 SysRq 键命令后,记得恢复日志级别到正常情况。
+
+我有很多问题时,可以请教谁?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+请教在内核邮件列表上的人,邮箱:
+ linux-kernel@vger.kernel.org
+
+致谢
+~~~~
+
+- Mydraal <vulpyne@vulpyne.net> 撰写了该文件
+- Adam Sulmicki <adam@cfar.umd.edu> 进行了更新
+- Jeremy M. Dolan <jmd@turbogeek.org> 在 2001/01/28 10:15:59 进行了更新
+- Crutcher Dunnavant <crutcher+kernel@datastacks.com> 添加键注册部分
diff --git a/Documentation/translations/zh_CN/admin-guide/tainted-kernels.rst b/Documentation/translations/zh_CN/admin-guide/tainted-kernels.rst
new file mode 100644
index 000000000000..bc51d7cff9b0
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/tainted-kernels.rst
@@ -0,0 +1,157 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: :doc:`../../../admin-guide/tainted-kernels`
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+受污染的内核
+-------------
+
+当发生一些在稍后调查问题时可能相关的事件时,内核会将自己标记为“受污染
+(tainted)”的。不用太过担心,大多数情况下运行受污染的内核没有问题;这些信息
+主要在有人想调查某个问题时才有意义的,因为问题的真正原因可能是导致内核受污染
+的事件。这就是为什么来自受污染内核的缺陷报告常常被开发人员忽略,因此请尝试用
+未受污染的内核重现问题。
+
+请注意,即使在您消除导致污染的原因(亦即卸载专有内核模块)之后,内核仍将保持
+污染状态,以表示内核仍然不可信。这也是为什么内核在注意到内部问题(“kernel
+bug”)、可恢复错误(“kernel oops”)或不可恢复错误(“kernel panic”)时会打印
+受污染状态,并将有关此的调试信息写入日志 ``dmesg`` 输出。也可以通过
+``/proc/`` 中的文件在运行时检查受污染的状态。
+
+
+BUG、Oops或Panics消息中的污染标志
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+在顶部以“CPU:”开头的一行中可以找到受污染的状态;内核是否受到污染和原因会显示
+在进程ID(“PID:”)和触发事件命令的缩写名称(“Comm:”)之后::
+
+ BUG: unable to handle kernel NULL pointer dereference at 0000000000000000
+ Oops: 0002 [#1] SMP PTI
+ CPU: 0 PID: 4424 Comm: insmod Tainted: P W O 4.20.0-0.rc6.fc30 #1
+ Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011
+ RIP: 0010:my_oops_init+0x13/0x1000 [kpanic]
+ [...]
+
+如果内核在事件发生时没有被污染,您将在那里看到“Not-tainted:”;如果被污染,那
+么它将是“Tainted:”以及字母或空格。在上面的例子中,它看起来是这样的::
+
+ Tainted: P W O
+
+下表解释了这些字符的含义。在本例中,由于加载了专有模块( ``P`` ),出现了
+警告( ``W`` ),并且加载了外部构建的模块( ``O`` ),所以内核早些时候受到
+了污染。要解码其他字符,请使用下表。
+
+
+解码运行时的污染状态
+~~~~~~~~~~~~~~~~~~~~~
+
+在运行时,您可以通过读取 ``cat /proc/sys/kernel/tainted`` 来查询受污染状态。
+如果返回 ``0`` ,则内核没有受到污染;任何其他数字都表示受到污染的原因。解码
+这个数字的最简单方法是使用脚本 ``tools/debugging/kernel-chktaint`` ,您的
+发行版可能会将其作为名为 ``linux-tools`` 或 ``kernel-tools`` 的包的一部分提
+供;如果没有,您可以从
+`git.kernel.org <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/tools/debugging/kernel-chktaint>`_
+网站下载此脚本并用 ``sh kernel-chktaint`` 执行,它会在上面引用的日志中有类似
+语句的机器上打印这样的内容::
+
+ Kernel is Tainted for following reasons:
+ * Proprietary module was loaded (#0)
+ * Kernel issued warning (#9)
+ * Externally-built ('out-of-tree') module was loaded (#12)
+ See Documentation/admin-guide/tainted-kernels.rst in the Linux kernel or
+ https://www.kernel.org/doc/html/latest/admin-guide/tainted-kernels.html for
+ a more details explanation of the various taint flags.
+ Raw taint value as int/string: 4609/'P W O '
+
+你也可以试着自己解码这个数字。如果内核被污染的原因只有一个,那么这很简单,
+在本例中您可以通过下表找到数字。如果你需要解码有多个原因的数字,因为它是一
+个位域(bitfield),其中每个位表示一个特定类型的污染的存在或不存在,最好让
+前面提到的脚本来处理。但是如果您需要快速看一下,可以使用这个shell命令来检查
+设置了哪些位::
+
+ $ for i in $(seq 18); do echo $(($i-1)) $(($(cat /proc/sys/kernel/tainted)>>($i-1)&1));done
+
+污染状态代码表
+~~~~~~~~~~~~~~~
+
+=== ===== ====== ========================================================
+ 位 日志 数字 内核被污染的原因
+=== ===== ====== ========================================================
+ 0 G/P 1 已加载专用模块
+ 1 _/F 2 模块被强制加载
+ 2 _/S 4 内核运行在不合规范的系统上
+ 3 _/R 8 模块被强制卸载
+ 4 _/M 16 处理器报告了机器检测异常(MCE)
+ 5 _/B 32 引用了错误的页或某些意外的页标志
+ 6 _/U 64 用户空间应用程序请求的污染
+ 7 _/D 128 内核最近死机了,即曾出现OOPS或BUG
+ 8 _/A 256 ACPI表被用户覆盖
+ 9 _/W 512 内核发出警告
+ 10 _/C 1024 已加载staging驱动程序
+ 11 _/I 2048 已应用平台固件缺陷的解决方案
+ 12 _/O 4096 已加载外部构建(“树外”)模块
+ 13 _/E 8192 已加载未签名的模块
+ 14 _/L 16384 发生软锁定
+ 15 _/K 32768 内核已实时打补丁
+ 16 _/X 65536 备用污染,为发行版定义并使用
+ 17 _/T 131072 内核是用结构随机化插件构建的
+=== ===== ====== ========================================================
+
+注:字符 ``_`` 表示空白,以便于阅读表。
+
+污染的更详细解释
+~~~~~~~~~~~~~~~~~
+
+ 0) ``G`` 加载的所有模块都有GPL或兼容许可证, ``P`` 加载了任何专有模块。
+ 没有MODULE_LICENSE(模块许可证)或MODULE_LICENSE未被insmod认可为GPL
+ 兼容的模块被认为是专有的。
+
+
+ 1) ``F`` 任何模块被 ``insmod -f`` 强制加载, ``' '`` 所有模块正常加载。
+
+ 2) ``S`` 内核运行在不合规范的处理器或系统上:硬件已运行在不受支持的配置中,
+ 因此无法保证正确执行。内核将被污染,例如:
+
+ - 在x86上:PAE是通过intel CPU(如Pentium M)上的forcepae强制执行的,这些
+ CPU不报告PAE,但可能有功能实现,SMP内核在非官方支持的SMP Athlon CPU上
+ 运行,MSR被暴露到用户空间中。
+ - 在arm上:在某些CPU(如Keystone 2)上运行的内核,没有启用某些内核特性。
+ - 在arm64上:CPU之间存在不匹配的硬件特性,引导加载程序以不同的模式引导CPU。
+ - 某些驱动程序正在被用在不受支持的体系结构上(例如x86_64以外的其他系统
+ 上的scsi/snic,非x86/x86_64/itanium上的scsi/ips,已经损坏了arm64上
+ irqchip/irq-gic的固件设置…)。
+
+ 3) ``R`` 模块被 ``rmmod -f`` 强制卸载, ``' '`` 所有模块都正常卸载。
+
+ 4) ``M`` 任何处理器报告了机器检测异常, ``' '`` 未发生机器检测异常。
+
+ 5) ``B`` 页面释放函数发现错误的页面引用或某些意外的页面标志。这表示硬件问题
+ 或内核错误;日志中应该有其他信息指示发生此污染的原因。
+
+ 6) ``U`` 用户或用户应用程序特意请求设置受污染标志,否则应为 ``' '`` 。
+
+ 7) ``D`` 内核最近死机了,即出现了OOPS或BUG。
+
+ 8) ``A`` ACPI表被重写。
+
+ 9) ``W`` 内核之前已发出过警告(尽管有些警告可能会设置更具体的污染标志)。
+
+ 10) ``C`` 已加载staging驱动程序。
+
+ 11) ``I`` 内核正在处理平台固件(BIOS或类似软件)中的严重错误。
+
+ 12) ``O`` 已加载外部构建(“树外”)模块。
+
+ 13) ``E`` 在支持模块签名的内核中加载了未签名的模块。
+
+ 14) ``L`` 系统上先前发生过软锁定。
+
+ 15) ``K`` 内核已经实时打了补丁。
+
+ 16) ``X`` 备用污染,由Linux发行版定义和使用。
+
+ 17) ``T`` 内核构建时使用了randstruct插件,它可以有意生成非常不寻常的内核结构
+ 布局(甚至是性能病态的布局),这在调试时非常有用。于构建时设置。
diff --git a/Documentation/translations/zh_CN/admin-guide/unicode.rst b/Documentation/translations/zh_CN/admin-guide/unicode.rst
new file mode 100644
index 000000000000..b0b08d2b6eb7
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/unicode.rst
@@ -0,0 +1,170 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/admin-guide/unicode.rst
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+Unicode(统一码)支持
+======================
+
+ (英文版)上次更新:2005-01-17,版本号 1.4
+
+此文档由H. Peter Anvin <unicode@lanana.org>管理,是Linux注册名称与编号管理局
+(Linux Assigned Names And Numbers Authority,LANANA)项目的一部分。
+现行版本请见:
+
+ http://www.lanana.org/docs/unicode/admin-guide/unicode.rst
+
+简介
+-----
+
+Linux内核代码已被重写以使用Unicode来将字符映射到字体。下载一个Unicode到字体
+(Unicode-to-font)表,八位字符集与UTF-8模式都将改用此字体来显示。
+
+这微妙地改变了八位字符表的语义。现在的四个字符表是:
+
+=============== =============================== ================
+映射代号 映射名称 Escape代码 (G0)
+=============== =============================== ================
+LAT1_MAP Latin-1 (ISO 8859-1) ESC ( B
+GRAF_MAP DEC VT100 pseudographics ESC ( 0
+IBMPC_MAP IBM code page 437 ESC ( U
+USER_MAP User defined ESC ( K
+=============== =============================== ================
+
+特别是 ESC ( U 不再是“直通字体”,因为字体可能与IBM字符集完全不同。
+例如,即使加载了一个Latin-1字体,也允许使用块图形(block graphics)。
+
+请注意,尽管这些代码与ISO 2022类似,但这些代码及其用途都与ISO 2022不匹配;
+Linux有两个八位代码(G0和G1),而ISO 2022有四个七位代码(G0-G3)。
+
+根据Unicode标准/ISO 10646,U+F000到U+F8FF被保留用于操作系统范围内的分配
+(Unicode标准将其称为“团体区域(Corporate Zone)”,因为这对于Linux是不准确
+的,所以我们称之为“Linux区域”)。选择U+F000作为起点,因为它允许直接映射
+区域以2的大倍数开始(以防需要1024或2048个字符的字体)。这就留下U+E000到
+U+EFFF作为最终用户区。
+
+[v1.2]:Unicodes范围从U+F000到U+F7FF已经被硬编码为直接映射到加载的字体,
+绕过了翻译表。用户定义的映射现在默认为U+F000到U+F0FF,模拟前述行为。实际上,
+此范围可能较短;例如,vgacon只能处理256字符(U+F000..U+F0FF)或512字符
+(U+F000..U+F1FF)字体。
+
+Linux 区域中定义的实际字符
+---------------------------
+
+此外,还定义了Unicode 1.1.4中不存在的以下字符;这些字符由DEC VT图形映射使用。
+[v1.2]此用法已过时,不应再使用;请参见下文。
+
+====== ======================================
+U+F800 DEC VT GRAPHICS HORIZONTAL LINE SCAN 1
+U+F801 DEC VT GRAPHICS HORIZONTAL LINE SCAN 3
+U+F803 DEC VT GRAPHICS HORIZONTAL LINE SCAN 7
+U+F804 DEC VT GRAPHICS HORIZONTAL LINE SCAN 9
+====== ======================================
+
+DEC VT220使用6x10字符矩阵,这些字符在DEC VT图形字符集中形成一个平滑的过渡。
+我省略了扫描5行,因为它也被用作块图形字符,因此被编码为U+2500 FORMS LIGHT
+HORIZONTAL。
+
+[v1.3]:这些字符已正式添加到Unicode 3.2.0中;它们在U+23BA、U+23BB、U+23BC、
+U+23BD处添加。Linux现在使用新值。
+
+[v1.2]:添加了以下字符来表示常见的键盘符号,这些符号不太可能被添加到Unicode
+中,因为它们非常讨厌地取决于特定供应商。当然,这是糟糕设计的一个好例子。
+
+====== ======================================
+U+F810 KEYBOARD SYMBOL FLYING FLAG
+U+F811 KEYBOARD SYMBOL PULLDOWN MENU
+U+F812 KEYBOARD SYMBOL OPEN APPLE
+U+F813 KEYBOARD SYMBOL SOLID APPLE
+====== ======================================
+
+克林贡(Klingon)语支持
+------------------------
+
+1996年,Linux是世界上第一个添加对人工语言克林贡支持的操作系统,克林贡是由
+Marc Okrand为《星际迷航》电视连续剧创造的。这种编码后来被征募Unicode注册表
+(ConScript Unicode Registry,CSUR)采用,并建议(但最终被拒绝)纳入Unicode
+平面一。不过,它仍然是Linux区域中的Linux/CSUR私有分配。
+
+这种编码已经得到克林贡语言研究所(Klingon Language Institute)的认可。
+有关更多信息,请联系他们:
+
+ http://www.kli.org/
+
+由于Linux CZ开头部分的字符大多是dingbats/symbols/forms类型,而且这是一种
+语言,因此根据标准Unicode惯例,我将它放置在16单元的边界上。
+
+.. note::
+
+ 这个范围现在由征募Unicode注册表正式管理。规范性引用文件为:
+
+ https://www.evertype.com/standards/csur/klingon.html
+
+克林贡语有一个26个字符的字母表,一个10位数的位置数字书写系统,从左到右
+,从上到下书写。
+
+克林贡字母的几种字形已经被提出。但是由于这组符号看起来始终是一致的,只有实际
+的形状不同,因此按照标准Unicode惯例,这些差异被认为是字体变体。
+
+====== =======================================================
+U+F8D0 KLINGON LETTER A
+U+F8D1 KLINGON LETTER B
+U+F8D2 KLINGON LETTER CH
+U+F8D3 KLINGON LETTER D
+U+F8D4 KLINGON LETTER E
+U+F8D5 KLINGON LETTER GH
+U+F8D6 KLINGON LETTER H
+U+F8D7 KLINGON LETTER I
+U+F8D8 KLINGON LETTER J
+U+F8D9 KLINGON LETTER L
+U+F8DA KLINGON LETTER M
+U+F8DB KLINGON LETTER N
+U+F8DC KLINGON LETTER NG
+U+F8DD KLINGON LETTER O
+U+F8DE KLINGON LETTER P
+U+F8DF KLINGON LETTER Q
+ - Written <q> in standard Okrand Latin transliteration
+U+F8E0 KLINGON LETTER QH
+ - Written <Q> in standard Okrand Latin transliteration
+U+F8E1 KLINGON LETTER R
+U+F8E2 KLINGON LETTER S
+U+F8E3 KLINGON LETTER T
+U+F8E4 KLINGON LETTER TLH
+U+F8E5 KLINGON LETTER U
+U+F8E6 KLINGON LETTER V
+U+F8E7 KLINGON LETTER W
+U+F8E8 KLINGON LETTER Y
+U+F8E9 KLINGON LETTER GLOTTAL STOP
+
+U+F8F0 KLINGON DIGIT ZERO
+U+F8F1 KLINGON DIGIT ONE
+U+F8F2 KLINGON DIGIT TWO
+U+F8F3 KLINGON DIGIT THREE
+U+F8F4 KLINGON DIGIT FOUR
+U+F8F5 KLINGON DIGIT FIVE
+U+F8F6 KLINGON DIGIT SIX
+U+F8F7 KLINGON DIGIT SEVEN
+U+F8F8 KLINGON DIGIT EIGHT
+U+F8F9 KLINGON DIGIT NINE
+
+U+F8FD KLINGON COMMA
+U+F8FE KLINGON FULL STOP
+U+F8FF KLINGON SYMBOL FOR EMPIRE
+====== =======================================================
+
+其他虚构和人工字母
+-------------------
+
+自从分配了克林贡Linux Unicode块之后,John Cowan <jcowan@reutershealth.com>
+和 Michael Everson <everson@evertype.com> 建立了一个虚构和人工字母的注册表。
+征募Unicode注册表请访问:
+
+ https://www.evertype.com/standards/csur/
+
+所使用的范围位于最终用户区域的低端,因此无法进行规范化分配,但建议希望对虚构
+字母进行编码的人员使用这些代码,以实现互操作性。对于克林贡语,CSUR采用了Linux
+编码。CSUR的人正在推动将Tengwar和Cirth添加到Unicode平面一;将克林贡添加到
+Unicode平面一被拒绝,因此上述编码仍然是官方的。
diff --git a/Documentation/translations/zh_CN/arm/Booting b/Documentation/translations/zh_CN/arch/arm/Booting
index 562e9a2957e6..f18585156b67 100644
--- a/Documentation/translations/zh_CN/arm/Booting
+++ b/Documentation/translations/zh_CN/arch/arm/Booting
@@ -1,4 +1,4 @@
-Chinese translated version of Documentation/arm/booting.rst
+Chinese translated version of Documentation/arch/arm/booting.rst
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
@@ -9,7 +9,7 @@ or if there is a problem with the translation.
Maintainer: Russell King <linux@arm.linux.org.uk>
Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
---------------------------------------------------------------------
-Documentation/arm/booting.rst 的中文翻译
+Documentation/arch/arm/booting.rst 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
@@ -124,7 +124,7 @@ bootloader 必须传递一个系统内存的位置和最小值,以及根文件
bootloader 必须以 64bit 地址对齐的形式加载一个设备树映像(dtb)到系统
RAM 中,并用启动数据初始化它。dtb 格式在文档
-Documentation/devicetree/booting-without-of.txt 中。内核将会在
+https://www.devicetree.org/specifications/ 中。内核将会在
dtb 物理地址处查找 dtb 魔数值(0xd00dfeed),以确定 dtb 是否已经代替
标签列表被传递进来。
diff --git a/Documentation/translations/zh_CN/arm/kernel_user_helpers.txt b/Documentation/translations/zh_CN/arch/arm/kernel_user_helpers.txt
index 99af4363984d..018eb7d54233 100644
--- a/Documentation/translations/zh_CN/arm/kernel_user_helpers.txt
+++ b/Documentation/translations/zh_CN/arch/arm/kernel_user_helpers.txt
@@ -1,4 +1,4 @@
-Chinese translated version of Documentation/arm/kernel_user_helpers.rst
+Chinese translated version of Documentation/arch/arm/kernel_user_helpers.rst
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
@@ -10,7 +10,7 @@ Maintainer: Nicolas Pitre <nicolas.pitre@linaro.org>
Dave Martin <dave.martin@linaro.org>
Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
---------------------------------------------------------------------
-Documentation/arm/kernel_user_helpers.rst 的中文翻译
+Documentation/arch/arm/kernel_user_helpers.rst 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
diff --git a/Documentation/translations/zh_CN/arch/arm64/amu.rst b/Documentation/translations/zh_CN/arch/arm64/amu.rst
new file mode 100644
index 000000000000..f8e09fd21ef5
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/arm64/amu.rst
@@ -0,0 +1,100 @@
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: :ref:`Documentation/arch/arm64/amu.rst <amu_index>`
+
+Translator: Bailu Lin <bailu.lin@vivo.com>
+
+==================================
+AArch64 Linux 中扩展的活动监控单元
+==================================
+
+作者: Ionela Voinescu <ionela.voinescu@arm.com>
+
+日期: 2019-09-10
+
+本文档简要描述了 AArch64 Linux 支持的活动监控单元的规范。
+
+
+架构总述
+--------
+
+活动监控是 ARMv8.4 CPU 架构引入的一个可选扩展特性。
+
+活动监控单元(在每个 CPU 中实现)为系统管理提供了性能计数器。既可以通
+过系统寄存器的方式访问计数器,同时也支持外部内存映射的方式访问计数器。
+
+AMUv1 架构实现了一个由4个固定的64位事件计数器组成的计数器组。
+
+ - CPU 周期计数器:同 CPU 的频率增长
+ - 常量计数器:同固定的系统时钟频率增长
+ - 淘汰指令计数器: 同每次架构指令执行增长
+ - 内存停顿周期计数器:计算由在时钟域内的最后一级缓存中未命中而引起
+ 的指令调度停顿周期数
+
+当处于 WFI 或者 WFE 状态时,计数器不会增长。
+
+AMU 架构提供了一个高达16位的事件计数器空间,未来新的 AMU 版本中可能
+用它来实现新增的事件计数器。
+
+另外,AMUv1 实现了一个多达16个64位辅助事件计数器的计数器组。
+
+冷复位时所有的计数器会清零。
+
+
+基本支持
+--------
+
+内核可以安全地运行在支持 AMU 和不支持 AMU 的 CPU 组合中。
+因此,当配置 CONFIG_ARM64_AMU_EXTN 后我们无条件使能后续
+(secondary or hotplugged) CPU 检测和使用这个特性。
+
+当在 CPU 上检测到该特性时,我们会标记为特性可用但是不能保证计数器的功能,
+仅表明有扩展属性。
+
+固件(代码运行在高异常级别,例如 arm-tf )需支持以下功能:
+
+ - 提供低异常级别(EL2 和 EL1)访问 AMU 寄存器的能力。
+ - 使能计数器。如果未使能,它的值应为 0。
+ - 在从电源关闭状态启动 CPU 前或后保存或者恢复计数器。
+
+当使用使能了该特性的内核启动但固件损坏时,访问计数器寄存器可能会遭遇
+panic 或者死锁。即使未发现这些症状,计数器寄存器返回的数据结果并不一
+定能反映真实情况。通常,计数器会返回 0,表明他们未被使能。
+
+如果固件没有提供适当的支持最好关闭 CONFIG_ARM64_AMU_EXTN。
+值得注意的是,出于安全原因,不要绕过 AMUSERRENR_EL0 设置而捕获从
+EL0(用户空间) 访问 EL1(内核空间)。 因此,固件应该确保访问 AMU寄存器
+不会困在 EL2或EL3。
+
+AMUv1 的固定计数器可以通过如下系统寄存器访问:
+
+ - SYS_AMEVCNTR0_CORE_EL0
+ - SYS_AMEVCNTR0_CONST_EL0
+ - SYS_AMEVCNTR0_INST_RET_EL0
+ - SYS_AMEVCNTR0_MEM_STALL_EL0
+
+特定辅助计数器可以通过 SYS_AMEVCNTR1_EL0(n) 访问,其中n介于0到15。
+
+详细信息定义在目录:arch/arm64/include/asm/sysreg.h。
+
+
+用户空间访问
+------------
+
+由于以下原因,当前禁止从用户空间访问 AMU 的寄存器:
+
+ - 安全因数:可能会暴露处于安全模式执行的代码信息。
+ - 意愿:AMU 是用于系统管理的。
+
+同样,该功能对用户空间不可见。
+
+
+虚拟化
+------
+
+由于以下原因,当前禁止从 KVM 客户端的用户空间(EL0)和内核空间(EL1)
+访问 AMU 的寄存器:
+
+ - 安全因数:可能会暴露给其他客户端或主机端执行的代码信息。
+
+任何试图访问 AMU 寄存器的行为都会触发一个注册在客户端的未定义异常。
diff --git a/Documentation/translations/zh_CN/arm64/booting.txt b/Documentation/translations/zh_CN/arch/arm64/booting.txt
index 5b0164132c71..630eb32a8854 100644
--- a/Documentation/translations/zh_CN/arm64/booting.txt
+++ b/Documentation/translations/zh_CN/arch/arm64/booting.txt
@@ -1,4 +1,4 @@
-Chinese translated version of Documentation/arm64/booting.rst
+Chinese translated version of Documentation/arch/arm64/booting.rst
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
@@ -10,7 +10,7 @@ M: Will Deacon <will.deacon@arm.com>
zh_CN: Fu Wei <wefu@redhat.com>
C: 55f058e7574c3615dea4615573a19bdb258696c6
---------------------------------------------------------------------
-Documentation/arm64/booting.rst 的中文翻译
+Documentation/arch/arm64/booting.rst 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
diff --git a/Documentation/translations/zh_CN/arch/arm64/elf_hwcaps.rst b/Documentation/translations/zh_CN/arch/arm64/elf_hwcaps.rst
new file mode 100644
index 000000000000..f60ac1580d3e
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/arm64/elf_hwcaps.rst
@@ -0,0 +1,240 @@
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: :ref:`Documentation/arch/arm64/elf_hwcaps.rst <elf_hwcaps_index>`
+
+Translator: Bailu Lin <bailu.lin@vivo.com>
+
+================
+ARM64 ELF hwcaps
+================
+
+这篇文档描述了 arm64 ELF hwcaps 的用法和语义。
+
+
+1. 简介
+-------
+
+有些硬件或软件功能仅在某些 CPU 实现上和/或在具体某个内核配置上可用,但
+对于处于 EL0 的用户空间代码没有可用的架构发现机制。内核通过在辅助向量表
+公开一组称为 hwcaps 的标志而把这些功能暴露给用户空间。
+
+用户空间软件可以通过获取辅助向量的 AT_HWCAP 或 AT_HWCAP2 条目来测试功能,
+并测试是否设置了相关标志,例如::
+
+ bool floating_point_is_present(void)
+ {
+ unsigned long hwcaps = getauxval(AT_HWCAP);
+ if (hwcaps & HWCAP_FP)
+ return true;
+
+ return false;
+ }
+
+如果软件依赖于 hwcap 描述的功能,在尝试使用该功能前则应检查相关的 hwcap
+标志以验证该功能是否存在。
+
+不能通过其他方式探查这些功能。当一个功能不可用时,尝试使用它可能导致不可
+预测的行为,并且无法保证能确切的知道该功能不可用,例如 SIGILL。
+
+
+2. Hwcaps 的说明
+----------------
+
+大多数 hwcaps 旨在说明通过架构 ID 寄存器(处于 EL0 的用户空间代码无法访问)
+描述的功能的存在。这些 hwcap 通过 ID 寄存器字段定义,并且应根据 ARM 体系
+结构参考手册(ARM ARM)中定义的字段来解释说明。
+
+这些 hwcaps 以下面的形式描述::
+
+ idreg.field == val 表示有某个功能。
+
+当 idreg.field 中有 val 时,hwcaps 表示 ARM ARM 定义的功能是有效的,但是
+并不是说要完全和 val 相等,也不是说 idreg.field 描述的其他功能就是缺失的。
+
+其他 hwcaps 可能表明无法仅由 ID 寄存器描述的功能的存在。这些 hwcaps 可能
+没有被 ID 寄存器描述,需要参考其他文档。
+
+
+3. AT_HWCAP 中揭示的 hwcaps
+---------------------------
+
+HWCAP_FP
+ ID_AA64PFR0_EL1.FP == 0b0000 表示有此功能。
+
+HWCAP_ASIMD
+ ID_AA64PFR0_EL1.AdvSIMD == 0b0000 表示有此功能。
+
+HWCAP_EVTSTRM
+ 通用计时器频率配置为大约100KHz以生成事件。
+
+HWCAP_AES
+ ID_AA64ISAR0_EL1.AES == 0b0001 表示有此功能。
+
+HWCAP_PMULL
+ ID_AA64ISAR0_EL1.AES == 0b0010 表示有此功能。
+
+HWCAP_SHA1
+ ID_AA64ISAR0_EL1.SHA1 == 0b0001 表示有此功能。
+
+HWCAP_SHA2
+ ID_AA64ISAR0_EL1.SHA2 == 0b0001 表示有此功能。
+
+HWCAP_CRC32
+ ID_AA64ISAR0_EL1.CRC32 == 0b0001 表示有此功能。
+
+HWCAP_ATOMICS
+ ID_AA64ISAR0_EL1.Atomic == 0b0010 表示有此功能。
+
+HWCAP_FPHP
+ ID_AA64PFR0_EL1.FP == 0b0001 表示有此功能。
+
+HWCAP_ASIMDHP
+ ID_AA64PFR0_EL1.AdvSIMD == 0b0001 表示有此功能。
+
+HWCAP_CPUID
+ 根据 Documentation/arch/arm64/cpu-feature-registers.rst 描述,EL0 可以访问
+ 某些 ID 寄存器。
+
+ 这些 ID 寄存器可能表示功能的可用性。
+
+HWCAP_ASIMDRDM
+ ID_AA64ISAR0_EL1.RDM == 0b0001 表示有此功能。
+
+HWCAP_JSCVT
+ ID_AA64ISAR1_EL1.JSCVT == 0b0001 表示有此功能。
+
+HWCAP_FCMA
+ ID_AA64ISAR1_EL1.FCMA == 0b0001 表示有此功能。
+
+HWCAP_LRCPC
+ ID_AA64ISAR1_EL1.LRCPC == 0b0001 表示有此功能。
+
+HWCAP_DCPOP
+ ID_AA64ISAR1_EL1.DPB == 0b0001 表示有此功能。
+
+HWCAP_SHA3
+ ID_AA64ISAR0_EL1.SHA3 == 0b0001 表示有此功能。
+
+HWCAP_SM3
+ ID_AA64ISAR0_EL1.SM3 == 0b0001 表示有此功能。
+
+HWCAP_SM4
+ ID_AA64ISAR0_EL1.SM4 == 0b0001 表示有此功能。
+
+HWCAP_ASIMDDP
+ ID_AA64ISAR0_EL1.DP == 0b0001 表示有此功能。
+
+HWCAP_SHA512
+ ID_AA64ISAR0_EL1.SHA2 == 0b0010 表示有此功能。
+
+HWCAP_SVE
+ ID_AA64PFR0_EL1.SVE == 0b0001 表示有此功能。
+
+HWCAP_ASIMDFHM
+ ID_AA64ISAR0_EL1.FHM == 0b0001 表示有此功能。
+
+HWCAP_DIT
+ ID_AA64PFR0_EL1.DIT == 0b0001 表示有此功能。
+
+HWCAP_USCAT
+ ID_AA64MMFR2_EL1.AT == 0b0001 表示有此功能。
+
+HWCAP_ILRCPC
+ ID_AA64ISAR1_EL1.LRCPC == 0b0010 表示有此功能。
+
+HWCAP_FLAGM
+ ID_AA64ISAR0_EL1.TS == 0b0001 表示有此功能。
+
+HWCAP_SSBS
+ ID_AA64PFR1_EL1.SSBS == 0b0010 表示有此功能。
+
+HWCAP_SB
+ ID_AA64ISAR1_EL1.SB == 0b0001 表示有此功能。
+
+HWCAP_PACA
+ 如 Documentation/arch/arm64/pointer-authentication.rst 所描述,
+ ID_AA64ISAR1_EL1.APA == 0b0001 或 ID_AA64ISAR1_EL1.API == 0b0001
+ 表示有此功能。
+
+HWCAP_PACG
+ 如 Documentation/arch/arm64/pointer-authentication.rst 所描述,
+ ID_AA64ISAR1_EL1.GPA == 0b0001 或 ID_AA64ISAR1_EL1.GPI == 0b0001
+ 表示有此功能。
+
+HWCAP2_DCPODP
+
+ ID_AA64ISAR1_EL1.DPB == 0b0010 表示有此功能。
+
+HWCAP2_SVE2
+
+ ID_AA64ZFR0_EL1.SVEVer == 0b0001 表示有此功能。
+
+HWCAP2_SVEAES
+
+ ID_AA64ZFR0_EL1.AES == 0b0001 表示有此功能。
+
+HWCAP2_SVEPMULL
+
+ ID_AA64ZFR0_EL1.AES == 0b0010 表示有此功能。
+
+HWCAP2_SVEBITPERM
+
+ ID_AA64ZFR0_EL1.BitPerm == 0b0001 表示有此功能。
+
+HWCAP2_SVESHA3
+
+ ID_AA64ZFR0_EL1.SHA3 == 0b0001 表示有此功能。
+
+HWCAP2_SVESM4
+
+ ID_AA64ZFR0_EL1.SM4 == 0b0001 表示有此功能。
+
+HWCAP2_FLAGM2
+
+ ID_AA64ISAR0_EL1.TS == 0b0010 表示有此功能。
+
+HWCAP2_FRINT
+
+ ID_AA64ISAR1_EL1.FRINTTS == 0b0001 表示有此功能。
+
+HWCAP2_SVEI8MM
+
+ ID_AA64ZFR0_EL1.I8MM == 0b0001 表示有此功能。
+
+HWCAP2_SVEF32MM
+
+ ID_AA64ZFR0_EL1.F32MM == 0b0001 表示有此功能。
+
+HWCAP2_SVEF64MM
+
+ ID_AA64ZFR0_EL1.F64MM == 0b0001 表示有此功能。
+
+HWCAP2_SVEBF16
+
+ ID_AA64ZFR0_EL1.BF16 == 0b0001 表示有此功能。
+
+HWCAP2_I8MM
+
+ ID_AA64ISAR1_EL1.I8MM == 0b0001 表示有此功能。
+
+HWCAP2_BF16
+
+ ID_AA64ISAR1_EL1.BF16 == 0b0001 表示有此功能。
+
+HWCAP2_DGH
+
+ ID_AA64ISAR1_EL1.DGH == 0b0001 表示有此功能。
+
+HWCAP2_RNG
+
+ ID_AA64ISAR0_EL1.RNDR == 0b0001 表示有此功能。
+
+HWCAP2_BTI
+
+ ID_AA64PFR0_EL1.BT == 0b0001 表示有此功能。
+
+
+4. 未使用的 AT_HWCAP 位
+-----------------------
+
+为了与用户空间交互,内核保证 AT_HWCAP 的第62、63位将始终返回0。
diff --git a/Documentation/translations/zh_CN/arch/arm64/hugetlbpage.rst b/Documentation/translations/zh_CN/arch/arm64/hugetlbpage.rst
new file mode 100644
index 000000000000..8079eadde29a
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/arm64/hugetlbpage.rst
@@ -0,0 +1,45 @@
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: :ref:`Documentation/arch/arm64/hugetlbpage.rst <hugetlbpage_index>`
+
+Translator: Bailu Lin <bailu.lin@vivo.com>
+
+=====================
+ARM64中的 HugeTLBpage
+=====================
+
+大页依靠有效利用 TLBs 来提高地址翻译的性能。这取决于以下
+两点 -
+
+ - 大页的大小
+ - TLBs 支持的条目大小
+
+ARM64 接口支持2种大页方式。
+
+1) pud/pmd 级别的块映射
+-----------------------
+
+这是常规大页,他们的 pmd 或 pud 页面表条目指向一个内存块。
+不管 TLB 中支持的条目大小如何,块映射可以减少翻译大页地址
+所需遍历的页表深度。
+
+2) 使用连续位
+-------------
+
+架构中转换页表条目(D4.5.3, ARM DDI 0487C.a)中提供一个连续
+位告诉 MMU 这个条目是一个连续条目集的一员,它可以被缓存在单
+个 TLB 条目中。
+
+在 Linux 中连续位用来增加 pmd 和 pte(最后一级)级别映射的大
+小。受支持的连续页表条目数量因页面大小和页表级别而异。
+
+
+支持以下大页尺寸配置 -
+
+ ====== ======== ==== ======== ===
+ - CONT PTE PMD CONT PMD PUD
+ ====== ======== ==== ======== ===
+ 4K: 64K 2M 32M 1G
+ 16K: 2M 32M 1G
+ 64K: 2M 512M 16G
+ ====== ======== ==== ======== ===
diff --git a/Documentation/translations/zh_CN/arch/arm64/index.rst b/Documentation/translations/zh_CN/arch/arm64/index.rst
new file mode 100644
index 000000000000..e12b9f6e5d6c
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/arm64/index.rst
@@ -0,0 +1,19 @@
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: :ref:`Documentation/arch/arm64/index.rst <arm64_index>`
+:Translator: Bailu Lin <bailu.lin@vivo.com>
+
+.. _cn_arm64_index:
+
+
+==========
+ARM64 架构
+==========
+
+.. toctree::
+ :maxdepth: 2
+
+ amu
+ hugetlbpage
+ perf
+ elf_hwcaps
diff --git a/Documentation/translations/zh_CN/arm64/legacy_instructions.txt b/Documentation/translations/zh_CN/arch/arm64/legacy_instructions.txt
index e295cf75f606..e469fccbe356 100644
--- a/Documentation/translations/zh_CN/arm64/legacy_instructions.txt
+++ b/Documentation/translations/zh_CN/arch/arm64/legacy_instructions.txt
@@ -1,4 +1,4 @@
-Chinese translated version of Documentation/arm64/legacy_instructions.rst
+Chinese translated version of Documentation/arch/arm64/legacy_instructions.rst
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
@@ -10,7 +10,7 @@ Maintainer: Punit Agrawal <punit.agrawal@arm.com>
Suzuki K. Poulose <suzuki.poulose@arm.com>
Chinese maintainer: Fu Wei <wefu@redhat.com>
---------------------------------------------------------------------
-Documentation/arm64/legacy_instructions.rst 的中文翻译
+Documentation/arch/arm64/legacy_instructions.rst 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
diff --git a/Documentation/translations/zh_CN/arm64/memory.txt b/Documentation/translations/zh_CN/arch/arm64/memory.txt
index be20f8228b91..c6962e9cb9f8 100644
--- a/Documentation/translations/zh_CN/arm64/memory.txt
+++ b/Documentation/translations/zh_CN/arch/arm64/memory.txt
@@ -1,4 +1,4 @@
-Chinese translated version of Documentation/arm64/memory.rst
+Chinese translated version of Documentation/arch/arm64/memory.rst
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
@@ -9,7 +9,7 @@ or if there is a problem with the translation.
Maintainer: Catalin Marinas <catalin.marinas@arm.com>
Chinese maintainer: Fu Wei <wefu@redhat.com>
---------------------------------------------------------------------
-Documentation/arm64/memory.rst 的中文翻译
+Documentation/arch/arm64/memory.rst 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
diff --git a/Documentation/translations/zh_CN/arch/arm64/perf.rst b/Documentation/translations/zh_CN/arch/arm64/perf.rst
new file mode 100644
index 000000000000..6be72704e659
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/arm64/perf.rst
@@ -0,0 +1,86 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: :ref:`Documentation/arch/arm64/perf.rst <perf_index>`
+
+Translator: Bailu Lin <bailu.lin@vivo.com>
+
+=============
+Perf 事件属性
+=============
+
+:作者: Andrew Murray <andrew.murray@arm.com>
+:日期: 2019-03-06
+
+exclude_user
+------------
+
+该属性排除用户空间。
+
+用户空间始终运行在 EL0,因此该属性将排除 EL0。
+
+
+exclude_kernel
+--------------
+
+该属性排除内核空间。
+
+打开 VHE 时内核运行在 EL2,不打开 VHE 时内核运行在 EL1。客户机
+内核总是运行在 EL1。
+
+对于宿主机,该属性排除 EL1 和 VHE 上的 EL2。
+
+对于客户机,该属性排除 EL1。请注意客户机从来不会运行在 EL2。
+
+
+exclude_hv
+----------
+
+该属性排除虚拟机监控器。
+
+对于 VHE 宿主机该属性将被忽略,此时我们认为宿主机内核是虚拟机监
+控器。
+
+对于 non-VHE 宿主机该属性将排除 EL2,因为虚拟机监控器运行在 EL2
+的任何代码主要用于客户机和宿主机的切换。
+
+对于客户机该属性无效。请注意客户机从来不会运行在 EL2。
+
+
+exclude_host / exclude_guest
+----------------------------
+
+这些属性分别排除了 KVM 宿主机和客户机。
+
+KVM 宿主机可能运行在 EL0(用户空间),EL1(non-VHE 内核)和
+EL2(VHE 内核 或 non-VHE 虚拟机监控器)。
+
+KVM 客户机可能运行在 EL0(用户空间)和 EL1(内核)。
+
+由于宿主机和客户机之间重叠的异常级别,我们不能仅仅依靠 PMU 的硬件异
+常过滤机制-因此我们必须启用/禁用对于客户机进入和退出的计数。而这在
+VHE 和 non-VHE 系统上表现不同。
+
+对于 non-VHE 系统的 exclude_host 属性排除 EL2 - 在进入和退出客户
+机时,我们会根据 exclude_host 和 exclude_guest 属性在适当的情况下
+禁用/启用该事件。
+
+对于 VHE 系统的 exclude_guest 属性排除 EL1,而对其中的 exclude_host
+属性同时排除 EL0,EL2。在进入和退出客户机时,我们会适当地根据
+exclude_host 和 exclude_guest 属性包括/排除 EL0。
+
+以上声明也适用于在 not-VHE 客户机使用这些属性时,但是请注意客户机从
+来不会运行在 EL2。
+
+
+准确性
+------
+
+在 non-VHE 宿主机上,我们在 EL2 进入/退出宿主机/客户机的切换时启用/
+关闭计数器 -但是在启用/禁用计数器和进入/退出客户机之间存在一段延时。
+对于 exclude_host, 我们可以通过过滤 EL2 消除在客户机进入/退出边界
+上用于计数客户机事件的宿主机事件计数器。但是当使用 !exclude_hv 时,
+在客户机进入/退出有一个小的停电窗口无法捕获到宿主机的事件。
+
+在 VHE 系统没有停电窗口。
diff --git a/Documentation/translations/zh_CN/arm64/silicon-errata.txt b/Documentation/translations/zh_CN/arch/arm64/silicon-errata.txt
index 440c59ac7dce..f4767ffdd61d 100644
--- a/Documentation/translations/zh_CN/arm64/silicon-errata.txt
+++ b/Documentation/translations/zh_CN/arch/arm64/silicon-errata.txt
@@ -1,4 +1,4 @@
-Chinese translated version of Documentation/arm64/silicon-errata.rst
+Chinese translated version of Documentation/arch/arm64/silicon-errata.rst
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
@@ -10,7 +10,7 @@ M: Will Deacon <will.deacon@arm.com>
zh_CN: Fu Wei <wefu@redhat.com>
C: 1926e54f115725a9248d0c4c65c22acaf94de4c4
---------------------------------------------------------------------
-Documentation/arm64/silicon-errata.rst 的中文翻译
+Documentation/arch/arm64/silicon-errata.rst 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
diff --git a/Documentation/translations/zh_CN/arm64/tagged-pointers.txt b/Documentation/translations/zh_CN/arch/arm64/tagged-pointers.txt
index 77ac3548a16d..27577c3c5e3f 100644
--- a/Documentation/translations/zh_CN/arm64/tagged-pointers.txt
+++ b/Documentation/translations/zh_CN/arch/arm64/tagged-pointers.txt
@@ -1,4 +1,4 @@
-Chinese translated version of Documentation/arm64/tagged-pointers.rst
+Chinese translated version of Documentation/arch/arm64/tagged-pointers.rst
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
@@ -9,7 +9,7 @@ or if there is a problem with the translation.
Maintainer: Will Deacon <will.deacon@arm.com>
Chinese maintainer: Fu Wei <wefu@redhat.com>
---------------------------------------------------------------------
-Documentation/arm64/tagged-pointers.rst 的中文翻译
+Documentation/arch/arm64/tagged-pointers.rst 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
diff --git a/Documentation/translations/zh_CN/arch/index.rst b/Documentation/translations/zh_CN/arch/index.rst
new file mode 100644
index 000000000000..71186d9df7c9
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/index.rst
@@ -0,0 +1,28 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+处理器体系结构
+==============
+
+以下文档提供了具体架构实现的编程细节。
+
+.. toctree::
+ :maxdepth: 2
+
+ mips/index
+ arm64/index
+ ../arch/riscv/index
+ openrisc/index
+ parisc/index
+ loongarch/index
+
+TODOList:
+
+* arm/index
+* m68k/index
+* nios2/index
+* powerpc/index
+* s390/index
+* sh/index
+* sparc/index
+* x86/index
+* xtensa/index
diff --git a/Documentation/translations/zh_CN/arch/loongarch/booting.rst b/Documentation/translations/zh_CN/arch/loongarch/booting.rst
new file mode 100644
index 000000000000..d2f55872904e
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/loongarch/booting.rst
@@ -0,0 +1,48 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/arch/loongarch/booting.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+====================
+启动 Linux/LoongArch
+====================
+
+:作者: 司延腾 <siyanteng@loongson.cn>
+:日期: 2022年11月18日
+
+BootLoader传递给内核的信息
+==========================
+
+LoongArch支持ACPI和FDT启动,需要传递给内核的信息包括memmap、initrd、cmdline、可
+选的ACPI/FDT表等。
+
+内核在 `kernel_entry` 入口处被传递以下参数:
+
+ - a0 = efi_boot: `efi_boot` 是一个标志,表示这个启动环境是否完全符合UEFI
+ 的要求。
+
+ - a1 = cmdline: `cmdline` 是一个指向内核命令行的指针。
+
+ - a2 = systemtable: `systemtable` 指向EFI的系统表,在这个阶段涉及的所有
+ 指针都是物理地址。
+
+Linux/LoongArch内核镜像文件头
+=============================
+
+内核镜像是EFI镜像。作为PE文件,它们有一个64字节的头部结构体,如下所示::
+
+ u32 MZ_MAGIC /* "MZ", MS-DOS 头 */
+ u32 res0 = 0 /* 保留 */
+ u64 kernel_entry /* 内核入口点 */
+ u64 _end - _text /* 内核镜像有效大小 */
+ u64 load_offset /* 加载内核镜像相对内存起始地址的偏移量 */
+ u64 res1 = 0 /* 保留 */
+ u64 res2 = 0 /* 保留 */
+ u64 res3 = 0 /* 保留 */
+ u32 LINUX_PE_MAGIC /* 魔术数 */
+ u32 pe_header - _head /* 到PE头的偏移量 */
diff --git a/Documentation/translations/zh_CN/arch/loongarch/features.rst b/Documentation/translations/zh_CN/arch/loongarch/features.rst
new file mode 100644
index 000000000000..cec38dda8298
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/loongarch/features.rst
@@ -0,0 +1,8 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/arch/loongarch/features.rst
+:Translator: Huacai Chen <chenhuacai@loongson.cn>
+
+.. kernel-feat:: features loongarch
diff --git a/Documentation/translations/zh_CN/arch/loongarch/index.rst b/Documentation/translations/zh_CN/arch/loongarch/index.rst
new file mode 100644
index 000000000000..4bd24f5ffed1
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/loongarch/index.rst
@@ -0,0 +1,27 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/arch/loongarch/index.rst
+:Translator: Huacai Chen <chenhuacai@loongson.cn>
+
+=================
+LoongArch体系结构
+=================
+
+.. toctree::
+ :maxdepth: 2
+ :numbered:
+
+ introduction
+ booting
+ irq-chip-model
+
+ features
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
diff --git a/Documentation/translations/zh_CN/arch/loongarch/introduction.rst b/Documentation/translations/zh_CN/arch/loongarch/introduction.rst
new file mode 100644
index 000000000000..bf463c5a4c51
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/loongarch/introduction.rst
@@ -0,0 +1,353 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/arch/loongarch/introduction.rst
+:Translator: Huacai Chen <chenhuacai@loongson.cn>
+
+=============
+LoongArch介绍
+=============
+
+LoongArch是一种新的RISC ISA,在一定程度上类似于MIPS和RISC-V。LoongArch指令集
+包括一个精简32位版(LA32R)、一个标准32位版(LA32S)、一个64位版(LA64)。
+LoongArch定义了四个特权级(PLV0~PLV3),其中PLV0是最高特权级,用于内核;而PLV3
+是最低特权级,用于应用程序。本文档介绍了LoongArch的寄存器、基础指令集、虚拟内
+存以及其他一些主题。
+
+寄存器
+======
+
+LoongArch的寄存器包括通用寄存器(GPRs)、浮点寄存器(FPRs)、向量寄存器(VRs)
+和用于特权模式(PLV0)的控制状态寄存器(CSRs)。
+
+通用寄存器
+----------
+
+LoongArch包括32个通用寄存器( ``$r0`` ~ ``$r31`` ),LA32中每个寄存器为32位宽,
+LA64中每个寄存器为64位宽。 ``$r0`` 的内容总是固定为0,而其他寄存器在体系结构层面
+没有特殊功能。( ``$r1`` 算是一个例外,在BL指令中固定用作链接返回寄存器。)
+
+内核使用了一套LoongArch寄存器约定,定义在LoongArch ELF psABI规范中,详细描述参见
+:ref:`参考文献 <loongarch-references-zh_CN>`:
+
+================= =============== =================== ==========
+寄存器名 别名 用途 跨调用保持
+================= =============== =================== ==========
+``$r0`` ``$zero`` 常量0 不使用
+``$r1`` ``$ra`` 返回地址 否
+``$r2`` ``$tp`` TLS/线程信息指针 不使用
+``$r3`` ``$sp`` 栈指针 是
+``$r4``-``$r11`` ``$a0``-``$a7`` 参数寄存器 否
+``$r4``-``$r5`` ``$v0``-``$v1`` 返回值 否
+``$r12``-``$r20`` ``$t0``-``$t8`` 临时寄存器 否
+``$r21`` ``$u0`` 每CPU变量基地址 不使用
+``$r22`` ``$fp`` 帧指针 是
+``$r23``-``$r31`` ``$s0``-``$s8`` 静态寄存器 是
+================= =============== =================== ==========
+
+.. note::
+ 注意: ``$r21`` 寄存器在ELF psABI中保留未使用,但是在Linux内核用于保
+ 存每CPU变量基地址。该寄存器没有ABI命名,不过在内核中称为 ``$u0`` 。在
+ 一些遗留代码中有时可能见到 ``$v0`` 和 ``$v1`` ,它们是 ``$a0`` 和
+ ``$a1`` 的别名,属于已经废弃的用法。
+
+浮点寄存器
+----------
+
+当系统中存在FPU时,LoongArch有32个浮点寄存器( ``$f0`` ~ ``$f31`` )。在LA64
+的CPU核上,每个寄存器均为64位宽。
+
+浮点寄存器的使用约定与LoongArch ELF psABI规范的描述相同:
+
+================= ================== =================== ==========
+寄存器名 别名 用途 跨调用保持
+================= ================== =================== ==========
+``$f0``-``$f7`` ``$fa0``-``$fa7`` 参数寄存器 否
+``$f0``-``$f1`` ``$fv0``-``$fv1`` 返回值 否
+``$f8``-``$f23`` ``$ft0``-``$ft15`` 临时寄存器 否
+``$f24``-``$f31`` ``$fs0``-``$fs7`` 静态寄存器 是
+================= ================== =================== ==========
+
+.. note::
+ 注意:在一些遗留代码中有时可能见到 ``$fv0`` 和 ``$fv1`` ,它们是
+ ``$fa0`` 和 ``$fa1`` 的别名,属于已经废弃的用法。
+
+
+向量寄存器
+----------
+
+LoongArch现有两种向量扩展:
+
+- 128位向量扩展LSX(全称Loongson SIMD eXtention),
+- 256位向量扩展LASX(全称Loongson Advanced SIMD eXtention)。
+
+LSX使用 ``$v0`` ~ ``$v31`` 向量寄存器,而LASX则使用 ``$x0`` ~ ``$x31`` 。
+
+浮点寄存器和向量寄存器是复用的,比如:在一个实现了LSX和LASX的核上, ``$x0`` 的
+低128位与 ``$v0`` 共用, ``$v0`` 的低64位与 ``$f0`` 共用,其他寄存器依此类推。
+
+控制状态寄存器
+--------------
+
+控制状态寄存器只能在特权模式(PLV0)下访问:
+
+================= ==================================== ==========
+地址 全称描述 简称
+================= ==================================== ==========
+0x0 当前模式信息 CRMD
+0x1 异常前模式信息 PRMD
+0x2 扩展部件使能 EUEN
+0x3 杂项控制 MISC
+0x4 异常配置 ECFG
+0x5 异常状态 ESTAT
+0x6 异常返回地址 ERA
+0x7 出错(Faulting)虚拟地址 BADV
+0x8 出错(Faulting)指令字 BADI
+0xC 异常入口地址 EENTRY
+0x10 TLB索引 TLBIDX
+0x11 TLB表项高位 TLBEHI
+0x12 TLB表项低位0 TLBELO0
+0x13 TLB表项低位1 TLBELO1
+0x18 地址空间标识符 ASID
+0x19 低半地址空间页全局目录基址 PGDL
+0x1A 高半地址空间页全局目录基址 PGDH
+0x1B 页全局目录基址 PGD
+0x1C 页表遍历控制低半部分 PWCL
+0x1D 页表遍历控制高半部分 PWCH
+0x1E STLB页大小 STLBPS
+0x1F 缩减虚地址配置 RVACFG
+0x20 CPU编号 CPUID
+0x21 特权资源配置信息1 PRCFG1
+0x22 特权资源配置信息2 PRCFG2
+0x23 特权资源配置信息3 PRCFG3
+0x30+n (0≤n≤15) 数据保存寄存器 SAVEn
+0x40 定时器编号 TID
+0x41 定时器配置 TCFG
+0x42 定时器值 TVAL
+0x43 计时器补偿 CNTC
+0x44 定时器中断清除 TICLR
+0x60 LLBit相关控制 LLBCTL
+0x80 实现相关控制1 IMPCTL1
+0x81 实现相关控制2 IMPCTL2
+0x88 TLB重填异常入口地址 TLBRENTRY
+0x89 TLB重填异常出错(Faulting)虚地址 TLBRBADV
+0x8A TLB重填异常返回地址 TLBRERA
+0x8B TLB重填异常数据保存 TLBRSAVE
+0x8C TLB重填异常表项低位0 TLBRELO0
+0x8D TLB重填异常表项低位1 TLBRELO1
+0x8E TLB重填异常表项高位 TLBEHI
+0x8F TLB重填异常前模式信息 TLBRPRMD
+0x90 机器错误控制 MERRCTL
+0x91 机器错误信息1 MERRINFO1
+0x92 机器错误信息2 MERRINFO2
+0x93 机器错误异常入口地址 MERRENTRY
+0x94 机器错误异常返回地址 MERRERA
+0x95 机器错误异常数据保存 MERRSAVE
+0x98 高速缓存标签 CTAG
+0x180+n (0≤n≤3) 直接映射配置窗口n DMWn
+0x200+2n (0≤n≤31) 性能监测配置n PMCFGn
+0x201+2n (0≤n≤31) 性能监测计数器n PMCNTn
+0x300 内存读写监视点整体控制 MWPC
+0x301 内存读写监视点整体状态 MWPS
+0x310+8n (0≤n≤7) 内存读写监视点n配置1 MWPnCFG1
+0x311+8n (0≤n≤7) 内存读写监视点n配置2 MWPnCFG2
+0x312+8n (0≤n≤7) 内存读写监视点n配置3 MWPnCFG3
+0x313+8n (0≤n≤7) 内存读写监视点n配置4 MWPnCFG4
+0x380 取指监视点整体控制 FWPC
+0x381 取指监视点整体状态 FWPS
+0x390+8n (0≤n≤7) 取指监视点n配置1 FWPnCFG1
+0x391+8n (0≤n≤7) 取指监视点n配置2 FWPnCFG2
+0x392+8n (0≤n≤7) 取指监视点n配置3 FWPnCFG3
+0x393+8n (0≤n≤7) 取指监视点n配置4 FWPnCFG4
+0x500 调试寄存器 DBG
+0x501 调试异常返回地址 DERA
+0x502 调试数据保存 DSAVE
+================= ==================================== ==========
+
+ERA,TLBRERA,MERRERA和DERA有时也分别称为EPC,TLBREPC,MERREPC和DEPC。
+
+基础指令集
+==========
+
+指令格式
+--------
+
+LoongArch的指令字长为32位,一共有9种基本指令格式(以及一些变体):
+
+=========== ==========================
+格式名称 指令构成
+=========== ==========================
+2R Opcode + Rj + Rd
+3R Opcode + Rk + Rj + Rd
+4R Opcode + Ra + Rk + Rj + Rd
+2RI8 Opcode + I8 + Rj + Rd
+2RI12 Opcode + I12 + Rj + Rd
+2RI14 Opcode + I14 + Rj + Rd
+2RI16 Opcode + I16 + Rj + Rd
+1RI21 Opcode + I21L + Rj + I21H
+I26 Opcode + I26L + I26H
+=========== ==========================
+
+Opcode是指令操作码,Rj和Rk是源操作数(寄存器),Rd是目标操作数(寄存器),Ra是
+4R-type格式特有的附加操作数(寄存器)。I8/I12/I14/I16/I21/I26分别是8位/12位/14位/
+16位/21位/26位的立即数。其中较长的21位和26位立即数在指令字中被分割为高位部分与低位
+部分,所以你们在这里的格式描述中能够看到I21L/I21H和I26L/I26H这样带后缀的表述。
+
+指令列表
+--------
+
+为了简便起见,我们在此只罗列一下指令名称(助记符),需要详细信息请阅读
+:ref:`参考文献 <loongarch-references-zh_CN>` 中的文档。
+
+1. 算术运算指令::
+
+ ADD.W SUB.W ADDI.W ADD.D SUB.D ADDI.D
+ SLT SLTU SLTI SLTUI
+ AND OR NOR XOR ANDN ORN ANDI ORI XORI
+ MUL.W MULH.W MULH.WU DIV.W DIV.WU MOD.W MOD.WU
+ MUL.D MULH.D MULH.DU DIV.D DIV.DU MOD.D MOD.DU
+ PCADDI PCADDU12I PCADDU18I
+ LU12I.W LU32I.D LU52I.D ADDU16I.D
+
+2. 移位运算指令::
+
+ SLL.W SRL.W SRA.W ROTR.W SLLI.W SRLI.W SRAI.W ROTRI.W
+ SLL.D SRL.D SRA.D ROTR.D SLLI.D SRLI.D SRAI.D ROTRI.D
+
+3. 位域操作指令::
+
+ EXT.W.B EXT.W.H CLO.W CLO.D SLZ.W CLZ.D CTO.W CTO.D CTZ.W CTZ.D
+ BYTEPICK.W BYTEPICK.D BSTRINS.W BSTRINS.D BSTRPICK.W BSTRPICK.D
+ REVB.2H REVB.4H REVB.2W REVB.D REVH.2W REVH.D BITREV.4B BITREV.8B BITREV.W BITREV.D
+ MASKEQZ MASKNEZ
+
+4. 分支转移指令::
+
+ BEQ BNE BLT BGE BLTU BGEU BEQZ BNEZ B BL JIRL
+
+5. 访存读写指令::
+
+ LD.B LD.BU LD.H LD.HU LD.W LD.WU LD.D ST.B ST.H ST.W ST.D
+ LDX.B LDX.BU LDX.H LDX.HU LDX.W LDX.WU LDX.D STX.B STX.H STX.W STX.D
+ LDPTR.W LDPTR.D STPTR.W STPTR.D
+ PRELD PRELDX
+
+6. 原子操作指令::
+
+ LL.W SC.W LL.D SC.D
+ AMSWAP.W AMSWAP.D AMADD.W AMADD.D AMAND.W AMAND.D AMOR.W AMOR.D AMXOR.W AMXOR.D
+ AMMAX.W AMMAX.D AMMIN.W AMMIN.D
+
+7. 栅障指令::
+
+ IBAR DBAR
+
+8. 特殊指令::
+
+ SYSCALL BREAK CPUCFG NOP IDLE ERTN(ERET) DBCL(DBGCALL) RDTIMEL.W RDTIMEH.W RDTIME.D
+ ASRTLE.D ASRTGT.D
+
+9. 特权指令::
+
+ CSRRD CSRWR CSRXCHG
+ IOCSRRD.B IOCSRRD.H IOCSRRD.W IOCSRRD.D IOCSRWR.B IOCSRWR.H IOCSRWR.W IOCSRWR.D
+ CACOP TLBP(TLBSRCH) TLBRD TLBWR TLBFILL TLBCLR TLBFLUSH INVTLB LDDIR LDPTE
+
+虚拟内存
+========
+
+LoongArch可以使用直接映射虚拟内存和分页映射虚拟内存。
+
+直接映射虚拟内存通过CSR.DMWn(n=0~3)来进行配置,虚拟地址(VA)和物理地址(PA)
+之间有简单的映射关系::
+
+ VA = PA + 固定偏移
+
+分页映射的虚拟地址(VA)和物理地址(PA)有任意的映射关系,这种关系记录在TLB和页
+表中。LoongArch的TLB包括一个全相联的MTLB(Multiple Page Size TLB,多样页大小TLB)
+和一个组相联的STLB(Single Page Size TLB,单一页大小TLB)。
+
+缺省状态下,LA32的整个虚拟地址空间配置如下:
+
+============ =========================== ===========================
+区段名 地址范围 属性
+============ =========================== ===========================
+``UVRANGE`` ``0x00000000 - 0x7FFFFFFF`` 分页映射, 可缓存, PLV0~3
+``KPRANGE0`` ``0x80000000 - 0x9FFFFFFF`` 直接映射, 非缓存, PLV0
+``KPRANGE1`` ``0xA0000000 - 0xBFFFFFFF`` 直接映射, 可缓存, PLV0
+``KVRANGE`` ``0xC0000000 - 0xFFFFFFFF`` 分页映射, 可缓存, PLV0
+============ =========================== ===========================
+
+用户态(PLV3)只能访问UVRANGE,对于直接映射的KPRANGE0和KPRANGE1,将虚拟地址的第
+30~31位清零就等于物理地址。例如:物理地址0x00001000对应的非缓存直接映射虚拟地址
+是0x80001000,而其可缓存直接映射虚拟地址是0xA0001000。
+
+缺省状态下,LA64的整个虚拟地址空间配置如下:
+
+============ ====================== ==================================
+区段名 地址范围 属性
+============ ====================== ==================================
+``XUVRANGE`` ``0x0000000000000000 - 分页映射, 可缓存, PLV0~3
+ 0x3FFFFFFFFFFFFFFF``
+``XSPRANGE`` ``0x4000000000000000 - 直接映射, 可缓存 / 非缓存, PLV0
+ 0x7FFFFFFFFFFFFFFF``
+``XKPRANGE`` ``0x8000000000000000 - 直接映射, 可缓存 / 非缓存, PLV0
+ 0xBFFFFFFFFFFFFFFF``
+``XKVRANGE`` ``0xC000000000000000 - 分页映射, 可缓存, PLV0
+ 0xFFFFFFFFFFFFFFFF``
+============ ====================== ==================================
+
+用户态(PLV3)只能访问XUVRANGE,对于直接映射的XSPRANGE和XKPRANGE,将虚拟地址的第
+60~63位清零就等于物理地址,而其缓存属性是通过虚拟地址的第60~61位配置的(0表示强序
+非缓存,1表示一致可缓存,2表示弱序非缓存)。
+
+目前,我们仅用XKPRANGE来进行直接映射,XSPRANGE保留给以后用。
+
+此处给出一个直接映射的例子:物理地址0x00000000_00001000的强序非缓存直接映射虚拟地址
+(在XKPRANGE中)是0x80000000_00001000,其一致可缓存直接映射虚拟地址(在XKPRANGE中)
+是0x90000000_00001000,而其弱序非缓存直接映射虚拟地址(在XKPRANGE中)是0xA0000000_
+00001000。
+
+Loongson与LoongArch的关系
+=========================
+
+LoongArch是一种RISC指令集架构(ISA),不同于现存的任何一种ISA,而Loongson(即龙
+芯)是一个处理器家族。龙芯包括三个系列:Loongson-1(龙芯1号)是32位处理器系列,
+Loongson-2(龙芯2号)是低端64位处理器系列,而Loongson-3(龙芯3号)是高端64位处理
+器系列。旧的龙芯处理器基于MIPS架构,而新的龙芯处理器基于LoongArch架构。以龙芯3号
+为例:龙芯3A1000/3B1500/3A2000/3A3000/3A4000都是兼容MIPS的,而龙芯3A5000(以及将
+来的型号)都是基于LoongArch的。
+
+.. _loongarch-references-zh_CN:
+
+参考文献
+========
+
+Loongson官方网站(龙芯中科技术股份有限公司):
+
+ http://www.loongson.cn/
+
+Loongson与LoongArch的开发者网站(软件与文档资源):
+
+ http://www.loongnix.cn/
+
+ https://github.com/loongson/
+
+ https://loongson.github.io/LoongArch-Documentation/
+
+LoongArch指令集架构的文档:
+
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.10-CN.pdf (中文版)
+
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.10-EN.pdf (英文版)
+
+LoongArch的ELF psABI文档:
+
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v2.01-CN.pdf (中文版)
+
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v2.01-EN.pdf (英文版)
+
+Loongson与LoongArch的Linux内核源码仓库:
+
+ https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson.git
diff --git a/Documentation/translations/zh_CN/arch/loongarch/irq-chip-model.rst b/Documentation/translations/zh_CN/arch/loongarch/irq-chip-model.rst
new file mode 100644
index 000000000000..f1e9ab18206c
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/loongarch/irq-chip-model.rst
@@ -0,0 +1,157 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/arch/loongarch/irq-chip-model.rst
+:Translator: Huacai Chen <chenhuacai@loongson.cn>
+
+==================================
+LoongArch的IRQ芯片模型(层级关系)
+==================================
+
+目前,基于LoongArch的处理器(如龙芯3A5000)只能与LS7A芯片组配合工作。LoongArch计算机
+中的中断控制器(即IRQ芯片)包括CPUINTC(CPU Core Interrupt Controller)、LIOINTC(
+Legacy I/O Interrupt Controller)、EIOINTC(Extended I/O Interrupt Controller)、
+HTVECINTC(Hyper-Transport Vector Interrupt Controller)、PCH-PIC(LS7A芯片组的主中
+断控制器)、PCH-LPC(LS7A芯片组的LPC中断控制器)和PCH-MSI(MSI中断控制器)。
+
+CPUINTC是一种CPU内部的每个核本地的中断控制器,LIOINTC/EIOINTC/HTVECINTC是CPU内部的
+全局中断控制器(每个芯片一个,所有核共享),而PCH-PIC/PCH-LPC/PCH-MSI是CPU外部的中
+断控制器(在配套芯片组里面)。这些中断控制器(或者说IRQ芯片)以一种层次树的组织形式
+级联在一起,一共有两种层级关系模型(传统IRQ模型和扩展IRQ模型)。
+
+传统IRQ模型
+===========
+
+在这种模型里面,IPI(Inter-Processor Interrupt)和CPU本地时钟中断直接发送到CPUINTC,
+CPU串口(UARTs)中断发送到LIOINTC,而其他所有设备的中断则分别发送到所连接的PCH-PIC/
+PCH-LPC/PCH-MSI,然后被HTVECINTC统一收集,再发送到LIOINTC,最后到达CPUINTC::
+
+ +-----+ +---------+ +-------+
+ | IPI | --> | CPUINTC | <-- | Timer |
+ +-----+ +---------+ +-------+
+ ^
+ |
+ +---------+ +-------+
+ | LIOINTC | <-- | UARTs |
+ +---------+ +-------+
+ ^
+ |
+ +-----------+
+ | HTVECINTC |
+ +-----------+
+ ^ ^
+ | |
+ +---------+ +---------+
+ | PCH-PIC | | PCH-MSI |
+ +---------+ +---------+
+ ^ ^ ^
+ | | |
+ +---------+ +---------+ +---------+
+ | PCH-LPC | | Devices | | Devices |
+ +---------+ +---------+ +---------+
+ ^
+ |
+ +---------+
+ | Devices |
+ +---------+
+
+扩展IRQ模型
+===========
+
+在这种模型里面,IPI(Inter-Processor Interrupt)和CPU本地时钟中断直接发送到CPUINTC,
+CPU串口(UARTs)中断发送到LIOINTC,而其他所有设备的中断则分别发送到所连接的PCH-PIC/
+PCH-LPC/PCH-MSI,然后被EIOINTC统一收集,再直接到达CPUINTC::
+
+ +-----+ +---------+ +-------+
+ | IPI | --> | CPUINTC | <-- | Timer |
+ +-----+ +---------+ +-------+
+ ^ ^
+ | |
+ +---------+ +---------+ +-------+
+ | EIOINTC | | LIOINTC | <-- | UARTs |
+ +---------+ +---------+ +-------+
+ ^ ^
+ | |
+ +---------+ +---------+
+ | PCH-PIC | | PCH-MSI |
+ +---------+ +---------+
+ ^ ^ ^
+ | | |
+ +---------+ +---------+ +---------+
+ | PCH-LPC | | Devices | | Devices |
+ +---------+ +---------+ +---------+
+ ^
+ |
+ +---------+
+ | Devices |
+ +---------+
+
+ACPI相关的定义
+==============
+
+CPUINTC::
+
+ ACPI_MADT_TYPE_CORE_PIC;
+ struct acpi_madt_core_pic;
+ enum acpi_madt_core_pic_version;
+
+LIOINTC::
+
+ ACPI_MADT_TYPE_LIO_PIC;
+ struct acpi_madt_lio_pic;
+ enum acpi_madt_lio_pic_version;
+
+EIOINTC::
+
+ ACPI_MADT_TYPE_EIO_PIC;
+ struct acpi_madt_eio_pic;
+ enum acpi_madt_eio_pic_version;
+
+HTVECINTC::
+
+ ACPI_MADT_TYPE_HT_PIC;
+ struct acpi_madt_ht_pic;
+ enum acpi_madt_ht_pic_version;
+
+PCH-PIC::
+
+ ACPI_MADT_TYPE_BIO_PIC;
+ struct acpi_madt_bio_pic;
+ enum acpi_madt_bio_pic_version;
+
+PCH-MSI::
+
+ ACPI_MADT_TYPE_MSI_PIC;
+ struct acpi_madt_msi_pic;
+ enum acpi_madt_msi_pic_version;
+
+PCH-LPC::
+
+ ACPI_MADT_TYPE_LPC_PIC;
+ struct acpi_madt_lpc_pic;
+ enum acpi_madt_lpc_pic_version;
+
+参考文献
+========
+
+龙芯3A5000的文档:
+
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/Loongson-3A5000-usermanual-1.02-CN.pdf (中文版)
+
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/Loongson-3A5000-usermanual-1.02-EN.pdf (英文版)
+
+龙芯LS7A芯片组的文档:
+
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/Loongson-7A1000-usermanual-2.00-CN.pdf (中文版)
+
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/Loongson-7A1000-usermanual-2.00-EN.pdf (英文版)
+
+.. note::
+ - CPUINTC:即《龙芯架构参考手册卷一》第7.4节所描述的CSR.ECFG/CSR.ESTAT寄存器及其
+ 中断控制逻辑;
+ - LIOINTC:即《龙芯3A5000处理器使用手册》第11.1节所描述的“传统I/O中断”;
+ - EIOINTC:即《龙芯3A5000处理器使用手册》第11.2节所描述的“扩展I/O中断”;
+ - HTVECINTC:即《龙芯3A5000处理器使用手册》第14.3节所描述的“HyperTransport中断”;
+ - PCH-PIC/PCH-MSI:即《龙芯7A1000桥片用户手册》第5章所描述的“中断控制器”;
+ - PCH-LPC:即《龙芯7A1000桥片用户手册》第24.3节所描述的“LPC中断”。
diff --git a/Documentation/translations/zh_CN/arch/mips/booting.rst b/Documentation/translations/zh_CN/arch/mips/booting.rst
new file mode 100644
index 000000000000..485b57e0ca0b
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/mips/booting.rst
@@ -0,0 +1,34 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/arch/mips/booting.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_booting:
+
+BMIPS设备树引导
+------------------------
+
+ 一些bootloaders只支持在内核镜像开始地址处的单一入口点。而其它
+ bootloaders将跳转到ELF的开始地址处。两种方案都支持的;因为
+ CONFIG_BOOT_RAW=y and CONFIG_NO_EXCEPT_FILL=y, 所以第一条指令
+ 会立即跳转到kernel_entry()入口处执行。
+
+ 与arch/arm情况(b)类似,dt感知的引导加载程序需要设置以下寄存器:
+
+ a0 : 0
+
+ a1 : 0xffffffff
+
+ a2 : RAM中指向设备树块的物理指针(在chapterII中定义)。
+ 设备树可以位于前512MB物理地址空间(0x00000000 -
+ 0x1fffffff)的任何位置,以64位边界对齐。
+
+ 传统bootloaders不会使用这样的约定,并且它们不传入DT块。
+ 在这种情况下,Linux将通过选中CONFIG_DT_*查找DTB。
+
+ 以上约定只在32位系统中定义,因为目前没有任何64位的BMIPS实现。
diff --git a/Documentation/translations/zh_CN/arch/mips/features.rst b/Documentation/translations/zh_CN/arch/mips/features.rst
new file mode 100644
index 000000000000..0d6df97db069
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/mips/features.rst
@@ -0,0 +1,13 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/arch/mips/features.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_features:
+
+.. kernel-feat:: features mips
diff --git a/Documentation/translations/zh_CN/arch/mips/index.rst b/Documentation/translations/zh_CN/arch/mips/index.rst
new file mode 100644
index 000000000000..2a34217119ea
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/mips/index.rst
@@ -0,0 +1,29 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/arch/mips/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+===========================
+MIPS特性文档
+===========================
+
+.. toctree::
+ :maxdepth: 2
+ :numbered:
+
+ booting
+ ingenic-tcu
+
+ features
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
diff --git a/Documentation/translations/zh_CN/arch/mips/ingenic-tcu.rst b/Documentation/translations/zh_CN/arch/mips/ingenic-tcu.rst
new file mode 100644
index 000000000000..3d599a36b571
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/mips/ingenic-tcu.rst
@@ -0,0 +1,72 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/arch/mips/ingenic-tcu.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_ingenic-tcu:
+
+===============================================
+君正 JZ47xx SoC定时器/计数器硬件单元
+===============================================
+
+君正 JZ47xx SoC中的定时器/计数器单元(TCU)是一个多功能硬件块。它有多达
+8个通道,可以用作计数器,计时器,或脉冲宽度调制器。
+
+- JZ4725B, JZ4750, JZ4755 只有6个TCU通道。其它SoC都有8个通道。
+
+- JZ4725B引入了一个独立的通道,称为操作系统计时器(OST)。这是一个32位可
+ 编程定时器。在JZ4760B及以上型号上,它是64位的。
+
+- 每个TCU通道都有自己的时钟源,可以通过 TCSR 寄存器设置通道的父级时钟
+ 源(pclk、ext、rtc)、开关以及分频。
+
+ - 看门狗和OST硬件模块在它们的寄存器空间中也有相同形式的TCSR寄存器。
+ - 用于关闭/开启的 TCU 寄存器也可以关闭/开启看门狗和 OST 时钟。
+
+- 每个TCU通道在两种模式的其中一种模式下运行:
+
+ - 模式 TCU1:通道无法在睡眠模式下运行,但更易于操作。
+ - 模式 TCU2:通道可以在睡眠模式下运行,但操作比 TCU1 通道复杂一些。
+
+- 每个 TCU 通道的模式取决于使用的SoC:
+
+ - 在最老的SoC(高于JZ4740),八个通道都运行在TCU1模式。
+ - 在 JZ4725B,通道5运行在TCU2,其它通道则运行在TCU1。
+ - 在最新的SoC(JZ4750及之后),通道1-2运行在TCU2,其它通道则运行
+ 在TCU1。
+
+- 每个通道都可以生成中断。有些通道共享一条中断线,而有些没有,其在SoC型
+ 号之间的变更:
+
+ - 在很老的SoC(JZ4740及更低),通道0和通道1有它们自己的中断线;通
+ 道2-7共享最后一条中断线。
+ - 在 JZ4725B,通道0有它自己的中断线;通道1-5共享一条中断线;OST
+ 使用最后一条中断线。
+ - 在比较新的SoC(JZ4750及以后),通道5有它自己的中断线;通
+ 道0-4和(如果是8通道)6-7全部共享一条中断线;OST使用最后一条中
+ 断线。
+
+实现
+====
+
+TCU硬件的功能分布在多个驱动程序:
+
+============== ===================================
+时钟 drivers/clk/ingenic/tcu.c
+中断 drivers/irqchip/irq-ingenic-tcu.c
+定时器 drivers/clocksource/ingenic-timer.c
+OST drivers/clocksource/ingenic-ost.c
+脉冲宽度调制器 drivers/pwm/pwm-jz4740.c
+看门狗 drivers/watchdog/jz4740_wdt.c
+============== ===================================
+
+因为可以从相同的寄存器控制属于不同驱动程序和框架的TCU的各种功能,所以
+所有这些驱动程序都通过相同的控制总线通用接口访问它们的寄存器。
+
+有关TCU驱动程序的设备树绑定的更多信息,请参阅:
+Documentation/devicetree/bindings/timer/ingenic,tcu.yaml.
diff --git a/Documentation/translations/zh_CN/arch/openrisc/index.rst b/Documentation/translations/zh_CN/arch/openrisc/index.rst
new file mode 100644
index 000000000000..da21f8ab894b
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/openrisc/index.rst
@@ -0,0 +1,32 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/arch/openrisc/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_openrisc_index:
+
+=================
+OpenRISC 体系架构
+=================
+
+.. toctree::
+ :maxdepth: 2
+
+ openrisc_port
+ todo
+
+Todolist:
+ features
+
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
diff --git a/Documentation/translations/zh_CN/arch/openrisc/openrisc_port.rst b/Documentation/translations/zh_CN/arch/openrisc/openrisc_port.rst
new file mode 100644
index 000000000000..cadc580fa23b
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/openrisc/openrisc_port.rst
@@ -0,0 +1,127 @@
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/arch/openrisc/openrisc_port.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_openrisc_port:
+
+==============
+OpenRISC Linux
+==============
+
+这是Linux对OpenRISC类微处理器的移植;具体来说,最早移植目标是32位
+OpenRISC 1000系列(或1k)。
+
+关于OpenRISC处理器和正在进行中的开发的信息:
+
+ ======= =============================
+ 网站 https://openrisc.io
+ 邮箱 openrisc@lists.librecores.org
+ ======= =============================
+
+---------------------------------------------------------------------
+
+OpenRISC工具链和Linux的构建指南
+===============================
+
+为了构建和运行Linux for OpenRISC,你至少需要一个基本的工具链,或许
+还需要架构模拟器。 这里概述了准备就位这些部分的步骤。
+
+1) 工具链
+
+工具链二进制文件可以从openrisc.io或我们的github发布页面获得。不同
+工具链的构建指南可以在openrisc.io或Stafford的工具链构建和发布脚本
+中找到。
+
+ ====== =================================================
+ 二进制 https://github.com/openrisc/or1k-gcc/releases
+ 工具链 https://openrisc.io/software
+ 构建 https://github.com/stffrdhrn/or1k-toolchain-build
+ ====== =================================================
+
+2) 构建
+
+像往常一样构建Linux内核::
+
+ make ARCH=openrisc CROSS_COMPILE="or1k-linux-" defconfig
+ make ARCH=openrisc CROSS_COMPILE="or1k-linux-"
+
+3) 在FPGA上运行(可选)
+
+OpenRISC社区通常使用FuseSoC来管理构建和编程SoC到FPGA中。 下面是用
+OpenRISC SoC对De0 Nano开发板进行编程的一个例子。 在构建过程中,
+FPGA RTL是从FuseSoC IP核库中下载的代码,并使用FPGA供应商工具构建。
+二进制文件用openocd加载到电路板上。
+
+::
+
+ git clone https://github.com/olofk/fusesoc
+ cd fusesoc
+ sudo pip install -e .
+
+ fusesoc init
+ fusesoc build de0_nano
+ fusesoc pgm de0_nano
+
+ openocd -f interface/altera-usb-blaster.cfg \
+ -f board/or1k_generic.cfg
+
+ telnet localhost 4444
+ > init
+ > halt; load_image vmlinux ; reset
+
+4) 在模拟器上运行(可选)
+
+QEMU是一个处理器仿真器,我们推荐它来模拟OpenRISC平台。 请按照QEMU网
+站上的OpenRISC说明,让Linux在QEMU上运行。 你可以自己构建QEMU,但你的
+Linux发行版可能提供了支持OpenRISC的二进制包。
+
+ ============= ======================================================
+ qemu openrisc https://wiki.qemu.org/Documentation/Platforms/OpenRISC
+ ============= ======================================================
+
+---------------------------------------------------------------------
+
+术语表
+======
+
+代码中使用了以下符号约定以将范围限制在几个特定处理器实现上:
+
+========= =======================
+openrisc: OpenRISC类型处理器
+or1k: OpenRISC 1000系列处理器
+or1200: OpenRISC 1200处理器
+========= =======================
+
+---------------------------------------------------------------------
+
+历史
+====
+
+2003-11-18 Matjaz Breskvar (phoenix@bsemi.com)
+ 将linux初步移植到OpenRISC或32架构。
+ 所有的核心功能都实现了,并且可以使用。
+
+2003-12-08 Matjaz Breskvar (phoenix@bsemi.com)
+ 彻底改变TLB失误处理。
+ 重写异常处理。
+ 在默认的initrd中实现了sash-3.6的所有功能。
+ 大幅改进的版本。
+
+2004-04-10 Matjaz Breskvar (phoenix@bsemi.com)
+ 大量的bug修复。
+ 支持以太网,http和telnet服务器功能。
+ 可以运行许多标准的linux应用程序。
+
+2004-06-26 Matjaz Breskvar (phoenix@bsemi.com)
+ 移植到2.6.x。
+
+2004-11-30 Matjaz Breskvar (phoenix@bsemi.com)
+ 大量的bug修复和增强功能。
+ 增加了opencores framebuffer驱动。
+
+2010-10-09 Jonas Bonn (jonas@southpole.se)
+ 重大重写,使其与上游的Linux 2.6.36看齐。
diff --git a/Documentation/translations/zh_CN/arch/openrisc/todo.rst b/Documentation/translations/zh_CN/arch/openrisc/todo.rst
new file mode 100644
index 000000000000..1f6f95616633
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/openrisc/todo.rst
@@ -0,0 +1,23 @@
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/arch/openrisc/todo.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_openrisc_todo.rst:
+
+========
+待办事项
+========
+
+OpenRISC Linux的移植已经完全投入使用,并且从 2.6.35 开始就一直在上游同步。
+然而,还有一些剩余的项目需要在未来几个月内完成。 下面是一个即将进行调查的已知
+不尽完美的项目列表,即我们的待办事项列表。
+
+- 实现其余的DMA API……dma_map_sg等。
+
+- 完成重命名清理工作……代码中提到了or32,这是架构的一个老名字。 我们
+ 已经确定的名字是or1k,这个改变正在以缓慢积累的方式进行。 目前,or32相当
+ 于or1k。
diff --git a/Documentation/translations/zh_CN/arch/parisc/debugging.rst b/Documentation/translations/zh_CN/arch/parisc/debugging.rst
new file mode 100644
index 000000000000..c6b9de6d3175
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/parisc/debugging.rst
@@ -0,0 +1,45 @@
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/arch/parisc/debugging.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_parisc_debugging:
+
+=================
+调试PA-RISC
+=================
+
+好吧,这里有一些关于调试linux/parisc的较底层部分的信息。
+
+
+1. 绝对地址
+=====================
+
+很多汇编代码目前运行在实模式下,这意味着会使用绝对地址,而不是像内核其他
+部分那样使用虚拟地址。要将绝对地址转换为虚拟地址,你可以在System.map中查
+找,添加__PAGE_OFFSET(目前是0x10000000)。
+
+
+2. HPMCs
+========
+
+当实模式的代码试图访问不存在的内存时,会出现HPMC(high priority machine
+check)而不是内核oops。若要调试HPMC,请尝试找到系统响应程序/请求程序地址。
+系统请求程序地址应该与(某)处理器的HPA(I/O范围内的高地址)相匹配;系统响应程
+序地址是实模式代码试图访问的地址。
+
+系统响应程序地址的典型值是大于__PAGE_OFFSET (0x10000000)的地址,这意味着
+在实模式试图访问它之前,虚拟地址没有被翻译成物理地址。
+
+
+3. 有趣的Q位
+============
+
+某些非常关键的代码必须清除PSW中的Q位。当Q位被清除时,CPU不会更新中断处理
+程序所读取的寄存器,以找出机器被中断的位置——所以如果你在清除Q位的指令和再
+次设置Q位的RFI之间遇到中断,你不知道它到底发生在哪里。如果你幸运的话,IAOQ
+会指向清除Q位的指令,如果你不幸运的话,它会指向任何地方。通常Q位的问题会
+表现为无法解释的系统挂起或物理内存越界。
diff --git a/Documentation/translations/zh_CN/arch/parisc/index.rst b/Documentation/translations/zh_CN/arch/parisc/index.rst
new file mode 100644
index 000000000000..9f69283bd1c9
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/parisc/index.rst
@@ -0,0 +1,31 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/arch/parisc/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_parisc_index:
+
+====================
+PA-RISC体系架构
+====================
+
+.. toctree::
+ :maxdepth: 2
+
+ debugging
+ registers
+
+Todolist:
+
+ features
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
diff --git a/Documentation/translations/zh_CN/arch/parisc/registers.rst b/Documentation/translations/zh_CN/arch/parisc/registers.rst
new file mode 100644
index 000000000000..a55250afcc27
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/parisc/registers.rst
@@ -0,0 +1,156 @@
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/arch/parisc/registers.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_parisc_registers:
+
+=========================
+Linux/PA-RISC的寄存器用法
+=========================
+
+[ 用星号表示目前尚未实现的计划用途。 ]
+
+ABI约定的通用寄存器
+===================
+
+控制寄存器
+----------
+
+============================ =================================
+CR 0 (恢复计数器) 用于ptrace
+CR 1-CR 7(无定义) 未使用
+CR 8 (Protection ID) 每进程值*
+CR 9, 12, 13 (PIDS) 未使用
+CR10 (CCR) FPU延迟保存*
+CR11 按照ABI的规定(SAR)
+CR14 (中断向量) 初始化为 fault_vector
+CR15 (EIEM) 所有位初始化为1*
+CR16 (间隔计时器) 读取周期数/写入开始时间间隔计时器
+CR17-CR22 中断参数
+CR19 中断指令寄存器
+CR20 中断空间寄存器
+CR21 中断偏移量寄存器
+CR22 中断 PSW
+CR23 (EIRR) 读取未决中断/写入清除位
+CR24 (TR 0) 内核空间页目录指针
+CR25 (TR 1) 用户空间页目录指针
+CR26 (TR 2) 不使用
+CR27 (TR 3) 线程描述符指针
+CR28 (TR 4) 不使用
+CR29 (TR 5) 不使用
+CR30 (TR 6) 当前 / 0
+CR31 (TR 7) 临时寄存器,在不同地方使用
+============================ =================================
+
+空间寄存器(内核模式)
+----------------------
+
+======== ==============================
+SR0 临时空间寄存器
+SR4-SR7 设置为0
+SR1 临时空间寄存器
+SR2 内核不应该破坏它
+SR3 用于用户空间访问(当前进程)
+======== ==============================
+
+空间寄存器(用户模式)
+----------------------
+
+======== ============================
+SR0 临时空间寄存器
+SR1 临时空间寄存器
+SR2 保存Linux gateway page的空间
+SR3 在内核中保存用户地址空间的值
+SR4-SR7 定义了用户/内核的短地址空间
+======== ============================
+
+
+处理器状态字
+------------
+
+====================== ================================================
+W (64位地址) 0
+E (小尾端) 0
+S (安全间隔计时器) 0
+T (产生分支陷阱) 0
+H (高特权级陷阱) 0
+L (低特权级陷阱) 0
+N (撤销下一条指令) 被C代码使用
+X (数据存储中断禁用) 0
+B (产生分支) 被C代码使用
+C (代码地址转译) 1, 在执行实模式代码时为0
+V (除法步长校正) 被C代码使用
+M (HPMC 掩码) 0, 在执行HPMC操作*时为1
+C/B (进/借 位) 被C代码使用
+O (有序引用) 1*
+F (性能监视器) 0
+R (回收计数器陷阱) 0
+Q (收集中断状态) 1 (在rfi之前的代码中为0)
+P (保护标识符) 1*
+D (数据地址转译) 1, 在执行实模式代码时为0
+I (外部中断掩码) 由cli()/sti()宏使用。
+====================== ================================================
+
+“隐形”寄存器(影子寄存器)
+---------------------------
+
+============= ===================
+PSW W 默认值 0
+PSW E 默认值 0
+影子寄存器 被中断处理代码使用
+TOC启用位 1
+============= ===================
+
+----------------------------------------------------------
+
+PA-RISC架构定义了7个寄存器作为“影子寄存器”。这些寄存器在
+RETURN FROM INTERRUPTION AND RESTORE指令中使用,通过消
+除中断处理程序中对一般寄存器(GR)的保存和恢复的需要来减
+少状态保存和恢复时间。影子寄存器是GRs 1, 8, 9, 16, 17,
+24和25。
+
+-------------------------------------------------------------------------
+
+寄存器使用说明,最初由John Marvin提供,并由Randolph Chung提供一些补充说明。
+
+对于通用寄存器:
+
+r1,r2,r19-r26,r28,r29 & r31可以在不保存它们的情况下被使用。当然,如果你
+关心它们,在调用另一个程序之前,你也需要保存它们。上面的一些寄存器确实
+有特殊的含义,你应该注意一下:
+
+ r1:
+ addil指令是硬性规定将其结果放在r1中,所以如果你使用这条指令要
+ 注意这点。
+
+ r2:
+ 这就是返回指针。一般来说,你不想使用它,因为你需要这个指针来返
+ 回给你的调用者。然而,它与这组寄存器组合在一起,因为调用者不能
+ 依赖你返回时的值是相同的,也就是说,你可以将r2复制到另一个寄存
+ 器,并在作废r2后通过该寄存器返回,这应该不会给调用程序带来问题。
+
+ r19-r22:
+ 这些通常被认为是临时寄存器。
+ 请注意,在64位中它们是arg7-arg4。
+
+ r23-r26:
+ 这些是arg3-arg0,也就是说,如果你不再关心传入的值,你可以使用
+ 它们。
+
+ r28,r29:
+ 这俩是ret0和ret1。它们是你传入返回值的地方。r28是主返回值。当返回
+ 小结构体时,r29也可以用来将数据传回给调用程序。
+
+ r30:
+ 栈指针
+
+ r31:
+ ble指令将返回指针放在这里。
+
+
+ r3-r18,r27,r30需要被保存和恢复。r3-r18只是一般用途的寄存器。
+ r27是数据指针,用来使对全局变量的引用更容易。r30是栈指针。
diff --git a/Documentation/translations/zh_CN/arch/riscv/boot-image-header.rst b/Documentation/translations/zh_CN/arch/riscv/boot-image-header.rst
new file mode 100644
index 000000000000..779b5172fe24
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/riscv/boot-image-header.rst
@@ -0,0 +1,69 @@
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/arch/riscv/boot-image-header.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_boot-image-header.rst:
+
+==========================
+RISC-V Linux启动镜像文件头
+==========================
+
+:Author: Atish Patra <atish.patra@wdc.com>
+:Date: 20 May 2019
+
+此文档仅描述RISC-V Linux 启动文件头的详情。
+
+TODO:
+ 写一个完整的启动指南。
+
+在解压后的Linux内核镜像中存在以下64字节的文件头::
+
+ u32 code0; /* Executable code */
+ u32 code1; /* Executable code */
+ u64 text_offset; /* Image load offset, little endian */
+ u64 image_size; /* Effective Image size, little endian */
+ u64 flags; /* kernel flags, little endian */
+ u32 version; /* Version of this header */
+ u32 res1 = 0; /* Reserved */
+ u64 res2 = 0; /* Reserved */
+ u64 magic = 0x5643534952; /* Magic number, little endian, "RISCV" */
+ u32 magic2 = 0x05435352; /* Magic number 2, little endian, "RSC\x05" */
+ u32 res3; /* Reserved for PE COFF offset */
+
+这种头格式与PE/COFF文件头兼容,并在很大程度上受到ARM64文件头的启发。因此,ARM64
+和RISC-V文件头可以在未来合并为一个共同的头。
+
+注意
+====
+
+- 将来也可以复用这个文件头,用来对RISC-V的EFI桩提供支持。为了使内核镜像如同一个
+ EFI应用程序一样加载,EFI规范中规定在内核镜像的开始需要PE/COFF镜像文件头。为了
+ 支持EFI桩,应该用“MZ”魔术字符替换掉code0,并且res3(偏移量未0x3c)应指向PE/COFF
+ 文件头的其余部分.
+
+- 表示文件头版本号的Drop-bit位域
+
+ ========== ==========
+ Bits 0:15 次要 版本
+ Bits 16:31 主要 版本
+ ========== ==========
+
+ 这保持了新旧版本之间的兼容性。
+ 当前版本被定义为0.2。
+
+- 从版本0.2开始,结构体成员“magic”就已经被弃用,在之后的版本中,可能会移除掉它。
+ 最初,该成员应该与ARM64头的“magic”成员匹配,但遗憾的是并没有。
+ “magic2”成员代替“magic”成员与ARM64头相匹配。
+
+- 在当前的文件头,标志位域只剩下了一个位。
+
+ ===== ==============================
+ Bit 0 内核字节序。1 if BE, 0 if LE.
+ ===== ==============================
+
+- 对于引导加载程序加载内核映像来说,image_size成员对引导加载程序而言是必须的,否
+ 则将引导失败。
diff --git a/Documentation/translations/zh_CN/arch/riscv/boot.rst b/Documentation/translations/zh_CN/arch/riscv/boot.rst
new file mode 100644
index 000000000000..0c2619095819
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/riscv/boot.rst
@@ -0,0 +1,155 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/arch/riscv/boot.rst
+
+:翻译:
+
+ 龙进 Jin Long <longjin@dragonos.org>
+
+========================
+RISC-V内核启动要求和限制
+========================
+
+:Author: Alexandre Ghiti <alexghiti@rivosinc.com>
+:Date: 23 May 2023
+
+这份文档描述了RISC-V内核对引导加载程序和固件的期望,以及任何开发者在接触
+早期启动过程时必须牢记的约束。在这份文档中, ``早期启动过程`` 指的是在最
+终虚拟映射设置之前运行的任何代码。
+
+内核预加载的要求和限制
+======================
+
+RISC-V内核对引导加载程序和平台固件有以下要求:
+
+寄存器状态
+----------
+
+RISC-V内核期望:
+
+ * ``$a0`` 应包含当前核心的hartid。
+ * ``$a1`` 应包含内存中设备树的地址。
+
+CSR 寄存器状态
+--------------
+
+RISC-V内核期望:
+
+ * ``$satp = 0``: 如果存在MMU,必须将其禁用。
+
+为常驻固件保留的内存
+--------------------
+
+RISC-V内核在直接映射中不能映射任何常驻内存或用PMPs保护的内存,
+因此固件必须根据设备树规范 和/或 UEFI规范正确标记这些区域。
+
+内核的位置
+----------
+
+RISC-V内核期望被放置在PMD边界(对于rv64为2MB对齐,对于rv32为4MB对齐)。
+请注意,如果不是这样,EFI stub 将重定位内核。
+
+硬件描述
+--------
+
+固件可以将设备树或ACPI表传递给RISC-V内核。
+
+设备树可以直接从前一阶段通过$a1寄存器传递给内核,或者在使用UEFI启动时,
+可以通过EFI配置表传递。
+
+ACPI表通过EFI配置表传递给内核。在这种情况下,EFI stub 仍然会创建一个
+小的设备树。请参阅下面的"EFI stub 和设备树"部分,了解这个设备树的详细
+信息。
+
+内核入口
+--------
+
+在SMP系统中,有两种方法可以进入内核:
+
+- ``RISCV_BOOT_SPINWAIT``:固件在内核中释放所有的hart,一个hart赢
+ 得抽奖并执行早期启动代码,而其他的hart则停在那里等待初始化完成。这种
+ 方法主要用于支持没有SBI HSM扩展和M模式RISC-V内核的旧固件。
+- ``有序启动``:固件只释放一个将执行初始化阶段的hart,然后使用SBI HSM
+ 扩展启动所有其他的hart。有序启动方法是启动RISC-V内核的首选启动方法,
+ 因为它可以支持CPU热插拔和kexec。
+
+UEFI
+----
+
+UEFI 内存映射
+~~~~~~~~~~~~~
+
+使用UEFI启动时,RISC-V内核将只使用EFI内存映射来填充系统内存。
+
+UEFI固件必须解析 ``/reserved-memory`` 设备树节点的子节点,并遵守设备
+树规范,将这些子节点的属性( ``no-map`` 和 ``reusable`` )转换为其正
+确的EFI等价物(参见设备树规范v0.4-rc1的"3.5.4/reserved-memory和
+UEFI"部分)。
+
+RISCV_EFI_BOOT_PROTOCOL
+~~~~~~~~~~~~~~~~~~~~~~~
+
+使用UEFI启动时,EFI stub 需要引导hartid以便将其传递给 ``$a1`` 中的
+RISC-V内核。EFI stub使用以下方法之一获取引导hartid:
+
+- ``RISCV_EFI_BOOT_PROTOCOL`` (**首选**)。
+- ``boot-hartid`` 设备树子节点(**已弃用**)。
+
+任何新的固件都必须实现 ``RISCV_EFI_BOOT_PROTOCOL``,因为基于设备树
+的方法现已被弃用。
+
+早期启动的要求和约束
+====================
+
+RISC-V内核的早期启动过程遵循以下约束:
+
+EFI stub 和设备树
+-----------------
+
+使用UEFI启动时,EFI stub 会用与arm64相同的参数补充(或创建)设备树,
+这些参数在Documentation/arch/arm/uefi.rst中的
+"UEFI kernel supporton ARM"段落中有描述。
+
+虚拟映射安装
+------------
+
+在RISC-V内核中,虚拟映射的安装分为两步进行:
+
+1. ``setup_vm()`` 在 ``early_pg_dir`` 中安装一个临时的内核映射,这
+ 允许发现系统内存。 此时只有内核文本/数据被映射。在建立这个映射时,
+ 不能进行分配(因为系统内存还未知),所以``early_pg_dir``页表是静
+ 态分配的(每个级别只使用一个表)。
+
+2. ``setup_vm_final()`` 在 ``swapper_pg_dir`` 中创建最终的内核映
+ 射,并利用发现的系统内存 创建线性映射。在建立这个映射时,内核可以
+ 分配内存,但不能直接访问它(因为直接映射还不存在),所以它使用fixmap
+ 区域的临时映射来访问新分配的页表级别。
+
+为了让 ``virt_to_phys()`` 和 ``phys_to_virt()`` 能够正确地将直接
+映射地址转换为物理地址,它们需要知道DRAM的起始位置。这发生在步骤1之后,
+就在步骤2安装直接映射之前(参见arch/riscv/mm/init.c中的
+``setup_bootmem()`` 函数)。在安装最终虚拟映射之前使用这些宏时必须
+仔细检查。
+
+通过fixmap进行设备树映射
+------------------------
+
+由于 ``reserved_mem`` 数组是用 ``setup_vm()`` 建立的虚拟地址初始化
+的,并且与``setup_vm_final()``建立的映射一起使用,RISC-V内核使用
+fixmap区域来映射设备树。这确保设备树可以通过两种虚拟映射访问。
+
+Pre-MMU执行
+-----------
+
+在建立第一个虚拟映射之前,需要运行一些代码。这些包括第一个虚拟映射的安装本身,
+早期替代方案的修补,以及内核命令行的早期解析。这些代码必须非常小心地编译,因为:
+
+- ``-fno-pie``:这对于使用``-fPIE``的可重定位内核是必需的,否则,任何对
+ 全局符号的访问都将通过 GOT进行,而GOT只是虚拟地重新定位。
+- ``-mcmodel=medany``:任何对全局符号的访问都必须是PC相对的,以避免在设
+ 置MMU之前发生任何重定位。
+- *所有* 的仪表化功能也必须被禁用(包括KASAN,ftrace和其他)。
+
+由于使用来自不同编译单元的符号需要用这些标志编译该单元,我们建议尽可能不要使用
+外部符号。
diff --git a/Documentation/translations/zh_CN/arch/riscv/index.rst b/Documentation/translations/zh_CN/arch/riscv/index.rst
new file mode 100644
index 000000000000..96573459105e
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/riscv/index.rst
@@ -0,0 +1,31 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/arch/riscv/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_riscv_index:
+
+===============
+RISC-V 体系结构
+===============
+
+.. toctree::
+ :maxdepth: 1
+
+ boot
+ boot-image-header
+ vm-layout
+ patch-acceptance
+
+
+.. only:: subproject and html
+
+ 目录
+ ====
+
+ * :ref:`genindex`
diff --git a/Documentation/translations/zh_CN/arch/riscv/patch-acceptance.rst b/Documentation/translations/zh_CN/arch/riscv/patch-acceptance.rst
new file mode 100644
index 000000000000..c8eb230ca8ee
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/riscv/patch-acceptance.rst
@@ -0,0 +1,33 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/arch/riscv/patch-acceptance.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_riscv_patch-acceptance:
+
+arch/riscv 开发者维护指南
+=========================
+
+概述
+----
+RISC-V指令集体系结构是公开开发的:
+正在进行的草案可供所有人查看和测试实现。新模块或者扩展草案可能会在开发过程中发
+生更改---有时以不兼容的方式对以前的草案进行更改。这种灵活性可能会给RISC-V Linux
+维护者带来挑战。Linux开发过程更喜欢经过良好检查和测试的代码,而不是试验代码。我
+们希望推广同样的规则到即将被内核合并的RISC-V相关代码。
+
+附加的提交检查单
+----------------
+我们仅接受相关标准已经被RISC-V基金会标准为“已批准”或“已冻结”的扩展或模块的补丁。
+(开发者当然可以维护自己的Linux内核树,其中包含所需代码扩展草案的代码。)
+
+此外,RISC-V规范允许爱好者创建自己的自定义扩展。这些自定义拓展不需要通过RISC-V
+基金会的任何审核或批准。为了避免将爱好者一些特别的RISC-V拓展添加进内核代码带来
+的维护复杂性和对性能的潜在影响,我们将只接受RISC-V基金会正式冻结或批准的的扩展
+补丁。(开发者当然可以维护自己的Linux内核树,其中包含他们想要的任何自定义扩展
+的代码。)
diff --git a/Documentation/translations/zh_CN/arch/riscv/vm-layout.rst b/Documentation/translations/zh_CN/arch/riscv/vm-layout.rst
new file mode 100644
index 000000000000..4b9f4dcf6c19
--- /dev/null
+++ b/Documentation/translations/zh_CN/arch/riscv/vm-layout.rst
@@ -0,0 +1,104 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/arch/riscv/vm-layout.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+ Binbin Zhou <zhoubinbin@loongson.cn>
+
+============================
+RISC-V Linux上的虚拟内存布局
+============================
+
+:作者: Alexandre Ghiti <alex@ghiti.fr>
+:日期: 12 February 2021
+
+这份文件描述了RISC-V Linux内核使用的虚拟内存布局。
+
+32位 RISC-V Linux 内核
+======================
+
+RISC-V Linux Kernel SV32
+------------------------
+
+TODO
+
+64位 RISC-V Linux 内核
+======================
+
+RISC-V特权架构文档指出,64位地址 "必须使第63-48位值都等于第47位,否则将发生缺页异常。":这将虚
+拟地址空间分成两半,中间有一个非常大的洞,下半部分是用户空间所在的地方,上半部分是RISC-V Linux
+内核所在的地方。
+
+RISC-V Linux Kernel SV39
+------------------------
+
+::
+
+ ========================================================================================================================
+ 开始地址 | 偏移 | 结束地址 | 大小 | 虚拟内存区域描述
+ ========================================================================================================================
+ | | | |
+ 0000000000000000 | 0 | 0000003fffffffff | 256 GB | 用户空间虚拟内存,每个内存管理器不同
+ __________________|____________|__________________|_________|___________________________________________________________
+ | | | |
+ 0000004000000000 | +256 GB | ffffffbfffffffff | ~16M TB | ... 巨大的、几乎64位宽的直到内核映射的-256GB地方
+ | | | | 开始偏移的非经典虚拟内存地址空洞。
+ | | | |
+ __________________|____________|__________________|_________|___________________________________________________________
+ |
+ | 内核空间的虚拟内存,在所有进程之间共享:
+ ____________________________________________________________|___________________________________________________________
+ | | | |
+ ffffffc6fee00000 | -228 GB | ffffffc6feffffff | 2 MB | fixmap
+ ffffffc6ff000000 | -228 GB | ffffffc6ffffffff | 16 MB | PCI io
+ ffffffc700000000 | -228 GB | ffffffc7ffffffff | 4 GB | vmemmap
+ ffffffc800000000 | -224 GB | ffffffd7ffffffff | 64 GB | vmalloc/ioremap space
+ ffffffd800000000 | -160 GB | fffffff6ffffffff | 124 GB | 直接映射所有物理内存
+ fffffff700000000 | -36 GB | fffffffeffffffff | 32 GB | kasan
+ __________________|____________|__________________|_________|____________________________________________________________
+ |
+ |
+ ____________________________________________________________|____________________________________________________________
+ | | | |
+ ffffffff00000000 | -4 GB | ffffffff7fffffff | 2 GB | modules, BPF
+ ffffffff80000000 | -2 GB | ffffffffffffffff | 2 GB | kernel
+ __________________|____________|__________________|_________|____________________________________________________________
+
+
+RISC-V Linux Kernel SV48
+------------------------
+
+::
+
+ ========================================================================================================================
+ 开始地址 | 偏移 | 结束地址 | 大小 | 虚拟内存区域描述
+ ========================================================================================================================
+ | | | |
+ 0000000000000000 | 0 | 00007fffffffffff | 128 TB | 用户空间虚拟内存,每个内存管理器不同
+ __________________|____________|__________________|_________|___________________________________________________________
+ | | | |
+ 0000800000000000 | +128 TB | ffff7fffffffffff | ~16M TB | ... 巨大的、几乎64位宽的直到内核映射的-128TB地方
+ | | | | 开始偏移的非经典虚拟内存地址空洞。
+ | | | |
+ __________________|____________|__________________|_________|___________________________________________________________
+ |
+ | 内核空间的虚拟内存,在所有进程之间共享:
+ ____________________________________________________________|___________________________________________________________
+ | | | |
+ ffff8d7ffee00000 | -114.5 TB | ffff8d7ffeffffff | 2 MB | fixmap
+ ffff8d7fff000000 | -114.5 TB | ffff8d7fffffffff | 16 MB | PCI io
+ ffff8d8000000000 | -114.5 TB | ffff8f7fffffffff | 2 TB | vmemmap
+ ffff8f8000000000 | -112.5 TB | ffffaf7fffffffff | 32 TB | vmalloc/ioremap space
+ ffffaf8000000000 | -80.5 TB | ffffef7fffffffff | 64 TB | 直接映射所有物理内存
+ ffffef8000000000 | -16.5 TB | fffffffeffffffff | 16.5 TB | kasan
+ __________________|____________|__________________|_________|____________________________________________________________
+ |
+ | 从此处开始,与39-bit布局相同:
+ ____________________________________________________________|____________________________________________________________
+ | | | |
+ ffffffff00000000 | -4 GB | ffffffff7fffffff | 2 GB | modules, BPF
+ ffffffff80000000 | -2 GB | ffffffffffffffff | 2 GB | kernel
+ __________________|____________|__________________|_________|____________________________________________________________
diff --git a/Documentation/translations/zh_CN/core-api/assoc_array.rst b/Documentation/translations/zh_CN/core-api/assoc_array.rst
new file mode 100644
index 000000000000..3649bf0d1488
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/assoc_array.rst
@@ -0,0 +1,473 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/assoc_array.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+
+.. _cn_core-api_assoc_array:
+
+==================
+通用关联数组的实现
+==================
+
+简介
+====
+
+这个关联数组的实现是一个具有以下属性的对象容器:
+
+1. 对象是不透明的指针。该实现不关心它们指向哪里(如果有的话)或它们指向什么(如果有的
+ 话)。
+
+ .. note::
+
+ 指向对象的指针 *必须* 在最小有效位为零。
+
+2. 对象不需要包含供数组使用的链接块。这允许一个对象同时位于多个数组中。相反,数组是
+ 由指向对象的元数据块组成的。
+
+3. 对象需要索引键来定位它们在阵列中的位置。
+
+4. 索引键必须是唯一的。插入一个与已经在数组中的且具有相同键值的对象将取代旧的对象。
+
+5. 索引键可以是任何长度,也可以是不同的长度。
+
+6. 索引键应该在早期就对长度进行编码,即在任何由于长度引起的变化出现之前。
+
+7. 索引键可以包括一个哈希值,以便将对象分散到整个数组中。
+
+8. 该数组可以迭代。对象不一定会按索引键的顺序出现。
+
+9. 数组可以在被修改的时候进行迭代,只要RCU的读锁被迭代器持有。然而,请注意,在这种情
+ 况下,一些对象可能会被看到不止一次。如果这是个问题,迭代器应该锁定以防止修改。然
+ 而,除非删除,否则对象不会被错过。
+
+10. 数组中的对象可以通过其索引键进行查询。
+
+11. 当数组被修改时,对象可以被查询,前提是进行查询的线程持有RCU的读锁。
+
+该实现在内部使用了一棵由16个指针节点组成的树,这些节点在每一层都由索引键的小数点进行索
+引,其方式与基数树相同。为了提高内存效率,可以放置快捷键,以跳过本来是一系列单占节点的地
+方。此外,节点将叶子对象指针打包到节点的空闲空间中,而不是做一个额外的分支,直到有对象
+需要被添加到一个完整的节点中。
+
+公用API
+=======
+
+公用API可以在 ``<linux/assoc_array.h>`` 中找到。关联数组的根是以下结构::
+
+ struct assoc_array {
+ ...
+ };
+
+该代码是通过启用 ``CONFIG_ASSOCIATIVE_ARRAY`` 来选择的,以::
+
+ ./script/config -e ASSOCIATIVE_ARRAY
+
+
+编辑脚本
+--------
+
+插入和删除功能会产生一个“编辑脚本”,以后可以应用这个脚本来实现更改,而不会造成 ``ENOMEM``
+风险。这保留了将被安装在内部树中的预分配的元数据块,并跟踪应用脚本时将从树中删除的元数
+据块。
+
+在脚本应用后,这也被用来跟踪死块和死对象,以便以后可以释放它们。释放是在RCU宽限期过后
+进行的--因此允许访问功能在RCU读锁下进行。
+
+脚本在API之外显示为一个类型为::
+
+ struct assoc_array_edit;
+
+有两个处理脚本的功能:
+
+1. 应用一个编辑脚本::
+
+ void assoc_array_apply_edit(struct assoc_array_edit *edit);
+
+这将执行编辑功能,插值各种写屏障,以允许在RCU读锁下的访问继续进行。然后,编辑脚本将被
+传递给 ``call_rcu()`` ,以释放它和它所指向的任何死的东西。
+
+2. Cancel an edit script::
+
+ void assoc_array_cancel_edit(struct assoc_array_edit *edit);
+
+这将立即释放编辑脚本和所有预分配的内存。如果这是为了插入,新的对象不会被这个函数释放,
+而是必须由调用者释放。
+
+这些函数保证不会失败。
+
+
+操作表
+------
+
+各种功能采用了一个操作表::
+
+ struct assoc_array_ops {
+ ...
+ };
+
+这指出了一些方法,所有这些方法都需要提供:
+
+1. 从调用者数据中获取索引键的一个块::
+
+ unsigned long (*get_key_chunk)(const void *index_key, int level);
+
+这应该返回一个由调用者提供的索引键的块,从level参数给出的 *比特* 位置开始。level参数将
+是 ``ASSOC_ARRAY_KEY_CHUNK_SIZE`` 的倍数,该函数应返回 ``ASSOC_ARRAY_KEY_CHUNK_SIZE``
+位。不可能出现错误。
+
+
+2. 获取一个对象的索引键的一个块::
+
+ unsigned long (*get_object_key_chunk)(const void *object, int level);
+
+和前面的函数一样,但是从数组中的一个对象而不是从调用者提供的索引键中获取数据。
+
+
+3. 看看这是否是我们要找的对象::
+
+ bool (*compare_object)(const void *object, const void *index_key);
+
+将对象与一个索引键进行比较,如果匹配则返回 ``true`` ,不匹配则返回 ``false`` 。
+
+
+4. 对两个对象的索引键进行比较::
+
+ int (*diff_objects)(const void *object, const void *index_key);
+
+返回指定对象的索引键与给定索引键不同的比特位置,如果它们相同,则返回-1。
+
+
+5. 释放一个对象::
+
+ void (*free_object)(void *object);
+
+释放指定的对象。注意,这可能是在调用 ``assoc_array_apply_edit()`` 后的一个RCU宽限期内
+调用的,所以在模块卸载时可能需要 ``synchronize_rcu()`` 。
+
+
+操控函数
+--------
+
+有一些函数用于操控关联数组:
+
+1. 初始化一个关联数组::
+
+ void assoc_array_init(struct assoc_array *array);
+
+这将初始化一个关联数组的基础结构。它不会失败。
+
+
+2. 在一个关联数组中插入/替换一个对象::
+
+ struct assoc_array_edit *
+ assoc_array_insert(struct assoc_array *array,
+ const struct assoc_array_ops *ops,
+ const void *index_key,
+ void *object);
+
+这将把给定的对象插入数组中。注意,指针的最小有效位必须是0,因为它被用来在内部标记指针的类
+型。
+
+如果该键已经存在一个对象,那么它将被新的对象所取代,旧的对象将被自动释放。
+
+``index_key`` 参数应持有索引键信息,并在调用OPP表中的方法时传递给它们。
+
+这个函数不对数组本身做任何改动,而是返回一个必须应用的编辑脚本。如果出现内存不足的错误,会
+返回 ``-ENOMEM`` 。
+
+调用者应专门锁定数组的其他修改器。
+
+
+3. 从一个关联数组中删除一个对象::
+
+ struct assoc_array_edit *
+ assoc_array_delete(struct assoc_array *array,
+ const struct assoc_array_ops *ops,
+ const void *index_key);
+
+这将从数组中删除一个符合指定数据的对象。
+
+``index_key`` 参数应持有索引键信息,并在调用OPP表中的方法时传递给它们。
+
+这个函数不对数组本身做任何改动,而是返回一个必须应用的编辑脚本。 ``-ENOMEM`` 在出现内存不足
+的错误时返回。如果在数组中没有找到指定的对象,将返回 ``NULL`` 。
+
+调用者应该对数组的其他修改者进行专门锁定。
+
+
+4. 从一个关联数组中删除所有对象::
+
+ struct assoc_array_edit *
+ assoc_array_clear(struct assoc_array *array,
+ const struct assoc_array_ops *ops);
+
+这个函数删除了一个关联数组中的所有对象,使其完全为空。
+
+这个函数没有对数组本身做任何改动,而是返回一个必须应用的编辑脚本。如果出现内存不足
+的错误,则返回 ``-ENOMEM`` 。
+
+调用者应专门锁定数组的其他修改者。
+
+
+5. 销毁一个关联数组,删除所有对象::
+
+ void assoc_array_destroy(struct assoc_array *array,
+ const struct assoc_array_ops *ops);
+
+这将破坏关联数组的内容,使其完全为空。在这个函数销毁数组的同时,不允许另一个线程在RCU读锁
+下遍历数组,因为在内存释放时不执行RCU延迟,这需要分配内存。
+
+调用者应该专门针对数组的其他修改者和访问者进行锁定。
+
+
+6. 垃圾回收一个关联数组::
+
+ int assoc_array_gc(struct assoc_array *array,
+ const struct assoc_array_ops *ops,
+ bool (*iterator)(void *object, void *iterator_data),
+ void *iterator_data);
+
+这是对一个关联数组中的对象进行迭代,并将每个对象传递给 ``iterator()`` 。如果 ``iterator()`` 返回
+true,该对象被保留。如果它返回 ``false`` ,该对象将被释放。如果 ``iterator()`` 函数返回 ``true`` ,它必须
+在返回之前对该对象进行适当的 ``refcount`` 递增。
+
+如果可能的话,内部树将被打包下来,作为迭代的一部分,以减少其中的节点数量。
+
+``iterator_data`` 被直接传递给 ``iterator()`` ,否则会被函数忽略。
+
+如果成功,该函数将返回 ``0`` ,如果没有足够的内存,则返回 ``-ENOMEM`` 。
+
+在这个函数执行过程中,其他线程有可能在RCU读锁下迭代或搜索阵列。调用者应该专门针对数组的其他
+修改者进行锁定。
+
+
+访问函数
+--------
+
+有两个函数用于访问一个关联数组:
+
+1. 遍历一个关联数组中的所有对象::
+
+ int assoc_array_iterate(const struct assoc_array *array,
+ int (*iterator)(const void *object,
+ void *iterator_data),
+ void *iterator_data);
+
+这将数组中的每个对象传递给迭代器回调函数。 ``iterator_data`` 是该函数的私有数据。
+
+在数组被修改的同时,可以在数组上使用这个方法,前提是RCU读锁被持有。在这种情况下,迭代函数有
+可能两次看到某些对象。如果这是个问题,那么修改应该被锁定。然而,迭代算法不应该错过任何对象。
+
+如果数组中没有对象,该函数将返回 ``0`` ,否则将返回最后一次调用的迭代器函数的结果。如果对迭代函数
+的任何调用导致非零返回,迭代立即停止。
+
+
+2. 在一个关联数组中寻找一个对象::
+
+ void *assoc_array_find(const struct assoc_array *array,
+ const struct assoc_array_ops *ops,
+ const void *index_key);
+
+这将直接穿过数组的内部树,到达索引键所指定的对象。
+
+这个函数可以在修改数组的同时用在数组上,前提是RCU读锁被持有。
+
+如果找到对象,该函数将返回对象(并将 ``*_type`` 设置为对象的类型),如果没有找到对象,将返回 ``NULL`` 。
+
+
+索引键形式
+----------
+
+索引键可以是任何形式的,但是由于算法没有被告知键有多长,所以强烈建议在任何由于长度而产生的变化
+对比较产生影响之前,索引键应该很早就包括其长度。
+
+这将导致具有不同长度键的叶子相互分散,而具有相同长度键的叶子则聚集在一起。
+
+我们还建议索引键以键的其余部分的哈希值开始,以最大限度地提高整个键空间的散布情况。
+
+分散性越好,内部树就越宽,越低。
+
+分散性差并不是一个太大的问题,因为有快捷键,节点可以包含叶子和元数据指针的混合物。
+
+索引键是以机器字的块状来读取的。每个块被细分为每层一个nibble(4比特),所以在32位CPU上这适合8层,
+在64位CPU上适合16层。除非散布情况真的很差,否则不太可能有超过一个字的任何特定索引键需要被使用。
+
+
+内部工作机制
+============
+
+关联数组数据结构有一个内部树。这个树由两种类型的元数据块构成:节点和快捷键。
+
+一个节点是一个槽的数组。每个槽可以包含以下四种东西之一:
+
+* 一个NULL的指针,表示槽是空的。
+* 一个指向对象(叶子)的指针。
+* 一个指向下一级节点的指针。
+* 一个指向快捷键的指针。
+
+
+基本的内部树形布局
+------------------
+
+暂时不考虑快捷键,节点形成一个多级树。索引键空间被树上的节点严格细分,节点出现在固定的层次上。例如::
+
+ Level: 0 1 2 3
+ =============== =============== =============== ===============
+ NODE D
+ NODE B NODE C +------>+---+
+ +------>+---+ +------>+---+ | | 0 |
+ NODE A | | 0 | | | 0 | | +---+
+ +---+ | +---+ | +---+ | : :
+ | 0 | | : : | : : | +---+
+ +---+ | +---+ | +---+ | | f |
+ | 1 |---+ | 3 |---+ | 7 |---+ +---+
+ +---+ +---+ +---+
+ : : : : | 8 |---+
+ +---+ +---+ +---+ | NODE E
+ | e |---+ | f | : : +------>+---+
+ +---+ | +---+ +---+ | 0 |
+ | f | | | f | +---+
+ +---+ | +---+ : :
+ | NODE F +---+
+ +------>+---+ | f |
+ | 0 | NODE G +---+
+ +---+ +------>+---+
+ : : | | 0 |
+ +---+ | +---+
+ | 6 |---+ : :
+ +---+ +---+
+ : : | f |
+ +---+ +---+
+ | f |
+ +---+
+
+在上述例子中,有7个节点(A-G),每个节点有16个槽(0-f)。假设树上没有其他元数据节点,那么密钥空间
+是这样划分的::
+
+ KEY PREFIX NODE
+ ========== ====
+ 137* D
+ 138* E
+ 13[0-69-f]* C
+ 1[0-24-f]* B
+ e6* G
+ e[0-57-f]* F
+ [02-df]* A
+
+因此,例如,具有以下示例索引键的键将在适当的节点中被找到::
+
+ INDEX KEY PREFIX NODE
+ =============== ======= ====
+ 13694892892489 13 C
+ 13795289025897 137 D
+ 13889dde88793 138 E
+ 138bbb89003093 138 E
+ 1394879524789 12 C
+ 1458952489 1 B
+ 9431809de993ba - A
+ b4542910809cd - A
+ e5284310def98 e F
+ e68428974237 e6 G
+ e7fffcbd443 e F
+ f3842239082 - A
+
+为了节省内存,如果一个节点可以容纳它的那部分键空间中的所有叶子,那么这个节点将有所有这些叶子,而不
+会有任何元数据指针——即使其中一些叶子想在同一个槽中。
+
+一个节点可以包含叶子和元数据指针的异质性混合。元数据指针必须在与它们的关键空间的细分相匹配的槽中。
+叶子可以在任何没有被元数据指针占据的槽中。保证一个节点中没有一个叶子会与元数据指针占据的槽相匹配。
+如果元数据指针在那里,任何键与元数据键前缀相匹配的叶必须在元数据指针指向的子树中。
+
+在上面的索引键的例子列表中,节点A将包含::
+
+ SLOT CONTENT INDEX KEY (PREFIX)
+ ==== =============== ==================
+ 1 PTR TO NODE B 1*
+ any LEAF 9431809de993ba
+ any LEAF b4542910809cd
+ e PTR TO NODE F e*
+ any LEAF f3842239082
+
+和节点B::
+
+ 3 PTR TO NODE C 13*
+ any LEAF 1458952489
+
+
+快捷键
+---------
+
+快捷键是跳过一块键空间的元数据记录。快捷键是一系列通过层次上升的单占节点的替代物。快捷键的存在是
+为了节省内存和加快遍历速度。
+
+树的根部有可能是一个快捷键——比如说,树至少包含17个节点,都有键前缀 ``1111`` 。插入算法将插入一个快捷键,
+以单次跳过 ``1111`` 的键位,并到达第四层,在这里,这些键位实际上变得不同。
+
+
+拆分和合并节点
+------------------------------
+
+每个节点的最大容量为16个叶子和元数据指针。如果插入算法发现它正试图将一个第17个对象插入到一个节点中,
+该节点将被拆分,使得至少两个在该层有一个共同的关键段的叶子最终在一个单独的节点中,该共同的关键段的根
+在该槽上。
+
+如果一个完整的节点中的叶子和被插入的叶子足够相似,那么就会在树中插入一个快捷键。
+
+当根植于某个节点的子树中的对象数量下降到16个或更少时,那么该子树将被合并成一个单独的节点——如果可能的
+话,这将向根部扩散。
+
+
+非递归式迭代
+------------
+
+每个节点和快捷键都包含一个指向其父节点的后置指针,以及该父节点中指向它的槽数。非递归迭代使用这些来
+通过树的根部进行,前往父节点,槽N+1,以确保在没有堆栈的情况下取得进展。
+
+然而,反向指针使得同时改变和迭代变得很棘手。
+
+
+同时改变和迭代
+--------------
+
+有一些情况需要考虑:
+
+1. 简单的插入/替换。这涉及到简单地将一个NULL或旧的匹配叶子的指针替换为屏障后的新叶子的指针。否则元数
+ 据块不会改变。一个旧的叶子直到RCU宽限期过后才会被释放。
+
+2. 简单删除。这只是涉及到清除一个旧的匹配叶子。元数据块不会有其他变化。旧的叶子直到RCU宽限期之后才会
+ 被释放。
+
+3. 插入,替换我们还没有进入的子树的一部分。这可能涉及到替换该子树的一部分——但这不会影响迭代,因为我们
+ 还没有到达它的指针,而且祖先块也不会被替换(这些块的布局不会改变)。
+
+4. 插入替换了我们正在处理的节点。这不是一个问题,因为我们已经通过了锚定指针,直到我们跟随后面的指针才
+ 会切换到新的布局上——这时我们已经检查了被替换节点的叶子(在跟随任何元数据指针之前,我们会迭代一个节
+ 点的所有叶子)。
+
+ 然而,我们可能会重新看到一些叶子,这些叶子已经被分割成一个新的分支,而这个分支的位置比我们之前的位
+ 置更远。
+
+5. 插入替换了我们正在处理的依赖分支的节点。这不会影响到我们,直到我们跟随后面的指针。与(4)类似。
+
+6. 删掉我们下面的一个分支。这不会影响我们,因为在我们看到新节点之前,回溯指针会让我们回到新节点的父节
+ 点。整个崩溃的子树被扔掉了,没有任何变化——而且仍然会在同一个槽上生根,所以我们不应该第二次处理它,
+ 因为我们会回到槽+1。
+
+.. note::
+
+ 在某些情况下,我们需要同时改变一个节点的父指针和父槽指针(比如说,我们在它之前插入了另一个节点,
+ 并把它往上移了一层)。我们不能在不锁定读取的情况下这样做——所以我们必须同时替换该节点。
+
+ 然而,当我们把一个快捷键改成一个节点时,这不是一个问题,因为快捷键只有一个槽,所以当向后遍
+ 历一个槽时,不会使用父槽号。这意味着先改变槽位号是可以的——只要使用适当的屏障来确保父槽位号在后
+ 退指针之后被读取。
+
+过时的块和叶子在RCU宽限期过后会被释放,所以只要任何进行遍历或迭代的人持有RCU读锁,旧的上层建筑就不
+应该在他们身上消失。
diff --git a/Documentation/translations/zh_CN/core-api/boot-time-mm.rst b/Documentation/translations/zh_CN/core-api/boot-time-mm.rst
new file mode 100644
index 000000000000..9e81dbec71f8
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/boot-time-mm.rst
@@ -0,0 +1,49 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/boot-time-mm.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 时奎亮 <alexs@kernel.org>
+
+.. _cn_core-api_boot-time-mm:
+
+================
+启动时的内存管理
+================
+
+系统初始化早期“正常”的内存管理由于没有设置完毕无法使用。但是内核仍然需要
+为各种数据结构分配内存,例如物理页分配器。
+
+一个叫做 ``memblock`` 的专用分配器执行启动时的内存管理。特定架构的初始化
+必须在setup_arch()中设置它,并在mem_init()函数中移除它。
+
+一旦早期的内存管理可用,它就为内存分配提供了各种函数和宏。分配请求可以指向
+第一个(也可能是唯一的)节点或NUMA系统中的某个特定节点。有一些API变体在分
+配失败时panic,也有一些不会panic的。
+
+Memblock还提供了各种控制其自身行为的API。
+
+Memblock概述
+============
+
+该API在以下内核代码中:
+
+mm/memblock.c
+
+
+函数和结构体
+============
+
+下面是关于memblock数据结构、函数和宏的描述。其中一些实际上是内部的,但由于
+它们被记录下来,漏掉它们是很愚蠢的。此外,阅读内部函数的注释可以帮助理解引
+擎盖下真正发生的事情。
+
+该API在以下内核代码中:
+
+include/linux/memblock.h
+mm/memblock.c
diff --git a/Documentation/translations/zh_CN/core-api/cachetlb.rst b/Documentation/translations/zh_CN/core-api/cachetlb.rst
new file mode 100644
index 000000000000..b4a76ec75daa
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/cachetlb.rst
@@ -0,0 +1,333 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/cachetlb.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
+
+:校译:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+.. _cn_core-api_cachetlb:
+
+======================
+Linux下的缓存和TLB刷新
+======================
+
+:作者: David S. Miller <davem@redhat.com>
+
+*译注:TLB,Translation Lookaside Buffer,页表缓存/变换旁查缓冲器*
+
+本文描述了由Linux虚拟内存子系统调用的缓存/TLB刷新接口。它列举了每个接
+口,描述了它的预期目的,以及接口被调用后的预期副作用。
+
+下面描述的副作用是针对单处理器的实现,以及在单个处理器上发生的情况。若
+为SMP,则只需将定义简单地扩展一下,使发生在某个特定接口的副作用扩展到系
+统的所有处理器上。不要被这句话吓到,以为SMP的缓存/tlb刷新一定是很低
+效的,事实上,这是一个可以进行很多优化的领域。例如,如果可以证明一个用
+户地址空间从未在某个cpu上执行过(见mm_cpumask()),那么就不需要在该
+cpu上对这个地址空间进行刷新。
+
+首先是TLB刷新接口,因为它们是最简单的。在Linux下,TLB被抽象为cpu
+用来缓存从软件页表获得的虚拟->物理地址转换的东西。这意味着,如果软件页
+表发生变化,这个“TLB”缓存中就有可能出现过时(脏)的翻译。因此,当软件页表
+发生变化时,内核会在页表发生 *变化后* 调用以下一种刷新方法:
+
+1) ``void flush_tlb_all(void)``
+
+ 最严格的刷新。在这个接口运行后,任何以前的页表修改都会对cpu可见。
+
+ 这通常是在内核页表被改变时调用的,因为这种转换在本质上是“全局”的。
+
+2) ``void flush_tlb_mm(struct mm_struct *mm)``
+
+ 这个接口从TLB中刷新整个用户地址空间。在运行后,这个接口必须确保
+ 以前对地址空间‘mm’的任何页表修改对cpu来说是可见的。也就是说,在
+ 运行后,TLB中不会有‘mm’的页表项。
+
+ 这个接口被用来处理整个地址空间的页表操作,比如在fork和exec过程
+ 中发生的事情。
+
+3) ``void flush_tlb_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)``
+
+ 这里我们要从TLB中刷新一个特定范围的(用户)虚拟地址转换。在运行后,
+ 这个接口必须确保以前对‘start’到‘end-1’范围内的地址空间‘vma->vm_mm’
+ 的任何页表修改对cpu来说是可见的。也就是说,在运行后,TLB中不会有
+ ‘mm’的页表项用于‘start’到‘end-1’范围内的虚拟地址。
+
+ “vma”是用于该区域的备份存储。主要是用于munmap()类型的操作。
+
+ 提供这个接口是希望端口能够找到一个合适的有效方法来从TLB中删除多
+ 个页面大小的转换,而不是让内核为每个可能被修改的页表项调用
+ flush_tlb_page(见下文)。
+
+4) ``void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)``
+
+ 这一次我们需要从TLB中删除PAGE_SIZE大小的转换。‘vma’是Linux用来跟
+ 踪进程的mmap区域的支持结构体,地址空间可以通过vma->vm_mm获得。另
+ 外,可以通过测试(vma->vm_flags & VM_EXEC)来查看这个区域是否是
+ 可执行的(因此在split-tlb类型的设置中可能在“指令TLB”中)。
+
+ 在运行后,这个接口必须确保之前对用户虚拟地址“addr”的地址空间
+ “vma->vm_mm”的页表修改对cpu来说是可见的。也就是说,在运行后,TLB
+ 中不会有虚拟地址‘addr’的‘vma->vm_mm’的页表项。
+
+ 这主要是在故障处理时使用。
+
+5) ``void update_mmu_cache(struct vm_area_struct *vma,
+ unsigned long address, pte_t *ptep)``
+
+ 在每个缺页异常结束时,这个程序被调用,以告诉体系结构特定的代码,在
+ 软件页表中,在地址空间“vma->vm_mm”的虚拟地址“地址”处,现在存在
+ 一个翻译。
+
+ 可以用它所选择的任何方式使用这个信息来进行移植。例如,它可以使用这
+ 个事件来为软件管理的TLB配置预装TLB转换。目前sparc64移植就是这么干
+ 的。
+
+接下来,我们有缓存刷新接口。一般来说,当Linux将现有的虚拟->物理映射
+改变为新的值时,其顺序将是以下形式之一::
+
+ 1) flush_cache_mm(mm);
+ change_all_page_tables_of(mm);
+ flush_tlb_mm(mm);
+
+ 2) flush_cache_range(vma, start, end);
+ change_range_of_page_tables(mm, start, end);
+ flush_tlb_range(vma, start, end);
+
+ 3) flush_cache_page(vma, addr, pfn);
+ set_pte(pte_pointer, new_pte_val);
+ flush_tlb_page(vma, addr);
+
+缓存级别的刷新将永远是第一位的,因为这允许我们正确处理那些缓存严格,
+且在虚拟地址被从缓存中刷新时要求一个虚拟地址的虚拟->物理转换存在的系统。
+HyperSparc cpu就是这样一个具有这种属性的cpu。
+
+下面的缓存刷新程序只需要在特定的cpu需要的范围内处理缓存刷新。大多数
+情况下,这些程序必须为cpu实现,这些cpu有虚拟索引的缓存,当虚拟->物
+理转换被改变或移除时,必须被刷新。因此,例如,IA32处理器的物理索引
+的物理标记的缓存没有必要实现这些接口,因为这些缓存是完全同步的,并
+且不依赖于翻译信息。
+
+下面逐个列出这些程序:
+
+1) ``void flush_cache_mm(struct mm_struct *mm)``
+
+ 这个接口将整个用户地址空间从高速缓存中刷掉。也就是说,在运行后,
+ 将没有与‘mm’相关的缓存行。
+
+ 这个接口被用来处理整个地址空间的页表操作,比如在退出和执行过程
+ 中发生的事情。
+
+2) ``void flush_cache_dup_mm(struct mm_struct *mm)``
+
+ 这个接口将整个用户地址空间从高速缓存中刷新掉。也就是说,在运行
+ 后,将没有与‘mm’相关的缓存行。
+
+ 这个接口被用来处理整个地址空间的页表操作,比如在fork过程中发生
+ 的事情。
+
+ 这个选项与flush_cache_mm分开,以允许对VIPT缓存进行一些优化。
+
+3) ``void flush_cache_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)``
+
+ 在这里,我们要从缓存中刷新一个特定范围的(用户)虚拟地址。运行
+ 后,在“start”到“end-1”范围内的虚拟地址的“vma->vm_mm”的缓存中
+ 将没有页表项。
+
+ “vma”是被用于该区域的备份存储。主要是用于munmap()类型的操作。
+
+ 提供这个接口是希望端口能够找到一个合适的有效方法来从缓存中删
+ 除多个页面大小的区域, 而不是让内核为每个可能被修改的页表项调
+ 用 flush_cache_page (见下文)。
+
+4) ``void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn)``
+
+ 这一次我们需要从缓存中删除一个PAGE_SIZE大小的区域。“vma”是
+ Linux用来跟踪进程的mmap区域的支持结构体,地址空间可以通过
+ vma->vm_mm获得。另外,我们可以通过测试(vma->vm_flags &
+ VM_EXEC)来查看这个区域是否是可执行的(因此在“Harvard”类
+ 型的缓存布局中可能是在“指令缓存”中)。
+
+ “pfn”表示“addr”所对应的物理页框(通过PAGE_SHIFT左移这个
+ 值来获得物理地址)。正是这个映射应该从缓存中删除。
+
+ 在运行之后,对于虚拟地址‘addr’的‘vma->vm_mm’,在缓存中不会
+ 有任何页表项,它被翻译成‘pfn’。
+
+ 这主要是在故障处理过程中使用。
+
+5) ``void flush_cache_kmaps(void)``
+
+ 只有在平台使用高位内存的情况下才需要实现这个程序。它将在所有的
+ kmaps失效之前被调用。
+
+ 运行后,内核虚拟地址范围PKMAP_ADDR(0)到PKMAP_ADDR(LAST_PKMAP)
+ 的缓存中将没有页表项。
+
+ 这个程序应该在asm/highmem.h中实现。
+
+6) ``void flush_cache_vmap(unsigned long start, unsigned long end)``
+ ``void flush_cache_vunmap(unsigned long start, unsigned long end)``
+
+ 在这里,在这两个接口中,我们从缓存中刷新一个特定范围的(内核)
+ 虚拟地址。运行后,在“start”到“end-1”范围内的虚拟地址的内核地
+ 址空间的缓存中不会有页表项。
+
+ 这两个程序中的第一个是在vmap_range()安装了页表项之后调用的。
+ 第二个是在vunmap_range()删除页表项之前调用的。
+
+还有一类cpu缓存问题,目前需要一套完全不同的接口来正确处理。最大
+的问题是处理器的数据缓存中的虚拟别名。
+
+.. note::
+
+ 这段内容有些晦涩,为了减轻中文阅读压力,特作此译注。
+
+ 别名(alias)属于缓存一致性问题,当不同的虚拟地址映射相同的
+ 物理地址,而这些虚拟地址的index不同,此时就发生了别名现象(多
+ 个虚拟地址被称为别名)。通俗点来说就是指同一个物理地址的数据被
+ 加载到不同的cacheline中就会出现别名现象。
+
+ 常见的解决方法有两种:第一种是硬件维护一致性,设计特定的cpu电
+ 路来解决问题(例如设计为PIPT的cache);第二种是软件维护一致性,
+ 就是下面介绍的sparc的解决方案——页面染色,涉及的技术细节太多,
+ 译者不便展开,请读者自行查阅相关资料。
+
+您的移植是否容易在其D-cache中出现虚拟别名?嗯,如果您的D-cache
+是虚拟索引的,且cache大于PAGE_SIZE(页大小),并且不能防止同一
+物理地址的多个cache行同时存在,您就会遇到这个问题。
+
+如果你的D-cache有这个问题,首先正确定义asm/shmparam.h SHMLBA,
+它基本上应该是你的虚拟寻址D-cache的大小(或者如果大小是可变的,
+则是最大的可能大小)。这个设置将迫使SYSv IPC层只允许用户进程在
+这个值的倍数的地址上对共享内存进行映射。
+
+.. note::
+
+ 这并不能解决共享mmaps的问题,请查看sparc64移植解决
+ 这个问题的一个方法(特别是 SPARC_FLAG_MMAPSHARED)。
+
+接下来,你必须解决所有其他情况下的D-cache别名问题。请记住这个事
+实,对于一个给定的页面映射到某个用户地址空间,总是至少还有一个映
+射,那就是内核在其线性映射中从PAGE_OFFSET开始。因此,一旦第一个
+用户将一个给定的物理页映射到它的地址空间,就意味着D-cache的别名
+问题有可能存在,因为内核已经将这个页映射到它的虚拟地址。
+
+ ``void copy_user_page(void *to, void *from, unsigned long addr, struct page *page)``
+ ``void clear_user_page(void *to, unsigned long addr, struct page *page)``
+
+ 这两个程序在用户匿名或COW页中存储数据。它允许一个端口有效地
+ 避免用户空间和内核之间的D-cache别名问题。
+
+ 例如,一个端口可以在复制过程中把“from”和“to”暂时映射到内核
+ 的虚拟地址上。这两个页面的虚拟地址的选择方式是,内核的加载/存
+ 储指令发生在虚拟地址上,而这些虚拟地址与用户的页面映射是相同
+ 的“颜色”。例如,Sparc64就使用这种技术。
+
+ “addr”参数告诉了用户最终要映射这个页面的虚拟地址,“page”参
+ 数给出了一个指向目标页结构体的指针。
+
+ 如果D-cache别名不是问题,这两个程序可以简单地直接调用
+ memcpy/memset而不做其他事情。
+
+ ``void flush_dcache_page(struct page *page)``
+
+ 任何时候,当内核写到一个页面缓存页,或者内核要从一个页面缓存
+ 页中读出,并且这个页面的用户空间共享/可写映射可能存在时,
+ 这个程序就会被调用。
+
+ .. note::
+
+ 这个程序只需要为有可能被映射到用户进程的地址空间的
+ 页面缓存调用。因此,例如,处理页面缓存中vfs符号链
+ 接的VFS层代码根本不需要调用这个接口。
+
+ “内核写入页面缓存的页面”这句话的意思是,具体来说,内核执行存
+ 储指令,在该页面的页面->虚拟映射处弄脏该页面的数据。在这里,通
+ 过刷新的手段处理D-cache的别名是很重要的,以确保这些内核存储对
+ 该页的用户空间映射是可见的。
+
+ 推论的情况也同样重要,如果有用户对这个文件有共享+可写的映射,
+ 我们必须确保内核对这些页面的读取会看到用户所做的最新的存储。
+
+ 如果D-cache别名不是一个问题,这个程序可以简单地定义为该架构上
+ 的nop。
+
+ 在page->flags (PG_arch_1)中有一个位是“架构私有”。内核保证,
+ 对于分页缓存的页面,当这样的页面第一次进入分页缓存时,它将清除
+ 这个位。
+
+ 这使得这些接口可以更有效地被实现。如果目前没有用户进程映射这个
+ 页面,它允许我们“推迟”(也许是无限期)实际的刷新过程。请看
+ sparc64的flush_dcache_page和update_mmu_cache实现,以了解如
+ 何做到这一点。
+
+ 这个想法是,首先在flush_dcache_page()时,如果page->mapping->i_mmap
+ 是一个空树,只需标记架构私有页标志位。之后,在update_mmu_cache()
+ 中,会对这个标志位进行检查,如果设置了,就进行刷新,并清除标志位。
+
+ .. important::
+
+ 通常很重要的是,如果你推迟刷新,实际的刷新发生在同一个
+ CPU上,因为它将cpu存储到页面上,使其变脏。同样,请看
+ sparc64关于如何处理这个问题的例子。
+
+ ``void flush_dcache_folio(struct folio *folio)``
+
+ 该函数的调用情形与flush_dcache_page()相同。它允许架构针对刷新整个
+ folio页面进行优化,而不是一次刷新一页。
+
+ ``void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long user_vaddr, void *dst, void *src, int len)``
+ ``void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long user_vaddr, void *dst, void *src, int len)``
+
+ 当内核需要复制任意的数据进出任意的用户页时(比如ptrace()),它将使
+ 用这两个程序。
+
+ 任何必要的缓存刷新或其他需要发生的一致性操作都应该在这里发生。如果
+ 处理器的指令缓存没有对cpu存储进行窥探,那么你很可能需要为
+ copy_to_user_page()刷新指令缓存。
+
+ ``void flush_anon_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long vmaddr)``
+
+ 当内核需要访问一个匿名页的内容时,它会调用这个函数(目前只有
+ get_user_pages())。注意:flush_dcache_page()故意对匿名页不起作
+ 用。默认的实现是nop(对于所有相干的架构应该保持这样)。对于不一致性
+ 的架构,它应该刷新vmaddr处的页面缓存。
+
+ ``void flush_icache_range(unsigned long start, unsigned long end)``
+
+ 当内核存储到它将执行的地址中时(例如在加载模块时),这个函数被调用。
+
+ 如果icache不对存储进行窥探,那么这个程序将需要对其进行刷新。
+
+ ``void flush_icache_page(struct vm_area_struct *vma, struct page *page)``
+
+ flush_icache_page的所有功能都可以在flush_dcache_page和update_mmu_cache
+ 中实现。在未来,我们希望能够完全删除这个接口。
+
+最后一类API是用于I/O到内核内特意设置的别名地址范围。这种别名是通过使用
+vmap/vmalloc API设置的。由于内核I/O是通过物理页进行的,I/O子系统假定用户
+映射和内核偏移映射是唯一的别名。这对vmap别名来说是不正确的,所以内核中任何
+试图对vmap区域进行I/O的东西都必须手动管理一致性。它必须在做I/O之前刷新vmap
+范围,并在I/O返回后使其失效。
+
+ ``void flush_kernel_vmap_range(void *vaddr, int size)``
+
+ 刷新vmap区域中指定的虚拟地址范围的内核缓存。这是为了确保内核在vmap范围
+ 内修改的任何数据对物理页是可见的。这个设计是为了使这个区域可以安全地执
+ 行I/O。注意,这个API并 *没有* 刷新该区域的偏移映射别名。
+
+ ``void invalidate_kernel_vmap_range(void *vaddr, int size) invalidates``
+
+ 在vmap区域的一个给定的虚拟地址范围的缓存,这可以防止处理器在物理页的I/O
+ 发生时通过投机性地读取数据而使缓存变脏。这只对读入vmap区域的数据是必要的。
diff --git a/Documentation/translations/zh_CN/core-api/circular-buffers.rst b/Documentation/translations/zh_CN/core-api/circular-buffers.rst
new file mode 100644
index 000000000000..694ad8e61070
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/circular-buffers.rst
@@ -0,0 +1,210 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/circular-buffers.rst
+
+:翻译:
+
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
+
+:校译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 吴想成 Wu Xiangcheng <bobwxc@email.cn>
+ 时奎亮 Alex Shi <alexs@kernel.org>
+
+==========
+环形缓冲区
+==========
+
+:作者: David Howells <dhowells@redhat.com>
+:作者: Paul E. McKenney <paulmck@linux.ibm.com>
+
+
+Linux 提供了许多可用于实现循环缓冲的特性。有两组这样的特性:
+
+ (1) 用于确定2次方大小的缓冲区信息的便利函数。
+
+ (2) 可以代替缓冲区中对象的生产者和消费者共享锁的内存屏障。
+
+如下所述,要使用这些设施,只需要一个生产者和一个消费者。可以通过序列化来处理多个
+生产者,并通过序列化来处理多个消费者。
+
+.. Contents:
+
+ (*) 什么是环形缓冲区?
+
+ (*) 测量2次幂缓冲区
+
+ (*) 内存屏障与环形缓冲区的结合使用
+ - 生产者
+ - 消费者
+
+ (*) 延伸阅读
+
+
+
+什么是环形缓冲区?
+==================
+
+首先,什么是环形缓冲区?环形缓冲区是具有固定的有限大小的缓冲区,它有两个索引:
+
+ (1) 'head'索引 - 生产者将元素插入缓冲区的位置。
+
+ (2) 'tail'索引 - 消费者在缓冲区中找到下一个元素的位置。
+
+通常,当tail指针等于head指针时,表明缓冲区是空的;而当head指针比tail指针少一个时,
+表明缓冲区是满的。
+
+添加元素时,递增head索引;删除元素时,递增tail索引。tail索引不应该跳过head索引,
+两个索引在到达缓冲区末端时都应该被赋值为0,从而允许海量的数据流过缓冲区。
+
+通常情况下,元素都有相同的单元大小,但这并不是使用以下技术的严格要求。如果要在缓
+冲区中包含多个元素或可变大小的元素,则索引可以增加超过1,前提是两个索引都没有超过
+另一个。然而,实现者必须小心,因为超过一个单位大小的区域可能会覆盖缓冲区的末端并
+且缓冲区会被分成两段。
+
+测量2次幂缓冲区
+===============
+
+计算任意大小的环形缓冲区的占用或剩余容量通常是一个费时的操作,需要使用模(除法)
+指令。但是如果缓冲区的大小为2次幂,则可以使用更快的按位与指令代替。
+
+Linux提供了一组用于处理2次幂环形缓冲区的宏。可以通过以下方式使用::
+
+ #include <linux/circ_buf.h>
+
+这些宏包括:
+
+ (#) 测量缓冲区的剩余容量::
+
+ CIRC_SPACE(head_index, tail_index, buffer_size);
+
+ 返回缓冲区[1]中可插入元素的剩余空间大小。
+
+
+ (#) 测量缓冲区中的最大连续立即可用空间::
+
+ CIRC_SPACE_TO_END(head_index, tail_index, buffer_size);
+
+ 返回缓冲区[1]中剩余的连续空间的大小,元素可以立即插入其中,而不必绕回到缓冲
+ 区的开头。
+
+
+ (#) 测量缓冲区的使用数::
+
+ CIRC_CNT(head_index, tail_index, buffer_size);
+
+ 返回当前占用缓冲区[2]的元素数量。
+
+
+ (#) 测量缓冲区的连续使用数::
+
+ CIRC_CNT_TO_END(head_index, tail_index, buffer_size);
+
+ 返回可以从缓冲区中提取的连续元素[2]的数量,而不必绕回到缓冲区的开头。
+
+这里的每一个宏名义上都会返回一个介于0和buffer_size-1之间的值,但是:
+
+ (1) CIRC_SPACE*()是为了在生产者中使用。对生产者来说,它们将返回一个下限,因为生
+ 产者控制着head索引,但消费者可能仍然在另一个CPU上耗尽缓冲区并移动tail索引。
+
+ 对消费者来说,它将显示一个上限,因为生产者可能正忙于耗尽空间。
+
+ (2) CIRC_CNT*()是为了在消费者中使用。对消费者来说,它们将返回一个下限,因为消费
+ 者控制着tail索引,但生产者可能仍然在另一个CPU上填充缓冲区并移动head索引。
+
+ 对于生产者,它将显示一个上限,因为消费者可能正忙于清空缓冲区。
+
+ (3) 对于第三方来说,生产者和消费者对索引的写入顺序是无法保证的,因为它们是独立的,
+ 而且可能是在不同的CPU上进行的,所以在这种情况下的结果只是一种猜测,甚至可能
+ 是错误的。
+
+内存屏障与环形缓冲区的结合使用
+==============================
+
+通过将内存屏障与环形缓冲区结合使用,可以避免以下需求:
+
+ (1) 使用单个锁来控制对缓冲区两端的访问,从而允许同时填充和清空缓冲区;以及
+
+ (2) 使用原子计数器操作。
+
+这有两个方面:填充缓冲区的生产者和清空缓冲区的消费者。在任何时候,只应有一个生产
+者在填充缓冲区,同样的也只应有一个消费者在清空缓冲区,但双方可以同时操作。
+
+
+生产者
+------
+
+生产者看起来像这样::
+
+ spin_lock(&producer_lock);
+
+ unsigned long head = buffer->head;
+ /* spin_unlock()和下一个spin_lock()提供必要的排序。 */
+ unsigned long tail = READ_ONCE(buffer->tail);
+
+ if (CIRC_SPACE(head, tail, buffer->size) >= 1) {
+ /* 添加一个元素到缓冲区 */
+ struct item *item = buffer[head];
+
+ produce_item(item);
+
+ smp_store_release(buffer->head,
+ (head + 1) & (buffer->size - 1));
+
+ /* wake_up()将确保在唤醒任何人之前提交head */
+ wake_up(consumer);
+ }
+
+ spin_unlock(&producer_lock);
+
+这将表明CPU必须在head索引使其对消费者可用之前写入新项目的内容,同时CPU必须在唤醒
+消费者之前写入修改后的head索引。
+
+请注意,wake_up()并不保证任何形式的屏障,除非确实唤醒了某些东西。因此我们不能依靠
+它来进行排序。但是数组中始终有一个元素留空,因此生产者必须产生两个元素,然后才可
+能破坏消费者当前正在读取的元素。同时,消费者连续调用之间成对的解锁-加锁提供了索引
+读取(指示消费者已清空给定元素)和生产者对该相同元素的写入之间的必要顺序。
+
+
+消费者
+------
+
+消费者看起来像这样::
+
+ spin_lock(&consumer_lock);
+
+ /* 读取该索引处的内容之前,先读取索引 */
+ unsigned long head = smp_load_acquire(buffer->head);
+ unsigned long tail = buffer->tail;
+
+ if (CIRC_CNT(head, tail, buffer->size) >= 1) {
+
+ /* 从缓冲区中提取一个元素 */
+ struct item *item = buffer[tail];
+
+ consume_item(item);
+
+ /* 在递增tail之前完成对描述符的读取。 */
+ smp_store_release(buffer->tail,
+ (tail + 1) & (buffer->size - 1));
+ }
+
+ spin_unlock(&consumer_lock);
+
+这表明CPU在读取新元素之前确保索引是最新的,然后在写入新的尾指针之前应确保CPU已完
+成读取该元素,这将擦除该元素。
+
+请注意,使用READ_ONCE()和smp_load_acquire()来读取反向(head)索引。这可以防止编译
+器丢弃并重新加载其缓存值。如果您能确定反向(head)索引将仅使用一次,则这不是必须
+的。smp_load_acquire()还可以强制CPU对后续的内存引用进行排序。类似地,两种算法都使
+用smp_store_release()来写入线程的索引。这记录了我们正在写入可以并发读取的内容的事
+实,以防止编译器破坏存储,并强制对以前的访问进行排序。
+
+
+延伸阅读
+========
+
+关于Linux的内存屏障设施的描述,请查看Documentation/memory-barriers.txt。
diff --git a/Documentation/translations/zh_CN/core-api/cpu_hotplug.rst b/Documentation/translations/zh_CN/core-api/cpu_hotplug.rst
new file mode 100644
index 000000000000..bc0d7ea6d834
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/cpu_hotplug.rst
@@ -0,0 +1,661 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/cpu_hotplug.rst
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
+
+:校译:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+.. _cn_core_api_cpu_hotplug:
+
+=================
+内核中的CPU热拔插
+=================
+
+:时间: 2021年9月
+:作者: Sebastian Andrzej Siewior <bigeasy@linutronix.de>,
+ Rusty Russell <rusty@rustcorp.com.au>,
+ Srivatsa Vaddagiri <vatsa@in.ibm.com>,
+ Ashok Raj <ashok.raj@intel.com>,
+ Joel Schopp <jschopp@austin.ibm.com>,
+ Thomas Gleixner <tglx@linutronix.de>
+
+简介
+====
+
+现代系统架构的演进已经在处理器中引入了先进的错误报告和纠正能力。有一些OEM也支
+持可热拔插的NUMA(Non Uniform Memory Access,非统一内存访问)硬件,其中物理
+节点的插入和移除需要支持CPU热插拔。
+
+这样的进步要求内核可用的CPU被移除,要么是出于配置的原因,要么是出于RAS的目的,
+以保持一个不需要的CPU不在系统执行路径。因此需要在Linux内核中支持CPU热拔插。
+
+CPU热拔插支持的一个更新颖的用途是它在SMP的暂停恢复支持中的应用。双核和超线程支
+持使得即使是笔记本电脑也能运行不支持这些方法的SMP内核。
+
+
+命令行开关
+==========
+
+``maxcpus=n``
+ 限制启动时的CPU为 *n* 个。例如,如果你有四个CPU,使用 ``maxcpus=2`` 将只能启
+ 动两个。你可以选择稍后让其他CPU上线。
+
+``nr_cpus=n``
+ 限制内核将支持的CPU总量。如果这里提供的数量低于实际可用的CPU数量,那么其他CPU
+ 以后就不能上线了。
+
+``possible_cpus=n``
+ 这个选项设置 ``cpu_possible_mask`` 中的 ``possible_cpus`` 位。
+
+ 这个选项只限于X86和S390架构。
+
+``cpu0_hotplug``
+ 允许关闭CPU0。
+
+ 这个选项只限于X86架构。
+
+CPU位图
+=======
+
+``cpu_possible_mask``
+ 系统中可能可用CPU的位图。这是用来为per_cpu变量分配一些启动时的内存,这些变量
+ 不会随着CPU的可用或移除而增加/减少。一旦在启动时的发现阶段被设置,该映射就是静态
+ 的,也就是说,任何时候都不会增加或删除任何位。根据你的系统需求提前准确地调整它
+ 可以节省一些启动时的内存。
+
+``cpu_online_mask``
+ 当前在线的所有CPU的位图。在一个CPU可用于内核调度并准备接收设备的中断后,它被
+ 设置在 ``__cpu_up()`` 中。当使用 ``__cpu_disable()`` 关闭一个CPU时,它被清
+ 空,在此之前,所有的操作系统服务包括中断都被迁移到另一个目标CPU。
+
+``cpu_present_mask``
+ 系统中当前存在的CPU的位图。它们并非全部在线。当物理热拔插被相关的子系统
+ (如ACPI)处理时,可以改变和添加新的位或从位图中删除,这取决于事件是
+ hot-add/hot-remove。目前还没有定死规定。典型的用法是在启动时启动拓扑结构,这时
+ 热插拔被禁用。
+
+你真的不需要操作任何系统的CPU映射。在大多数情况下,它们应该是只读的。当设置每个
+CPU资源时,几乎总是使用 ``cpu_possible_mask`` 或 ``for_each_possible_cpu()``
+来进行迭代。宏 ``for_each_cpu()`` 可以用来迭代一个自定义的CPU掩码。
+
+不要使用 ``cpumask_t`` 以外的任何东西来表示CPU的位图。
+
+
+使用CPU热拔插
+=============
+
+内核选项 *CONFIG_HOTPLUG_CPU* 需要被启用。它目前可用于多种架构,包括ARM、MIPS、
+PowerPC和X86。配置是通过sysfs接口完成的::
+
+ $ ls -lh /sys/devices/system/cpu
+ total 0
+ drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu0
+ drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu1
+ drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu2
+ drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu3
+ drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu4
+ drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu5
+ drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu6
+ drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu7
+ drwxr-xr-x 2 root root 0 Dec 21 16:33 hotplug
+ -r--r--r-- 1 root root 4.0K Dec 21 16:33 offline
+ -r--r--r-- 1 root root 4.0K Dec 21 16:33 online
+ -r--r--r-- 1 root root 4.0K Dec 21 16:33 possible
+ -r--r--r-- 1 root root 4.0K Dec 21 16:33 present
+
+文件 *offline* 、 *online* 、*possible* 、*present* 代表CPU掩码。每个CPU文件
+夹包含一个 *online* 文件,控制逻辑上的开(1)和关(0)状态。要在逻辑上关闭CPU4::
+
+ $ echo 0 > /sys/devices/system/cpu/cpu4/online
+ smpboot: CPU 4 is now offline
+
+一旦CPU被关闭,它将从 */proc/interrupts* 、*/proc/cpuinfo* 中被删除,也不应该
+被 *top* 命令显示出来。要让CPU4重新上线::
+
+ $ echo 1 > /sys/devices/system/cpu/cpu4/online
+ smpboot: Booting Node 0 Processor 4 APIC 0x1
+
+CPU又可以使用了。这应该对所有的CPU都有效。CPU0通常比较特殊,被排除在CPU热拔插之外。
+在X86上,内核选项 *CONFIG_BOOTPARAM_HOTPLUG_CPU0* 必须被启用,以便能够关闭CPU0。
+或者,可以使用内核命令选项 *cpu0_hotplug* 。CPU0的一些已知的依赖性:
+
+* 从休眠/暂停中恢复。如果CPU0处于离线状态,休眠/暂停将失败。
+* PIC中断。如果检测到PIC中断,CPU0就不能被移除。
+
+如果你发现CPU0上有任何依赖性,请告知Fenghua Yu <fenghua.yu@intel.com>。
+
+CPU的热拔插协作
+===============
+
+下线情况
+--------
+
+一旦CPU被逻辑关闭,注册的热插拔状态的清除回调将被调用,从 ``CPUHP_ONLINE`` 开始,到
+``CPUHP_OFFLINE`` 状态结束。这包括:
+
+* 如果任务因暂停操作而被冻结,那么 *cpuhp_tasks_frozen* 将被设置为true。
+
+* 所有进程都会从这个将要离线的CPU迁移到新的CPU上。新的CPU是从每个进程的当前cpuset中
+ 选择的,它可能是所有在线CPU的一个子集。
+
+* 所有针对这个CPU的中断都被迁移到新的CPU上。
+
+* 计时器也会被迁移到新的CPU上。
+
+* 一旦所有的服务被迁移,内核会调用一个特定的例程 ``__cpu_disable()`` 来进行特定的清
+ 理。
+
+CPU热插拔API
+============
+
+CPU热拔插状态机
+---------------
+
+CPU热插拔使用一个从CPUHP_OFFLINE到CPUHP_ONLINE的线性状态空间的普通状态机。每个状态都
+有一个startup和teardown的回调。
+
+当一个CPU上线时,将按顺序调用startup回调,直到达到CPUHP_ONLINE状态。当设置状态的回调
+或将实例添加到多实例状态时,也可以调用它们。
+
+当一个CPU下线时,将按相反的顺序依次调用teardown回调,直到达到CPUHP_OFFLINE状态。当删
+除状态的回调或从多实例状态中删除实例时,也可以调用它们。
+
+如果某个使用场景只需要一个方向的热插拔操作回调(CPU上线或CPU下线),则在设置状态时,
+可以将另一个不需要的回调设置为NULL。
+
+状态空间被划分成三个阶段:
+
+* PREPARE阶段
+
+ PREPARE阶段涵盖了从CPUHP_OFFLINE到CPUHP_BRINGUP_CPU之间的状态空间。
+
+ 在该阶段中,startup回调在CPU上线操作启动CPU之前被调用,teardown回调在CPU下线操作使
+ CPU功能失效之后被调用。
+
+ 这些回调是在控制CPU上调用的,因为它们显然不能在热插拔的CPU上运行,此时热插拔的CPU要
+ 么还没有启动,要么已经功能失效。
+
+ startup回调用于设置CPU成功上线所需要的资源。teardown回调用于释放资源或在热插拔的CPU
+ 功能失效后,将待处理的工作转移到在线的CPU上。
+
+ 允许startup回调失败。如果回调失败,CPU上线操作被中止,CPU将再次被降到之前的状态(通
+ 常是CPUHP_OFFLINE)。
+
+ 本阶段中的teardown回调不允许失败。
+
+* STARTING阶段
+
+ STARTING阶段涵盖了CPUHP_BRINGUP_CPU + 1到CPUHP_AP_ONLINE之间的状态空间。
+
+ 该阶段中的startup回调是在早期CPU设置代码中的CPU上线操作期间,禁用中断的情况下在热拔
+ 插的CPU上被调用。teardown回调是在CPU完全关闭前不久的CPU下线操作期间,禁用中断的情况
+ 下在热拔插的CPU上被调用。
+
+ 该阶段中的回调不允许失败。
+
+ 回调用于低级别的硬件初始化/关机和核心子系统。
+
+* ONLINE阶段
+
+ ONLINE阶段涵盖了CPUHP_AP_ONLINE + 1到CPUHP_ONLINE之间的状态空间。
+
+ 该阶段中的startup回调是在CPU上线时在热插拔的CPU上调用的。teardown回调是在CPU下线操
+ 作时在热插拔CPU上调用的。
+
+ 回调是在每个CPU热插拔线程的上下文中调用的,该线程绑定在热插拔的CPU上。回调是在启用
+ 中断和抢占的情况下调用的。
+
+ 允许回调失败。如果回调失败,CPU热插拔操作被中止,CPU将恢复到之前的状态。
+
+CPU 上线/下线操作
+-----------------
+
+一个成功的上线操作如下::
+
+ [CPUHP_OFFLINE]
+ [CPUHP_OFFLINE + 1]->startup() -> 成功
+ [CPUHP_OFFLINE + 2]->startup() -> 成功
+ [CPUHP_OFFLINE + 3] -> 略过,因为startup == NULL
+ ...
+ [CPUHP_BRINGUP_CPU]->startup() -> 成功
+ === PREPARE阶段结束
+ [CPUHP_BRINGUP_CPU + 1]->startup() -> 成功
+ ...
+ [CPUHP_AP_ONLINE]->startup() -> 成功
+ === STARTUP阶段结束
+ [CPUHP_AP_ONLINE + 1]->startup() -> 成功
+ ...
+ [CPUHP_ONLINE - 1]->startup() -> 成功
+ [CPUHP_ONLINE]
+
+一个成功的下线操作如下::
+
+ [CPUHP_ONLINE]
+ [CPUHP_ONLINE - 1]->teardown() -> 成功
+ ...
+ [CPUHP_AP_ONLINE + 1]->teardown() -> 成功
+ === STARTUP阶段开始
+ [CPUHP_AP_ONLINE]->teardown() -> 成功
+ ...
+ [CPUHP_BRINGUP_ONLINE - 1]->teardown()
+ ...
+ === PREPARE阶段开始
+ [CPUHP_BRINGUP_CPU]->teardown()
+ [CPUHP_OFFLINE + 3]->teardown()
+ [CPUHP_OFFLINE + 2] -> 略过,因为teardown == NULL
+ [CPUHP_OFFLINE + 1]->teardown()
+ [CPUHP_OFFLINE]
+
+一个失败的上线操作如下::
+
+ [CPUHP_OFFLINE]
+ [CPUHP_OFFLINE + 1]->startup() -> 成功
+ [CPUHP_OFFLINE + 2]->startup() -> 成功
+ [CPUHP_OFFLINE + 3] -> 略过,因为startup == NULL
+ ...
+ [CPUHP_BRINGUP_CPU]->startup() -> 成功
+ === PREPARE阶段结束
+ [CPUHP_BRINGUP_CPU + 1]->startup() -> 成功
+ ...
+ [CPUHP_AP_ONLINE]->startup() -> 成功
+ === STARTUP阶段结束
+ [CPUHP_AP_ONLINE + 1]->startup() -> 成功
+ ---
+ [CPUHP_AP_ONLINE + N]->startup() -> 失败
+ [CPUHP_AP_ONLINE + (N - 1)]->teardown()
+ ...
+ [CPUHP_AP_ONLINE + 1]->teardown()
+ === STARTUP阶段开始
+ [CPUHP_AP_ONLINE]->teardown()
+ ...
+ [CPUHP_BRINGUP_ONLINE - 1]->teardown()
+ ...
+ === PREPARE阶段开始
+ [CPUHP_BRINGUP_CPU]->teardown()
+ [CPUHP_OFFLINE + 3]->teardown()
+ [CPUHP_OFFLINE + 2] -> 略过,因为teardown == NULL
+ [CPUHP_OFFLINE + 1]->teardown()
+ [CPUHP_OFFLINE]
+
+一个失败的下线操作如下::
+
+ [CPUHP_ONLINE]
+ [CPUHP_ONLINE - 1]->teardown() -> 成功
+ ...
+ [CPUHP_ONLINE - N]->teardown() -> 失败
+ [CPUHP_ONLINE - (N - 1)]->startup()
+ ...
+ [CPUHP_ONLINE - 1]->startup()
+ [CPUHP_ONLINE]
+
+递归失败不能被合理地处理。
+请看下面的例子,由于下线操作失败而导致的递归失败::
+
+ [CPUHP_ONLINE]
+ [CPUHP_ONLINE - 1]->teardown() -> 成功
+ ...
+ [CPUHP_ONLINE - N]->teardown() -> 失败
+ [CPUHP_ONLINE - (N - 1)]->startup() -> 成功
+ [CPUHP_ONLINE - (N - 2)]->startup() -> 失败
+
+CPU热插拔状态机在此停止,且不再尝试回滚,因为这可能会导致死循环::
+
+ [CPUHP_ONLINE - (N - 1)]->teardown() -> 成功
+ [CPUHP_ONLINE - N]->teardown() -> 失败
+ [CPUHP_ONLINE - (N - 1)]->startup() -> 成功
+ [CPUHP_ONLINE - (N - 2)]->startup() -> 失败
+ [CPUHP_ONLINE - (N - 1)]->teardown() -> 成功
+ [CPUHP_ONLINE - N]->teardown() -> 失败
+
+周而复始,不断重复。在这种情况下,CPU留在该状态中::
+
+ [CPUHP_ONLINE - (N - 1)]
+
+这至少可以让系统取得进展,让用户有机会进行调试,甚至解决这个问题。
+
+分配一个状态
+------------
+
+有两种方式分配一个CPU热插拔状态:
+
+* 静态分配
+
+ 当子系统或驱动程序有相对于其他CPU热插拔状态的排序要求时,必须使用静态分配。例如,
+ 在CPU上线操作期间,PERF核心startup回调必须在PERF驱动startup回调之前被调用。在CPU
+ 下线操作中,驱动teardown回调必须在核心teardown回调之前调用。静态分配的状态由
+ cpuhp_state枚举中的常量描述,可以在include/linux/cpuhotplug.h中找到。
+
+ 在适当的位置将状态插入枚举中,这样就满足了排序要求。状态常量必须被用于状态的设置
+ 和移除。
+
+ 当状态回调不是在运行时设置的,并且是kernel/cpu.c中CPU热插拔状态数组初始化的一部分
+ 时,也需要静态分配。
+
+* 动态分配
+
+ 当对状态回调没有排序要求时,动态分配是首选方法。状态编号由setup函数分配,并在成功
+ 后返回给调用者。
+
+ 只有PREPARE和ONLINE阶段提供了一个动态分配范围。STARTING阶段则没有,因为该部分的大多
+ 数回调都有明确的排序要求。
+
+CPU热插拔状态的设置
+-------------------
+
+核心代码提供了以下函数用来设置状态:
+
+* cpuhp_setup_state(state, name, startup, teardown)
+* cpuhp_setup_state_nocalls(state, name, startup, teardown)
+* cpuhp_setup_state_cpuslocked(state, name, startup, teardown)
+* cpuhp_setup_state_nocalls_cpuslocked(state, name, startup, teardown)
+
+对于一个驱动程序或子系统有多个实例,并且每个实例都需要调用相同的CPU hotplug状态回
+调的情况,CPU hotplug核心提供多实例支持。与驱动程序特定的实例列表相比,其优势在于
+与实例相关的函数完全针对CPU hotplug操作进行序列化,并在添加和删除时提供状态回调的
+自动调用。要设置这样一个多实例状态,可以使用以下函数:
+
+* cpuhp_setup_state_multi(state, name, startup, teardown)
+
+@state参数要么是静态分配的状态,要么是动态分配状态(PUHP_PREPARE_DYN,CPUHP_ONLINE_DYN)
+的常量之一, 具体取决于应该分配动态状态的状态阶段(PREPARE,ONLINE)。
+
+@name参数用于sysfs输出和检测。命名惯例是"subsys:mode"或"subsys/driver:mode",
+例如 "perf:mode"或"perf/x86:mode"。常见的mode名称有:
+
+======== ============================================
+prepare 对应PREPARE阶段中的状态
+
+dead 对应PREPARE阶段中不提供startup回调的状态
+
+starting 对应STARTING阶段中的状态
+
+dying 对应STARTING阶段中不提供startup回调的状态
+
+online 对应ONLINE阶段中的状态
+
+offline 对应ONLINE阶段中不提供startup回调的状态
+======== ============================================
+
+由于@name参数只用于sysfs和检测,如果其他mode描述符比常见的描述符更好地描述状态的性质,
+也可以使用。
+
+@name参数的示例:"perf/online", "perf/x86:prepare", "RCU/tree:dying", "sched/waitempty"
+
+@startup参数是一个指向回调的函数指针,在CPU上线操作时被调用。若应用不需要startup
+回调,则将该指针设为NULL。
+
+@teardown参数是一个指向回调的函数指针,在CPU下线操作时调用。若应用不需要teardown
+回调,则将该指针设为NULL。
+
+这些函数在处理已注册回调的方式上有所不同:
+
+ * cpuhp_setup_state_nocalls(), cpuhp_setup_state_nocalls_cpuslocked()和
+ cpuhp_setup_state_multi()只注册回调。
+
+ * cpuhp_setup_state()和cpuhp_setup_state_cpuslocked()注册回调,并对当前状态大于新
+ 安装状态的所有在线CPU调用@startup回调(如果不是NULL)。根据状态阶段,回调要么在
+ 当前的CPU上调用(PREPARE阶段),要么在CPU的热插拔线程中调用每个在线CPU(ONLINE阶段)。
+
+ 如果CPU N的回调失败,那么CPU 0...N-1的teardown回调被调用以回滚操作。状态设置失败,
+ 状态的回调没有被注册,在动态分配的情况下,分配的状态被释放。
+
+状态设置和回调调用是针对CPU热拔插操作进行序列化的。如果设置函数必须从CPU热插拔的读
+锁定区域调用,那么必须使用_cpuslocked()变体。这些函数不能在CPU热拔插回调中使用。
+
+函数返回值:
+ ======== ==========================================================
+ 0 静态分配的状态设置成功
+
+ >0 动态分配的状态设置成功
+
+ 返回的数值是被分配的状态编号。如果状态回调后来必须被移除,
+ 例如模块移除,那么这个数值必须由调用者保存,并作为状态移
+ 除函数的@state参数。对于多实例状态,动态分配的状态编号也
+ 需要作为实例添加/删除操作的@state参数。
+
+ <0 操作失败
+ ======== ==========================================================
+
+移除CPU热拔插状态
+-----------------
+
+为了移除一个之前设置好的状态,提供了如下函数:
+
+* cpuhp_remove_state(state)
+* cpuhp_remove_state_nocalls(state)
+* cpuhp_remove_state_nocalls_cpuslocked(state)
+* cpuhp_remove_multi_state(state)
+
+@state参数要么是静态分配的状态,要么是由cpuhp_setup_state*()在动态范围内分配
+的状态编号。如果状态在动态范围内,则状态编号被释放,可再次进行动态分配。
+
+这些函数在处理已注册回调的方式上有所不同:
+
+ * cpuhp_remove_state_nocalls(), cpuhp_remove_state_nocalls_cpuslocked()
+ 和 cpuhp_remove_multi_state()只删除回调。
+
+ * cpuhp_remove_state()删除回调,并调用所有当前状态大于被删除状态的在线CPU的
+ teardown回调(如果不是NULL)。根据状态阶段,回调要么在当前的CPU上调用
+ (PREPARE阶段),要么在CPU的热插拔线程中调用每个在线CPU(ONLINE阶段)。
+
+ 为了完成移除工作,teardown回调不能失败。
+
+状态移除和回调调用是针对CPU热拔插操作进行序列化的。如果移除函数必须从CPU hotplug
+读取锁定区域调用,那么必须使用_cpuslocked()变体。这些函数不能从CPU热插拔的回调中使用。
+
+如果一个多实例的状态被移除,那么调用者必须先移除所有的实例。
+
+多实例状态实例管理
+------------------
+
+一旦多实例状态被建立,实例就可以被添加到状态中:
+
+ * cpuhp_state_add_instance(state, node)
+ * cpuhp_state_add_instance_nocalls(state, node)
+
+@state参数是一个静态分配的状态或由cpuhp_setup_state_multi()在动态范围内分配的状
+态编号。
+
+@node参数是一个指向hlist_node的指针,它被嵌入到实例的数据结构中。这个指针被交给
+多实例状态的回调,可以被回调用来通过container_of()检索到实例。
+
+这些函数在处理已注册回调的方式上有所不同:
+
+ * cpuhp_state_add_instance_nocalls()只将实例添加到多实例状态的节点列表中。
+
+ * cpuhp_state_add_instance()为所有当前状态大于@state的在线CPU添加实例并调用与
+ @state相关的startup回调(如果不是NULL)。该回调只对将要添加的实例进行调用。
+ 根据状态阶段,回调要么在当前的CPU上调用(PREPARE阶段),要么在CPU的热插拔线
+ 程中调用每个在线CPU(ONLINE阶段)。
+
+ 如果CPU N的回调失败,那么CPU 0 ... N-1的teardown回调被调用以回滚操作,该函数
+ 失败,实例不会被添加到多实例状态的节点列表中。
+
+要从状态的节点列表中删除一个实例,可以使用这些函数:
+
+ * cpuhp_state_remove_instance(state, node)
+ * cpuhp_state_remove_instance_nocalls(state, node)
+
+参数与上述cpuhp_state_add_instance*()变体相同。
+
+这些函数在处理已注册回调的方式上有所不同:
+
+ * cpuhp_state_remove_instance_nocalls()只从状态的节点列表中删除实例。
+
+ * cpuhp_state_remove_instance()删除实例并调用与@state相关的回调(如果不是NULL),
+ 用于所有当前状态大于@state的在线CPU。 该回调只对将要被移除的实例进行调用。
+ 根据状态阶段,回调要么在当前的CPU上调用(PREPARE阶段),要么在CPU的热插拔
+ 线程中调用每个在线CPU(ONLINE阶段)。
+
+ 为了完成移除工作,teardown回调不能失败。
+
+节点列表的添加/删除操作和回调调用是针对CPU热拔插操作进行序列化。这些函数不能在
+CPU hotplug回调和CPU hotplug读取锁定区域内使用。
+
+样例
+----
+
+在STARTING阶段设置和取消静态分配的状态,以获取上线和下线操作的通知::
+
+ ret = cpuhp_setup_state(CPUHP_SUBSYS_STARTING, "subsys:starting", subsys_cpu_starting, subsys_cpu_dying);
+ if (ret < 0)
+ return ret;
+ ....
+ cpuhp_remove_state(CPUHP_SUBSYS_STARTING);
+
+在ONLINE阶段设置和取消动态分配的状态,以获取下线操作的通知::
+
+ state = cpuhp_setup_state(CPUHP_ONLINE_DYN, "subsys:offline", NULL, subsys_cpu_offline);
+ if (state < 0)
+ return state;
+ ....
+ cpuhp_remove_state(state);
+
+在ONLINE阶段设置和取消动态分配的状态,以获取有关上线操作的通知,而无需调用回调::
+
+ state = cpuhp_setup_state_nocalls(CPUHP_ONLINE_DYN, "subsys:online", subsys_cpu_online, NULL);
+ if (state < 0)
+ return state;
+ ....
+ cpuhp_remove_state_nocalls(state);
+
+在ONLINE阶段设置、使用和取消动态分配的多实例状态,以获得上线和下线操作的通知::
+
+ state = cpuhp_setup_state_multi(CPUHP_ONLINE_DYN, "subsys:online", subsys_cpu_online, subsys_cpu_offline);
+ if (state < 0)
+ return state;
+ ....
+ ret = cpuhp_state_add_instance(state, &inst1->node);
+ if (ret)
+ return ret;
+ ....
+ ret = cpuhp_state_add_instance(state, &inst2->node);
+ if (ret)
+ return ret;
+ ....
+ cpuhp_remove_instance(state, &inst1->node);
+ ....
+ cpuhp_remove_instance(state, &inst2->node);
+ ....
+ remove_multi_state(state);
+
+测试热拔插状态
+==============
+
+验证自定义状态是否按预期工作的一个方法是关闭一个CPU,然后再把它上线。也可以把CPU放到某
+些状态(例如 ``CPUHP_AP_ONLINE`` ),然后再回到 ``CPUHP_ONLINE`` 。这将模拟在
+``CPUHP_AP_ONLINE`` 之后的一个状态出现错误,从而导致回滚到在线状态。
+
+所有注册的状态都被列举在 ``/sys/devices/system/cpu/hotplug/states`` ::
+
+ $ tail /sys/devices/system/cpu/hotplug/states
+ 138: mm/vmscan:online
+ 139: mm/vmstat:online
+ 140: lib/percpu_cnt:online
+ 141: acpi/cpu-drv:online
+ 142: base/cacheinfo:online
+ 143: virtio/net:online
+ 144: x86/mce:online
+ 145: printk:online
+ 168: sched:active
+ 169: online
+
+要将CPU4回滚到 ``lib/percpu_cnt:online`` ,再回到在线状态,只需发出::
+
+ $ cat /sys/devices/system/cpu/cpu4/hotplug/state
+ 169
+ $ echo 140 > /sys/devices/system/cpu/cpu4/hotplug/target
+ $ cat /sys/devices/system/cpu/cpu4/hotplug/state
+ 140
+
+需要注意的是,状态140的清除回调已经被调用。现在重新上线::
+
+ $ echo 169 > /sys/devices/system/cpu/cpu4/hotplug/target
+ $ cat /sys/devices/system/cpu/cpu4/hotplug/state
+ 169
+
+启用追踪事件后,单个步骤也是可见的::
+
+ # TASK-PID CPU# TIMESTAMP FUNCTION
+ # | | | | |
+ bash-394 [001] 22.976: cpuhp_enter: cpu: 0004 target: 140 step: 169 (cpuhp_kick_ap_work)
+ cpuhp/4-31 [004] 22.977: cpuhp_enter: cpu: 0004 target: 140 step: 168 (sched_cpu_deactivate)
+ cpuhp/4-31 [004] 22.990: cpuhp_exit: cpu: 0004 state: 168 step: 168 ret: 0
+ cpuhp/4-31 [004] 22.991: cpuhp_enter: cpu: 0004 target: 140 step: 144 (mce_cpu_pre_down)
+ cpuhp/4-31 [004] 22.992: cpuhp_exit: cpu: 0004 state: 144 step: 144 ret: 0
+ cpuhp/4-31 [004] 22.993: cpuhp_multi_enter: cpu: 0004 target: 140 step: 143 (virtnet_cpu_down_prep)
+ cpuhp/4-31 [004] 22.994: cpuhp_exit: cpu: 0004 state: 143 step: 143 ret: 0
+ cpuhp/4-31 [004] 22.995: cpuhp_enter: cpu: 0004 target: 140 step: 142 (cacheinfo_cpu_pre_down)
+ cpuhp/4-31 [004] 22.996: cpuhp_exit: cpu: 0004 state: 142 step: 142 ret: 0
+ bash-394 [001] 22.997: cpuhp_exit: cpu: 0004 state: 140 step: 169 ret: 0
+ bash-394 [005] 95.540: cpuhp_enter: cpu: 0004 target: 169 step: 140 (cpuhp_kick_ap_work)
+ cpuhp/4-31 [004] 95.541: cpuhp_enter: cpu: 0004 target: 169 step: 141 (acpi_soft_cpu_online)
+ cpuhp/4-31 [004] 95.542: cpuhp_exit: cpu: 0004 state: 141 step: 141 ret: 0
+ cpuhp/4-31 [004] 95.543: cpuhp_enter: cpu: 0004 target: 169 step: 142 (cacheinfo_cpu_online)
+ cpuhp/4-31 [004] 95.544: cpuhp_exit: cpu: 0004 state: 142 step: 142 ret: 0
+ cpuhp/4-31 [004] 95.545: cpuhp_multi_enter: cpu: 0004 target: 169 step: 143 (virtnet_cpu_online)
+ cpuhp/4-31 [004] 95.546: cpuhp_exit: cpu: 0004 state: 143 step: 143 ret: 0
+ cpuhp/4-31 [004] 95.547: cpuhp_enter: cpu: 0004 target: 169 step: 144 (mce_cpu_online)
+ cpuhp/4-31 [004] 95.548: cpuhp_exit: cpu: 0004 state: 144 step: 144 ret: 0
+ cpuhp/4-31 [004] 95.549: cpuhp_enter: cpu: 0004 target: 169 step: 145 (console_cpu_notify)
+ cpuhp/4-31 [004] 95.550: cpuhp_exit: cpu: 0004 state: 145 step: 145 ret: 0
+ cpuhp/4-31 [004] 95.551: cpuhp_enter: cpu: 0004 target: 169 step: 168 (sched_cpu_activate)
+ cpuhp/4-31 [004] 95.552: cpuhp_exit: cpu: 0004 state: 168 step: 168 ret: 0
+ bash-394 [005] 95.553: cpuhp_exit: cpu: 0004 state: 169 step: 140 ret: 0
+
+可以看到,CPU4一直下降到时间戳22.996,然后又上升到95.552。所有被调用的回调,
+包括它们的返回代码都可以在跟踪中看到。
+
+架构的要求
+==========
+
+需要具备以下功能和配置:
+
+``CONFIG_HOTPLUG_CPU``
+ 这个配置项需要在Kconfig中启用
+
+``__cpu_up()``
+ 调出一个cpu的架构接口
+
+``__cpu_disable()``
+ 关闭CPU的架构接口,在此程序返回后,内核不能再处理任何中断。这包括定时器的关闭。
+
+``__cpu_die()``
+ 这实际上是为了确保CPU的死亡。实际上,看看其他架构中实现CPU热拔插的一些示例代
+ 码。对于那个特定的架构,处理器被从 ``idle()`` 循环中拿下来。 ``__cpu_die()``
+ 通常会等待一些per_cpu状态的设置,以确保处理器的死亡例程被调用来保持活跃。
+
+用户空间通知
+============
+
+在CPU成功上线或下线后,udev事件被发送。一个udev规则,比如::
+
+ SUBSYSTEM=="cpu", DRIVERS=="processor", DEVPATH=="/devices/system/cpu/*", RUN+="the_hotplug_receiver.sh"
+
+将接收所有事件。一个像这样的脚本::
+
+ #!/bin/sh
+
+ if [ "${ACTION}" = "offline" ]
+ then
+ echo "CPU ${DEVPATH##*/} offline"
+
+ elif [ "${ACTION}" = "online" ]
+ then
+ echo "CPU ${DEVPATH##*/} online"
+
+ fi
+
+可以进一步处理该事件。
+
+内核内联文档参考
+================
+
+该API在以下内核代码中:
+
+include/linux/cpuhotplug.h
diff --git a/Documentation/translations/zh_CN/core-api/errseq.rst b/Documentation/translations/zh_CN/core-api/errseq.rst
new file mode 100644
index 000000000000..815fb303ea2f
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/errseq.rst
@@ -0,0 +1,145 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/errseq.rst
+
+:翻译:
+
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
+
+:校译:
+
+ 吴想成 Wu Xiangcheng <bobwxc@email.cn>
+
+================
+errseq_t数据类型
+================
+
+``errseq_t`` 是一种在一个地方记录错误的方法,并允许任意数量的 ``订阅者`` 判断自上
+次采样点以来是否发生了变化。
+
+最初的用例是跟踪文件同步系统调用( ``fsync``, ``fdatasync``, ``msync`` 和
+``sync_file_range`` )的错误,但它也可以用于其他情况。
+
+它被实现为一个无符号的32位值。低位被指定保存错误代码(在1和MAX_ERRNO之间)。高位
+用作计数器。这里是用原子操作而不是锁来完成的,因此可以从任何上下文中调用这些函数。
+
+请注意,如果频繁记录新错误,则存在冲突风险,因为我们用作计数器的位很少。
+
+为了缓解这种情况,错误值和计数器之间的位被用作一个标志,以判断自记录新值以来是否
+对该值进行了采样。这使我们能够避免在上次记录错误后没有人取样的情况下碰撞计数器。
+
+因此,我们得到了一个类似这样的值:
+
++--------------------------------------+------+------------------------+
+| 31..13 | 12 | 11..0 |
++--------------------------------------+------+------------------------+
+| 计数器 | 标志 | 错误值 |
++--------------------------------------+------+------------------------+
+
+总体思路是让 ``观察者`` 对errseq_t值进行采样,并将其保留为运行游标。该值稍后可用
+于判断自采样完成后是否发生了任何新错误,并原子地记录检查时的状态。这使得我们能在
+一个地方记录错误,然后有许多 ``观察者`` 可以判断自上次检查以来该值是否发生了变化。
+
+新的errseq_t应始终清零。全零的errseq_t值是从未出现错误的特殊(但常见)情况。因此,
+如果您希望知道自首次初始化以来是否曾经有过错误集,则全零值被用作 ``纪元`` 。
+
+API的使用方法
+=============
+
+让我给你们讲一个关于员工drone的故事。现在,他总体上是个好员工,但公司有点...管理
+繁重。他今天必须向77名主管汇报,明天 ``大老板`` 要从外地赶来,他肯定也会考验这个
+可怜的家伙。
+
+他们都把工作交给他去做---多到他都记不住谁交给他什么了,但这并不是什么大问题。主管
+们只想知道他什么时候完成他们迄今为止交给他的所有工作,以及自从他们上次询问以来他
+是否犯了任何错误。
+
+他可能在他们实际上并没有交给他的工作上犯了错误,但他无法在那么详细的层面上记录事
+情,他所能记得的只是他最近犯的错误。
+
+下面是我们 ``worker_drone`` 的表达式::
+
+ struct worker_drone {
+ errseq_t wd_err; /* 用来记录错误 */
+ };
+
+每天, ``worker_drone`` 都是以一张白纸开始的::
+
+ struct worker_drone wd;
+
+ wd.wd_err = (errseq_t)0;
+
+主管们进来后对当天的工作进行初步了解。他们并不关心在他们观察开始之前发生的任何事
+情::
+
+ struct supervisor {
+ errseq_t s_wd_err; /* wd_err的私有“游标” */
+ spinlock_t s_wd_err_lock; /* 保护s_wd_err */
+ }
+
+ struct supervisor su;
+
+ su.s_wd_err = errseq_sample(&wd.wd_err);
+ spin_lock_init(&su.s_wd_err_lock);
+
+现在他们开始给他布置任务。每隔几分钟,他们就要求他完成迄今为止交给他的所有工作。
+然后问他是否有犯任何错误::
+
+ spin_lock(&su.su_wd_err_lock);
+ err = errseq_check_and_advance(&wd.wd_err, &su.s_wd_err);
+ spin_unlock(&su.su_wd_err_lock);
+
+到目前为止,它只是不断返回0。
+
+现在,这家公司的老板非常吝啬,给了他不合格的设备来完成他的工作。偶尔设备会出现故
+障,导致他犯错。他重重地叹了一口气,并把它记录下来::
+
+ errseq_set(&wd.wd_err, -EIO);
+
+...然后继续工作。主管们最终会再次检查,他们在下次检查时都会发现这个错误。后续的调
+用将返回0,直到记录下另一个错误,此时将向每个调用报告一次。
+
+请注意,主管们无法知道他们犯了多少错误,只能知道自上次检查以来是否犯了一个错误,
+以及记录的最新值。
+
+偶尔,大老板会来抽查,要求员工为他做一次性的工作。他并不像主管们那样全职观察员工,
+但他确实需要知道在他的工作处理过程中是否发生了错误。
+
+他只需对员工当前的errseq_t进行采样,然后用它来判断后来是否发生了错误::
+
+ errseq_t since = errseq_sample(&wd.wd_err);
+ /* 提交一些工作,等待完成 */
+ err = errseq_check(&wd.wd_err, since);
+
+由于他只是要在那个点之后丢弃 ``since`` ,所以他不需要在这里推进它。同时他也不需要
+任何锁,因为它不能被其他人使用。
+
+序列化更新errseq_t游标
+======================
+
+请注意,errseq_t API在check_and_advance_operation期间不保护errseq_t游标。只有典型
+的错误代码是被原子化处理的。在多任务同时使用同一个errseq_t游标的情况下,对该游标
+的更新进行序列化是很重要的。
+
+如果不这样做,那么游标就有可能向后移动。在这种情况下,同一个错误可能被报告多次。
+
+因此,通常先执行errseq_check检查是否有任何变化,然后在获取锁后才执行
+errseq_check_and_advance。例如::
+
+ if (errseq_check(&wd.wd_err, READ_ONCE(su.s_wd_err)) {
+ /* su.s_wd_err被s_wd_err_lock保护 */
+ spin_lock(&su.s_wd_err_lock);
+ err = errseq_check_and_advance(&wd.wd_err, &su.s_wd_err);
+ spin_unlock(&su.s_wd_err_lock);
+ }
+
+这就避免了自上次检查以来没有任何变化的常见情况下的自旋锁。
+
+函数
+====
+
+该API在以下内核代码中:
+
+lib/errseq.c
diff --git a/Documentation/translations/zh_CN/core-api/genalloc.rst b/Documentation/translations/zh_CN/core-api/genalloc.rst
new file mode 100644
index 000000000000..3c78452aaa7c
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/genalloc.rst
@@ -0,0 +1,109 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/genalloc.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 时奎亮 <alexs@kernel.org>
+
+.. _cn_core-api_genalloc:
+
+genalloc/genpool子系统
+======================
+
+内核中有许多内存分配子系统,每一个都是针对特定的需求。然而,有时候,内核开发者需
+要为特定范围的特殊用途的内存实现一个新的分配器;通常这个内存位于某个设备上。该设
+备的驱动程序的作者当然可以写一个小的分配器来完成工作,但这是让内核充满几十个测试
+差劲的分配器的方法。早在2005年,Jes Sorensen从sym53c8xx_2驱动中提取了其中的一
+个分配器,并将其作为一个通用模块发布,用于创建特设的内存分配器。这段代码在2.6.13
+版本中被合并;此后它被大大地修改了。
+
+.. _posted: https://lwn.net/Articles/125842/
+
+使用这个分配器的代码应该包括<linux/genalloc.h>。这个动作从创建一个池开始,使用
+一个:
+
+该API在以下内核代码中:
+
+lib/genalloc.c
+
+对gen_pool_create()的调用将创建一个内存池。分配的粒度由min_alloc_order设置;它
+是一个log-base-2(以2为底的对数)的数字,就像页面分配器使用的数字一样,但它指的是
+字节而不是页面。因此,如果min_alloc_order被传递为3,那么所有的分配将是8字节的倍数。
+增加min_alloc_order可以减少跟踪池中内存所需的内存。nid参数指定哪一个NUMA节点应该被
+用于分配管家结构体;如果调用者不关心,它可以是-1。
+
+“管理的”接口devm_gen_pool_create()将内存池与一个特定的设备联系起来。在其他方面,
+当给定的设备被销毁时,它将自动清理内存池。
+
+一个内存池池被关闭的方法是:
+
+该API在以下内核代码中:
+
+lib/genalloc.c
+
+值得注意的是,如果在给定的内存池中仍有未完成的分配,这个函数将采取相当极端的步骤,调用
+BUG(),使整个系统崩溃。你已经被警告了。
+
+一个新创建的内存池没有内存可以分配。在这种状态下,它是相当无用的,所以首要任务之一通常
+是向内存池里添加内存。这可以通过以下方式完成:
+
+该API在以下内核代码中:
+
+include/linux/genalloc.h
+
+lib/genalloc.c
+
+对gen_pool_add()的调用将把从地址(在内核的虚拟地址空间)开始的内存的大小字节放入
+给定的池中,再次使用nid作为节点ID进行辅助内存分配。gen_pool_add_virt()变体将显式
+物理地址与内存联系起来;只有在内存池被用于DMA分配时,这才是必要的。
+
+从内存池中分配内存(并将其放回)的函数是:
+
+该API在以下内核代码中:
+
+include/linux/genalloc.h
+
+lib/genalloc.c
+
+正如人们所期望的,gen_pool_alloc()将从给定的池中分配size<字节。gen_pool_dma_alloc()
+变量分配内存用于DMA操作,返回dma所指向的空间中的相关物理地址。这只有在内存是用
+gen_pool_add_virt()添加的情况下才会起作用。请注意,这个函数偏离了genpool通常使用
+无符号长值来表示内核地址的模式;它返回一个void * 来代替。
+
+这一切看起来都比较简单;事实上,一些开发者显然认为这太简单了。毕竟,上面的接口没有提
+供对分配函数如何选择返回哪块特定内存的控制。如果需要这样的控制,下面的函数将是有意义
+的:
+
+该API在以下内核代码中:
+
+lib/genalloc.c
+
+使用gen_pool_alloc_algo()进行的分配指定了一种用于选择要分配的内存的算法;默认算法可
+以用gen_pool_set_algo()来设置。数据值被传递给算法;大多数算法会忽略它,但偶尔也会需
+要它。当然,人们可以写一个特殊用途的算法,但是已经有一套公平的算法可用了:
+
+- gen_pool_first_fit是一个简单的初配分配器;如果没有指定其他算法,这是默认算法。
+
+- gen_pool_first_fit_align强迫分配有一个特定的对齐方式(通过genpool_data_align结
+ 构中的数据传递)。
+
+- gen_pool_first_fit_order_align 按照大小的顺序排列分配。例如,一个60字节的分配将
+ 以64字节对齐。
+
+- gen_pool_best_fit,正如人们所期望的,是一个简单的最佳匹配分配器。
+
+- gen_pool_fixed_alloc在池中的一个特定偏移量(通过数据参数在genpool_data_fixed结
+ 构中传递)进行分配。如果指定的内存不可用,则分配失败。
+
+还有一些其他的函数,主要是为了查询内存池中的可用空间或迭代内存块等目的。然而,大多数
+用户应该不需要以上描述的功能。如果幸运的话,对这个模块的广泛认识将有助于防止在未来编
+写特殊用途的内存分配器。
+
+该API在以下内核代码中:
+
+lib/genalloc.c
diff --git a/Documentation/translations/zh_CN/core-api/generic-radix-tree.rst b/Documentation/translations/zh_CN/core-api/generic-radix-tree.rst
new file mode 100644
index 000000000000..eacd1d2ebddc
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/generic-radix-tree.rst
@@ -0,0 +1,23 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/generic-radix-tree.rst
+
+:翻译:
+
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
+
+===================
+通用基数树/稀疏数组
+===================
+
+通用基数树/稀疏数组的相关内容请见include/linux/generic-radix-tree.h文件中的
+“DOC: Generic radix trees/sparse arrays”。
+
+通用基数树函数
+--------------
+
+该API在以下内核代码中:
+
+include/linux/generic-radix-tree.h
diff --git a/Documentation/translations/zh_CN/core-api/genericirq.rst b/Documentation/translations/zh_CN/core-api/genericirq.rst
new file mode 100644
index 000000000000..05ccb954c18d
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/genericirq.rst
@@ -0,0 +1,409 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/genericirq.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+.. include:: <isonum.txt>
+
+.. _cn_core-api_genericirq:
+
+================
+Linux通用IRQ处理
+================
+
+:版权: |copy| 2005-2010: Thomas Gleixner
+:版权: |copy| 2005-2006: Ingo Molnar
+
+简介
+====
+
+通用中断处理层是为了给设备驱动程序提供一个完整的中断处理抽象(层)。它能够处
+理所有不同类型的中断控制器硬件。设备驱动程序使用通用API函数来请求、启用、禁
+用和释放中断。驱动程序不需要知道任何关于硬件处理中断的细节,所以它们可以在不同的
+平台上使用而不需要修改代码。
+
+本文档提供给那些希望在通用IRQ处理层的帮助下实现基于其架构的中断子系统的开发
+者。
+
+理论依据
+========
+
+Linux中中断处理的原始实现使用__do_IRQ()超级处理程序,它能够处理每种类型的
+中断逻辑。
+
+最初,Russell King确定了不同类型的处理程序,以便为Linux 2.5/2.6中的ARM中
+断处理程序实现建立一个相当通用的集合。他区分了以下几种类型:
+
+- 电平触发型
+
+- 边沿触发型
+
+- 简单型
+
+在实现过程中,我们发现了另一种类型:
+
+- 响应EOI(end of interrupt)型
+
+在SMP的__do_IRQ()超级处理程序中,还需定义一种类型:
+
+-  每cpu型(针对CPU SMP)
+
+这种高层IRQ处理程序的拆分实现使我们能够为每个特定的中断类型优化中断处理的流
+程。这减少了该特定代码路径的复杂性,并允许对特定类型进行优化处理。
+
+最初的通用IRQ实现使用hw_interrupt_type结构体及其 ``->ack`` ``->end`` 等回
+调来区分超级处理程序中的流控制。这导致了流逻辑和低级硬件逻辑的混合,也导致了
+不必要的代码重复:例如i386中的 ``ioapic_level_irq`` 和 ``ioapic_edge_irq`` ,
+这两个IRQ类型共享许多低级的细节,但有不同的流处理。
+
+一个更自然的抽象是“irq流”和“芯片细节”的干净分离。
+
+分析一些架构的IRQ子系统的实现可以发现,他们中的大多数可以使用一套通用的“irq
+流”方法,只需要添加芯片级的特定代码。这种分离对于那些需要IRQ流本身而不需要芯
+片细节的特定(子)架构也很有价值——以提供了一个更透明的IRQ子系统设计。
+
+每个中断描述符都被分配给它自己的高层流程处理程序,这通常是一个通用的实现。(这
+种高层次的流程处理程序的实现也使得提供解复用处理程序变得简单,这可以在各种架
+构的嵌入式平台上找到。)
+
+这种分离使得通用中断处理层更加灵活和可扩展。例如,一个(子)架构可以使用通用
+的IRQ流实现“电平触发型”中断,并添加一个(子)架构特定的“边沿型”实现。
+
+为了使向新模型的过渡更容易,并防止破坏现有实现,__do_IRQ()超级处理程序仍然
+可用。这导致了一种暂时的双重性。随着时间的推移,新的模型应该在越来越多的架构中
+被使用,因为它能使IRQ子系统更小更干净。它已经被废弃三年了,即将被删除。
+
+已知的缺陷和假设
+================
+
+没有(但愿如此)。
+
+抽象层
+======
+
+中断代码中主要有三个抽象层次:
+
+1. 高级别的驱动API
+
+2. 高级别的IRQ流处理器
+
+3. 芯片级的硬件封装
+
+中断控制流
+----------
+
+每个中断都由一个中断描述符结构体irq_desc来描述。中断是由一个“无符号整型”的数值来
+引用的,它在描述符结构体数组中选择相应的中断描述符结构体。描述符结构体包含状态
+信息和指向中断流方法和中断芯片结构的指针,这些都是分配给这个中断的。
+
+每当中断触发时,低级架构代码通过调用desc->handle_irq()调用到通用中断代码中。
+这个高层IRQ处理函数只使用由分配的芯片描述符结构体引用的desc->irq_data.chip
+基元。
+
+高级驱动程序API
+---------------
+
+高层驱动API由以下函数组成:
+
+- request_irq()
+
+- request_threaded_irq()
+
+- free_irq()
+
+- disable_irq()
+
+- enable_irq()
+
+- disable_irq_nosync() (SMP only)
+
+- synchronize_irq() (SMP only)
+
+- irq_set_irq_type()
+
+- irq_set_irq_wake()
+
+- irq_set_handler_data()
+
+- irq_set_chip()
+
+- irq_set_chip_data()
+
+详见自动生成的函数文档。
+
+.. note::
+
+ 由于文档构建流程所限,中文文档中并没有引入自动生成的函数文档,所以请读者直接
+ 阅读源码注释。
+
+电平触发型IRQ流处理程序
+-----------------------
+
+通用层提供了一套预定义的irq-flow方法:
+
+- handle_level_irq()
+
+- handle_edge_irq()
+
+- handle_fasteoi_irq()
+
+- handle_simple_irq()
+
+- handle_percpu_irq()
+
+- handle_edge_eoi_irq()
+
+- handle_bad_irq()
+
+中断流处理程序(无论是预定义的还是架构特定的)由架构在启动期间或设备初始化期间分配给
+特定中断。
+
+默认流实现
+~~~~~~~~~~
+
+辅助函数
+^^^^^^^^
+
+辅助函数调用芯片基元,并被默认流实现所使用。以下是实现的辅助函数(简化摘录)::
+
+ default_enable(struct irq_data *data)
+ {
+ desc->irq_data.chip->irq_unmask(data);
+ }
+
+ default_disable(struct irq_data *data)
+ {
+ if (!delay_disable(data))
+ desc->irq_data.chip->irq_mask(data);
+ }
+
+ default_ack(struct irq_data *data)
+ {
+ chip->irq_ack(data);
+ }
+
+ default_mask_ack(struct irq_data *data)
+ {
+ if (chip->irq_mask_ack) {
+ chip->irq_mask_ack(data);
+ } else {
+ chip->irq_mask(data);
+ chip->irq_ack(data);
+ }
+ }
+
+ noop(struct irq_data *data))
+ {
+ }
+
+
+
+默认流处理程序的实现
+~~~~~~~~~~~~~~~~~~~~
+
+电平触发型IRQ流处理器
+^^^^^^^^^^^^^^^^^^^^^
+
+handle_level_irq为电平触发型的中断提供了一个通用实现。
+
+实现的控制流如下(简化摘录)::
+
+ desc->irq_data.chip->irq_mask_ack();
+ handle_irq_event(desc->action);
+ desc->irq_data.chip->irq_unmask();
+
+
+默认的需回应IRQ流处理器
+^^^^^^^^^^^^^^^^^^^^^^^
+
+handle_fasteoi_irq为中断提供了一个通用的实现,它只需要在处理程序的末端有一个EOI。
+
+实现的控制流如下(简化摘录)::
+
+ handle_irq_event(desc->action);
+ desc->irq_data.chip->irq_eoi();
+
+
+默认的边沿触发型IRQ流处理器
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+handle_edge_irq为边沿触发型的中断提供了一个通用的实现。
+
+实现的控制流如下(简化摘录)::
+
+ if (desc->status & running) {
+ desc->irq_data.chip->irq_mask_ack();
+ desc->status |= pending | masked;
+ return;
+ }
+ desc->irq_data.chip->irq_ack();
+ desc->status |= running;
+ do {
+ if (desc->status & masked)
+ desc->irq_data.chip->irq_unmask();
+ desc->status &= ~pending;
+ handle_irq_event(desc->action);
+ } while (status & pending);
+ desc->status &= ~running;
+
+
+默认的简单型IRQ流处理器
+^^^^^^^^^^^^^^^^^^^^^^^
+
+handle_simple_irq提供了一个简单型中断的通用实现。
+
+.. note::
+
+ 简单型的流处理程序不调用任何处理程序/芯片基元。
+
+实现的控制流程如下(简化摘录)::
+
+ handle_irq_event(desc->action);
+
+
+默认的每CPU型流处理程序
+^^^^^^^^^^^^^^^^^^^^^^^
+
+handle_percpu_irq为每CPU型中断提供一个通用的实现。
+
+每个CPU中断只在SMP上可用,该处理程序提供了一个没有锁的简化版本。
+
+以下是控制流的实现(简化摘录)::
+
+ if (desc->irq_data.chip->irq_ack)
+ desc->irq_data.chip->irq_ack();
+ handle_irq_event(desc->action);
+ if (desc->irq_data.chip->irq_eoi)
+ desc->irq_data.chip->irq_eoi();
+
+
+EOI边沿型IRQ流处理器
+^^^^^^^^^^^^^^^^^^^^
+
+handle_edge_eoi_irq提供了一个异常的边沿触发型处理程序,它只用于拯救powerpc/cell
+上的一个严重失控的irq控制器。
+
+坏的IRQ流处理器
+^^^^^^^^^^^^^^^
+
+handle_bad_irq用于处理没有真正分配处理程序的假中断。
+
+特殊性和优化
+~~~~~~~~~~~~
+
+通用函数是为“干净”的架构和芯片设计的,它们没有平台特定的IRQ处理特殊性。如果一
+个架构需要在“流”的层面上实现特殊性,那么它可以通过覆盖高层的IRQ-流处理程序来实
+现。
+
+延迟中断禁用
+~~~~~~~~~~~~
+
+每个中断可选择的功能是由Russell King在ARM中断实现中引入的,当调用disable_irq()
+时,不会在硬件层面上屏蔽中断。中断保持启用状态,而在中断事件发生时在流处理器中被
+屏蔽。这可以防止在硬件上丢失边沿中断,因为硬件上不存储边沿中断事件,而中断在硬件
+级被禁用。当一个中断在IRQ_DISABLED标志被设置时到达,那么该中断在硬件层面被屏蔽,
+IRQ_PENDING位被设置。当中断被enable_irq()重新启用时,将检查挂起位,如果它被设置,
+中断将通过硬件或软件重发机制重新发送。(当你想使用延迟中断禁用功能,而你的硬件又不
+能重新触发中断时,有必要启用CONFIG_HARDIRQS_SW_RESEND。) 延迟中断禁止功能是不可
+配置的。
+
+芯片级硬件封装
+--------------
+
+芯片级硬件描述符结构体 :c:type:`irq_chip` 包含了所有与芯片直接相关的功能,这些功
+能可以被irq流实现所利用。
+
+- ``irq_ack``
+
+- ``irq_mask_ack`` - 可选的,建议使用的性能
+
+- ``irq_mask``
+
+- ``irq_unmask``
+
+- ``irq_eoi`` - 可选的,EOI流处理程序需要
+
+- ``irq_retrigger`` - 可选的
+
+- ``irq_set_type`` - 可选的
+
+- ``irq_set_wake`` - 可选的
+
+这些基元的意思是严格意义上的:ack是指ACK,masking是指对IRQ线的屏蔽,等等。这取决
+于流处理器如何使用这些基本的低级功能单元。
+
+__do_IRQ入口点
+==============
+
+最初的实现__do_IRQ()是所有类型中断的替代入口点。它已经不存在了。
+
+这个处理程序被证明不适合所有的中断硬件,因此被重新实现了边沿/级别/简单/超高速中断
+的拆分功能。这不仅是一个功能优化。它也缩短了中断的代码路径。
+
+在SMP上的锁
+===========
+
+芯片寄存器的锁定是由定义芯片基元的架构决定的。每个寄存器的结构通过desc->lock,由
+通用层保护。
+
+通用中断芯片
+============
+
+为了避免复制相同的IRQ芯片实现,核心提供了一个可配置的通用中断芯片实现。开发者在自
+己实现相同的功能之前,应该仔细检查通用芯片是否符合他们的需求,并以稍微不同的方式实
+现相同的功能。
+
+该API在以下内核代码中:
+
+kernel/irq/generic-chip.c
+
+结构体
+======
+
+本章包含自动生成的结构体文档,这些结构体在通用IRQ层中使用。
+
+该API在以下内核代码中:
+
+include/linux/irq.h
+
+include/linux/interrupt.h
+
+提供的通用函数
+==============
+
+这一章包含了自动生成的内核API函数的文档,这些函数被导出。
+
+该API在以下内核代码中:
+
+kernel/irq/manage.c
+
+kernel/irq/chip.c
+
+提供的内部函数
+==============
+
+本章包含自动生成的内部函数的文档。
+
+该API在以下内核代码中:
+
+kernel/irq/irqdesc.c
+
+kernel/irq/handle.c
+
+kernel/irq/chip.c
+
+鸣谢
+====
+
+感谢以下人士对本文档作出的贡献:
+
+1. Thomas Gleixner tglx@linutronix.de
+
+2. Ingo Molnar mingo@elte.hu
diff --git a/Documentation/translations/zh_CN/core-api/gfp_mask-from-fs-io.rst b/Documentation/translations/zh_CN/core-api/gfp_mask-from-fs-io.rst
new file mode 100644
index 000000000000..75d2997e9bc3
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/gfp_mask-from-fs-io.rst
@@ -0,0 +1,66 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/gfp_mask-from-fs-io.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 时奎亮 <alexs@kernel.org>
+
+.. _cn_core-api_gfp_mask-from-fs-io:
+
+============================
+从FS/IO上下文中使用的GFP掩码
+============================
+
+:日期: 2018年5月
+:作者: Michal Hocko <mhocko@kernel.org>
+
+简介
+====
+
+文件系统和IO栈中的代码路径在分配内存时必须小心,以防止因直接调用FS或IO路径的内
+存回收和阻塞已经持有的资源(例如锁--最常见的是用于事务上下文的锁)而造成递归死
+锁。
+
+避免这种死锁问题的传统方法是在调用分配器时,在gfp掩码中清除__GFP_FS和__GFP_IO
+(注意后者意味着也要清除第一个)。GFP_NOFS和GFP_NOIO可以作为快捷方式使用。但事
+实证明,上述方法导致了滥用,当限制性的gfp掩码被用于“万一”时,没有更深入的考虑,
+这导致了问题,因为过度使用GFP_NOFS/GFP_NOIO会导致内存过度回收或其他内存回收的问
+题。
+
+新API
+=====
+
+从4.12开始,我们为NOFS和NOIO上下文提供了一个通用的作用域API,分别是
+``memalloc_nofs_save`` , ``memalloc_nofs_restore`` 和 ``memalloc_noio_save`` ,
+``memalloc_noio_restore`` ,允许从文件系统或I/O的角度将一个作用域标记为一个
+关键部分。从该作用域的任何分配都将从给定的掩码中删除__GFP_FS和__GFP_IO,所以
+没有内存分配可以追溯到FS/IO中。
+
+
+该API在以下内核代码中:
+
+include/linux/sched/mm.h
+
+然后,FS/IO代码在任何与回收有关的关键部分开始之前简单地调用适当的保存函数
+——例如,与回收上下文共享的锁或当事务上下文嵌套可能通过回收进行时。恢复函数
+应该在关键部分结束时被调用。所有这一切最好都伴随着解释什么是回收上下文,以
+方便维护。
+
+请注意,保存/恢复函数的正确配对允许嵌套,所以从现有的NOIO或NOFS范围分别调
+用 ``memalloc_noio_save`` 或 ``memalloc_noio_restore`` 是安全的。
+
+那么__vmalloc(GFP_NOFS)呢?
+===========================
+
+vmalloc不支持GFP_NOFS语义,因为在分配器的深处有硬编码的GFP_KERNEL分配,要修
+复这些分配是相当不容易的。这意味着用GFP_NOFS/GFP_NOIO调用 ``vmalloc`` 几乎
+总是一个错误。好消息是,NOFS/NOIO语义可以通过范围API实现。
+
+在理想的世界中,上层应该已经标记了危险的上下文,因此不需要特别的照顾, ``vmalloc``
+的调用应该没有任何问题。有时,如果上下文不是很清楚,或者有叠加的违规行为,那么
+推荐的方法是用范围API包装vmalloc,并加上注释来解释问题。
diff --git a/Documentation/translations/zh_CN/core-api/idr.rst b/Documentation/translations/zh_CN/core-api/idr.rst
new file mode 100644
index 000000000000..97a16e76b81b
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/idr.rst
@@ -0,0 +1,80 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/idr.rst
+
+:翻译:
+
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
+
+:校译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 吴想成 Wu Xiangcheng <bobwxc@email.cn>
+ 时奎亮 Alex Shi <alexs@kernel.org>
+
+======
+ID分配
+======
+
+:作者: Matthew Wilcox
+
+概述
+====
+
+要解决的一个常见问题是分配标识符(IDs);它通常是标识事物的数字。比如包括文件描述
+符、进程ID、网络协议中的数据包标识符、SCSI标记和设备实例编号。IDR和IDA为这个问题
+提供了一个合理的解决方案,以避免每个人都自创。IDR提供将ID映射到指针的能力,而IDA
+仅提供ID分配,因此内存效率更高。
+
+IDR接口已经被废弃,请使用 ``XArray`` 。
+
+IDR的用法
+=========
+
+首先初始化一个IDR,对于静态分配的IDR使用DEFINE_IDR(),或者对于动态分配的IDR使用
+idr_init()。
+
+您可以调用idr_alloc()来分配一个未使用的ID。通过调用idr_find()查询与该ID相关的指针,
+并通过调用idr_remove()释放该ID。
+
+如果需要更改与一个ID相关联的指针,可以调用idr_replace()。这样做的一个常见原因是通
+过将 ``NULL`` 指针传递给分配函数来保留ID;用保留的ID初始化对象,最后将初始化的对
+象插入IDR。
+
+一些用户需要分配大于 ``INT_MAX`` 的ID。到目前为止,所有这些用户都满足 ``UINT_MAX``
+的限制,他们使用idr_alloc_u32()。如果您需要超出u32的ID,我们将与您合作以满足您的
+需求。
+
+如果需要按顺序分配ID,可以使用idr_alloc_cyclic()。处理较大数量的ID时,IDR的效率会
+降低,所以使用这个函数会有一点代价。
+
+要对IDR使用的所有指针进行操作,您可以使用基于回调的idr_for_each()或迭代器样式的
+idr_for_each_entry()。您可能需要使用idr_for_each_entry_continue()来继续迭代。如果
+迭代器不符合您的需求,您也可以使用idr_get_next()。
+
+当使用完IDR后,您可以调用idr_destroy()来释放IDR占用的内存。这并不会释放IDR指向的
+对象;如果您想这样做,请使用其中一个迭代器来执行此操作。
+
+您可以使用idr_is_empty()来查看当前是否分配了任何ID。
+
+如果在从IDR分配一个新ID时需要带锁,您可能需要传递一组限制性的GFP标志,但这可能导
+致IDR无法分配内存。为了解决该问题,您可以在获取锁之前调用idr_preload(),然后在分
+配之后调用idr_preload_end()。
+
+IDR同步的相关内容请见include/linux/idr.h文件中的“DOC: idr sync”。
+
+IDA的用法
+=========
+
+IDA的用法的相关内容请见lib/idr.c文件中的“DOC: IDA description”。
+
+函数和数据结构
+==============
+
+该API在以下内核代码中:
+
+include/linux/idr.h
+
+lib/idr.c
diff --git a/Documentation/translations/zh_CN/core-api/index.rst b/Documentation/translations/zh_CN/core-api/index.rst
new file mode 100644
index 000000000000..922cabf7b5dd
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/index.rst
@@ -0,0 +1,147 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_core-api_index.rst:
+
+===========
+核心API文档
+===========
+
+这是核心内核API手册的首页。 非常感谢为本手册转换(和编写!)的文档!
+
+核心实用程序
+============
+
+本节包含通用的和“核心中的核心”文档。 第一部分是 docbook 时期遗留下
+来的大量 kerneldoc 信息;有朝一日,若有人有动力的话,应当把它们拆分
+出来。
+
+.. toctree::
+ :maxdepth: 1
+
+ kernel-api
+ printk-basics
+ printk-formats
+ workqueue
+ watch_queue
+ symbol-namespaces
+
+数据结构和低级实用程序
+======================
+
+在整个内核中使用的函数库。
+
+.. toctree::
+ :maxdepth: 1
+
+ kobject
+ kref
+ assoc_array
+ xarray
+ rbtree
+ idr
+ circular-buffers
+ generic-radix-tree
+ packing
+ this_cpu_ops
+
+=======
+
+Todolist:
+
+ timekeeping
+ errseq
+
+并发原语
+========
+
+Linux如何让一切同时发生。 详情请参阅
+:doc:`/locking/index`
+
+.. toctree::
+ :maxdepth: 1
+
+ irq/index
+ refcount-vs-atomic
+ local_ops
+ padata
+
+Todolist:
+
+ ../RCU/index
+
+低级硬件管理
+============
+
+缓存管理,CPU热插拔管理等。
+
+.. toctree::
+ :maxdepth: 1
+
+ cachetlb
+ cpu_hotplug
+ genericirq
+ memory-hotplug
+ protection-keys
+
+Todolist:
+
+
+ memory-hotplug
+ cpu_hotplug
+ genericirq
+
+
+内存管理
+========
+
+如何在内核中分配和使用内存。请注意,在
+:doc:`/mm/index` 中有更多的内存管理文档。
+
+.. toctree::
+ :maxdepth: 1
+
+ memory-allocation
+ unaligned-memory-access
+ mm-api
+ genalloc
+ boot-time-mm
+ gfp_mask-from-fs-io
+
+Todolist:
+
+ dma-api
+ dma-api-howto
+ dma-attributes
+ dma-isa-lpc
+ pin_user_pages
+
+内核调试的接口
+==============
+
+Todolist:
+
+ debug-objects
+ tracepoint
+ debugging-via-ohci1394
+
+其它文档
+========
+
+不适合放在其它地方或尚未归类的文件;
+
+Todolist:
+
+ librs
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
diff --git a/Documentation/translations/zh_CN/core-api/irq/concepts.rst b/Documentation/translations/zh_CN/core-api/irq/concepts.rst
new file mode 100644
index 000000000000..9957f0453353
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/irq/concepts.rst
@@ -0,0 +1,26 @@
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/irq/concepts.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_concepts.rst:
+
+===========
+什么是IRQ?
+===========
+
+IRQ (Interrupt ReQuest) 指来自设备的中断请求。
+目前,它们可以通过一个引脚或通过一个数据包进入。
+多个设备可以连接到同一个引脚,从而共享一个IRQ。
+
+IRQ编号是用来描述硬件中断源的内核标识符。通常它是一个到全局irq_desc数组的索引,
+但是除了在linux/interrupt.h中实现的之外,其它细节是体系结构特征相关的。
+
+IRQ编号是对机器上可能的中断源的枚举。通常枚举的是系统中所有中断控制器的输入引脚
+编号。在ISA(工业标准体系结构)的情况下所枚举的是两个i8259中断控制器的16个输入引脚。
+
+体系结构可以给IRQ号赋予额外的含义,在涉及到硬件手动配置的情况下,我们鼓励这样做。
+ISA IRQ是赋予这种额外含义的一个典型例子。
diff --git a/Documentation/translations/zh_CN/core-api/irq/index.rst b/Documentation/translations/zh_CN/core-api/irq/index.rst
new file mode 100644
index 000000000000..ba6acc4b48e5
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/irq/index.rst
@@ -0,0 +1,22 @@
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/irq/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_irq_index.rst:
+
+
+====
+IRQs
+====
+
+.. toctree::
+ :maxdepth: 1
+
+ concepts
+ irq-affinity
+ irq-domain
+ irqflags-tracing
diff --git a/Documentation/translations/zh_CN/core-api/irq/irq-affinity.rst b/Documentation/translations/zh_CN/core-api/irq/irq-affinity.rst
new file mode 100644
index 000000000000..36b085226d0b
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/irq/irq-affinity.rst
@@ -0,0 +1,78 @@
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/irq/irq-affinity.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_irq-affinity.rst:
+
+==============
+SMP IRQ 亲和性
+==============
+
+变更记录:
+ - 作者:最初由Ingo Molnar <mingo@redhat.com>开始撰写
+ - 后期更新维护: Max Krasnyansky <maxk@qualcomm.com>
+
+
+/proc/irq/IRQ#/smp_affinity和/proc/irq/IRQ#/smp_affinity_list指定了哪些CPU能
+够关联到一个给定的IRQ源,这两个文件包含了这些指定cpu的cpu位掩码(smp_affinity)和cpu列
+表(smp_affinity_list)。它不允许关闭所有CPU, 同时如果IRQ控制器不支持中断请求亲和
+(IRQ affinity),那么所有cpu的默认值将保持不变(即关联到所有CPU).
+
+/proc/irq/default_smp_affinity指明了适用于所有非激活IRQ的默认亲和性掩码。一旦IRQ被
+分配/激活,它的亲和位掩码将被设置为默认掩码。然后可以如上所述改变它。默认掩码是0xffffffff。
+
+下面是一个先将IRQ44(eth1)限制在CPU0-3上,然后限制在CPU4-7上的例子(这是一个8CPU的SMP box)
+
+::
+
+ [root@moon 44]# cd /proc/irq/44
+ [root@moon 44]# cat smp_affinity
+ ffffffff
+
+ [root@moon 44]# echo 0f > smp_affinity
+ [root@moon 44]# cat smp_affinity
+ 0000000f
+ [root@moon 44]# ping -f h
+ PING hell (195.4.7.3): 56 data bytes
+ ...
+ --- hell ping statistics ---
+ 6029 packets transmitted, 6027 packets received, 0% packet loss
+ round-trip min/avg/max = 0.1/0.1/0.4 ms
+ [root@moon 44]# cat /proc/interrupts | grep 'CPU\|44:'
+ CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7
+ 44: 1068 1785 1785 1783 0 0 0 0 IO-APIC-level eth1
+
+从上面一行可以看出,IRQ44只传递给前四个处理器(0-3)。
+现在让我们把这个IRQ限制在CPU(4-7)。
+
+::
+
+ [root@moon 44]# echo f0 > smp_affinity
+ [root@moon 44]# cat smp_affinity
+ 000000f0
+ [root@moon 44]# ping -f h
+ PING hell (195.4.7.3): 56 data bytes
+ ..
+ --- hell ping statistics ---
+ 2779 packets transmitted, 2777 packets received, 0% packet loss
+ round-trip min/avg/max = 0.1/0.5/585.4 ms
+ [root@moon 44]# cat /proc/interrupts | 'CPU\|44:'
+ CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7
+ 44: 1068 1785 1785 1783 1784 1069 1070 1069 IO-APIC-level eth1
+
+这次IRQ44只传递给最后四个处理器。
+即CPU0-3的计数器没有变化。
+
+下面是一个将相同的irq(44)限制在cpus 1024到1031的例子
+
+::
+
+ [root@moon 44]# echo 1024-1031 > smp_affinity_list
+ [root@moon 44]# cat smp_affinity_list
+ 1024-1031
+
+需要注意的是,如果要用位掩码来做这件事,就需要32个为0的位掩码来追踪其相关的一个。
diff --git a/Documentation/translations/zh_CN/core-api/irq/irq-domain.rst b/Documentation/translations/zh_CN/core-api/irq/irq-domain.rst
new file mode 100644
index 000000000000..9174fce12c1b
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/irq/irq-domain.rst
@@ -0,0 +1,243 @@
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/irq/irq-domain.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
+
+.. _cn_irq-domain.rst:
+
+=======================
+irq_domain 中断号映射库
+=======================
+
+目前Linux内核的设计使用了一个巨大的数字空间,每个独立的IRQ源都被分配了一个不
+同的数字。
+当只有一个中断控制器时,这很简单,但在有多个中断控制器的系统中,内核必须确保每
+个中断控制器都能得到非重复的Linux IRQ号(数字)分配。
+
+注册为唯一的irqchips的中断控制器编号呈现出上升的趋势:例如GPIO控制器等不同
+种类的子驱动程序通过将其中断处理程序建模为irqchips,即实际上是级联中断控制器,
+避免了重新实现与IRQ核心系统相同的回调机制。
+
+在这里,中断号与硬件中断号离散了所有种类的对应关系:而在过去,IRQ号可以选择,
+使它们与硬件IRQ线进入根中断控制器(即实际向CPU发射中断线的组件)相匹配,现
+在这个编号仅仅是一个数字。
+
+出于这个原因,我们需要一种机制将控制器本地中断号(即硬件irq编号)与Linux IRQ
+号分开。
+
+irq_alloc_desc*() 和 irq_free_desc*() API 提供了对irq号的分配,但它们不
+提供任何对控制器本地IRQ(hwirq)号到Linux IRQ号空间的反向映射的支持。
+
+irq_domain 库在 irq_alloc_desc*() API 的基础上增加了 hwirq 和 IRQ 号码
+之间的映射。 相比于中断控制器驱动开放编码自己的反向映射方案,我们更喜欢用
+irq_domain来管理映射。
+
+irq_domain还实现了从抽象的irq_fwspec结构体到hwirq号的转换(到目前为止是
+Device Tree和ACPI GSI),并且可以很容易地扩展以支持其它IRQ拓扑数据源。
+
+irq_domain的用法
+================
+
+中断控制器驱动程序通过以下方式创建并注册一个irq_domain。调用
+irq_domain_add_*() 或 irq_domain_create_*()函数之一(每个映射方法都有不
+同的分配器函数,后面会详细介绍)。 函数成功后会返回一个指向irq_domain的指针。
+调用者必须向分配器函数提供一个irq_domain_ops结构体。
+
+在大多数情况下,irq_domain在开始时是空的,没有任何hwirq和IRQ号之间的映射。
+通过调用irq_create_mapping()将映射添加到irq_domain中,该函数接受
+irq_domain和一个hwirq号作为参数。 如果hwirq的映射还不存在,那么它将分配
+一个新的Linux irq_desc,将其与hwirq关联起来,并调用.map()回调,这样驱动
+程序就可以执行任何必要的硬件设置。
+
+一旦建立了映射,可以通过多种方法检索或使用它:
+
+- irq_resolve_mapping()返回一个指向给定域和hwirq号的irq_desc结构指针,
+ 如果没有映射则返回NULL。
+
+- irq_find_mapping()返回给定域和hwirq的Linux IRQ号,如果没有映射则返回0。
+
+- irq_linear_revmap()现与irq_find_mapping()相同,已被废弃。
+
+- generic_handle_domain_irq()处理一个由域和hwirq号描述的中断。
+
+请注意,irq域的查找必须发生在与RCU读临界区兼容的上下文中。
+
+在调用irq_find_mapping()之前,至少要调用一次irq_create_mapping()函数,
+以免描述符不能被分配。
+
+如果驱动程序有Linux的IRQ号或irq_data指针,并且需要知道相关的hwirq号(比
+如在irq_chip回调中),那么可以直接从irq_data->hwirq中获得。
+
+irq_domain映射的类型
+====================
+
+从hwirq到Linux irq的反向映射有几种机制,每种机制使用不同的分配函数。应该
+使用哪种反向映射类型取决于用例。 下面介绍每一种反向映射类型:
+
+线性映射
+--------
+
+::
+
+ irq_domain_add_linear()
+ irq_domain_create_linear()
+
+线性反向映射维护了一个固定大小的表,该表以hwirq号为索引。 当一个hwirq被映射
+时,会给hwirq分配一个irq_desc,并将irq号存储在表中。
+
+当最大的hwirq号固定且数量相对较少时,线性图是一个很好的选择(~<256)。 这种
+映射的优点是固定时间查找IRQ号,而且irq_descs只分配给在用的IRQ。 缺点是该表
+必须尽可能大的hwirq号。
+
+irq_domain_add_linear()和irq_domain_create_linear()在功能上是等价的,
+除了第一个参数不同--前者接受一个Open Firmware特定的 'struct device_node' 而
+后者接受一个更通用的抽象 'struct fwnode_handle' 。
+
+大多数驱动应该使用线性映射
+
+树状映射
+--------
+
+::
+
+ irq_domain_add_tree()
+ irq_domain_create_tree()
+
+irq_domain维护着从hwirq号到Linux IRQ的radix的树状映射。 当一个hwirq被映射时,
+一个irq_desc被分配,hwirq被用作radix树的查找键。
+
+如果hwirq号可以非常大,树状映射是一个很好的选择,因为它不需要分配一个和最大hwirq
+号一样大的表。 缺点是,hwirq到IRQ号的查找取决于表中有多少条目。
+
+irq_domain_add_tree()和irq_domain_create_tree()在功能上是等价的,除了第一
+个参数不同——前者接受一个Open Firmware特定的 'struct device_node' ,而后者接受
+一个更通用的抽象 'struct fwnode_handle' 。
+
+很少有驱动应该需要这个映射。
+
+无映射
+------
+
+::
+
+ irq_domain_add_nomap()
+
+当硬件中的hwirq号是可编程的时候,就可以采用无映射类型。 在这种情况下,最好将
+Linux IRQ号编入硬件本身,这样就不需要映射了。 调用irq_create_direct_mapping()
+会分配一个Linux IRQ号,并调用.map()回调,这样驱动就可以将Linux IRQ号编入硬件中。
+
+大多数驱动程序无法使用此映射,现在它由CONFIG_IRQ_DOMAIN_NOMAP选项控制。
+请不要引入此API的新用户。
+
+传统映射类型
+------------
+
+::
+
+ irq_domain_add_simple()
+ irq_domain_add_legacy()
+ irq_domain_create_simple()
+ irq_domain_create_legacy()
+
+传统映射是已经为 hwirqs 分配了一系列 irq_descs 的驱动程序的特殊情况。 当驱动程
+序不能立即转换为使用线性映射时,就会使用它。 例如,许多嵌入式系统板卡支持文件使用
+一组用于IRQ号的定义(#define),这些定义被传递给struct设备注册。 在这种情况下,
+不能动态分配Linux IRQ号,应该使用传统映射。
+
+顾名思义,\*_legacy()系列函数已被废弃,只是为了方便对古老平台的支持而存在。
+不应该增加新的用户。当\*_simple()系列函数的使用导致遗留行为时,他们也是如此。
+
+传统映射假设已经为控制器分配了一个连续的IRQ号范围,并且可以通过向hwirq号添加一
+个固定的偏移来计算IRQ号,反之亦然。 缺点是需要中断控制器管理IRQ分配,并且需要为每
+个hwirq分配一个irq_desc,即使它没有被使用。
+
+只有在必须支持固定的IRQ映射时,才应使用传统映射。 例如,ISA控制器将使用传统映射来
+映射Linux IRQ 0-15,这样现有的ISA驱动程序就能得到正确的IRQ号。
+
+大多数使用传统映射的用户应该使用irq_domain_add_simple()或
+irq_domain_create_simple(),只有在系统提供IRQ范围时才会使用传统域,否则将使用
+线性域映射。这个调用的语义是这样的:如果指定了一个IRQ范围,那么 描述符将被即时分配
+给它,如果没有范围被分配,它将不会执行 irq_domain_add_linear() 或
+irq_domain_create_linear(),这意味着 *no* irq 描述符将被分配。
+
+一个简单域的典型用例是,irqchip供应商同时支持动态和静态IRQ分配。
+
+为了避免最终出现使用线性域而没有描述符被分配的情况,确保使用简单域的驱动程序在任何
+irq_find_mapping()之前调用irq_create_mapping()是非常重要的,因为后者实际上
+将用于静态IRQ分配情况。
+
+irq_domain_add_simple()和irq_domain_create_simple()以及
+irq_domain_add_legacy()和irq_domain_create_legacy()在功能上是等价的,只
+是第一个参数不同--前者接受Open Firmware特定的 'struct device_node' ,而后者
+接受一个更通用的抽象 'struct fwnode_handle' 。
+
+IRQ域层级结构
+-------------
+
+在某些架构上,可能有多个中断控制器参与将一个中断从设备传送到目标CPU。
+让我们来看看x86平台上典型的中断传递路径吧
+::
+
+ Device --> IOAPIC -> Interrupt remapping Controller -> Local APIC -> CPU
+
+涉及到的中断控制器有三个:
+
+1) IOAPIC 控制器
+2) 中断重映射控制器
+3) Local APIC 控制器
+
+为了支持这样的硬件拓扑结构,使软件架构与硬件架构相匹配,为每个中断控制器建立一
+个irq_domain数据结构,并将这些irq_domain组织成层次结构。
+
+在建立irq_domain层次结构时,靠近设备的irq_domain为子域,靠近CPU的
+irq_domain为父域。所以在上面的例子中,将建立如下的层次结构。
+::
+
+ CPU Vector irq_domain (root irq_domain to manage CPU vectors)
+ ^
+ |
+ Interrupt Remapping irq_domain (manage irq_remapping entries)
+ ^
+ |
+ IOAPIC irq_domain (manage IOAPIC delivery entries/pins)
+
+使用irq_domain层次结构的主要接口有四个:
+
+1) irq_domain_alloc_irqs(): 分配IRQ描述符和与中断控制器相关的资源来传递这些中断。
+2) irq_domain_free_irqs(): 释放IRQ描述符和与这些中断相关的中断控制器资源。
+3) irq_domain_activate_irq(): 激活中断控制器硬件以传递中断。
+4) irq_domain_deactivate_irq(): 停用中断控制器硬件,停止传递中断。
+
+为了支持irq_domain层次结构,需要做如下修改:
+
+1) 一个新的字段 'parent' 被添加到irq_domain结构中;它用于维护irq_domain的层次信息。
+2) 一个新的字段 'parent_data' 被添加到irq_data结构中;它用于建立层次结构irq_data以
+ 匹配irq_domain层次结构。irq_data用于存储irq_domain指针和硬件irq号。
+3) 新的回调被添加到irq_domain_ops结构中,以支持层次结构的irq_domain操作。
+
+在支持分层irq_domain和分层irq_data准备就绪后,为每个中断控制器建立一个irq_domain结
+构,并为每个与IRQ相关联的irq_domain分配一个irq_data结构。现在我们可以再进一步支持堆
+栈式(层次结构)的irq_chip。也就是说,一个irq_chip与层次结构中的每个irq_data相关联。
+一个子irq_chip可以自己或通过与它的父irq_chip合作来实现一个所需的操作。
+
+通过堆栈式的irq_chip,中断控制器驱动只需要处理自己管理的硬件,在需要的时候可以向其父
+irq_chip请求服务。所以我们可以实现更简洁的软件架构。
+
+为了让中断控制器驱动程序支持irq_domain层次结构,它需要做到以下几点:
+
+1) 实现 irq_domain_ops.alloc 和 irq_domain_ops.free
+2) 可选择地实现 irq_domain_ops.activate 和 irq_domain_ops.deactivate.
+3) 可选择地实现一个irq_chip来管理中断控制器硬件。
+4) 不需要实现irq_domain_ops.map和irq_domain_ops.unmap,它们在层次结构
+ irq_domain中是不用的。
+
+irq_domain层次结构绝不是x86特有的,大量用于支持其他架构,如ARM、ARM64等。
+
+调试功能
+========
+
+打开CONFIG_GENERIC_IRQ_DEBUGFS,可让IRQ子系统的大部分内部结构都在debugfs中暴露出来。
diff --git a/Documentation/translations/zh_CN/core-api/irq/irqflags-tracing.rst b/Documentation/translations/zh_CN/core-api/irq/irqflags-tracing.rst
new file mode 100644
index 000000000000..9af50b4b8c2d
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/irq/irqflags-tracing.rst
@@ -0,0 +1,47 @@
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/irq/irqflags-tracing.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_irqflags-tracing.rst:
+
+=================
+IRQ-flags状态追踪
+=================
+
+:Author: 最初由Ingo Molnar <mingo@redhat.com>开始撰写
+
+“irq-flags tracing”(中断标志追踪)功能可以 “追踪” hardirq和softirq的状态,它让
+感兴趣的子系统有机会了解到到内核中发生的每一个
+hardirqs-off/hardirqs-on、softirqs-off/softirqs-on事件。
+
+CONFIG_TRACE_IRQFLAGS_SUPPORT是通用锁调试代码提供的CONFIG_PROVE_SPIN_LOCKING
+和CONFIG_PROVE_RW_LOCKING所需要的。否则将只有CONFIG_PROVE_MUTEX_LOCKING和
+CONFIG_PROVE_RWSEM_LOCKING在一个架构上被提供--这些都是不在IRQ上下文中使用的
+锁API。(rwsems的一个异常是可以解决的)
+
+架构对这一点的支持当然不属于“微不足道”的范畴,因为很多低级的汇编代码都要处理irq-flags
+的状态变化。但是一个架构可以以一种相当直接且无风险的方式启用irq-flags-tracing。
+
+架构如果想支持这个,需要先做一些代码组织上的改变:
+
+- 在他们的arch级Kconfig文件中添加并启用TRACE_IRQFLAGS_SUPPORT。
+
+然后还需要做一些功能上的改变来实现对irq-flags-tracing的支持:
+
+- 在低级入口代码中增加(构建条件)对trace_hardirqs_off()/trace_hardirqs_on()
+ 函数的调用。锁验证器会密切关注 “real”的irq-flags是否与 “virtual”的irq-flags
+ 状态相匹配,如果两者不匹配,则会发出警告(并关闭自己)。通常维护arch中
+ irq-flags-track的大部分时间都是在这种状态下度过的:看看lockdep的警告,试着
+ 找出我们还没有搞定的汇编代码。修复并重复。一旦系统启动,并且在irq-flags跟踪功
+ 能中没有出现lockdep警告的情况下,arch支持就完成了。
+
+- 如果该架构有不可屏蔽的中断,那么需要通过lockdep_off()/lockdep_on()将这些中
+ 断从irq跟踪[和锁验证]机制中排除。
+
+ 一般来说,在一个架构中,不完整的irq-flags-tracing实现是没有风险的:lockdep
+ 会检测到这一点,并将自己关闭。即锁验证器仍然可靠。应该不会因为irq-tracing的错
+ 误而崩溃。(除非通过修改不该修改的条件来更改汇编或寄存器而破坏其他代码)
diff --git a/Documentation/translations/zh_CN/core-api/kernel-api.rst b/Documentation/translations/zh_CN/core-api/kernel-api.rst
new file mode 100644
index 000000000000..a1ea7081077c
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/kernel-api.rst
@@ -0,0 +1,378 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/kernel-api.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
+
+.. _cn_kernel-api.rst:
+
+============
+Linux内核API
+============
+
+
+列表管理函数
+============
+
+该API在以下内核代码中:
+
+include/linux/list.h
+
+基本的C库函数
+=============
+
+在编写驱动程序时,一般不能使用C库中的例程。部分函数通常很有用,它们在
+下面被列出。这些函数的行为可能会与ANSI定义的略有不同,这些偏差会在文中
+注明。
+
+字符串转换
+----------
+
+该API在以下内核代码中:
+
+lib/vsprintf.c
+
+include/linux/kernel.h
+
+include/linux/kernel.h
+
+lib/kstrtox.c
+
+lib/string_helpers.c
+
+字符串处理
+----------
+
+该API在以下内核代码中:
+
+include/linux/fortify-string.h
+
+lib/string.c
+
+include/linux/string.h
+
+mm/util.c
+
+基本的内核库函数
+================
+
+Linux内核提供了很多实用的基本函数。
+
+位运算
+------
+
+该API在以下内核代码中:
+
+include/asm-generic/bitops/instrumented-atomic.h
+
+include/asm-generic/bitops/instrumented-non-atomic.h
+
+include/asm-generic/bitops/instrumented-lock.h
+
+位图运算
+--------
+
+该API在以下内核代码中:
+
+lib/bitmap.c
+
+include/linux/bitmap.h
+
+include/linux/bitmap.h
+
+include/linux/bitmap.h
+
+lib/bitmap.c
+
+lib/bitmap.c
+
+include/linux/bitmap.h
+
+命令行解析
+----------
+
+该API在以下内核代码中:
+
+lib/cmdline.c
+
+排序
+----
+
+该API在以下内核代码中:
+
+lib/sort.c
+
+lib/list_sort.c
+
+文本检索
+--------
+
+该API在以下内核代码中:
+
+lib/textsearch.c
+
+lib/textsearch.c
+
+include/linux/textsearch.h
+
+Linux中的CRC和数学函数
+======================
+
+算术溢出检查
+------------
+
+该API在以下内核代码中:
+
+include/linux/overflow.h
+
+CRC函数
+-------
+
+*译注:CRC,Cyclic Redundancy Check,循环冗余校验*
+
+该API在以下内核代码中:
+
+lib/crc4.c
+
+lib/crc7.c
+
+lib/crc8.c
+
+lib/crc16.c
+
+lib/crc32.c
+
+lib/crc-ccitt.c
+
+lib/crc-itu-t.c
+
+基数为2的对数和幂函数
+---------------------
+
+该API在以下内核代码中:
+
+include/linux/log2.h
+
+整数幂函数
+----------
+
+该API在以下内核代码中:
+
+lib/math/int_pow.c
+
+lib/math/int_sqrt.c
+
+除法函数
+--------
+
+该API在以下内核代码中:
+
+include/asm-generic/div64.h
+
+include/linux/math64.h
+
+lib/math/gcd.c
+
+UUID/GUID
+---------
+
+该API在以下内核代码中:
+
+lib/uuid.c
+
+内核IPC设备
+===========
+
+IPC实用程序
+-----------
+
+该API在以下内核代码中:
+
+ipc/util.c
+
+FIFO 缓冲区
+===========
+
+kfifo接口
+---------
+
+该API在以下内核代码中:
+
+include/linux/kfifo.h
+
+转发接口支持
+============
+
+转发接口支持旨在为工具和设备提供一种有效的机制,将大量数据从内核空间
+转发到用户空间。
+
+转发接口
+--------
+
+该API在以下内核代码中:
+
+kernel/relay.c
+
+kernel/relay.c
+
+模块支持
+========
+
+模块加载
+--------
+
+该API在以下内核代码中:
+
+kernel/module/kmod.c
+
+模块接口支持
+------------
+
+更多信息请参阅kernel/module/目录下的文件。
+
+硬件接口
+========
+
+
+该API在以下内核代码中:
+
+kernel/dma.c
+
+资源管理
+--------
+
+该API在以下内核代码中:
+
+kernel/resource.c
+
+kernel/resource.c
+
+MTRR处理
+--------
+
+该API在以下内核代码中:
+
+arch/x86/kernel/cpu/mtrr/mtrr.c
+
+安全框架
+========
+
+该API在以下内核代码中:
+
+security/security.c
+
+security/inode.c
+
+审计接口
+========
+
+该API在以下内核代码中:
+
+kernel/audit.c
+
+kernel/auditsc.c
+
+kernel/auditfilter.c
+
+核算框架
+========
+
+该API在以下内核代码中:
+
+kernel/acct.c
+
+块设备
+======
+
+该API在以下内核代码中:
+
+include/linux/bio.h
+
+block/blk-core.c
+
+block/blk-core.c
+
+block/blk-map.c
+
+block/blk-sysfs.c
+
+block/blk-settings.c
+
+block/blk-flush.c
+
+block/blk-lib.c
+
+block/blk-integrity.c
+
+kernel/trace/blktrace.c
+
+block/genhd.c
+
+block/genhd.c
+
+字符设备
+========
+
+该API在以下内核代码中:
+
+fs/char_dev.c
+
+时钟框架
+========
+
+时钟框架定义了编程接口,以支持系统时钟树的软件管理。该框架广泛用于系统级芯片(SOC)平
+台,以支持电源管理和各种可能需要自定义时钟速率的设备。请注意,这些 “时钟”与计时或实
+时时钟(RTC)无关,它们都有单独的框架。这些:c:type: `struct clk <clk>` 实例可用于管理
+各种时钟信号,例如一个96理例如96MHz的时钟信号,该信号可被用于总线或外设的数据交换,或以
+其他方式触发系统硬件中的同步状态机转换。
+
+通过明确的软件时钟门控来支持电源管理:未使用的时钟被禁用,因此系统不会因为改变不在使用
+中的晶体管的状态而浪费电源。在某些系统中,这可能是由硬件时钟门控支持的,其中时钟被门控
+而不在软件中被禁用。芯片的部分,在供电但没有时钟的情况下,可能会保留其最后的状态。这种
+低功耗状态通常被称为*保留模式*。这种模式仍然会产生漏电流,特别是在电路几何结构较细的情
+况下,但对于CMOS电路来说,电能主要是随着时钟翻转而被消耗的。
+
+电源感知驱动程序只有在其管理的设备处于活动使用状态时才会启用时钟。此外,系统睡眠状态通
+常根据哪些时钟域处于活动状态而有所不同:“待机”状态可能允许从多个活动域中唤醒,而
+"mem"(暂停到RAM)状态可能需要更全面地关闭来自高速PLL和振荡器的时钟,从而限制了可能
+的唤醒事件源的数量。驱动器的暂停方法可能需要注意目标睡眠状态的系统特定时钟约束。
+
+一些平台支持可编程时钟发生器。这些可以被各种外部芯片使用,如其他CPU、多媒体编解码器以
+及对接口时钟有严格要求的设备。
+
+该API在以下内核代码中:
+
+include/linux/clk.h
+
+同步原语
+========
+
+读-复制-更新(RCU)
+-------------------
+
+该API在以下内核代码中:
+
+include/linux/rcupdate.h
+
+kernel/rcu/tree.c
+
+kernel/rcu/tree_exp.h
+
+kernel/rcu/update.c
+
+include/linux/srcu.h
+
+kernel/rcu/srcutree.c
+
+include/linux/rculist_bl.h
+
+include/linux/rculist.h
+
+include/linux/rculist_nulls.h
+
+include/linux/rcu_sync.h
+
+kernel/rcu/sync.c
diff --git a/Documentation/translations/zh_CN/core-api/kobject.rst b/Documentation/translations/zh_CN/core-api/kobject.rst
new file mode 100644
index 000000000000..0747b472fdea
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/kobject.rst
@@ -0,0 +1,379 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/kobject.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_core_api_kobject.rst:
+
+=======================================================
+关于kobjects、ksets和ktypes的一切你没想过需要了解的东西
+=======================================================
+
+:作者: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+:最后一次更新: December 19, 2007
+
+根据Jon Corbet于2003年10月1日为lwn.net撰写的原创文章改编,网址是:
+https://lwn.net/Articles/51437/
+
+理解驱动模型和建立在其上的kobject抽象的部分的困难在于,没有明显的切入点。
+处理kobjects需要理解一些不同的类型,所有这些类型都会相互引用。为了使事情
+变得更简单,我们将多路并进,从模糊的术语开始,并逐渐增加细节。那么,先来
+了解一些我们将要使用的术语的简明定义吧。
+
+ - 一个kobject是一个kobject结构体类型的对象。Kobjects有一个名字和一个
+ 引用计数。一个kobject也有一个父指针(允许对象被排列成层次结构),一个
+ 特定的类型,并且,通常在sysfs虚拟文件系统中表示。
+
+ Kobjects本身通常并不引人关注;相反它们常常被嵌入到其他包含真正引人注目
+ 的代码的结构体中。
+
+ 任何结构体都 **不应该** 有一个以上的kobject嵌入其中。如果有的话,对象的引用计
+ 数肯定会被打乱,而且不正确,你的代码就会出现错误。所以不要这样做。
+
+ - ktype是嵌入一个kobject的对象的类型。每个嵌入kobject的结构体都需要一个
+ 相应的ktype。ktype控制着kobject在被创建和销毁时的行为。
+
+ - 一个kset是一组kobjects。这些kobjects可以是相同的ktype或者属于不同的
+ ktype。kset是kobjects集合的基本容器类型。Ksets包含它们自己的kobjects,
+ 但你可以安全地忽略这个实现细节,因为kset的核心代码会自动处理这个kobject。
+
+ 当你看到一个下面全是其他目录的sysfs目录时,通常这些目录中的每一个都对应
+ 于同一个kset中的一个kobject。
+
+ 我们将研究如何创建和操作所有这些类型。将采取一种自下而上的方法,所以我们
+ 将回到kobjects。
+
+
+嵌入kobjects
+=============
+
+内核代码很少创建孤立的kobject,只有一个主要的例外,下面会解释。相反,
+kobjects被用来控制对一个更大的、特定领域的对象的访问。为此,kobjects会被
+嵌入到其他结构中。如果你习惯于用面向对象的术语来思考问题,那么kobjects可
+以被看作是一个顶级的抽象类,其他的类都是从它派生出来的。一个kobject实现了
+一系列的功能,这些功能本身并不特别有用,但在其他对象中却很好用。C语言不允
+许直接表达继承,所以必须使用其他技术——比如结构体嵌入。
+
+(对于那些熟悉内核链表实现的人来说,这类似于“list_head”结构本身很少有用,
+但总是被嵌入到感兴趣的更大的对象中)。
+
+例如, ``drivers/uio/uio.c`` 中的IO代码有一个结构体,定义了与uio设备相
+关的内存区域::
+
+ struct uio_map {
+ struct kobject kobj;
+ struct uio_mem *mem;
+ };
+
+如果你有一个uio_map结构体,找到其嵌入的kobject只是一个使用kobj成员的问题。
+然而,与kobjects一起工作的代码往往会遇到相反的问题:给定一个结构体kobject
+的指针,指向包含结构体的指针是什么?你必须避免使用一些技巧(比如假设
+kobject在结构的开头),相反,你得使用container_of()宏,其可以在 ``<linux/kernel.h>``
+中找到::
+
+ container_of(ptr, type, member)
+
+其中:
+
+ * ``ptr`` 是一个指向嵌入kobject的指针,
+ * ``type`` 是包含结构体的类型,
+ * ``member`` 是 ``指针`` 所指向的结构体域的名称。
+
+container_of()的返回值是一个指向相应容器类型的指针。因此,例如,一个嵌入到
+uio_map结构 **中** 的kobject结构体的指针kp可以被转换为一个指向 **包含** uio_map
+结构体的指针,方法是::
+
+ struct uio_map *u_map = container_of(kp, struct uio_map, kobj);
+
+为了方便起见,程序员经常定义一个简单的宏,用于将kobject指针 **反推** 到包含
+类型。在早期的 ``drivers/uio/uio.c`` 中正是如此,你可以在这里看到::
+
+ struct uio_map {
+ struct kobject kobj;
+ struct uio_mem *mem;
+ };
+
+ #define to_map(map) container_of(map, struct uio_map, kobj)
+
+其中宏的参数“map”是一个指向有关的kobject结构体的指针。该宏随后被调用::
+
+ struct uio_map *map = to_map(kobj);
+
+
+kobjects的初始化
+================
+
+当然,创建kobject的代码必须初始化该对象。一些内部字段是通过(强制)调用kobject_init()
+来设置的::
+
+ void kobject_init(struct kobject *kobj, struct kobj_type *ktype);
+
+ktype是正确创建kobject的必要条件,因为每个kobject都必须有一个相关的kobj_type。
+在调用kobject_init()后,为了向sysfs注册kobject,必须调用函数kobject_add()::
+
+ int kobject_add(struct kobject *kobj, struct kobject *parent,
+ const char *fmt, ...);
+
+这将正确设置kobject的父级和kobject的名称。如果该kobject要与一个特定的kset相关
+联,在调用kobject_add()之前必须分配kobj->kset。如果kset与kobject相关联,则
+kobject的父级可以在调用kobject_add()时被设置为NULL,则kobject的父级将是kset
+本身。
+
+由于kobject的名字是在它被添加到内核时设置的,所以kobject的名字不应该被直接操作。
+如果你必须改变kobject的名字,请调用kobject_rename()::
+
+ int kobject_rename(struct kobject *kobj, const char *new_name);
+
+kobject_rename()函数不会执行任何锁定操作,也不会对name进行可靠性检查,所以调用
+者自己检查和串行化操作是明智的选择
+
+有一个叫kobject_set_name()的函数,但那是历史遗产,正在被删除。如果你的代码需
+要调用这个函数,那么它是不正确的,需要被修复。
+
+要正确访问kobject的名称,请使用函数kobject_name()::
+
+ const char *kobject_name(const struct kobject * kobj);
+
+有一个辅助函数可以同时初始化和添加kobject到内核中,令人惊讶的是,该函数被称为
+kobject_init_and_add()::
+
+ int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
+ struct kobject *parent, const char *fmt, ...);
+
+参数与上面描述的单个kobject_init()和kobject_add()函数相同。
+
+
+Uevents
+=======
+
+当一个kobject被注册到kobject核心后,你需要向全世界宣布它已经被创建了。这可以通
+过调用kobject_uevent()来实现::
+
+ int kobject_uevent(struct kobject *kobj, enum kobject_action action);
+
+当kobject第一次被添加到内核时,使用 *KOBJ_ADD* 动作。这应该在该kobject的任
+何属性或子对象被正确初始化后进行,因为当这个调用发生时,用户空间会立即开始寻
+找它们。
+
+当kobject从内核中移除时(关于如何做的细节在下面), **KOBJ_REMOVE** 的uevent
+将由kobject核心自动创建,所以调用者不必担心手动操作。
+
+
+引用计数
+========
+
+kobject的关键功能之一是作为它所嵌入的对象的一个引用计数器。只要对该对象的引用
+存在,该对象(以及支持它的代码)就必须继续存在。用于操作kobject的引用计数的低
+级函数是::
+
+ struct kobject *kobject_get(struct kobject *kobj);
+ void kobject_put(struct kobject *kobj);
+
+对kobject_get()的成功调用将增加kobject的引用计数器值并返回kobject的指针。
+
+当引用被释放时,对kobject_put()的调用将递减引用计数值,并可能释放该对象。请注
+意,kobject_init()将引用计数设置为1,所以设置kobject的代码最终需要kobject_put()
+来释放该引用。
+
+因为kobjects是动态的,所以它们不能以静态方式或在堆栈中声明,而总是以动态方式分
+配。未来版本的内核将包含对静态创建的kobjects的运行时检查,并将警告开发者这种不
+当的使用。
+
+如果你使用struct kobject只是为了给你的结构体提供一个引用计数器,请使用struct kref
+来代替;kobject是多余的。关于如何使用kref结构体的更多信息,请参见Linux内核源代
+码树中的文件Documentation/core-api/kref.rst
+
+
+创建“简单的”kobjects
+====================
+
+有时,开发者想要的只是在sysfs层次结构中创建一个简单的目录,而不必去搞那些复杂
+的ksets、显示和存储函数,以及其他细节。这是一个应该创建单个kobject的例外。要
+创建这样一个条目(即简单的目录),请使用函数::
+
+ struct kobject *kobject_create_and_add(const char *name, struct kobject *parent);
+
+这个函数将创建一个kobject,并将其放在sysfs中指定的父kobject下面的位置。要创
+建与此kobject相关的简单属性,请使用::
+
+ int sysfs_create_file(struct kobject *kobj, const struct attribute *attr);
+
+或者::
+
+ int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp);
+
+这里使用的两种类型的属性,与已经用kobject_create_and_add()创建的kobject,
+都可以是kobj_attribute类型,所以不需要创建特殊的自定义属性。
+
+参见示例模块, ``samples/kobject/kobject-example.c`` ,以了解一个简单的
+kobject和属性的实现。
+
+
+
+ktypes和释放方法
+================
+
+以上讨论中还缺少一件重要的事情,那就是当一个kobject的引用次数达到零的时候
+会发生什么。创建kobject的代码通常不知道何时会发生这种情况;首先,如果它知
+道,那么使用kobject就没有什么意义。当sysfs被引入时,即使是可预测的对象生命
+周期也会变得更加复杂,因为内核的其他部分可以获得在系统中注册的任何kobject
+的引用。
+
+最终的结果是,一个由kobject保护的结构体在其引用计数归零之前不能被释放。引
+用计数不受创建kobject的代码的直接控制。因此,每当它的一个kobjects的最后一
+个引用消失时,必须异步通知该代码。
+
+一旦你通过kobject_add()注册了你的kobject,你绝对不能使用kfree()来直接释
+放它。唯一安全的方法是使用kobject_put()。在kobject_init()之后总是使用
+kobject_put()以避免错误的发生是一个很好的做法。
+
+这个通知是通过kobject的release()方法完成的。通常这样的方法有如下形式::
+
+ void my_object_release(struct kobject *kobj)
+ {
+ struct my_object *mine = container_of(kobj, struct my_object, kobj);
+
+ /* Perform any additional cleanup on this object, then... */
+ kfree(mine);
+ }
+
+有一点很重要:每个kobject都必须有一个release()方法,而且这个kobject必
+须持续存在(处于一致的状态),直到这个方法被调用。如果这些约束条件没有
+得到满足,那么代码就是有缺陷的。注意,如果你忘记提供release()方法,内
+核会警告你。不要试图通过提供一个“空”的释放函数来摆脱这个警告。
+
+如果你的清理函数只需要调用kfree(),那么你必须创建一个包装函数,该函数
+使用container_of()来向上造型到正确的类型(如上面的例子所示),然后在整个
+结构体上调用kfree()。
+
+注意,kobject的名字在release函数中是可用的,但它不能在这个回调中被改
+变。否则,在kobject核心中会出现内存泄漏,这让人很不爽。
+
+有趣的是,release()方法并不存储在kobject本身;相反,它与ktype相关。
+因此,让我们引入结构体kobj_type::
+
+ struct kobj_type {
+ void (*release)(struct kobject *kobj);
+ const struct sysfs_ops *sysfs_ops;
+ const struct attribute_group **default_groups;
+ const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
+ const void *(*namespace)(struct kobject *kobj);
+ void (*get_ownership)(struct kobject *kobj, kuid_t *uid, kgid_t *gid);
+ };
+
+这个结构提用来描述一个特定类型的kobject(或者更正确地说,包含对象的
+类型)。每个kobject都需要有一个相关的kobj_type结构;当你调用
+kobject_init()或kobject_init_and_add()时必须指定一个指向该结构的
+指针。
+
+当然,kobj_type结构中的release字段是指向这种类型的kobject的release()
+方法的一个指针。另外两个字段(sysfs_ops 和 default_groups)控制这种
+类型的对象如何在 sysfs 中被表示;它们超出了本文的范围。
+
+default_groups 指针是一个默认属性的列表,它将为任何用这个 ktype 注册
+的 kobject 自动创建。
+
+
+ksets
+=====
+
+一个kset仅仅是一个希望相互关联的kobjects的集合。没有限制它们必须是相
+同的ktype,但是如果它们不是相同的,就要非常小心。
+
+一个kset有以下功能:
+
+ - 它像是一个包含一组对象的袋子。一个kset可以被内核用来追踪“所有块
+ 设备”或“所有PCI设备驱动”。
+
+ - kset也是sysfs中的一个子目录,与kset相关的kobjects可以在这里显示
+ 出来。每个kset都包含一个kobject,它可以被设置为其他kobject的父对象;
+ sysfs层次结构的顶级目录就是以这种方式构建的。
+
+ - Ksets可以支持kobjects的 "热插拔",并影响uevent事件如何被报告给
+ 用户空间。
+
+ 在面向对象的术语中,“kset”是顶级的容器类;ksets包含它们自己的kobject,
+ 但是这个kobject是由kset代码管理的,不应该被任何其他用户所操纵。
+
+ kset在一个标准的内核链表中保存它的子对象。Kobjects通过其kset字段指向其
+ 包含的kset。在几乎所有的情况下,属于一个kset的kobjects在它们的父
+ 对象中都有那个kset(或者,严格地说,它的嵌入kobject)。
+
+ 由于kset中包含一个kobject,它应该总是被动态地创建,而不是静态地
+ 或在堆栈中声明。要创建一个新的kset,请使用::
+
+ struct kset *kset_create_and_add(const char *name,
+ const struct kset_uevent_ops *uevent_ops,
+ struct kobject *parent_kobj);
+
+当你完成对kset的处理后,调用::
+
+ void kset_unregister(struct kset *k);
+
+来销毁它。这将从sysfs中删除该kset并递减其引用计数值。当引用计数
+为零时,该kset将被释放。因为对该kset的其他引用可能仍然存在,
+释放可能发生在kset_unregister()返回之后。
+
+一个使用kset的例子可以在内核树中的 ``samples/kobject/kset-example.c``
+文件中看到。
+
+如果一个kset希望控制与它相关的kobjects的uevent操作,它可以使用
+结构体kset_uevent_ops来处理它::
+
+ struct kset_uevent_ops {
+ int (* const filter)(struct kobject *kobj);
+ const char *(* const name)(struct kobject *kobj);
+ int (* const uevent)(struct kobject *kobj, struct kobj_uevent_env *env);
+ };
+
+
+过滤器函数允许kset阻止一个特定kobject的uevent被发送到用户空间。
+如果该函数返回0,该uevent将不会被发射出去。
+
+name函数将被调用以覆盖uevent发送到用户空间的kset的默认名称。默
+认情况下,该名称将与kset本身相同,但这个函数,如果存在,可以覆盖
+该名称。
+
+当uevent即将被发送至用户空间时,uevent函数将被调用,以允许更多
+的环境变量被添加到uevent中。
+
+有人可能会问,鉴于没有提出执行该功能的函数,究竟如何将一个kobject
+添加到一个kset中。答案是这个任务是由kobject_add()处理的。当一个
+kobject被传递给kobject_add()时,它的kset成员应该指向这个kobject
+所属的kset。 kobject_add()将处理剩下的部分。
+
+如果属于一个kset的kobject没有父kobject集,它将被添加到kset的目
+录中。并非所有的kset成员都必须住在kset目录中。如果在添加kobject
+之前分配了一个明确的父kobject,那么该kobject将被注册到kset中,
+但是被添加到父kobject下面。
+
+
+移除Kobject
+===========
+
+当一个kobject在kobject核心注册成功后,在代码使用完它时,必须将其
+清理掉。要做到这一点,请调用kobject_put()。通过这样做,kobject核
+心会自动清理这个kobject分配的所有内存。如果为这个对象发送了 ``KOBJ_ADD``
+uevent,那么相应的 ``KOBJ_REMOVE`` uevent也将被发送,任何其他的
+sysfs内务将被正确处理。
+
+如果你需要分两次对kobject进行删除(比如说在你要销毁对象时无权睡眠),
+那么调用kobject_del()将从sysfs中取消kobject的注册。这使得kobject
+“不可见”,但它并没有被清理掉,而且该对象的引用计数仍然是一样的。在稍
+后的时间调用kobject_put()来完成与该kobject相关的内存的清理。
+
+kobject_del()可以用来放弃对父对象的引用,如果循环引用被构建的话。
+在某些情况下,一个父对象引用一个子对象是有效的。循环引用必须通过明
+确调用kobject_del()来打断,这样一个释放函数就会被调用,前一个循环
+中的对象会相互释放。
+
+
+示例代码出处
+============
+
+关于正确使用ksets和kobjects的更完整的例子,请参见示例程序
+``samples/kobject/{kobject-example.c,kset-example.c}`` ,如果
+您选择 ``CONFIG_SAMPLE_KOBJECT`` ,它们将被构建为可加载模块。
diff --git a/Documentation/translations/zh_CN/core-api/kref.rst b/Documentation/translations/zh_CN/core-api/kref.rst
new file mode 100644
index 000000000000..b9902af310c5
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/kref.rst
@@ -0,0 +1,311 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/kref.rst
+
+翻译:
+
+司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+校译:
+
+ <此处请校译员签名(自愿),我将在下一个版本添加>
+
+.. _cn_core_api_kref.rst:
+
+=================================
+为内核对象添加引用计数器(krefs)
+=================================
+
+:作者: Corey Minyard <minyard@acm.org>
+:作者: Thomas Hellstrom <thellstrom@vmware.com>
+
+其中很多内容都是从Greg Kroah-Hartman2004年关于krefs的OLS论文和演讲中摘
+录的,可以在以下网址找到:
+
+ - http://www.kroah.com/linux/talks/ols_2004_kref_paper/Reprint-Kroah-Hartman-OLS2004.pdf
+ - http://www.kroah.com/linux/talks/ols_2004_kref_talk/
+
+简介
+====
+
+krefs允许你为你的对象添加引用计数器。如果你有在多个地方使用和传递的对象,
+而你没有refcounts,你的代码几乎肯定是坏的。如果你想要引用计数,krefs是个
+好办法。
+
+要使用kref,请在你的数据结构中添加一个,如::
+
+ struct my_data
+ {
+ .
+ .
+ struct kref refcount;
+ .
+ .
+ };
+
+kref可以出现在数据结构体中的任何地方。
+
+初始化
+======
+
+你必须在分配kref之后初始化它。 要做到这一点,可以这样调用kref_init::
+
+ struct my_data *data;
+
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ kref_init(&data->refcount);
+
+这将kref中的refcount设置为1。
+
+Kref规则
+========
+
+一旦你有一个初始化的kref,你必须遵循以下规则:
+
+1) 如果你对一个指针做了一个非临时性的拷贝,特别是如果它可以被传递给另一个执
+ 行线程,你必须在传递之前用kref_get()增加refcount::
+
+ kref_get(&data->refcount);
+
+ 如果你已经有了一个指向kref-ed结构体的有效指针(refcount不能为零),你
+ 可以在没有锁的情况下这样做。
+
+2) 当你完成对一个指针的处理时,你必须调用kref_put()::
+
+ kref_put(&data->refcount, data_release);
+
+ 如果这是对该指针的最后一次引用,释放程序将被调用。如果代码从来没有尝试过
+ 在没有已经持有有效指针的情况下获得一个kref-ed结构体的有效指针,那么在没
+ 有锁的情况下这样做是安全的。
+
+3) 如果代码试图获得对一个kref-ed结构体的引用,而不持有一个有效的指针,它必
+ 须按顺序访问,在kref_put()期间不能发生kref_get(),并且该结构体在kref_get()
+ 期间必须保持有效。
+
+例如,如果你分配了一些数据,然后将其传递给另一个线程来处理::
+
+ void data_release(struct kref *ref)
+ {
+ struct my_data *data = container_of(ref, struct my_data, refcount);
+ kfree(data);
+ }
+
+ void more_data_handling(void *cb_data)
+ {
+ struct my_data *data = cb_data;
+ .
+ . do stuff with data here
+ .
+ kref_put(&data->refcount, data_release);
+ }
+
+ int my_data_handler(void)
+ {
+ int rv = 0;
+ struct my_data *data;
+ struct task_struct *task;
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ kref_init(&data->refcount);
+
+ kref_get(&data->refcount);
+ task = kthread_run(more_data_handling, data, "more_data_handling");
+ if (task == ERR_PTR(-ENOMEM)) {
+ rv = -ENOMEM;
+ kref_put(&data->refcount, data_release);
+ goto out;
+ }
+
+ .
+ . do stuff with data here
+ .
+ out:
+ kref_put(&data->refcount, data_release);
+ return rv;
+ }
+
+这样,两个线程处理数据的顺序并不重要,kref_put()处理知道数据不再被引用并释
+放它。kref_get()不需要锁,因为我们已经有了一个有效的指针,我们拥有一个
+refcount。put不需要锁,因为没有任何东西试图在没有持有指针的情况下获取数据。
+
+在上面的例子中,kref_put()在成功和错误路径中都会被调用2次。这是必要的,因
+为引用计数被kref_init()和kref_get()递增了2次。
+
+请注意,规则1中的 "before "是非常重要的。你不应该做类似于::
+
+ task = kthread_run(more_data_handling, data, "more_data_handling");
+ if (task == ERR_PTR(-ENOMEM)) {
+ rv = -ENOMEM;
+ goto out;
+ } else
+ /* BAD BAD BAD - 在交接后得到 */
+ kref_get(&data->refcount);
+
+不要以为你知道自己在做什么而使用上述构造。首先,你可能不知道自己在做什么。
+其次,你可能知道自己在做什么(有些情况下涉及到锁,上述做法可能是合法的),
+但其他不知道自己在做什么的人可能会改变代码或复制代码。这是很危险的作风。请
+不要这样做。
+
+在有些情况下,你可以优化get和put。例如,如果你已经完成了一个对象,并且给其
+他对象排队,或者把它传递给其他对象,那么就没有理由先做一个get,然后再做一个
+put::
+
+ /* 糟糕的额外获取(get)和输出(put) */
+ kref_get(&obj->ref);
+ enqueue(obj);
+ kref_put(&obj->ref, obj_cleanup);
+
+只要做enqueue就可以了。 我们随时欢迎对这个问题的评论::
+
+ enqueue(obj);
+ /* 我们已经完成了对obj的处理,所以我们把我们的refcount传给了队列。
+ 在这之后不要再碰obj了! */
+
+最后一条规则(规则3)是最难处理的一条。例如,你有一个每个项目都被krefed的列表,
+而你希望得到第一个项目。你不能只是从列表中抽出第一个项目,然后kref_get()它。
+这违反了规则3,因为你还没有持有一个有效的指针。你必须添加一个mutex(或其他锁)。
+比如说::
+
+ static DEFINE_MUTEX(mutex);
+ static LIST_HEAD(q);
+ struct my_data
+ {
+ struct kref refcount;
+ struct list_head link;
+ };
+
+ static struct my_data *get_entry()
+ {
+ struct my_data *entry = NULL;
+ mutex_lock(&mutex);
+ if (!list_empty(&q)) {
+ entry = container_of(q.next, struct my_data, link);
+ kref_get(&entry->refcount);
+ }
+ mutex_unlock(&mutex);
+ return entry;
+ }
+
+ static void release_entry(struct kref *ref)
+ {
+ struct my_data *entry = container_of(ref, struct my_data, refcount);
+
+ list_del(&entry->link);
+ kfree(entry);
+ }
+
+ static void put_entry(struct my_data *entry)
+ {
+ mutex_lock(&mutex);
+ kref_put(&entry->refcount, release_entry);
+ mutex_unlock(&mutex);
+ }
+
+如果你不想在整个释放操作过程中持有锁,kref_put()的返回值是有用的。假设你不想在
+上面的例子中在持有锁的情况下调用kfree()(因为这样做有点无意义)。你可以使用kref_put(),
+如下所示::
+
+ static void release_entry(struct kref *ref)
+ {
+ /* 所有的工作都是在从kref_put()返回后完成的。*/
+ }
+
+ static void put_entry(struct my_data *entry)
+ {
+ mutex_lock(&mutex);
+ if (kref_put(&entry->refcount, release_entry)) {
+ list_del(&entry->link);
+ mutex_unlock(&mutex);
+ kfree(entry);
+ } else
+ mutex_unlock(&mutex);
+ }
+
+如果你必须调用其他程序作为释放操作的一部分,而这些程序可能需要很长的时间,或者可
+能要求相同的锁,那么这真的更有用。请注意,在释放例程中做所有的事情还是比较好的,
+因为它比较整洁。
+
+上面的例子也可以用kref_get_unless_zero()来优化,方法如下::
+
+ static struct my_data *get_entry()
+ {
+ struct my_data *entry = NULL;
+ mutex_lock(&mutex);
+ if (!list_empty(&q)) {
+ entry = container_of(q.next, struct my_data, link);
+ if (!kref_get_unless_zero(&entry->refcount))
+ entry = NULL;
+ }
+ mutex_unlock(&mutex);
+ return entry;
+ }
+
+ static void release_entry(struct kref *ref)
+ {
+ struct my_data *entry = container_of(ref, struct my_data, refcount);
+
+ mutex_lock(&mutex);
+ list_del(&entry->link);
+ mutex_unlock(&mutex);
+ kfree(entry);
+ }
+
+ static void put_entry(struct my_data *entry)
+ {
+ kref_put(&entry->refcount, release_entry);
+ }
+
+这对于在put_entry()中移除kref_put()周围的mutex锁是很有用的,但是重要的是
+kref_get_unless_zero被封装在查找表中的同一关键部分,否则kref_get_unless_zero
+可能引用已经释放的内存。注意,在不检查其返回值的情况下使用kref_get_unless_zero
+是非法的。如果你确信(已经有了一个有效的指针)kref_get_unless_zero()会返回true,
+那么就用kref_get()代替。
+
+Krefs和RCU
+==========
+
+函数kref_get_unless_zero也使得在上述例子中使用rcu锁进行查找成为可能::
+
+ struct my_data
+ {
+ struct rcu_head rhead;
+ .
+ struct kref refcount;
+ .
+ .
+ };
+
+ static struct my_data *get_entry_rcu()
+ {
+ struct my_data *entry = NULL;
+ rcu_read_lock();
+ if (!list_empty(&q)) {
+ entry = container_of(q.next, struct my_data, link);
+ if (!kref_get_unless_zero(&entry->refcount))
+ entry = NULL;
+ }
+ rcu_read_unlock();
+ return entry;
+ }
+
+ static void release_entry_rcu(struct kref *ref)
+ {
+ struct my_data *entry = container_of(ref, struct my_data, refcount);
+
+ mutex_lock(&mutex);
+ list_del_rcu(&entry->link);
+ mutex_unlock(&mutex);
+ kfree_rcu(entry, rhead);
+ }
+
+ static void put_entry(struct my_data *entry)
+ {
+ kref_put(&entry->refcount, release_entry_rcu);
+ }
+
+但要注意的是,在调用release_entry_rcu后,结构kref成员需要在有效内存中保留一个rcu
+宽限期。这可以通过使用上面的kfree_rcu(entry, rhead)来实现,或者在使用kfree之前
+调用synchronize_rcu(),但注意synchronize_rcu()可能会睡眠相当长的时间。
diff --git a/Documentation/translations/zh_CN/core-api/local_ops.rst b/Documentation/translations/zh_CN/core-api/local_ops.rst
new file mode 100644
index 000000000000..eb5423f60f17
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/local_ops.rst
@@ -0,0 +1,196 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/local_ops.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_local_ops:
+
+========================
+本地原子操作的语义和行为
+========================
+
+:作者: Mathieu Desnoyers
+
+
+本文解释了本地原子操作的目的,如何为任何给定的架构实现这些操作,并说明了
+如何正确使用这些操作。它还强调了在内存写入顺序很重要的情况下,跨CPU读取
+这些本地变量时必须采取的预防措施。
+
+.. note::
+
+ 注意,基于 ``local_t`` 的操作不建议用于一般内核操作。请使用 ``this_cpu``
+ 操作来代替使用,除非真的有特殊目的。大多数内核中使用的 ``local_t`` 已
+ 经被 ``this_cpu`` 操作所取代。 ``this_cpu`` 操作在一条指令中结合了重
+ 定位和类似 ``local_t`` 的语义,产生了更紧凑和更快的执行代码。
+
+
+本地原子操作的目的
+==================
+
+本地原子操作的目的是提供快速和高度可重入的每CPU计数器。它们通过移除LOCK前
+缀和通常需要在CPU间同步的内存屏障,将标准原子操作的性能成本降到最低。
+
+在许多情况下,拥有快速的每CPU原子计数器是很有吸引力的:它不需要禁用中断来保护中
+断处理程序,它允许在NMI(Non Maskable Interrupt)处理程序中使用连贯的计数器。
+它对追踪目的和各种性能监测计数器特别有用。
+
+本地原子操作只保证在拥有数据的CPU上的变量修改的原子性。因此,必须注意确保只
+有一个CPU写到 ``local_t`` 的数据。这是通过使用每CPU的数据来实现的,并确
+保我们在一个抢占式安全上下文中修改它。然而,从任何一个CPU读取 ``local_t``
+数据都是允许的:这样它就会显得与所有者CPU的其他内存写入顺序不一致。
+
+
+针对特定架构的实现
+==================
+
+这可以通过稍微修改标准的原子操作来实现:只有它们的UP变体必须被保留。这通常
+意味着删除LOCK前缀(在i386和x86_64上)和任何SMP同步屏障。如果架构在SMP和
+UP之间没有不同的行为,在你的架构的 ``local.h`` 中包括 ``asm-generic/local.h``
+就足够了。
+
+通过在一个结构体中嵌入一个 ``atomic_long_t`` , ``local_t`` 类型被定义为
+一个不透明的 ``signed long`` 。这样做的目的是为了使从这个类型到
+``long`` 的转换失败。该定义看起来像::
+
+ typedef struct { atomic_long_t a; } local_t;
+
+
+使用本地原子操作时应遵循的规则
+==============================
+
+* 被本地操作触及的变量必须是每cpu的变量。
+
+* *只有* 这些变量的CPU所有者才可以写入这些变量。
+
+* 这个CPU可以从任何上下文(进程、中断、软中断、nmi...)中使用本地操作来更新
+ 它的local_t变量。
+
+* 当在进程上下文中使用本地操作时,必须禁用抢占(或中断),以确保进程在获得每
+ CPU变量和进行实际的本地操作之间不会被迁移到不同的CPU。
+
+* 当在中断上下文中使用本地操作时,在主线内核上不需要特别注意,因为它们将在局
+ 部CPU上运行,并且已经禁用了抢占。然而,我建议无论如何都要明确地禁用抢占,
+ 以确保它在-rt内核上仍能正确工作。
+
+* 读取本地cpu变量将提供该变量的当前拷贝。
+
+* 对这些变量的读取可以从任何CPU进行,因为对 “ ``long`` ”,对齐的变量的更新
+ 总是原子的。由于写入程序的CPU没有进行内存同步,所以在读取 *其他* cpu的变
+ 量时,可以读取该变量的过期副本。
+
+
+如何使用本地原子操作
+====================
+
+::
+
+ #include <linux/percpu.h>
+ #include <asm/local.h>
+
+ static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0);
+
+
+计数器
+======
+
+计数是在一个signed long的所有位上进行的。
+
+在可抢占的上下文中,围绕本地原子操作使用 ``get_cpu_var()`` 和
+``put_cpu_var()`` :它确保在对每个cpu变量进行写访问时,抢占被禁用。比如
+说::
+
+ local_inc(&get_cpu_var(counters));
+ put_cpu_var(counters);
+
+如果你已经在一个抢占安全上下文中,你可以使用 ``this_cpu_ptr()`` 代替::
+
+ local_inc(this_cpu_ptr(&counters));
+
+
+
+读取计数器
+==========
+
+那些本地计数器可以从外部的CPU中读取,以求得计数的总和。请注意,local_read
+所看到的跨CPU的数据必须被认为是相对于拥有该数据的CPU上发生的其他内存写入来
+说不符合顺序的::
+
+ long sum = 0;
+ for_each_online_cpu(cpu)
+ sum += local_read(&per_cpu(counters, cpu));
+
+如果你想使用远程local_read来同步CPU之间对资源的访问,必须在写入者和读取者
+的CPU上分别使用显式的 ``smp_wmb()`` 和 ``smp_rmb()`` 内存屏障。如果你使
+用 ``local_t`` 变量作为写在缓冲区中的字节的计数器,就会出现这种情况:在缓
+冲区写和计数器增量之间应该有一个 ``smp_wmb()`` ,在计数器读和缓冲区读之间
+也应有一个 ``smp_rmb()`` 。
+
+下面是一个使用 ``local.h`` 实现每个cpu基本计数器的示例模块::
+
+ /* test-local.c
+ *
+ * Sample module for local.h usage.
+ */
+
+
+ #include <asm/local.h>
+ #include <linux/module.h>
+ #include <linux/timer.h>
+
+ static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0);
+
+ static struct timer_list test_timer;
+
+ /* IPI called on each CPU. */
+ static void test_each(void *info)
+ {
+ /* Increment the counter from a non preemptible context */
+ printk("Increment on cpu %d\n", smp_processor_id());
+ local_inc(this_cpu_ptr(&counters));
+
+ /* This is what incrementing the variable would look like within a
+ * preemptible context (it disables preemption) :
+ *
+ * local_inc(&get_cpu_var(counters));
+ * put_cpu_var(counters);
+ */
+ }
+
+ static void do_test_timer(unsigned long data)
+ {
+ int cpu;
+
+ /* Increment the counters */
+ on_each_cpu(test_each, NULL, 1);
+ /* Read all the counters */
+ printk("Counters read from CPU %d\n", smp_processor_id());
+ for_each_online_cpu(cpu) {
+ printk("Read : CPU %d, count %ld\n", cpu,
+ local_read(&per_cpu(counters, cpu)));
+ }
+ mod_timer(&test_timer, jiffies + 1000);
+ }
+
+ static int __init test_init(void)
+ {
+ /* initialize the timer that will increment the counter */
+ timer_setup(&test_timer, do_test_timer, 0);
+ mod_timer(&test_timer, jiffies + 1);
+
+ return 0;
+ }
+
+ static void __exit test_exit(void)
+ {
+ timer_shutdown_sync(&test_timer);
+ }
+
+ module_init(test_init);
+ module_exit(test_exit);
+
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Mathieu Desnoyers");
+ MODULE_DESCRIPTION("Local Atomic Ops");
diff --git a/Documentation/translations/zh_CN/core-api/memory-allocation.rst b/Documentation/translations/zh_CN/core-api/memory-allocation.rst
new file mode 100644
index 000000000000..e17b87dfd1c8
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/memory-allocation.rst
@@ -0,0 +1,138 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/memory-allocation.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 时奎亮 <alexs@kernel.org>
+
+.. _cn_core-api_memory-allocation:
+
+============
+内存分配指南
+============
+
+Linux为内存分配提供了多种API。你可以使用 `kmalloc` 或 `kmem_cache_alloc`
+系列分配小块内存,使用 `vmalloc` 及其派生产品分配大的几乎连续的区域,或者
+你可以用 alloc_pages 直接向页面分配器请求页面。也可以使用更专业的分配器,
+例如 `cma_alloc` 或 `zs_malloc` 。
+
+大多数的内存分配API使用GFP标志来表达该内存应该如何分配。GFP的缩写代表
+“(get free pages)获取空闲页”,是底层的内存分配功能。
+
+(内存)分配API的多样性与众多的GFP标志相结合,使得“我应该如何分配内存?”这个问
+题不那么容易回答,尽管很可能你应该使用
+
+::
+
+ kzalloc(<size>, GFP_KERNEL);
+
+当然,有些情况下必须使用其他分配API和不同的GFP标志。
+
+获取空闲页标志
+==============
+GFP标志控制分配器的行为。它们告诉我们哪些内存区域可以被使用,分配器应该多努力寻
+找空闲的内存,这些内存是否可以被用户空间访问等等。内存管理API为GFP标志和它们的
+组合提供了参考文件,这里我们简要介绍一下它们的推荐用法:
+
+ * 大多数时候, ``GFP_KERNEL`` 是你需要的。内核数据结构的内存,DMA可用内存,inode
+ 缓存,所有这些和其他许多分配类型都可以使用 ``GFP_KERNEL`` 。注意,使用 ``GFP_KERNEL``
+ 意味着 ``GFP_RECLAIM`` ,这意味着在有内存压力的情况下可能会触发直接回收;调用上
+ 下文必须允许睡眠。
+
+ * 如果分配是从一个原子上下文中进行的,例如中断处理程序,使用 ``GFP_NOWAIT`` 。这个
+ 标志可以防止直接回收和IO或文件系统操作。因此,在内存压力下, ``GFP_NOWAIT`` 分配
+ 可能会失败。有合理退路的分配应该使用 ``GFP_NOWARN`` 。
+
+ * 如果你认为访问保留内存区是合理的,并且除非分配成功,否则内核会有压力,你可以使用 ``GFP_ATOMIC`` 。
+
+ * 从用户空间触发的不可信任的分配应该是kmem核算的对象,必须设置 ``__GFP_ACCOUNT`` 位。
+ 有一个方便的用于 ``GFP_KERNEL`` 分配的 ``GFP_KERNEL_ACCOUNT`` 快捷键,其应该被核
+ 算。
+
+ * 用户空间的分配应该使用 ``GFP_USER`` 、 ``GFP_HIGHUSER`` 或 ``GFP_HIGHUSER_MOVABLE``
+ 中的一个标志。标志名称越长,限制性越小。
+
+ ``GFP_HIGHUSER_MOVABLE`` 不要求分配的内存将被内核直接访问,并意味着数据是可迁移的。
+
+ ``GFP_HIGHUSER`` 意味着所分配的内存是不可迁移的,但也不要求它能被内核直接访问。举个
+ 例子就是一个硬件分配内存,这些数据直接映射到用户空间,但没有寻址限制。
+
+ ``GFP_USER`` 意味着分配的内存是不可迁移的,它必须被内核直接访问。
+
+你可能会注意到,在现有的代码中,有相当多的分配指定了 ``GFP_NOIO`` 或 ``GFP_NOFS`` 。
+从历史上看,它们被用来防止递归死锁,这种死锁是由直接内存回收调用到FS或IO路径以及对已
+经持有的资源进行阻塞引起的。从4.12开始,解决这个问题的首选方法是使用新的范围API,即
+:ref:`Documentation/core-api/gfp_mask-from-fs-io.rst <gfp_mask_from_fs_io>`.
+
+其他传统的GFP标志是 ``GFP_DMA`` 和 ``GFP_DMA32`` 。它们用于确保分配的内存可以被寻
+址能力有限的硬件访问。因此,除非你正在为一个有这种限制的设备编写驱动程序,否则要避免
+使用这些标志。而且,即使是有限制的硬件,也最好使用dma_alloc* APIs。
+
+GFP标志和回收行为
+-----------------
+内存分配可能会触发直接或后台回收,了解页面分配器将如何努力满足该请求或其他请求是非常
+有用的。
+
+ * ``GFP_KERNEL & ~__GFP_RECLAIM`` - 乐观分配,完全不尝试释放内存。最轻量级的模
+ 式,甚至不启动后台回收。应该小心使用,因为它可能会耗尽内存,而下一个用户可能会启
+ 动更积极的回收。
+
+ * ``GFP_KERNEL & ~__GFP_DIRECT_RECLAIM`` (or ``GFP_NOWAIT`` ) - 乐观分配,不
+ 试图从当前上下文中释放内存,但如果该区域低于低水位,可以唤醒kswapd来回收内存。可
+ 以从原子上下文中使用,或者当请求是一个性能优化,并且有另一个慢速路径的回退。
+
+ * ``(GFP_KERNEL|__GFP_HIGH) & ~__GFP_DIRECT_RECLAIM`` (aka ``GFP_ATOMIC`` ) - 非
+ 睡眠分配,有一个昂贵的回退,所以它可以访问某些部分的内存储备。通常从中断/底层上下
+ 文中使用,有一个昂贵的慢速路径回退。
+
+ * ``GFP_KERNEL`` - 允许后台和直接回收,并使用默认的页面分配器行为。这意味着廉价
+ 的分配请求基本上是不会失败的,但不能保证这种行为,所以失败必须由调用者适当检查(例
+ 如,目前允许OOM杀手失败)。
+
+ * ``GFP_KERNEL | __GFP_NORETRY`` - 覆盖默认的分配器行为,所有的分配请求都会提前
+ 失败,而不是导致破坏性的回收(在这个实现中是一轮的回收)。OOM杀手不被调用。
+
+ * ``GFP_KERNEL | __GFP_RETRY_MAYFAIL`` - 覆盖 **默认** 的分配器行为,所有分配请求都非
+ 常努力。如果回收不能取得任何进展,该请求将失败。OOM杀手不会被触发。
+
+ * ``GFP_KERNEL | __GFP_NOFAIL`` - 覆盖默认的分配器行为,所有分配请求将无休止地循
+ 环,直到成功。这可能真的很危险,特别是对于较大的需求。
+
+选择内存分配器
+==============
+
+分配内存的最直接的方法是使用kmalloc()系列的函数。而且,为了安全起见,最好使用将内存
+设置为零的例程,如kzalloc()。如果你需要为一个数组分配内存,有kmalloc_array()和kcalloc()
+辅助程序。辅助程序struct_size()、array_size()和array3_size()可以用来安全地计算对
+象的大小而不会溢出。
+
+可以用 `kmalloc` 分配的块的最大尺寸是有限的。实际的限制取决于硬件和内核配置,但是对于
+小于页面大小的对象,使用 `kmalloc` 是一个好的做法。
+
+用 `kmalloc` 分配的块的地址至少要对齐到ARCH_KMALLOC_MINALIGN字节。对于2的幂的大小,
+对齐方式也被保证为至少是各自的大小。
+
+用kmalloc()分配的块可以用krealloc()调整大小。与kmalloc_array()类似:以krealloc_array()
+的形式提供了一个用于调整数组大小的辅助工具。
+
+对于大量的分配,你可以使用vmalloc()和vzalloc(),或者直接向页面分配器请求页面。由vmalloc
+和相关函数分配的内存在物理上是不连续的。
+
+如果你不确定分配的大小对 `kmalloc` 来说是否太大,可以使用kvmalloc()及其派生函数。它将尝
+试用kmalloc分配内存,如果分配失败,将用 `vmalloc` 重新尝试。对于哪些GFP标志可以与 `kvmalloc`
+一起使用是有限制的;请看kvmalloc_node()参考文档。注意, `kvmalloc` 可能会返回物理上不连
+续的内存。
+
+如果你需要分配许多相同的对象,你可以使用slab缓存分配器。在使用缓存之前,应该用
+kmem_cache_create()或kmem_cache_create_usercopy()来设置缓存。如果缓存的一部分可能被复
+制到用户空间,应该使用第二个函数。在缓存被创建后,kmem_cache_alloc()和它的封装可以从该缓
+存中分配内存。
+
+当分配的内存不再需要时,它必须被释放。你可以使用kvfree()来处理用 `kmalloc` 、 `vmalloc`
+和 `kvmalloc` 分配的内存。slab缓存应该用kmem_cache_free()来释放。不要忘记用
+kmem_cache_destroy()来销毁缓存。
diff --git a/Documentation/translations/zh_CN/core-api/memory-hotplug.rst b/Documentation/translations/zh_CN/core-api/memory-hotplug.rst
new file mode 100644
index 000000000000..9b2841fb9a5f
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/memory-hotplug.rst
@@ -0,0 +1,122 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/memory-hotplug.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+.. _cn_core-api_memory-hotplug:
+
+==========
+内存热插拔
+==========
+
+内存热拔插事件通知器
+====================
+
+热插拔事件被发送到一个通知队列中。
+
+在 ``include/linux/memory.h`` 中定义了六种类型的通知:
+
+MEM_GOING_ONLINE
+ 在新内存可用之前生成,以便能够为子系统处理内存做准备。页面分配器仍然无法从新
+ 的内存中进行分配。
+
+MEM_CANCEL_ONLINE
+ 如果MEM_GOING_ONLINE失败,则生成。
+
+MEM_ONLINE
+ 当内存成功上线时产生。回调可以从新的内存中分配页面。
+
+MEM_GOING_OFFLINE
+ 在开始对内存进行下线处理时生成。从内存中的分配不再可能,但是一些要下线的内存
+ 仍然在使用。回调可以用来释放一个子系统在指定内存块中已知的内存。
+
+MEM_CANCEL_OFFLINE
+ 如果MEM_GOING_OFFLINE失败,则生成。来自我们试图离线的内存块中的内存又可以使
+ 用了。
+
+MEM_OFFLINE
+ 在内存下线完成后生成。
+
+可以通过调用如下函数来注册一个回调程序:
+
+ hotplug_memory_notifier(callback_func, priority)
+
+优先级数值较高的回调函数在数值较低的回调函数之前被调用。
+
+一个回调函数必须有以下原型::
+
+ int callback_func(
+ struct notifier_block *self, unsigned long action, void *arg);
+
+回调函数的第一个参数(self)是指向回调函数本身的通知器链块的一个指针。第二个参
+数(action)是上述的事件类型之一。第三个参数(arg)传递一个指向
+memory_notify结构体的指针::
+
+ struct memory_notify {
+ unsigned long start_pfn;
+ unsigned long nr_pages;
+ int status_change_nid_normal;
+ int status_change_nid;
+ }
+
+- start_pfn是在线/离线内存的start_pfn。
+
+- nr_pages是在线/离线内存的页数。
+
+- status_change_nid_normal是当nodemask的N_NORMAL_MEMORY被设置/清除时设置节
+ 点id,如果是-1,则nodemask状态不改变。
+
+- status_change_nid是当nodemask的N_MEMORY被(将)设置/清除时设置的节点id。这
+ 意味着一个新的(没上线的)节点通过联机获得新的内存,而一个节点失去了所有的内
+ 存。如果这个值为-1,那么nodemask的状态就不会改变。
+
+ 如果 status_changed_nid* >= 0,回调应该在必要时为节点创建/丢弃结构体。
+
+回调程序应返回 ``include/linux/notifier.h`` 中定义的NOTIFY_DONE, NOTIFY_OK,
+NOTIFY_BAD, NOTIFY_STOP中的一个值。
+
+NOTIFY_DONE和NOTIFY_OK对进一步处理没有影响。
+
+NOTIFY_BAD是作为对MEM_GOING_ONLINE、MEM_GOING_OFFLINE、MEM_ONLINE或MEM_OFFLINE
+动作的回应,用于取消热插拔。它停止对通知队列的进一步处理。
+
+NOTIFY_STOP停止对通知队列的进一步处理。
+
+内部锁
+======
+
+当添加/删除使用内存块设备(即普通RAM)的内存时,device_hotplug_lock应该被保持
+为:
+
+- 针对在线/离线请求进行同步(例如,通过sysfs)。这样一来,内存块设备只有在内存
+ 被完全添加后才能被用户空间访问(.online/.state属性)。而在删除内存时,我们知
+ 道没有人在临界区。
+
+- 与CPU热拔插或类似操作同步(例如ACPI和PPC相关操作)
+
+特别是,在添加内存和用户空间试图以比预期更快的速度上线该内存时,有可能出现锁反转,
+使用device_hotplug_lock可以避免此情况:
+
+- device_online()将首先接受device_lock(),然后是mem_hotplug_lock。
+
+- add_memory_resource()将首先使用mem_hotplug_lock,然后是device_lock()(在创
+ 建设备时,在bus_add_device()期间)。
+
+由于在使用device_lock()之前,设备对用户空间是可见的,这可能导致锁的反转。
+
+内存的上线/下线应该通过device_online()/device_offline()完成————确保它与通过
+sysfs进行的操作正确同步。建议持有device_hotplug_lock(例如,保护online_type)。
+
+当添加/删除/上线/下线内存或者添加/删除异构或设备内存时,我们应该始终持有写模式的
+mem_hotplug_lock,以序列化内存热插拔(例如访问全局/区域变量)。
+
+此外,mem_hotplug_lock(与device_hotplug_lock相反)在读取模式下允许一个相当
+有效的get_online_mems/put_online_mems实现,所以访问内存的代码可以防止该内存
+消失。
diff --git a/Documentation/translations/zh_CN/core-api/mm-api.rst b/Documentation/translations/zh_CN/core-api/mm-api.rst
new file mode 100644
index 000000000000..113359bdb7be
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/mm-api.rst
@@ -0,0 +1,131 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/mm-api.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
+
+:校译:
+
+ 时奎亮<alexs@kernel.org>
+
+.. _cn_core-api_mm-api:
+
+============
+内存管理APIs
+============
+
+API(Application Programming Interface,应用程序接口)
+
+用户空间内存访问
+================
+
+该API在以下内核代码中:
+
+arch/x86/include/asm/uaccess.h
+
+arch/x86/lib/usercopy_32.c
+
+mm/gup.c
+
+.. _cn_mm-api-gfp-flags:
+
+内存分配控制
+============
+
+该API在以下内核代码中:
+
+include/linux/gfp_types.h
+
+Slab缓存
+========
+
+此缓存非cpu片上缓存,请读者自行查阅资料。
+
+该API在以下内核代码中:
+
+include/linux/slab.h
+
+mm/slab.c
+
+mm/slab_common.c
+
+mm/util.c
+
+虚拟连续(内存页)映射
+======================
+
+该API在以下内核代码中:
+
+mm/vmalloc.c
+
+
+文件映射和页面缓存
+==================
+
+该API在以下内核代码中:
+
+文件映射
+--------
+
+mm/filemap.c
+
+预读
+----
+
+mm/readahead.c
+
+回写
+----
+
+mm/page-writeback.c
+
+截断
+----
+
+mm/truncate.c
+
+include/linux/pagemap.h
+
+内存池
+======
+
+该API在以下内核代码中:
+
+mm/mempool.c
+
+DMA池
+=====
+
+DMA(Direct Memory Access,直接存储器访问)
+
+该API在以下内核代码中:
+
+mm/dmapool.c
+
+更多的内存管理函数
+==================
+
+该API在以下内核代码中:
+
+mm/memory.c
+
+mm/page_alloc.c
+
+mm/mempolicy.c
+
+include/linux/mm_types.h
+
+include/linux/mm_inline.h
+
+include/linux/page-flags.h
+
+include/linux/mm.h
+
+include/linux/page_ref.h
+
+include/linux/mmzone.h
+
+mm/util.c
diff --git a/Documentation/translations/zh_CN/core-api/packing.rst b/Documentation/translations/zh_CN/core-api/packing.rst
new file mode 100644
index 000000000000..c0aab3a349d0
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/packing.rst
@@ -0,0 +1,160 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/packing.rst
+
+:翻译:
+
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
+
+:校译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 吴想成 Wu Xiangcheng <bobwxc@email.cn>
+ 时奎亮 Alex Shi <alexs@kernel.org>
+
+========================
+通用的位域打包和解包函数
+========================
+
+问题陈述
+--------
+
+使用硬件时,必须在几种与其交互的方法之间进行选择。
+
+可以将指针映射到在硬件设备的内存区上精心设计的结构体,并将其字段作为结构成员(可
+能声明为位域)访问。但是由于CPU和硬件设备之间潜在的字节顺序不匹配,以这种方式编写
+代码会降低其可移植性。
+
+此外,必须密切注意将硬件文档中的寄存器定义转换为结构的位域索引。此外,一些硬件
+(通常是网络设备)倾向于以违反任何合理字边界(有时甚至是64位)的方式对其寄存器字
+段进行分组。这就造成了不得不在结构中定义寄存器字段的“高”和“低”部分的不便。
+
+结构域定义的更可靠的替代方法是通过移动适当数量的位来提取所需的字段。但这仍然不能
+防止字节顺序不匹配,除非所有内存访问都是逐字节执行的。此外,代码很容易变得杂乱无
+章,同时可能会在所需的许多位移操作中丢失一些高层次的想法。
+
+许多驱动程序采用了位移的方法,然后试图用定制的宏来减少杂乱无章的东西,但更多的时
+候,这些宏所采用的捷径依旧妨碍了代码真正的可移植性。
+
+解决方案
+--------
+
+该API涉及2个基本操作:
+
+ - 将一个CPU可使用的数字打包到内存缓冲区中(具有硬件约束/特殊性)。
+ - 将内存缓冲区(具有硬件约束/特殊性)解压缩为一个CPU可使用的数字。
+
+该API提供了对所述硬件约束和特殊性以及CPU字节序的抽象,因此这两者之间可能不匹配。
+
+这些API函数的基本单元是u64。从CPU的角度来看,位63总是意味着字节7的位偏移量7,尽管
+只是逻辑上的。问题是:我们将这个比特放在内存的什么位置?
+
+以下示例介绍了打包u64字段的内存布局。打包缓冲区中的字节偏移量始终默认为0,1...7。
+示例显示的是逻辑字节和位所在的位置。
+
+1. 通常情况下(无特殊性),我们会这样做:
+
+::
+
+ 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32
+ 7 6 5 4
+ 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ 3 2 1 0
+
+也就是说,CPU可使用的u64的MSByte(7)位于内存偏移量0处,而u64的LSByte(0)位于内存偏移量7处。
+
+这对应于大多数人认为的“大端”,其中位i对应于数字2^i。这在代码注释中也称为“逻辑”符号。
+
+
+2. 如果设置了QUIRK_MSB_ON_THE_RIGHT,我们按如下方式操作:
+
+::
+
+ 56 57 58 59 60 61 62 63 48 49 50 51 52 53 54 55 40 41 42 43 44 45 46 47 32 33 34 35 36 37 38 39
+ 7 6 5 4
+ 24 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7
+ 3 2 1 0
+
+也就是说,QUIRK_MSB_ON_THE_RIGHT不会影响字节定位,但会反转字节内的位偏移量。
+
+
+3. 如果设置了QUIRK_LITTLE_ENDIAN,我们按如下方式操作:
+
+::
+
+ 39 38 37 36 35 34 33 32 47 46 45 44 43 42 41 40 55 54 53 52 51 50 49 48 63 62 61 60 59 58 57 56
+ 4 5 6 7
+ 7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24
+ 0 1 2 3
+
+因此,QUIRK_LITTLE_ENDIAN意味着在内存区域内,每个4字节的字的每个字节都被放置在与
+该字的边界相比的镜像位置。
+
+
+4. 如果设置了QUIRK_MSB_ON_THE_RIGHT和QUIRK_LITTLE_ENDIAN,我们这样做:
+
+::
+
+ 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
+ 4 5 6 7
+ 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
+ 0 1 2 3
+
+
+5. 如果只设置了QUIRK_LSW32_IS_FIRST,我们这样做:
+
+::
+
+ 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ 3 2 1 0
+ 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32
+ 7 6 5 4
+
+在这种情况下,8字节内存区域解释如下:前4字节对应最不重要的4字节的字,后4字节对应
+更重要的4字节的字。
+
+6. 如果设置了QUIRK_LSW32_IS_FIRST和QUIRK_MSB_ON_THE_RIGHT,我们这样做:
+
+::
+
+ 24 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7
+ 3 2 1 0
+ 56 57 58 59 60 61 62 63 48 49 50 51 52 53 54 55 40 41 42 43 44 45 46 47 32 33 34 35 36 37 38 39
+ 7 6 5 4
+
+
+7. 如果设置了QUIRK_LSW32_IS_FIRST和QUIRK_LITTLE_ENDIAN,则如下所示:
+
+::
+
+ 7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24
+ 0 1 2 3
+ 39 38 37 36 35 34 33 32 47 46 45 44 43 42 41 40 55 54 53 52 51 50 49 48 63 62 61 60 59 58 57 56
+ 4 5 6 7
+
+
+8. 如果设置了QUIRK_LSW32_IS_FIRST,QUIRK_LITTLE_ENDIAN和QUIRK_MSB_ON_THE_RIGHT,
+ 则如下所示:
+
+::
+
+ 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
+ 0 1 2 3
+ 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
+ 4 5 6 7
+
+
+我们总是认为我们的偏移量好像没有特殊性,然后在访问内存区域之前翻译它们。
+
+预期用途
+--------
+
+选择使用该API的驱动程序首先需要确定上述3种quirk组合(共8种)中的哪一种与硬件文档
+中描述的相匹配。然后,他们应该封装packing()函数,创建一个新的xxx_packing(),使用
+适当的QUIRK_* one-hot 位集合来调用它。
+
+packing()函数返回一个int类型的错误码,以防止程序员使用不正确的API。这些错误预计不
+会在运行时发生,因此xxx_packing()返回void并简单地接受这些错误是合理的。它可以选择
+转储栈或打印错误描述。
diff --git a/Documentation/translations/zh_CN/core-api/padata.rst b/Documentation/translations/zh_CN/core-api/padata.rst
new file mode 100644
index 000000000000..781d30675afd
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/padata.rst
@@ -0,0 +1,161 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/padata.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_core_api_padata.rst:
+
+==================
+padata并行执行机制
+==================
+
+:日期: 2020年5月
+
+Padata是一种机制,内核可以通过此机制将工作分散到多个CPU上并行完成,同时
+可以选择保持它们的顺序。
+
+它最初是为IPsec开发的,它需要在不对这些数据包重新排序的其前提下,为大量的数
+据包进行加密和解密。这是目前padata的序列化作业支持的唯一用途。
+
+Padata还支持多线程作业,将作业平均分割,同时在线程之间进行负载均衡和协调。
+
+执行序列化作业
+==============
+
+初始化
+------
+
+使用padata执行序列化作业的第一步是建立一个padata_instance结构体,以全面
+控制作业的运行方式::
+
+ #include <linux/padata.h>
+
+ struct padata_instance *padata_alloc(const char *name);
+
+'name'即标识了这个实例。
+
+然后,通过分配一个padata_shell来完成padata的初始化::
+
+ struct padata_shell *padata_alloc_shell(struct padata_instance *pinst);
+
+一个padata_shell用于向padata提交一个作业,并允许一系列这样的作业被独立地
+序列化。一个padata_instance可以有一个或多个padata_shell与之相关联,每个
+都允许一系列独立的作业。
+
+修改cpumasks
+------------
+
+用于运行作业的CPU可以通过两种方式改变,通过padata_set_cpumask()编程或通
+过sysfs。前者的定义是::
+
+ int padata_set_cpumask(struct padata_instance *pinst, int cpumask_type,
+ cpumask_var_t cpumask);
+
+这里cpumask_type是PADATA_CPU_PARALLEL(并行)或PADATA_CPU_SERIAL(串行)之一,其中并
+行cpumask描述了哪些处理器将被用来并行执行提交给这个实例的作业,串行cpumask
+定义了哪些处理器被允许用作串行化回调处理器。 cpumask指定了要使用的新cpumask。
+
+一个实例的cpumasks可能有sysfs文件。例如,pcrypt的文件在
+/sys/kernel/pcrypt/<instance-name>。在一个实例的目录中,有两个文件,parallel_cpumask
+和serial_cpumask,任何一个cpumask都可以通过在文件中回显(echo)一个bitmask
+来改变,比如说::
+
+ echo f > /sys/kernel/pcrypt/pencrypt/parallel_cpumask
+
+读取其中一个文件会显示用户提供的cpumask,它可能与“可用”的cpumask不同。
+
+Padata内部维护着两对cpumask,用户提供的cpumask和“可用的”cpumask(每一对由一个
+并行和一个串行cpumask组成)。用户提供的cpumasks在实例分配时默认为所有可能的CPU,
+并且可以如上所述进行更改。可用的cpumasks总是用户提供的cpumasks的一个子集,只包
+含用户提供的掩码中的在线CPU;这些是padata实际使用的cpumasks。因此,向padata提
+供一个包含离线CPU的cpumask是合法的。一旦用户提供的cpumask中的一个离线CPU上线,
+padata就会使用它。
+
+改变CPU掩码的操作代价很高,所以不应频繁更改。
+
+运行一个作业
+-------------
+
+实际上向padata实例提交工作需要创建一个padata_priv结构体,它代表一个作业::
+
+ struct padata_priv {
+ /* Other stuff here... */
+ void (*parallel)(struct padata_priv *padata);
+ void (*serial)(struct padata_priv *padata);
+ };
+
+这个结构体几乎肯定会被嵌入到一些针对要做的工作的大结构体中。它的大部分字段对
+padata来说是私有的,但是这个结构在初始化时应该被清零,并且应该提供parallel()和
+serial()函数。在完成工作的过程中,这些函数将被调用,我们马上就会遇到。
+
+工作的提交是通过::
+
+ int padata_do_parallel(struct padata_shell *ps,
+ struct padata_priv *padata, int *cb_cpu);
+
+ps和padata结构体必须如上所述进行设置;cb_cpu指向作业完成后用于最终回调的首选CPU;
+它必须在当前实例的CPU掩码中(如果不是,cb_cpu指针将被更新为指向实际选择的CPU)。
+padata_do_parallel()的返回值在成功时为0,表示工作正在进行中。-EBUSY意味着有人
+在其他地方正在搞乱实例的CPU掩码,而当cb_cpu不在串行cpumask中、并行或串行cpumasks
+中无在线CPU,或实例停止时,则会出现-EINVAL反馈。
+
+每个提交给padata_do_parallel()的作业将依次传递给一个CPU上的上述parallel()函数
+的一个调用,所以真正的并行是通过提交多个作业来实现的。parallel()在运行时禁用软
+件中断,因此不能睡眠。parallel()函数把获得的padata_priv结构体指针作为其唯一的参
+数;关于实际要做的工作的信息可能是通过使用container_of()找到封装结构体来获得的。
+
+请注意,parallel()没有返回值;padata子系统假定parallel()将从此时开始负责这项工
+作。作业不需要在这次调用中完成,但是,如果parallel()留下了未完成的工作,它应该准
+备在前一个作业完成之前,被以新的作业再次调用
+
+序列化作业
+----------
+
+当一个作业完成时,parallel()(或任何实际完成该工作的函数)应该通过调用通知padata此
+事::
+
+ void padata_do_serial(struct padata_priv *padata);
+
+在未来的某个时刻,padata_do_serial()将触发对padata_priv结构体中serial()函数的调
+用。这个调用将发生在最初要求调用padata_do_parallel()的CPU上;它也是在本地软件中断
+被禁用的情况下运行的。
+请注意,这个调用可能会被推迟一段时间,因为padata代码会努力确保作业按照提交的顺序完
+成。
+
+销毁
+----
+
+清理一个padata实例时,可以预见的是调用两个free函数,这两个函数对应于分配的逆过程::
+
+ void padata_free_shell(struct padata_shell *ps);
+ void padata_free(struct padata_instance *pinst);
+
+用户有责任确保在调用上述任何一项之前,所有未完成的工作都已完成。
+
+运行多线程作业
+==============
+
+一个多线程作业有一个主线程和零个或多个辅助线程,主线程参与作业,然后等待所有辅助线
+程完成。padata将作业分割成称为chunk的单元,其中chunk是一个线程在一次调用线程函数
+中完成的作业片段。
+
+用户必须做三件事来运行一个多线程作业。首先,通过定义一个padata_mt_job结构体来描述
+作业,这在接口部分有解释。这包括一个指向线程函数的指针,padata每次将作业块分配给线
+程时都会调用这个函数。然后,定义线程函数,它接受三个参数: ``start`` 、 ``end`` 和 ``arg`` ,
+其中前两个参数限定了线程操作的范围,最后一个是指向作业共享状态的指针,如果有的话。
+准备好共享状态,它通常被分配在主线程的堆栈中。最后,调用padata_do_multithreaded(),
+它将在作业完成后返回。
+
+接口
+====
+
+该API在以下内核代码中:
+
+include/linux/padata.h
+
+kernel/padata.c
diff --git a/Documentation/translations/zh_CN/core-api/printk-basics.rst b/Documentation/translations/zh_CN/core-api/printk-basics.rst
new file mode 100644
index 000000000000..cafa01bccff2
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/printk-basics.rst
@@ -0,0 +1,111 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/printk-basics.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
+
+.. _cn_printk-basics.rst:
+
+==================
+使用printk记录消息
+==================
+
+printk()是Linux内核中最广为人知的函数之一。它是我们打印消息的标准工具,通常也是追踪和调试
+的最基本方法。如果你熟悉printf(3),你就能够知道printk()是基于它的,尽管它在功能上有一些不
+同之处:
+
+ - printk() 消息可以指定日志级别。
+
+ - 格式字符串虽然与C99基本兼容,但并不遵循完全相同的规范。它有一些扩展和一些限制(没
+ 有 ``%n`` 或浮点转换指定符)。参见:ref: `如何正确地获得printk格式指定符<printk-specifiers>` 。
+
+所有的printk()消息都会被打印到内核日志缓冲区,这是一个通过/dev/kmsg输出到用户空间的环
+形缓冲区。读取它的通常方法是使用 ``dmesg`` 。
+
+printk()的用法通常是这样的::
+
+ printk(KERN_INFO "Message: %s\n", arg);
+
+其中 ``KERN_INFO`` 是日志级别(注意,它与格式字符串连在一起,日志级别不是一个单独的参数)。
+可用的日志级别是:
+
+
++----------------+--------+-----------------------------------------------+
+| 名称 | 字符串 | 别名函数 |
++================+========+===============================================+
+| KERN_EMERG | "0" | pr_emerg() |
++----------------+--------+-----------------------------------------------+
+| KERN_ALERT | "1" | pr_alert() |
++----------------+--------+-----------------------------------------------+
+| KERN_CRIT | "2" | pr_crit() |
++----------------+--------+-----------------------------------------------+
+| KERN_ERR | "3" | pr_err() |
++----------------+--------+-----------------------------------------------+
+| KERN_WARNING | "4" | pr_warn() |
++----------------+--------+-----------------------------------------------+
+| KERN_NOTICE | "5" | pr_notice() |
++----------------+--------+-----------------------------------------------+
+| KERN_INFO | "6" | pr_info() |
++----------------+--------+-----------------------------------------------+
+| KERN_DEBUG | "7" | pr_debug() and pr_devel() 若定义了DEBUG |
++----------------+--------+-----------------------------------------------+
+| KERN_DEFAULT | "" | |
++----------------+--------+-----------------------------------------------+
+| KERN_CONT | "c" | pr_cont() |
++----------------+--------+-----------------------------------------------+
+
+
+日志级别指定了一条消息的重要性。内核根据日志级别和当前 *console_loglevel* (一个内核变量)决
+定是否立即显示消息(将其打印到当前控制台)。如果消息的优先级比 *console_loglevel* 高(日志级
+别值较低),消息将被打印到控制台。
+
+如果省略了日志级别,则以 ``KERN_DEFAULT`` 级别打印消息。
+
+你可以用以下方法检查当前的 *console_loglevel* ::
+
+ $ cat /proc/sys/kernel/printk
+ 4 4 1 7
+
+结果显示了 *current*, *default*, *minimum* 和 *boot-time-default* 日志级别
+
+要改变当前的 console_loglevel,只需在 ``/proc/sys/kernel/printk`` 中写入所需的
+级别。例如,要打印所有的消息到控制台上::
+
+ # echo 8 > /proc/sys/kernel/printk
+
+另一种方式,使用 ``dmesg``::
+
+ # dmesg -n 5
+
+设置 console_loglevel 打印 KERN_WARNING (4) 或更严重的消息到控制台。更多消息参
+见 ``dmesg(1)`` 。
+
+作为printk()的替代方案,你可以使用 ``pr_*()`` 别名来记录日志。这个系列的宏在宏名中
+嵌入了日志级别。例如::
+
+ pr_info("Info message no. %d\n", msg_num);
+
+打印 ``KERN_INFO`` 消息。
+
+除了比等效的printk()调用更简洁之外,它们还可以通过pr_fmt()宏为格式字符串使用一个通用
+的定义。例如,在源文件的顶部(在任何 ``#include`` 指令之前)定义这样的内容。::
+
+ #define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
+
+会在该文件中的每一条 pr_*() 消息前加上发起该消息的模块和函数名称。
+
+为了调试,还有两个有条件编译的宏:
+pr_debug()和pr_devel(),除非定义了 ``DEBUG`` (或者在pr_debug()的情况下定义了
+``CONFIG_DYNAMIC_DEBUG`` ),否则它们不会被编译。
+
+
+函数接口
+========
+
+该API在以下内核代码中:
+
+include/linux/printk.h
diff --git a/Documentation/translations/zh_CN/core-api/printk-formats.rst b/Documentation/translations/zh_CN/core-api/printk-formats.rst
new file mode 100644
index 000000000000..bd36d35eba4e
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/printk-formats.rst
@@ -0,0 +1,598 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/printk-formats.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
+
+.. _cn_printk-formats.rst:
+
+==============================
+如何获得正确的printk格式占位符
+==============================
+
+
+
+:作者: Randy Dunlap <rdunlap@infradead.org>
+:作者: Andrew Murray <amurray@mpc-data.co.uk>
+
+
+整数类型
+========
+
+::
+
+ 若变量类型是Type,则使用printk格式占位符。
+ -------------------------------------------
+ char %d 或 %x
+ unsigned char %u 或 %x
+ short int %d 或 %x
+ unsigned short int %u 或 %x
+ int %d 或 %x
+ unsigned int %u 或 %x
+ long %ld 或 %lx
+ unsigned long %lu 或 %lx
+ long long %lld 或 %llx
+ unsigned long long %llu 或 %llx
+ size_t %zu 或 %zx
+ ssize_t %zd 或 %zx
+ s8 %d 或 %x
+ u8 %u 或 %x
+ s16 %d 或 %x
+ u16 %u 或 %x
+ s32 %d 或 %x
+ u32 %u 或 %x
+ s64 %lld 或 %llx
+ u64 %llu 或 %llx
+
+
+如果 <type> 的大小依赖于配置选项 (例如 sector_t, blkcnt_t) 或其大小依赖于架构
+(例如 tcflag_t),则使用其可能的最大类型的格式占位符并显式强制转换为它。
+
+例如
+
+::
+
+ printk("test: sector number/total blocks: %llu/%llu\n",
+ (unsigned long long)sector, (unsigned long long)blockcount);
+
+提醒:sizeof()返回类型为size_t。
+
+内核的printf不支持%n。显而易见,浮点格式(%e, %f, %g, %a)也不被识别。使用任何不
+支持的占位符或长度限定符都会导致一个WARN并且终止vsnprintf()执行。
+
+指针类型
+========
+
+一个原始指针值可以用%p打印,它将在打印前对地址进行哈希处理。内核也支持扩展占位符来打印
+不同类型的指针。
+
+一些扩展占位符会打印给定地址上的数据,而不是打印地址本身。在这种情况下,以下错误消息可能
+会被打印出来,而不是无法访问的消息::
+
+ (null) data on plain NULL address
+ (efault) data on invalid address
+ (einval) invalid data on a valid address
+
+普通指针
+----------
+
+::
+
+ %p abcdef12 or 00000000abcdef12
+
+没有指定扩展名的指针(即没有修饰符的%p)被哈希(hash),以防止内核内存布局消息的泄露。这
+样还有一个额外的好处,就是提供一个唯一的标识符。在64位机器上,前32位被清零。当没有足够的
+熵进行散列处理时,内核将打印(ptrval)代替
+
+如果可能的话,使用专门的修饰符,如%pS或%pB(如下所述),以避免打印一个必须事后解释的非哈
+希地址。如果不可能,而且打印地址的目的是为调试提供更多的消息,使用%p,并在调试过程中
+用 ``no_hash_pointers`` 参数启动内核,这将打印所有未修改的%p地址。如果你 *真的* 想知
+道未修改的地址,请看下面的%px。
+
+如果(也只有在)你将地址作为虚拟文件的内容打印出来,例如在procfs或sysfs中(使用
+seq_printf(),而不是printk())由用户空间进程读取,使用下面描述的%pK修饰符,不
+要用%p或%px。
+
+
+错误指针
+--------
+
+::
+
+ %pe -ENOSPC
+
+用于打印错误指针(即IS_ERR()为真的指针)的符号错误名。不知道符号名的错误值会以十进制打印,
+而作为%pe参数传递的非ERR_PTR会被视为普通的%p。
+
+符号/函数指针
+-------------
+
+::
+
+ %pS versatile_init+0x0/0x110
+ %ps versatile_init
+ %pSR versatile_init+0x9/0x110
+ (with __builtin_extract_return_addr() translation)
+ %pB prev_fn_of_versatile_init+0x88/0x88
+
+
+``S`` 和 ``s`` 占位符用于打印符号格式的指针。它们的结果是符号名称带有(S)或不带有(s)偏移
+量。如果禁用KALLSYMS,则打印符号地址。
+
+``B`` 占位符的结果是带有偏移量的符号名,在打印堆栈回溯时应该使用。占位符将考虑编译器优化
+的影响,当使用尾部调用并使用noreturn GCC属性标记时,可能会发生这种优化。
+
+如果指针在一个模块内,模块名称和可选的构建ID将被打印在符号名称之后,并在说明符的末尾添加
+一个额外的 ``b`` 。
+
+::
+
+ %pS versatile_init+0x0/0x110 [module_name]
+ %pSb versatile_init+0x0/0x110 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e]
+ %pSRb versatile_init+0x9/0x110 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e]
+ (with __builtin_extract_return_addr() translation)
+ %pBb prev_fn_of_versatile_init+0x88/0x88 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e]
+
+来自BPF / tracing追踪的探查指针
+----------------------------------
+
+::
+
+ %pks kernel string
+ %pus user string
+
+``k`` 和 ``u`` 指定符用于打印来自内核内存(k)或用户内存(u)的先前探测的内存。后面的 ``s`` 指
+定符的结果是打印一个字符串。对于直接在常规的vsnprintf()中使用时,(k)和(u)注释被忽略,但是,当
+在BPF的bpf_trace_printk()之外使用时,它会读取它所指向的内存,不会出现错误。
+
+内核指针
+--------
+
+::
+
+ %pK 01234567 or 0123456789abcdef
+
+用于打印应该对非特权用户隐藏的内核指针。%pK的行为取决于kptr_restrict sysctl——详见
+Documentation/admin-guide/sysctl/kernel.rst。
+
+未经修改的地址
+--------------
+
+::
+
+ %px 01234567 or 0123456789abcdef
+
+对于打印指针,当你 *真的* 想打印地址时。在用%px打印指针之前,请考虑你是否泄露了内核内
+存布局的敏感消息。%px在功能上等同于%lx(或%lu)。%px是首选,因为它在grep查找时更唯一。
+如果将来我们需要修改内核处理打印指针的方式,我们将能更好地找到调用点。
+
+在使用%px之前,请考虑使用%p并在调试过程中启用' ' no_hash_pointer ' '内核参数是否足
+够(参见上面的%p描述)。%px的一个有效场景可能是在panic发生之前立即打印消息,这样无论如何
+都可以防止任何敏感消息被利用,使用%px就不需要用no_hash_pointer来重现panic。
+
+指针差异
+--------
+
+::
+
+ %td 2560
+ %tx a00
+
+为了打印指针的差异,使用ptrdiff_t的%t修饰符。
+
+例如::
+
+ printk("test: difference between pointers: %td\n", ptr2 - ptr1);
+
+结构体资源(Resources)
+-----------------------
+
+::
+
+ %pr [mem 0x60000000-0x6fffffff flags 0x2200] or
+ [mem 0x0000000060000000-0x000000006fffffff flags 0x2200]
+ %pR [mem 0x60000000-0x6fffffff pref] or
+ [mem 0x0000000060000000-0x000000006fffffff pref]
+
+用于打印结构体资源。 ``R`` 和 ``r`` 占位符的结果是打印出的资源带有(R)或不带有(r)解码标志
+成员。
+
+通过引用传递。
+
+物理地址类型 phys_addr_t
+------------------------
+
+::
+
+ %pa[p] 0x01234567 or 0x0123456789abcdef
+
+用于打印phys_addr_t类型(以及它的衍生物,如resource_size_t),该类型可以根据构建选项而
+变化,无论CPU数据真实物理地址宽度如何。
+
+通过引用传递。
+
+DMA地址类型dma_addr_t
+---------------------
+
+::
+
+ %pad 0x01234567 or 0x0123456789abcdef
+
+用于打印dma_addr_t类型,该类型可以根据构建选项而变化,而不考虑CPU数据路径的宽度。
+
+通过引用传递。
+
+原始缓冲区为转义字符串
+----------------------
+
+::
+
+ %*pE[achnops]
+
+用于将原始缓冲区打印成转义字符串。对于以下缓冲区::
+
+ 1b 62 20 5c 43 07 22 90 0d 5d
+
+几个例子展示了如何进行转换(不包括两端的引号)。::
+
+ %*pE "\eb \C\a"\220\r]"
+ %*pEhp "\x1bb \C\x07"\x90\x0d]"
+ %*pEa "\e\142\040\\\103\a\042\220\r\135"
+
+转换规则是根据可选的标志组合来应用的(详见:c:func:`string_escape_mem` 内核文档):
+
+ - a - ESCAPE_ANY
+ - c - ESCAPE_SPECIAL
+ - h - ESCAPE_HEX
+ - n - ESCAPE_NULL
+ - o - ESCAPE_OCTAL
+ - p - ESCAPE_NP
+ - s - ESCAPE_SPACE
+
+默认情况下,使用 ESCAPE_ANY_NP。
+
+ESCAPE_ANY_NP是许多情况下的明智选择,特别是对于打印SSID。
+
+如果字段宽度被省略,那么将只转义1个字节。
+
+原始缓冲区为十六进制字符串
+--------------------------
+
+::
+
+ %*ph 00 01 02 ... 3f
+ %*phC 00:01:02: ... :3f
+ %*phD 00-01-02- ... -3f
+ %*phN 000102 ... 3f
+
+对于打印小的缓冲区(最长64个字节),可以用一定的分隔符作为一个
+十六进制字符串。对于较大的缓冲区,可以考虑使用
+:c:func:`print_hex_dump` 。
+
+MAC/FDDI地址
+------------
+
+::
+
+ %pM 00:01:02:03:04:05
+ %pMR 05:04:03:02:01:00
+ %pMF 00-01-02-03-04-05
+ %pm 000102030405
+ %pmR 050403020100
+
+用于打印以十六进制表示的6字节MAC/FDDI地址。 ``M`` 和 ``m`` 占位符导致打印的
+地址有(M)或没有(m)字节分隔符。默认的字节分隔符是冒号(:)。
+
+对于FDDI地址,可以在 ``M`` 占位符之后使用 ``F`` 说明,以使用破折号(——)分隔符
+代替默认的分隔符。
+
+对于蓝牙地址, ``R`` 占位符应使用在 ``M`` 占位符之后,以使用反转的字节顺序,适
+合于以小尾端顺序的蓝牙地址的肉眼可见的解析。
+
+通过引用传递。
+
+IPv4地址
+--------
+
+::
+
+ %pI4 1.2.3.4
+ %pi4 001.002.003.004
+ %p[Ii]4[hnbl]
+
+用于打印IPv4点分隔的十进制地址。 ``I4`` 和 ``i4`` 占位符的结果是打印的地址
+有(i4)或没有(I4)前导零。
+
+附加的 ``h`` 、 ``n`` 、 ``b`` 和 ``l`` 占位符分别用于指定主机、网络、大
+尾端或小尾端地址。如果没有提供占位符,则使用默认的网络/大尾端顺序。
+
+通过引用传递。
+
+IPv6 地址
+---------
+
+::
+
+ %pI6 0001:0002:0003:0004:0005:0006:0007:0008
+ %pi6 00010002000300040005000600070008
+ %pI6c 1:2:3:4:5:6:7:8
+
+用于打印IPv6网络顺序的16位十六进制地址。 ``I6`` 和 ``i6`` 占位符的结果是
+打印的地址有(I6)或没有(i6)分号。始终使用前导零。
+
+额外的 ``c`` 占位符可与 ``I`` 占位符一起使用,以打印压缩的IPv6地址,如
+https://tools.ietf.org/html/rfc5952 所述
+
+通过引用传递。
+
+IPv4/IPv6地址(generic, with port, flowinfo, scope)
+--------------------------------------------------
+
+::
+
+ %pIS 1.2.3.4 or 0001:0002:0003:0004:0005:0006:0007:0008
+ %piS 001.002.003.004 or 00010002000300040005000600070008
+ %pISc 1.2.3.4 or 1:2:3:4:5:6:7:8
+ %pISpc 1.2.3.4:12345 or [1:2:3:4:5:6:7:8]:12345
+ %p[Ii]S[pfschnbl]
+
+用于打印一个IP地址,不需要区分它的类型是AF_INET还是AF_INET6。一个指向有效结构
+体sockaddr的指针,通过 ``IS`` 或 ``IS`` 指定,可以传递给这个格式占位符。
+
+附加的 ``p`` 、 ``f`` 和 ``s`` 占位符用于指定port(IPv4, IPv6)、
+flowinfo (IPv6)和sope(IPv6)。port有一个 ``:`` 前缀,flowinfo是 ``/`` 和
+范围是 ``%`` ,每个后面都跟着实际的值。
+
+对于IPv6地址,如果指定了额外的指定符 ``c`` ,则使用
+https://tools.ietf.org/html/rfc5952 描述的压缩IPv6地址。
+如https://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-07
+所建议的,IPv6地址由'[',']'包围,以防止出现额外的占位符 ``p`` , ``f`` 或 ``s`` 。
+
+对于IPv4地址,也可以使用额外的 ``h`` , ``n`` , ``b`` 和 ``l`` 说
+明符,但对于IPv6地址则忽略。
+
+通过引用传递。
+
+更多例子::
+
+ %pISfc 1.2.3.4 or [1:2:3:4:5:6:7:8]/123456789
+ %pISsc 1.2.3.4 or [1:2:3:4:5:6:7:8]%1234567890
+ %pISpfc 1.2.3.4:12345 or [1:2:3:4:5:6:7:8]:12345/123456789
+
+UUID/GUID地址
+-------------
+
+::
+
+ %pUb 00010203-0405-0607-0809-0a0b0c0d0e0f
+ %pUB 00010203-0405-0607-0809-0A0B0C0D0E0F
+ %pUl 03020100-0504-0706-0809-0a0b0c0e0e0f
+ %pUL 03020100-0504-0706-0809-0A0B0C0E0E0F
+
+用于打印16字节的UUID/GUIDs地址。附加的 ``l`` , ``L`` , ``b`` 和 ``B`` 占位符用
+于指定小写(l)或大写(L)十六进制表示法中的小尾端顺序,以及小写(b)或大写(B)十六进制表
+示法中的大尾端顺序。
+
+如果没有使用额外的占位符,则将打印带有小写十六进制表示法的默认大端顺序。
+
+通过引用传递。
+
+目录项(dentry)的名称
+----------------------
+
+::
+
+ %pd{,2,3,4}
+ %pD{,2,3,4}
+
+用于打印dentry名称;如果我们用 :c:func:`d_move` 和它比较,名称可能是新旧混合的,但
+不会oops。 %pd dentry比较安全,其相当于我们以前用的%s dentry->d_name.name,%pd<n>打
+印 ``n`` 最后的组件。 %pD对结构文件做同样的事情。
+
+
+通过引用传递。
+
+块设备(block_device)名称
+--------------------------
+
+::
+
+ %pg sda, sda1 or loop0p1
+
+用于打印block_device指针的名称。
+
+va_format结构体
+---------------
+
+::
+
+ %pV
+
+用于打印结构体va_format。这些结构包含一个格式字符串
+和va_list如下
+
+::
+
+ struct va_format {
+ const char *fmt;
+ va_list *va;
+ };
+
+实现 "递归vsnprintf"。
+
+如果没有一些机制来验证格式字符串和va_list参数的正确性,请不要使用这个功能。
+
+通过引用传递。
+
+设备树节点
+----------
+
+::
+
+ %pOF[fnpPcCF]
+
+
+用于打印设备树节点结构。默认行为相当于%pOFf。
+
+ - f - 设备节点全称
+ - n - 设备节点名
+ - p - 设备节点句柄
+ - P - 设备节点路径规范(名称+@单位)
+ - F - 设备节点标志
+ - c - 主要兼容字符串
+ - C - 全兼容字符串
+
+当使用多个参数时,分隔符是':'。
+
+例如
+
+::
+
+ %pOF /foo/bar@0 - Node full name
+ %pOFf /foo/bar@0 - Same as above
+ %pOFfp /foo/bar@0:10 - Node full name + phandle
+ %pOFfcF /foo/bar@0:foo,device:--P- - Node full name +
+ major compatible string +
+ node flags
+ D - dynamic
+ d - detached
+ P - Populated
+ B - Populated bus
+
+通过引用传递。
+
+Fwnode handles
+--------------
+
+::
+
+ %pfw[fP]
+
+用于打印fwnode_handles的消息。默认情况下是打印完整的节点名称,包括路径。
+这些修饰符在功能上等同于上面的%pOF。
+
+ - f - 节点的全名,包括路径。
+ - P - 节点名称,包括地址(如果有的话)。
+
+例如 (ACPI)
+
+::
+
+ %pfwf \_SB.PCI0.CIO2.port@1.endpoint@0 - Full node name
+ %pfwP endpoint@0 - Node name
+
+例如 (OF)
+
+::
+
+ %pfwf /ocp@68000000/i2c@48072000/camera@10/port/endpoint - Full name
+ %pfwP endpoint - Node name
+
+时间和日期
+----------
+
+::
+
+ %pt[RT] YYYY-mm-ddTHH:MM:SS
+ %pt[RT]s YYYY-mm-dd HH:MM:SS
+ %pt[RT]d YYYY-mm-dd
+ %pt[RT]t HH:MM:SS
+ %pt[RT][dt][r][s]
+
+用于打印日期和时间::
+
+ R struct rtc_time structure
+ T time64_t type
+
+以我们(人类)可读的格式。
+
+默认情况下,年将以1900为单位递增,月将以1为单位递增。 使用%pt[RT]r (raw)
+来抑制这种行为。
+
+%pt[RT]s(空格)将覆盖ISO 8601的分隔符,在日期和时间之间使用''(空格)而
+不是'T'(大写T)。当日期或时间被省略时,它不会有任何影响。
+
+通过引用传递。
+
+clk结构体
+---------
+
+::
+
+ %pC pll1
+ %pCn pll1
+
+用于打印clk结构。%pC 和 %pCn 打印时钟的名称(通用时钟框架)或唯一的32位
+ID(传统时钟框架)。
+
+通过引用传递。
+
+位图及其衍生物,如cpumask和nodemask
+-----------------------------------
+
+::
+
+ %*pb 0779
+ %*pbl 0,3-6,8-10
+
+对于打印位图(bitmap)及其派生的cpumask和nodemask,%*pb输出以字段宽度为位数的位图,
+%*pbl输出以字段宽度为位数的范围列表。
+
+字段宽度用值传递,位图用引用传递。可以使用辅助宏cpumask_pr_args()和
+nodemask_pr_args()来方便打印cpumask和nodemask。
+
+标志位字段,如页标志、gfp_flags
+-------------------------------
+
+::
+
+ %pGp 0x17ffffc0002036(referenced|uptodate|lru|active|private|node=0|zone=2|lastcpupid=0x1fffff)
+ %pGg GFP_USER|GFP_DMA32|GFP_NOWARN
+ %pGv read|exec|mayread|maywrite|mayexec|denywrite
+
+将flags位字段打印为构造值的符号常量集合。标志的类型由第三个字符给出。目前支持的
+是[p]age flags, [v]ma_flags(都期望 ``unsigned long *`` )和
+[g]fp_flags(期望 ``gfp_t *`` )。标志名称和打印顺序取决于特定的类型。
+
+注意,这种格式不应该直接用于跟踪点的:c:func:`TP_printk()` 部分。相反,应使
+用 <trace/events/mmflags.h>中的show_*_flags()函数。
+
+通过引用传递。
+
+网络设备特性
+------------
+
+::
+
+ %pNF 0x000000000000c000
+
+用于打印netdev_features_t。
+
+通过引用传递。
+
+V4L2和DRM FourCC代码(像素格式)
+------------------------------
+
+::
+
+ %p4cc
+
+打印V4L2或DRM使用的FourCC代码,包括格式端序及其十六进制的数值。
+
+通过引用传递。
+
+例如::
+
+ %p4cc BG12 little-endian (0x32314742)
+ %p4cc Y10 little-endian (0x20303159)
+ %p4cc NV12 big-endian (0xb231564e)
+
+谢谢
+====
+
+如果您添加了其他%p扩展,请在可行的情况下,用一个或多个测试用例扩展<lib/test_printf.c>。
+
+谢谢你的合作和关注。
diff --git a/Documentation/translations/zh_CN/core-api/protection-keys.rst b/Documentation/translations/zh_CN/core-api/protection-keys.rst
new file mode 100644
index 000000000000..d07830050153
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/protection-keys.rst
@@ -0,0 +1,99 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/protection-keys.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+.. _cn_core-api_protection-keys:
+
+============
+内存保护密钥
+============
+
+用户空间的内存保护密钥(Memory Protection Keys for Userspace,PKU,亦
+即PKEYs)是英特尔Skylake(及以后)“可扩展处理器”服务器CPU上的一项功能。
+它将在未来的非服务器英特尔处理器和未来的AMD处理器中可用。
+
+对于任何希望测试或使用该功能的人来说,它在亚马逊的EC2 C5实例中是可用的,
+并且已知可以在那里使用Ubuntu 17.04镜像运行。
+
+内存保护密钥提供了一种机制来执行基于页面的保护,但在应用程序改变保护域
+时不需要修改页表。它的工作原理是在每个页表项中为“保护密钥”分配4个以
+前被忽略的位,从而提供16个可能的密钥。
+
+还有一个新的用户可访问寄存器(PKRU),为每个密钥提供两个单独的位(访
+问禁止和写入禁止)。作为一个CPU寄存器,PKRU在本质上是线程本地的,可能
+会给每个线程提供一套不同于其他线程的保护措施。
+
+有两条新指令(RDPKRU/WRPKRU)用于读取和写入新的寄存器。该功能仅在64位
+模式下可用,尽管物理地址扩展页表中理论上有空间。这些权限只在数据访问上
+强制执行,对指令获取没有影响。
+
+
+系统调用
+========
+
+有3个系统调用可以直接与pkeys进行交互::
+
+ int pkey_alloc(unsigned long flags, unsigned long init_access_rights)
+ int pkey_free(int pkey);
+ int pkey_mprotect(unsigned long start, size_t len,
+ unsigned long prot, int pkey);
+
+在使用一个pkey之前,必须先用pkey_alloc()分配它。一个应用程序直接调用
+WRPKRU指令,以改变一个密钥覆盖的内存的访问权限。在这个例子中,WRPKRU
+被一个叫做pkey_set()的C函数所封装::
+
+ int real_prot = PROT_READ|PROT_WRITE;
+ pkey = pkey_alloc(0, PKEY_DISABLE_WRITE);
+ ptr = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ ret = pkey_mprotect(ptr, PAGE_SIZE, real_prot, pkey);
+ ... application runs here
+
+现在,如果应用程序需要更新'ptr'处的数据,它可以获得访问权,进行更新,
+然后取消其写访问权::
+
+ pkey_set(pkey, 0); // clear PKEY_DISABLE_WRITE
+ *ptr = foo; // assign something
+ pkey_set(pkey, PKEY_DISABLE_WRITE); // set PKEY_DISABLE_WRITE again
+
+现在,当它释放内存时,它也将释放pkey,因为它不再被使用了::
+
+ munmap(ptr, PAGE_SIZE);
+ pkey_free(pkey);
+
+.. note:: pkey_set()是RDPKRU和WRPKRU指令的一个封装器。在tools/testing/selftests/x86/protection_keys.c中可以找到一个实现实例。
+ tools/testing/selftests/x86/protection_keys.c.
+
+行为
+====
+
+内核试图使保护密钥与普通的mprotect()的行为一致。例如,如果你这样做::
+
+ mprotect(ptr, size, PROT_NONE);
+ something(ptr);
+
+这样做的时候,你可以期待保护密钥的相同效果::
+
+ pkey = pkey_alloc(0, PKEY_DISABLE_WRITE | PKEY_DISABLE_READ);
+ pkey_mprotect(ptr, size, PROT_READ|PROT_WRITE, pkey);
+ something(ptr);
+
+无论something()是否是对'ptr'的直接访问,这都应该为真。
+如::
+
+ *ptr = foo;
+
+或者当内核代表应用程序进行访问时,比如read()::
+
+ read(fd, ptr, 1);
+
+在这两种情况下,内核都会发送一个SIGSEGV,但当违反保护密钥时,si_code
+将被设置为SEGV_PKERR,而当违反普通的mprotect()权限时,则是SEGV_ACCERR。
diff --git a/Documentation/translations/zh_CN/core-api/rbtree.rst b/Documentation/translations/zh_CN/core-api/rbtree.rst
new file mode 100644
index 000000000000..a3e1555cb974
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/rbtree.rst
@@ -0,0 +1,391 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/rbtree.rst
+
+:翻译:
+
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+=========================
+Linux中的红黑树(rbtree)
+=========================
+
+
+:日期: 2007年1月18日
+:作者: Rob Landley <rob@landley.net>
+
+何为红黑树,它们有什么用?
+--------------------------
+
+红黑树是一种自平衡二叉搜索树,被用来存储可排序的键/值数据对。这与基数树(被用来高效
+存储稀疏数组,因此使用长整型下标来插入/访问/删除结点)和哈希表(没有保持排序因而无法
+容易地按序遍历,同时必须调节其大小和哈希函数,然而红黑树可以优雅地伸缩以便存储任意
+数量的键)不同。
+
+红黑树和AVL树类似,但在插入和删除时提供了更快的实时有界的最坏情况性能(分别最多两次
+旋转和三次旋转,来平衡树),查询时间轻微变慢(但时间复杂度仍然是O(log n))。
+
+引用Linux每周新闻(Linux Weekly News):
+
+ 内核中有多处红黑树的使用案例。最后期限调度器和完全公平排队(CFQ)I/O调度器利用
+ 红黑树跟踪请求;数据包CD/DVD驱动程序也是如此。高精度时钟代码使用一颗红黑树组织
+ 未完成的定时器请求。ext3文件系统用红黑树跟踪目录项。虚拟内存区域(VMAs)、epoll
+ 文件描述符、密码学密钥和在“分层令牌桶”调度器中的网络数据包都由红黑树跟踪。
+
+本文档涵盖了对Linux红黑树实现的使用方法。更多关于红黑树的性质和实现的信息,参见:
+
+ Linux每周新闻关于红黑树的文章
+ https://lwn.net/Articles/184495/
+
+ 维基百科红黑树词条
+ https://en.wikipedia.org/wiki/Red-black_tree
+
+红黑树的Linux实现
+-----------------
+
+Linux的红黑树实现在文件“lib/rbtree.c”中。要使用它,需要“#include <linux/rbtree.h>”。
+
+Linux的红黑树实现对速度进行了优化,因此比传统的实现少一个间接层(有更好的缓存局部性)。
+每个rb_node结构体的实例嵌入在它管理的数据结构中,因此不需要靠指针来分离rb_node和它
+管理的数据结构。用户应该编写他们自己的树搜索和插入函数,来调用已提供的红黑树函数,
+而不是使用一个比较回调函数指针。加锁代码也留给红黑树的用户编写。
+
+创建一颗红黑树
+--------------
+
+红黑树中的数据结点是包含rb_node结构体成员的结构体::
+
+ struct mytype {
+ struct rb_node node;
+ char *keystring;
+ };
+
+当处理一个指向内嵌rb_node结构体的指针时,包住rb_node的结构体可用标准的container_of()
+宏访问。此外,个体成员可直接用rb_entry(node, type, member)访问。
+
+每颗红黑树的根是一个rb_root数据结构,它由以下方式初始化为空:
+
+ struct rb_root mytree = RB_ROOT;
+
+在一颗红黑树中搜索值
+--------------------
+
+为你的树写一个搜索函数是相当简单的:从树根开始,比较每个值,然后根据需要继续前往左边或
+右边的分支。
+
+示例::
+
+ struct mytype *my_search(struct rb_root *root, char *string)
+ {
+ struct rb_node *node = root->rb_node;
+
+ while (node) {
+ struct mytype *data = container_of(node, struct mytype, node);
+ int result;
+
+ result = strcmp(string, data->keystring);
+
+ if (result < 0)
+ node = node->rb_left;
+ else if (result > 0)
+ node = node->rb_right;
+ else
+ return data;
+ }
+ return NULL;
+ }
+
+在一颗红黑树中插入数据
+----------------------
+
+在树中插入数据的步骤包括:首先搜索插入新结点的位置,然后插入结点并对树再平衡
+("recoloring")。
+
+插入的搜索和上文的搜索不同,它要找到嫁接新结点的位置。新结点也需要一个指向它的父节点
+的链接,以达到再平衡的目的。
+
+示例::
+
+ int my_insert(struct rb_root *root, struct mytype *data)
+ {
+ struct rb_node **new = &(root->rb_node), *parent = NULL;
+
+ /* Figure out where to put new node */
+ while (*new) {
+ struct mytype *this = container_of(*new, struct mytype, node);
+ int result = strcmp(data->keystring, this->keystring);
+
+ 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(&data->node, parent, new);
+ rb_insert_color(&data->node, root);
+
+ return TRUE;
+ }
+
+在一颗红黑树中删除或替换已经存在的数据
+--------------------------------------
+
+若要从树中删除一个已经存在的结点,调用::
+
+ void rb_erase(struct rb_node *victim, struct rb_root *tree);
+
+示例::
+
+ struct mytype *data = mysearch(&mytree, "walrus");
+
+ if (data) {
+ rb_erase(&data->node, &mytree);
+ myfree(data);
+ }
+
+若要用一个新结点替换树中一个已经存在的键值相同的结点,调用::
+
+ void rb_replace_node(struct rb_node *old, struct rb_node *new,
+ struct rb_root *tree);
+
+通过这种方式替换结点不会对树做重排序:如果新结点的键值和旧结点不同,红黑树可能被
+破坏。
+
+(按排序的顺序)遍历存储在红黑树中的元素
+----------------------------------------
+
+我们提供了四个函数,用于以排序的方式遍历一颗红黑树的内容。这些函数可以在任意红黑树
+上工作,并且不需要被修改或包装(除非加锁的目的)::
+
+ struct rb_node *rb_first(struct rb_root *tree);
+ struct rb_node *rb_last(struct rb_root *tree);
+ struct rb_node *rb_next(struct rb_node *node);
+ struct rb_node *rb_prev(struct rb_node *node);
+
+要开始迭代,需要使用一个指向树根的指针调用rb_first()或rb_last(),它将返回一个指向
+树中第一个或最后一个元素所包含的节点结构的指针。要继续的话,可以在当前结点上调用
+rb_next()或rb_prev()来获取下一个或上一个结点。当没有剩余的结点时,将返回NULL。
+
+迭代器函数返回一个指向被嵌入的rb_node结构体的指针,由此,包住rb_node的结构体可用
+标准的container_of()宏访问。此外,个体成员可直接用rb_entry(node, type, member)
+访问。
+
+示例::
+
+ struct rb_node *node;
+ for (node = rb_first(&mytree); node; node = rb_next(node))
+ printk("key=%s\n", rb_entry(node, struct mytype, node)->keystring);
+
+带缓存的红黑树
+--------------
+
+计算最左边(最小的)结点是二叉搜索树的一个相当常见的任务,例如用于遍历,或用户根据
+他们自己的逻辑依赖一个特定的顺序。为此,用户可以使用'struct rb_root_cached'来优化
+时间复杂度为O(logN)的rb_first()的调用,以简单地获取指针,避免了潜在的昂贵的树迭代。
+维护操作的额外运行时间开销可忽略,不过内存占用较大。
+
+和rb_root结构体类似,带缓存的红黑树由以下方式初始化为空::
+
+ struct rb_root_cached mytree = RB_ROOT_CACHED;
+
+带缓存的红黑树只是一个常规的rb_root,加上一个额外的指针来缓存最左边的节点。这使得
+rb_root_cached可以存在于rb_root存在的任何地方,并且只需增加几个接口来支持带缓存的
+树::
+
+ struct rb_node *rb_first_cached(struct rb_root_cached *tree);
+ void rb_insert_color_cached(struct rb_node *, struct rb_root_cached *, bool);
+ void rb_erase_cached(struct rb_node *node, struct rb_root_cached *);
+
+操作和删除也有对应的带缓存的树的调用::
+
+ void rb_insert_augmented_cached(struct rb_node *node, struct rb_root_cached *,
+ bool, struct rb_augment_callbacks *);
+ void rb_erase_augmented_cached(struct rb_node *, struct rb_root_cached *,
+ struct rb_augment_callbacks *);
+
+
+对增强型红黑树的支持
+--------------------
+
+增强型红黑树是一种在每个结点里存储了“一些”附加数据的红黑树,其中结点N的附加数据
+必须是以N为根的子树中所有结点的内容的函数。它是建立在红黑树基础设施之上的可选特性。
+想要使用这个特性的红黑树用户,插入和删除结点时必须调用增强型接口并提供增强型回调函数。
+
+实现增强型红黑树操作的C文件必须包含<linux/rbtree_augmented.h>而不是<linux/rbtree.h>。
+注意,linux/rbtree_augmented.h暴露了一些红黑树实现的细节而你不应依赖它们,请坚持
+使用文档记录的API,并且不要在头文件中包含<linux/rbtree_augmented.h>,以最小化你的
+用户意外地依赖这些实现细节的可能。
+
+插入时,用户必须更新通往被插入节点的路径上的增强信息,然后像往常一样调用rb_link_node(),
+然后是rb_augment_inserted()而不是平时的rb_insert_color()调用。如果
+rb_augment_inserted()再平衡了红黑树,它将回调至一个用户提供的函数来更新受影响的
+子树上的增强信息。
+
+删除一个结点时,用户必须调用rb_erase_augmented()而不是rb_erase()。
+rb_erase_augmented()回调至一个用户提供的函数来更新受影响的子树上的增强信息。
+
+在两种情况下,回调都是通过rb_augment_callbacks结构体提供的。必须定义3个回调:
+
+- 一个传播回调,它更新一个给定结点和它的祖先们的增强数据,直到一个给定的停止点
+ (如果是NULL,将更新一路更新到树根)。
+
+- 一个复制回调,它将一颗给定子树的增强数据复制到一个新指定的子树树根。
+
+- 一个树旋转回调,它将一颗给定的子树的增强值复制到新指定的子树树根上,并重新计算
+ 先前的子树树根的增强值。
+
+rb_erase_augmented()编译后的代码可能会内联传播、复制回调,这将导致函数体积更大,
+因此每个增强型红黑树的用户应该只有一个rb_erase_augmented()的调用点,以限制编译后
+的代码大小。
+
+
+使用示例
+^^^^^^^^
+
+区间树是增强型红黑树的一个例子。参考Cormen,Leiserson,Rivest和Stein写的
+《算法导论》。区间树的更多细节:
+
+经典的红黑树只有一个键,它不能直接用来存储像[lo:hi]这样的区间范围,也不能快速查找
+与新的lo:hi重叠的部分,或者查找是否有与新的lo:hi完全匹配的部分。
+
+然而,红黑树可以被增强,以一种结构化的方式来存储这种区间范围,从而使高效的查找和
+精确匹配成为可能。
+
+这个存储在每个节点中的“额外信息”是其所有后代结点中的最大hi(max_hi)值。这个信息
+可以保持在每个结点上,只需查看一下该结点和它的直系子结点们。这将被用于时间复杂度
+为O(log n)的最低匹配查找(所有可能的匹配中最低的起始地址),就像这样::
+
+ struct interval_tree_node *
+ interval_tree_first_match(struct rb_root *root,
+ unsigned long start, unsigned long last)
+ {
+ struct interval_tree_node *node;
+
+ if (!root->rb_node)
+ return NULL;
+ node = rb_entry(root->rb_node, struct interval_tree_node, rb);
+
+ while (true) {
+ if (node->rb.rb_left) {
+ struct interval_tree_node *left =
+ rb_entry(node->rb.rb_left,
+ struct interval_tree_node, rb);
+ if (left->__subtree_last >= start) {
+ /*
+ * 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 (node->start <= last) { /* Cond1 */
+ if (node->last >= start) /* Cond2 */
+ return node; /* node is leftmost match */
+ if (node->rb.rb_right) {
+ node = rb_entry(node->rb.rb_right,
+ struct interval_tree_node, rb);
+ if (node->__subtree_last >= start)
+ continue;
+ }
+ }
+ return NULL; /* No match */
+ }
+ }
+
+插入/删除是通过以下增强型回调来定义的::
+
+ static inline unsigned long
+ compute_subtree_last(struct interval_tree_node *node)
+ {
+ unsigned long max = node->last, subtree_last;
+ if (node->rb.rb_left) {
+ subtree_last = rb_entry(node->rb.rb_left,
+ struct interval_tree_node, rb)->__subtree_last;
+ if (max < subtree_last)
+ max = subtree_last;
+ }
+ if (node->rb.rb_right) {
+ subtree_last = rb_entry(node->rb.rb_right,
+ struct interval_tree_node, rb)->__subtree_last;
+ if (max < subtree_last)
+ max = subtree_last;
+ }
+ return max;
+ }
+
+ static void augment_propagate(struct rb_node *rb, struct rb_node *stop)
+ {
+ while (rb != stop) {
+ struct interval_tree_node *node =
+ rb_entry(rb, struct interval_tree_node, rb);
+ unsigned long subtree_last = compute_subtree_last(node);
+ if (node->__subtree_last == subtree_last)
+ break;
+ node->__subtree_last = subtree_last;
+ rb = rb_parent(&node->rb);
+ }
+ }
+
+ static void augment_copy(struct rb_node *rb_old, struct rb_node *rb_new)
+ {
+ struct interval_tree_node *old =
+ rb_entry(rb_old, struct interval_tree_node, rb);
+ struct interval_tree_node *new =
+ rb_entry(rb_new, struct interval_tree_node, rb);
+
+ new->__subtree_last = old->__subtree_last;
+ }
+
+ static void augment_rotate(struct rb_node *rb_old, struct rb_node *rb_new)
+ {
+ struct interval_tree_node *old =
+ rb_entry(rb_old, struct interval_tree_node, rb);
+ struct interval_tree_node *new =
+ rb_entry(rb_new, struct interval_tree_node, rb);
+
+ new->__subtree_last = old->__subtree_last;
+ old->__subtree_last = compute_subtree_last(old);
+ }
+
+ static const struct rb_augment_callbacks augment_callbacks = {
+ augment_propagate, augment_copy, augment_rotate
+ };
+
+ void interval_tree_insert(struct interval_tree_node *node,
+ struct rb_root *root)
+ {
+ struct rb_node **link = &root->rb_node, *rb_parent = NULL;
+ unsigned long start = node->start, last = node->last;
+ struct interval_tree_node *parent;
+
+ while (*link) {
+ rb_parent = *link;
+ parent = rb_entry(rb_parent, struct interval_tree_node, rb);
+ if (parent->__subtree_last < last)
+ parent->__subtree_last = last;
+ if (start < parent->start)
+ link = &parent->rb.rb_left;
+ else
+ link = &parent->rb.rb_right;
+ }
+
+ node->__subtree_last = last;
+ rb_link_node(&node->rb, rb_parent, link);
+ rb_insert_augmented(&node->rb, root, &augment_callbacks);
+ }
+
+ void interval_tree_remove(struct interval_tree_node *node,
+ struct rb_root *root)
+ {
+ rb_erase_augmented(&node->rb, root, &augment_callbacks);
+ }
diff --git a/Documentation/translations/zh_CN/core-api/refcount-vs-atomic.rst b/Documentation/translations/zh_CN/core-api/refcount-vs-atomic.rst
new file mode 100644
index 000000000000..e2467fd26fc0
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/refcount-vs-atomic.rst
@@ -0,0 +1,156 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/refcount-vs-atomic.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_refcount-vs-atomic:
+
+=======================================
+与atomic_t相比,refcount_t的API是这样的
+=======================================
+
+.. contents:: :local:
+
+简介
+====
+
+refcount_t API的目标是为实现对象的引用计数器提供一个最小的API。虽然来自
+lib/refcount.c的独立于架构的通用实现在下面使用了原子操作,但一些 ``refcount_*()``
+和 ``atomic_*()`` 函数在内存顺序保证方面有很多不同。本文档概述了这些差异,并
+提供了相应的例子,以帮助开发者根据这些内存顺序保证的变化来验证他们的代码。
+
+本文档中使用的术语尽量遵循tools/memory-model/Documentation/explanation.txt
+中定义的正式LKMM。
+
+memory-barriers.txt和atomic_t.txt提供了更多关于内存顺序的背景,包括通用的
+和针对原子操作的。
+
+内存顺序的相关类型
+==================
+
+.. note:: 下面的部分只涵盖了本文使用的与原子操作和引用计数器有关的一些内存顺
+ 序类型。如果想了解更广泛的情况,请查阅memory-barriers.txt文件。
+
+在没有任何内存顺序保证的情况下(即完全无序),atomics和refcounters只提供原
+子性和程序顺序(program order, po)关系(在同一个CPU上)。它保证每个
+``atomic_* ()`` 和 ``refcount_*()`` 操作都是原子性的,指令在单个CPU上按程序
+顺序执行。这是用READ_ONCE()/WRITE_ONCE()和比较并交换原语实现的。
+
+强(完全)内存顺序保证在同一CPU上的所有较早加载和存储的指令(所有程序顺序较早
+[po-earlier]指令)在执行任何程序顺序较后指令(po-later)之前完成。它还保证
+同一CPU上储存的程序优先较早的指令和来自其他CPU传播的指令必须在该CPU执行任何
+程序顺序较后指令之前传播到其他CPU(A-累积属性)。这是用smp_mb()实现的。
+
+RELEASE内存顺序保证了在同一CPU上所有较早加载和存储的指令(所有程序顺序较早
+指令)在此操作前完成。它还保证同一CPU上储存的程序优先较早的指令和来自其他CPU
+传播的指令必须在释放(release)操作之前传播到所有其他CPU(A-累积属性)。这是用
+smp_store_release()实现的。
+
+ACQUIRE内存顺序保证了同一CPU上的所有后加载和存储的指令(所有程序顺序较后
+指令)在获取(acquire)操作之后完成。它还保证在获取操作执行后,同一CPU上
+储存的所有程序顺序较后指令必须传播到所有其他CPU。这是用
+smp_acquire__after_ctrl_dep()实现的。
+
+对Refcounters的控制依赖(取决于成功)保证了如果一个对象的引用被成功获得(引用计数
+器的增量或增加行为发生了,函数返回true),那么进一步的存储是针对这个操作的命令。对存
+储的控制依赖没有使用任何明确的屏障来实现,而是依赖于CPU不对存储进行猜测。这只是
+一个单一的CPU关系,对其他CPU不提供任何保证。
+
+
+函数的比较
+==========
+
+情况1) - 非 “读/修改/写”(RMW)操作
+------------------------------------
+
+函数变化:
+
+ * atomic_set() --> refcount_set()
+ * atomic_read() --> refcount_read()
+
+内存顺序保证变化:
+
+ * none (两者都是完全无序的)
+
+
+情况2) - 基于增量的操作,不返回任何值
+--------------------------------------
+
+函数变化:
+
+ * atomic_inc() --> refcount_inc()
+ * atomic_add() --> refcount_add()
+
+内存顺序保证变化:
+
+ * none (两者都是完全无序的)
+
+情况3) - 基于递减的RMW操作,没有返回值
+---------------------------------------
+
+函数变化:
+
+ * atomic_dec() --> refcount_dec()
+
+内存顺序保证变化:
+
+ * 完全无序的 --> RELEASE顺序
+
+
+情况4) - 基于增量的RMW操作,返回一个值
+---------------------------------------
+
+函数变化:
+
+ * atomic_inc_not_zero() --> refcount_inc_not_zero()
+ * 无原子性对应函数 --> refcount_add_not_zero()
+
+内存顺序保证变化:
+
+ * 完全有序的 --> 控制依赖于存储的成功
+
+.. note:: 此处 **假设** 了,必要的顺序是作为获得对象指针的结果而提供的。
+
+
+情况 5) - 基于Dec/Sub递减的通用RMW操作,返回一个值
+---------------------------------------------------
+
+函数变化:
+
+ * atomic_dec_and_test() --> refcount_dec_and_test()
+ * atomic_sub_and_test() --> refcount_sub_and_test()
+
+内存顺序保证变化:
+
+ * 完全有序的 --> RELEASE顺序 + 成功后ACQUIRE顺序
+
+
+情况6)其他基于递减的RMW操作,返回一个值
+----------------------------------------
+
+函数变化:
+
+ * 无原子性对应函数 --> refcount_dec_if_one()
+ * ``atomic_add_unless(&var, -1, 1)`` --> ``refcount_dec_not_one(&var)``
+
+内存顺序保证变化:
+
+ * 完全有序的 --> RELEASE顺序 + 控制依赖
+
+.. note:: atomic_add_unless()只在执行成功时提供完整的顺序。
+
+
+情况7)--基于锁的RMW
+--------------------
+
+函数变化:
+
+ * atomic_dec_and_lock() --> refcount_dec_and_lock()
+ * atomic_dec_and_mutex_lock() --> refcount_dec_and_mutex_lock()
+
+内存顺序保证变化:
+
+ * 完全有序 --> RELEASE顺序 + 控制依赖 + 持有
diff --git a/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst b/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst
new file mode 100644
index 000000000000..bb16f0611046
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst
@@ -0,0 +1,144 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/symbol-namespaces.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_symbol-namespaces.rst:
+
+=================================
+符号命名空间(Symbol Namespaces)
+=================================
+
+本文档描述了如何使用符号命名空间来构造通过EXPORT_SYMBOL()系列宏导出的内核内符号的导出面。
+
+.. 目录
+
+ === 1 简介
+ === 2 如何定义符号命名空间
+ --- 2.1 使用EXPORT_SYMBOL宏
+ --- 2.2 使用DEFAULT_SYMBOL_NAMESPACE定义
+ === 3 如何使用命名空间中导出的符号
+ === 4 加载使用命名空间符号的模块
+ === 5 自动创建MODULE_IMPORT_NS声明
+
+1. 简介
+=======
+
+符号命名空间已经被引入,作为构造内核内API的导出面的一种手段。它允许子系统维护者将
+他们导出的符号划分进独立的命名空间。这对于文档的编写非常有用(想想SUBSYSTEM_DEBUG
+命名空间),也可以限制一组符号在内核其他部分的使用。今后,使用导出到命名空间的符号
+的模块必须导入命名空间。否则,内核将根据其配置,拒绝加载该模块或警告说缺少
+导入。
+
+2. 如何定义符号命名空间
+=======================
+
+符号可以用不同的方法导出到命名空间。所有这些都在改变 EXPORT_SYMBOL 和与之类似的那些宏
+被检测到的方式,以创建 ksymtab 条目。
+
+2.1 使用EXPORT_SYMBOL宏
+=======================
+
+除了允许将内核符号导出到内核符号表的宏EXPORT_SYMBOL()和EXPORT_SYMBOL_GPL()之外,
+这些宏的变体还可以将符号导出到某个命名空间:EXPORT_SYMBOL_NS() 和 EXPORT_SYMBOL_NS_GPL()。
+它们需要一个额外的参数:命名空间(the namespace)。请注意,由于宏扩展,该参数需
+要是一个预处理器符号。例如,要把符号 ``usb_stor_suspend`` 导出到命名空间 ``USB_STORAGE``,
+请使用::
+
+ EXPORT_SYMBOL_NS(usb_stor_suspend, USB_STORAGE);
+
+相应的 ksymtab 条目结构体 ``kernel_symbol`` 将有相应的成员 ``命名空间`` 集。
+导出时未指明命名空间的符号将指向 ``NULL`` 。如果没有定义命名空间,则默认没有。
+``modpost`` 和kernel/module/main.c分别在构建时或模块加载时使用名称空间。
+
+2.2 使用DEFAULT_SYMBOL_NAMESPACE定义
+====================================
+
+为一个子系统的所有符号定义命名空间可能会非常冗长,并可能变得难以维护。因此,我
+们提供了一个默认定义(DEFAULT_SYMBOL_NAMESPACE),如果设置了这个定义, 它将成
+为所有没有指定命名空间的 EXPORT_SYMBOL() 和 EXPORT_SYMBOL_GPL() 宏扩展的默认
+定义。
+
+有多种方法来指定这个定义,使用哪种方法取决于子系统和维护者的喜好。第一种方法是在
+子系统的 ``Makefile`` 中定义默认命名空间。例如,如果要将usb-common中定义的所有符号导
+出到USB_COMMON命名空间,可以在drivers/usb/common/Makefile中添加这样一行::
+
+ ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=USB_COMMON
+
+这将影响所有 EXPORT_SYMBOL() 和 EXPORT_SYMBOL_GPL() 语句。当这个定义存在时,
+用EXPORT_SYMBOL_NS()导出的符号仍然会被导出到作为命名空间参数传递的命名空间中,
+因为这个参数优先于默认的符号命名空间。
+
+定义默认命名空间的第二个选项是直接在编译单元中作为预处理声明。上面的例子就会变
+成::
+
+ #undef DEFAULT_SYMBOL_NAMESPACE
+ #define DEFAULT_SYMBOL_NAMESPACE USB_COMMON
+
+应置于相关编译单元中任何 EXPORT_SYMBOL 宏之前
+
+3. 如何使用命名空间中导出的符号
+===============================
+
+为了使用被导出到命名空间的符号,内核模块需要明确地导入这些命名空间。
+否则内核可能会拒绝加载该模块。模块代码需要使用宏MODULE_IMPORT_NS来
+表示它所使用的命名空间的符号。例如,一个使用usb_stor_suspend符号的
+模块,需要使用如下语句导入命名空间USB_STORAGE::
+
+ MODULE_IMPORT_NS(USB_STORAGE);
+
+这将在模块中为每个导入的命名空间创建一个 ``modinfo`` 标签。这也顺带
+使得可以用modinfo检查模块已导入的命名空间::
+
+ $ modinfo drivers/usb/storage/ums-karma.ko
+ [...]
+ import_ns: USB_STORAGE
+ [...]
+
+
+建议将 MODULE_IMPORT_NS() 语句添加到靠近其他模块元数据定义的地方,
+如 MODULE_AUTHOR() 或 MODULE_LICENSE() 。关于自动创建缺失的导入
+语句的方法,请参考第5节。
+
+4. 加载使用命名空间符号的模块
+=============================
+
+在模块加载时(比如 ``insmod`` ),内核将检查每个从模块中引用的符号是否可
+用,以及它可能被导出到的名字空间是否被模块导入。内核的默认行为是拒绝
+加载那些没有指明足以导入的模块。此错误会被记录下来,并且加载将以
+EINVAL方式失败。要允许加载不满足这个前提条件的模块,可以使用此配置选项:
+设置 MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS=y 将使加载不受影响,但会
+发出警告。
+
+5. 自动创建MODULE_IMPORT_NS声明
+===============================
+
+缺少命名空间的导入可以在构建时很容易被检测到。事实上,如果一个模块
+使用了一个命名空间的符号而没有导入它,modpost会发出警告。
+MODULE_IMPORT_NS()语句通常会被添加到一个明确的位置(和其他模块元
+数据一起)。为了使模块作者(和子系统维护者)的生活更加轻松,我们提
+供了一个脚本和make目标来修复丢失的导入。修复丢失的导入可以用::
+
+ $ make nsdeps
+
+对模块作者来说,以下情况可能很典型::
+
+ - 编写依赖未导入命名空间的符号的代码
+ - ``make``
+ - 注意 ``modpost`` 的警告,提醒你有一个丢失的导入。
+ - 运行 ``make nsdeps``将导入添加到正确的代码位置。
+
+对于引入命名空间的子系统维护者来说,其步骤非常相似。同样,make nsdeps最终将
+为树内模块添加缺失的命名空间导入::
+
+ - 向命名空间转移或添加符号(例如,使用EXPORT_SYMBOL_NS())。
+ - `make e`(最好是用allmodconfig来覆盖所有的内核模块)。
+ - 注意 ``modpost`` 的警告,提醒你有一个丢失的导入。
+ - 运行 ``maknsdeps``将导入添加到正确的代码位置。
+
+你也可以为外部模块的构建运行nsdeps。典型的用法是::
+
+ $ make -C <path_to_kernel_src> M=$PWD nsdeps
diff --git a/Documentation/translations/zh_CN/core-api/this_cpu_ops.rst b/Documentation/translations/zh_CN/core-api/this_cpu_ops.rst
new file mode 100644
index 000000000000..bea5ee8eb8a0
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/this_cpu_ops.rst
@@ -0,0 +1,285 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/this_cpu_ops.rst
+
+:翻译:
+
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
+
+:校译:
+
+ 吴想成 Wu Xiangcheng <bobwxc@email.cn>
+
+============
+this_cpu操作
+============
+
+:作者: Christoph Lameter, 2014年8月4日
+:作者: Pranith Kumar, 2014年8月2日
+
+this_cpu操作是一种优化访问与当前执行处理器相关的每CPU变量的方法。这是通过使用段寄
+存器(或专用寄存器,cpu在其中永久存储特定处理器的每CPU区域的起始)来完成的。
+
+this_cpu操作将每CPU变量的偏移量添加到处理器特定的每CPU基址上,并将该操作编码到对
+每CPU变量进行操作的指令中。
+
+这意味着在偏移量的计算和对数据的操作之间不存在原子性问题。因此,没有必要禁用抢占
+或中断来确保处理器在计算地址和数据操作之间不被改变。
+
+读取-修改-写入操作特别值得关注。通常处理器具有特殊的低延迟指令,可以在没有典型同
+步开销的情况下运行,但仍提供某种宽松的原子性保证。例如,x86可以执行RMW(读取,
+修改,写入)指令,如同inc/dec/cmpxchg,而无需锁前缀和相关的延迟损失。
+
+对没有锁前缀的变量的访问是不同步的,也不需要同步,因为我们处理的是当前执行的处理
+器所特有的每CPU数据。只有当前的处理器可以访问该变量,因此系统中的其他处理器不存在
+并发性问题。
+
+请注意,远程处理器对每CPU区域的访问是特殊情况,可能会影响通过 ``this_cpu_*`` 的本
+地RMW操作的性能和正确性(远程写操作)。
+
+this_cpu操作的主要用途是优化计数器操作。
+
+定义了以下具有隐含抢占保护的this_cpu()操作。可以使用这些操作而不用担心抢占和中断::
+
+ this_cpu_read(pcp)
+ this_cpu_write(pcp, val)
+ this_cpu_add(pcp, val)
+ this_cpu_and(pcp, val)
+ this_cpu_or(pcp, val)
+ this_cpu_add_return(pcp, val)
+ this_cpu_xchg(pcp, nval)
+ this_cpu_cmpxchg(pcp, oval, nval)
+ this_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2)
+ this_cpu_sub(pcp, val)
+ this_cpu_inc(pcp)
+ this_cpu_dec(pcp)
+ this_cpu_sub_return(pcp, val)
+ this_cpu_inc_return(pcp)
+ this_cpu_dec_return(pcp)
+
+
+this_cpu操作的内部工作
+----------------------
+
+在x86上,fs:或gs:段寄存器包含每CPU区域的基址。这样就可以简单地使用段覆盖,将每CPU
+相对地址重定位到处理器适当的每CPU区域。所以对每CPU基址的重定位是通过段寄存器前缀
+在指令中编码完成的。
+
+例如::
+
+ DEFINE_PER_CPU(int, x);
+ int z;
+
+ z = this_cpu_read(x);
+
+产生的单指令为::
+
+ mov ax, gs:[x]
+
+而不是像每CPU操作那样,先是一系列的地址计算,然后从该地址获取。在this_cpu_ops之前,
+这样的序列还需要先禁用/启用抢占功能,以防止内核在计算过程中将线程移动到不同的处理
+器上。
+
+请思考下面this_cpu操作::
+
+ this_cpu_inc(x)
+
+这将产生如下单指令(无锁前缀!)::
+
+ inc gs:[x]
+
+而不是在没有段寄存器的情况下所需要的以下操作::
+
+ int *y;
+ int cpu;
+
+ cpu = get_cpu();
+ y = per_cpu_ptr(&x, cpu);
+ (*y)++;
+ put_cpu();
+
+请注意,这些操作只能用于为特定处理器保留的每CPU数据。如果不在上下文代码中禁用抢占,
+``this_cpu_inc()`` 将仅保证每CPU的某一个计数器被正确地递增,但不能保证操作系统不
+会在this_cpu指令执行的前后直接移动该进程。一般来说,这意味着每个处理器的单个计数
+器的值是没有意义的。所有每CPU计数器的总和才是唯一有意义的值。
+
+每CPU变量的使用是出于性能的考虑。如果多个处理器同时处理相同的代码路径,可以避免缓
+存行跳转。每个处理器都有自己的每CPU变量,因此不会发生并发缓存行更新。为这种优化必
+须付出的代价是,当需要计数器的值时要将每CPU计数器相加。
+
+
+特殊的操作
+----------
+
+::
+
+ y = this_cpu_ptr(&x)
+
+使用每CPU变量的偏移量(&x!),并返回属于当前执行处理器的每CPU变量的地址。
+``this_cpu_ptr`` 避免了通用 ``get_cpu``/``put_cpu`` 序列所需的多个步骤。没有可用
+的处理器编号。相反,本地每CPU区域的偏移量只是简单地添加到每CPU偏移量上。
+
+请注意,这个操作通常是在抢占被禁用后再在代码段中使用。然后该指针用来访问临界区中
+的本地每CPU数据。当重新启用抢占时,此指针通常不再有用,因为它可能不再指向当前处理
+器的每CPU数据。
+
+每CPU变量和偏移量
+-----------------
+
+每CPU变量相对于每CPU区域的起始点是有偏移的。它们没有地址,尽管代码里看起来像有一
+样。不能直接对偏移量解引用,必须用处理器每CPU区域基指针加上偏移量,以构成有效地址。
+
+因此,在每CPU操作的上下文之外使用x或&x是无效的,这种行为通常会被当作一个空指针的
+解引用来处理。
+
+::
+
+ DEFINE_PER_CPU(int, x);
+
+在每CPU操作的上下文中,上面表达式说明x是一个每CPU变量。大多数this_cpu操作都需要一
+个cpu变量。
+
+::
+
+ int __percpu *p = &x;
+
+&x和p是每CPU变量的偏移量。 ``this_cpu_ptr()`` 使用每CPU变量的偏移量,这让它看起来
+有点奇怪。
+
+
+每CPU结构体字段的操作
+---------------------
+
+假设我们有一个每CPU结构::
+
+ struct s {
+ int n,m;
+ };
+
+ DEFINE_PER_CPU(struct s, p);
+
+
+这些字段的操作非常简单::
+
+ this_cpu_inc(p.m)
+
+ z = this_cpu_cmpxchg(p.m, 0, 1);
+
+
+如果我们有一个相对于结构体s的偏移量::
+
+ struct s __percpu *ps = &p;
+
+ this_cpu_dec(ps->m);
+
+ z = this_cpu_inc_return(ps->n);
+
+
+如果我们后面不使用 ``this_cpu ops`` 来操作字段,则指针的计算可能需要使用
+``this_cpu_ptr()``::
+
+ struct s *pp;
+
+ pp = this_cpu_ptr(&p);
+
+ pp->m--;
+
+ z = pp->n++;
+
+
+this_cpu ops的变体
+------------------
+
+this_cpu的操作是中断安全的。一些架构不支持这些每CPU的本地操作。在这种情况下,该操
+作必须被禁用中断的代码所取代,然后做那些保证是原子的操作,再重新启用中断。当然这
+样做是很昂贵的。如果有其他原因导致调度器不能改变我们正在执行的处理器,那么就没有
+理由禁用中断了。为此,我们提供了以下__this_cpu操作。
+
+这些操作不能保证并发中断或抢占。如果在中断上下文中不使用每CPU变量并且调度程序无法
+抢占,那么它们是安全的。如果在操作进行时仍有中断发生,并且中断也修改了变量,则无
+法保证RMW操作是安全的::
+
+ __this_cpu_read(pcp)
+ __this_cpu_write(pcp, val)
+ __this_cpu_add(pcp, val)
+ __this_cpu_and(pcp, val)
+ __this_cpu_or(pcp, val)
+ __this_cpu_add_return(pcp, val)
+ __this_cpu_xchg(pcp, nval)
+ __this_cpu_cmpxchg(pcp, oval, nval)
+ __this_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2)
+ __this_cpu_sub(pcp, val)
+ __this_cpu_inc(pcp)
+ __this_cpu_dec(pcp)
+ __this_cpu_sub_return(pcp, val)
+ __this_cpu_inc_return(pcp)
+ __this_cpu_dec_return(pcp)
+
+
+将增加x,并且不会回退到在无法通过地址重定位和同一指令中的读取-修改-写入操作实现原
+子性的平台上禁用中断的代码。
+
+
+&this_cpu_ptr(pp)->n 对比 this_cpu_ptr(&pp->n)
+----------------------------------------------
+
+第一个操作使用偏移量并形成一个地址,然后再加上n字段的偏移量。这可能会导致编译器产
+生两条加法指令。
+
+第二个操作先加上两个偏移量,然后进行重定位。恕我直言,第二种形式看起来更干净,而
+且更容易与 ``()`` 结合。第二种形式也与 ``this_cpu_read()`` 和大家的使用方式一致。
+
+
+远程访问每CPU数据
+-----------------
+
+每CPU数据结构被设计为由一个CPU独占使用。如果您按预期使用变量,则 ``this_cpu_ops()``
+保证是 ``原子的`` ,因为没有其他CPU可以访问这些数据结构。
+
+在某些特殊情况下,您可能需要远程访问每CPU数据结构。通常情况下,进行远程读访问是安
+全的,这经常是为了统计计数器值。远程写访问可能会出现问题,因为this_cpu操作没有锁
+语义。远程写可能会干扰this_cpu RMW操作。
+
+除非绝对必要,否则强烈建议不要对每CPU数据结构进行远程写访问。请考虑使用IPI来唤醒
+远程CPU,并对其每CPU区域进行更新。
+
+要远程访问每CPU数据结构,通常使用 ``per_cpu_ptr()`` 函数::
+
+
+ DEFINE_PER_CPU(struct data, datap);
+
+ struct data *p = per_cpu_ptr(&datap, cpu);
+
+这清楚地表明,我们正准备远程访问每CPU区域。
+
+您还可以执行以下操作以将datap偏移量转换为地址::
+
+ struct data *p = this_cpu_ptr(&datap);
+
+但是,将通过this_cpu_ptr计算的指针传递给其他cpu是不寻常的,应该避免。
+
+远程访问通常只用于读取另一个cpu的每CPU数据状态。由于this_cpu操作宽松的同步要求,
+写访问可能会导致奇特的问题。
+
+下面的情况说明了写入操作的一些问题,由于两个每CPU变量共享一个缓存行,但宽松的同步
+仅应用于更新缓存行的一个进程。
+
+考虑以下示例::
+
+
+ struct test {
+ atomic_t a;
+ int b;
+ };
+
+ DEFINE_PER_CPU(struct test, onecacheline);
+
+如果一个处理器远程更新字段 ``a`` ,而本地处理器将使用this_cpu ops来更新字段 ``b`` ,
+会发生什么情况,这一点值得注意。应避免在同一缓存行内同时访问数据。此外,可能还需
+要进行代价高昂的同步。在这种情况下,通常建议使用IPI,而不是远程写入另一个处理器的
+每CPU区域。
+
+即使在远程写很少的情况下,请记住远程写将从最有可能访问它的处理器中逐出缓存行。如
+果处理器唤醒时发现每CPU区域缺少本地缓存行,其性能和唤醒时间将受到影响。
diff --git a/Documentation/translations/zh_CN/core-api/unaligned-memory-access.rst b/Documentation/translations/zh_CN/core-api/unaligned-memory-access.rst
new file mode 100644
index 000000000000..29c33e7e0855
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/unaligned-memory-access.rst
@@ -0,0 +1,229 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/unaligned-memory-access.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 时奎亮 <alexs@kernel.org>
+
+.. _cn_core-api_unaligned-memory-access:
+
+==============
+非对齐内存访问
+==============
+
+:作者: Daniel Drake <dsd@gentoo.org>,
+:作者: Johannes Berg <johannes@sipsolutions.net>
+
+:感谢他们的帮助: Alan Cox, Avuton Olrich, Heikki Orsila, Jan Engelhardt,
+ Kyle McMartin, Kyle Moffett, Randy Dunlap, Robert Hancock, Uli Kunitz,
+ Vadim Lobanov
+
+
+Linux运行在各种各样的架构上,这些架构在内存访问方面有不同的表现。本文介绍了一些
+关于不对齐访问的细节,为什么你需要编写不引起不对齐访问的代码,以及如何编写这样的
+代码
+
+
+非对齐访问的定义
+================
+
+当你试图从一个不被N偶数整除的地址(即addr % N != 0)开始读取N字节的数据时,就
+会发生无对齐内存访问。例如,从地址0x10004读取4个字节的数据是可以的,但从地址
+0x10005读取4个字节的数据将是一个不对齐的内存访问。
+
+上述内容可能看起来有点模糊,因为内存访问可以以不同的方式发生。这里的背景是在机器
+码层面上:某些指令在内存中读取或写入一些字节(例如x86汇编中的movb、movw、movl)。
+正如将变得清晰的那样,相对容易发现那些将编译为多字节内存访问指令的C语句,即在处理
+u16、u32和u64等类型时。
+
+
+自然对齐
+========
+
+上面提到的规则构成了我们所说的自然对齐。当访问N个字节的内存时,基础内存地址必须被
+N平均分割,即addr % N == 0。
+
+在编写代码时,假设目标架构有自然对齐的要求。
+
+在现实中,只有少数架构在所有大小的内存访问上都要求自然对齐。然而,我们必须考虑所
+有支持的架构;编写满足自然对齐要求的代码是实现完全可移植性的最简单方法。
+
+
+为什么非对齐访问时坏事
+======================
+
+执行非对齐内存访问的效果因架构不同而不同。在这里写一整篇关于这些差异的文档是很容
+易的;下面是对常见情况的总结:
+
+ - 一些架构能够透明地执行非对齐内存访问,但通常会有很大的性能代价。
+ - 当不对齐的访问发生时,一些架构会引发处理器异常。异常处理程序能够纠正不对齐的
+ 访问,但要付出很大的性能代价。
+ - 一些架构在发生不对齐访问时,会引发处理器异常,但异常中并没有包含足够的信息来
+ 纠正不对齐访问。
+ - 有些架构不能进行无对齐内存访问,但会默默地执行与请求不同的内存访问,从而导致
+ 难以发现的微妙的代码错误!
+
+从上文可以看出,如果你的代码导致不对齐的内存访问发生,那么你的代码在某些平台上将无
+法正常工作,在其他平台上将导致性能问题。
+
+不会导致非对齐访问的代码
+========================
+
+起初,上面的概念似乎有点难以与实际编码实践联系起来。毕竟,你对某些变量的内存地址没
+有很大的控制权,等等。
+
+幸运的是事情并不复杂,因为在大多数情况下,编译器会确保代码工作正常。例如,以下面的
+结构体为例::
+
+ struct foo {
+ u16 field1;
+ u32 field2;
+ u8 field3;
+ };
+
+让我们假设上述结构体的一个实例驻留在从地址0x10000开始的内存中。根据基本的理解,访问
+field2会导致非对齐访问,这并不是不合理的。你会期望field2位于该结构体的2个字节的偏移
+量,即地址0x10002,但该地址不能被4平均整除(注意,我们在这里读一个4字节的值)。
+
+幸运的是,编译器理解对齐约束,所以在上述情况下,它会在field1和field2之间插入2个字节
+的填充。因此,对于标准的结构体类型,你总是可以依靠编译器来填充结构体,以便对字段的访
+问可以适当地对齐(假设你没有将字段定义不同长度的类型)。
+
+同样,你也可以依靠编译器根据变量类型的大小,将变量和函数参数对齐到一个自然对齐的方案。
+
+在这一点上,应该很清楚,访问单个字节(u8或char)永远不会导致无对齐访问,因为所有的内
+存地址都可以被1均匀地整除。
+
+在一个相关的话题上,考虑到上述因素,你可以观察到,你可以对结构体中的字段进行重新排序,
+以便将字段放在不重排就会插入填充物的地方,从而减少结构体实例的整体常驻内存大小。上述
+例子的最佳布局是::
+
+ struct foo {
+ u32 field2;
+ u16 field1;
+ u8 field3;
+ };
+
+对于一个自然对齐方案,编译器只需要在结构的末尾添加一个字节的填充。添加这种填充是为了满
+足这些结构的数组的对齐约束。
+
+另一点值得一提的是在结构体类型上使用__attribute__((packed))。这个GCC特有的属性告诉编
+译器永远不要在结构体中插入任何填充,当你想用C结构体来表示一些“off the wire”的固定排列
+的数据时,这个属性很有用。
+
+你可能会倾向于认为,在访问不满足架构对齐要求的字段时,使用这个属性很容易导致不对齐的访
+问。然而,编译器也意识到了对齐的限制,并且会产生额外的指令来执行内存访问,以避免造成不
+对齐的访问。当然,与non-packed的情况相比,额外的指令显然会造成性能上的损失,所以packed
+属性应该只在避免结构填充很重要的时候使用。
+
+
+导致非对齐访问的代码
+====================
+
+考虑到上述情况,让我们来看看一个现实生活中可能导致非对齐内存访问的函数的例子。下面这个
+函数取自include/linux/etherdevice.h,是一个优化的例程,用于比较两个以太网MAC地址是否
+相等::
+
+ bool ether_addr_equal(const u8 *addr1, const u8 *addr2)
+ {
+ #ifdef 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
+ }
+
+在上述函数中,当硬件具有高效的非对齐访问能力时,这段代码没有问题。但是当硬件不能在任意
+边界上访问内存时,对a[0]的引用导致从地址addr1开始的2个字节(16位)被读取。
+
+想一想,如果addr1是一个奇怪的地址,如0x10003,会发生什么?(提示:这将是一个非对齐访
+问。)
+
+尽管上述函数存在潜在的非对齐访问问题,但它还是被包含在内核中,但被理解为只在16位对齐
+的地址上正常工作。调用者应该确保这种对齐方式或者根本不使用这个函数。这个不对齐的函数
+仍然是有用的,因为它是在你能确保对齐的情况下的一个很好的优化,这在以太网网络环境中几
+乎是一直如此。
+
+
+下面是另一个可能导致非对齐访问的代码的例子::
+
+ void myfunc(u8 *data, u32 value)
+ {
+ [...]
+ *((u32 *) data) = cpu_to_le32(value);
+ [...]
+ }
+
+每当数据参数指向的地址不被4均匀整除时,这段代码就会导致非对齐访问。
+
+综上所述,你可能遇到非对齐访问问题的两种主要情况包括:
+
+ 1. 将变量定义不同长度的类型
+ 2. 指针运算后访问至少2个字节的数据
+
+
+避免非对齐访问
+==============
+
+避免非对齐访问的最简单方法是使用<asm/unaligned.h>头文件提供的get_unaligned()和
+put_unaligned()宏。
+
+回到前面的一个可能导致非对齐访问的代码例子::
+
+ void myfunc(u8 *data, u32 value)
+ {
+ [...]
+ *((u32 *) data) = cpu_to_le32(value);
+ [...]
+ }
+
+为了避免非对齐的内存访问,你可以将其改写如下::
+
+ void myfunc(u8 *data, u32 value)
+ {
+ [...]
+ value = cpu_to_le32(value);
+ put_unaligned(value, (u32 *) data);
+ [...]
+ }
+
+get_unaligned()宏的工作原理与此类似。假设'data'是一个指向内存的指针,并且你希望避免
+非对齐访问,其用法如下::
+
+ u32 value = get_unaligned((u32 *) data);
+
+这些宏适用于任何长度的内存访问(不仅仅是上面例子中的32位)。请注意,与标准的对齐内存
+访问相比,使用这些宏来访问非对齐内存可能会在性能上付出代价。
+
+如果使用这些宏不方便,另一个选择是使用memcpy(),其中源或目标(或两者)的类型为u8*或
+非对齐char*。由于这种操作的字节性质,避免了非对齐访问。
+
+
+对齐 vs. 网络
+=============
+
+在需要对齐负载的架构上,网络要求IP头在四字节边界上对齐,以优化IP栈。对于普通的以太网
+硬件,常数NET_IP_ALIGN被使用。在大多数架构上,这个常数的值是2,因为正常的以太网头是
+14个字节,所以为了获得适当的对齐,需要DMA到一个可以表示为4*n+2的地址。一个值得注意的
+例外是powerpc,它将NET_IP_ALIGN定义为0,因为DMA到未对齐的地址可能非常昂贵,与未对齐
+的负载的成本相比相形见绌。
+
+对于一些不能DMA到未对齐地址的以太网硬件,如4*n+2或非以太网硬件,这可能是一个问题,这
+时需要将传入的帧复制到一个对齐的缓冲区。因为这在可以进行非对齐访问的架构上是不必要的,
+所以可以使代码依赖于CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS,像这样::
+
+ #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+ skb = original skb
+ #else
+ skb = copy skb
+ #endif
diff --git a/Documentation/translations/zh_CN/core-api/watch_queue.rst b/Documentation/translations/zh_CN/core-api/watch_queue.rst
new file mode 100644
index 000000000000..23b17ae2e4e2
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/watch_queue.rst
@@ -0,0 +1,313 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/watch_queue.rst
+
+:翻译:
+
+周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
+
+:校译:
+
+司延腾 Yanteng Si <siyanteng@loongson.cn>
+吴想成 Wu Xiangcheng <bobwxc@email.cn>
+
+
+============
+通用通知机制
+============
+
+通用通知机制是建立在标准管道驱动之上的,它可以有效地将来自内核的通知消息拼接到用
+户空间打开的管道中。这可以与以下方面结合使用::
+
+ * Key/keyring 通知
+
+通知缓冲区可以通过以下方式启用:
+
+ “General setup”/“General notification queue”
+ (CONFIG_WATCH_QUEUE)
+
+文档包含以下章节:
+
+.. contents:: :local:
+
+
+概述
+====
+
+该设施以一种特殊模式打开的管道形式出现,管道的内部环形缓冲区用于保存内核生成的消
+息。然后通过read()读出这些消息。在此类管道上禁用拼接以及类似的操作,因为它们希望
+在某些情况下将其添加的内容还原到环中-这可能最终会与通知消息重叠。
+
+管道的所有者必须告诉内核它想通过该管道观察哪些源。只有连接到该管道上的源才会将消
+息插入其中。请注意,一个源可能绑定到多个管道,并同时将消息插入到所有管道中。
+
+还可以将过滤器放置在管道上,以便在不感兴趣时可以忽略某些源类型和子事件。
+
+如果环中没有可用的插槽,或者没有预分配的消息缓冲区可用,则将丢弃消息。在这两种情
+况下,read()都会在读取缓冲区中当前的最后一条消息后,将WATCH_META_LOSS_NOTIFICATION
+插入到输出缓冲区中。
+
+请注意,当生成一个通知时,内核不会等待消费者收集它,而是继续执行。这意味着可以在
+持有自旋锁的同时生成通知,并且还可以保护内核不被用户空间故障无限期地阻碍。
+
+
+消息结构
+========
+
+通知消息由一个简短的头部开始::
+
+ struct watch_notification {
+ __u32 type:24;
+ __u32 subtype:8;
+ __u32 info;
+ };
+
+“type”表示通知记录的来源,“subtype”表示该来源的记录类型(见下文观测源章节)。该类
+型也可以是“WATCH_TYPE_META”。这是一个由观测队列本身在内部生成的特殊记录类型。有两
+个子类型:
+
+ * WATCH_META_REMOVAL_NOTIFICATION
+ * WATCH_META_LOSS_NOTIFICATION
+
+第一个表示安装了观察的对象已被删除或销毁,第二个表示某些消息已丢失。
+
+“info”表示一系列东西,包括:
+
+ * 消息的长度,以字节为单位,包括头(带有WATCH_INFO_LENGTH的掩码,并按
+ WATCH_INFO_LENGTH__SHIFT移位)。这表示记录的大小,可能在8到127字节之间。
+
+ * 观测ID(带有WATCH_INFO_ID掩码,并按WATCH_INFO_ID__SHIFT移位)。这表示观测的主
+ 叫ID,可能在0到255之间。多个观测组可以共享一个队列,这提供了一种区分它们的方法。
+
+ * 特定类型的字段(WATCH_INFO_TYPE_INFO)。这是由通知生产者设置的,以指示类型和
+ 子类型的某些特定含义。
+
+除长度外,信息中的所有内容都可以用于过滤。
+
+头部后面可以有补充信息。此格式是由类型和子类型决定的。
+
+
+观测列表(通知源)API
+=====================
+
+“观测列表“是订阅通知源的观测者的列表。列表可以附加到对象(比如键或超级块),也可
+以是全局的(比如对于设备事件)。从用户空间的角度来看,一个非全局的观测列表通常是
+通过引用它所属的对象来引用的(比如使用KEYCTL_NOTIFY并给它一个密钥序列号来观测特定
+的密钥)。
+
+为了管理观测列表,提供了以下函数:
+
+ * ::
+
+ void init_watch_list(struct watch_list *wlist,
+ void (*release_watch)(struct watch *wlist));
+
+ 初始化一个观测列表。 如果 ``release_watch`` 不是NULL,那么这表示当watch_list对
+ 象被销毁时,应该调用函数来丢弃观测列表对被观测对象的任何引用。
+
+ * ``void remove_watch_list(struct watch_list *wlist);``
+
+ 这将删除订阅watch_list的所有观测,并释放它们,然后销毁watch_list对象本身。
+
+
+观测队列(通知输出)API
+=======================
+
+“观测队列”是由应用程序分配的用以记录通知的缓冲区,其工作原理完全隐藏在管道设备驱
+动中,但必须获得对它的引用才能设置观测。可以通过以下方式进行管理:
+
+ * ``struct watch_queue *get_watch_queue(int fd);``
+
+ 由于观测队列在内核中通过实现缓冲区的管道的文件描述符表示,用户空间必须通过系
+ 统调用传递该文件描述符,这可以用于从系统调用中查找指向观测队列的不透明指针。
+
+ * ``void put_watch_queue(struct watch_queue *wqueue);``
+
+ 该函数用以丢弃从 ``get_watch_queue()`` 获得的引用。
+
+
+观测订阅API
+===========
+
+“观测”是观测列表上的订阅,表示观测队列,从而表示应写入通知记录的缓冲区。观测队列
+对象还可以携带该对象的过滤规则,由用户空间设置。watch结构体的某些部分可以由驱动程
+序设置::
+
+ struct watch {
+ union {
+ u32 info_id; /* 在info字段中进行OR运算的ID */
+ ...
+ };
+ void *private; /* 被观测对象的私有数据 */
+ u64 id; /* 内部标识符 */
+ ...
+ };
+
+``info_id`` 值是从用户空间获得并按WATCH_INFO_ID__SHIFT移位的8位数字。当通知写入关
+联的观测队列缓冲区时,这将与struct watch_notification::info的WATCH_INFO_ID字段进
+行或运算。
+
+``private`` 字段是与watch_list相关联的驱动程序数据,并由 ``watch_list::release_watch()``
+函数清除。
+
+``id`` 字段是源的ID。使用不同ID发布的通知将被忽略。
+
+提供以下函数来管理观测:
+
+ * ``void init_watch(struct watch *watch, struct watch_queue *wqueue);``
+
+ 初始化一个观测对象,把它的指针设置到观察队列中,使用适当的限制来避免死锁。
+
+ * ``int add_watch_to_object(struct watch *watch, struct watch_list *wlist);``
+
+ 将观测订阅到观测列表(通知源)。watch结构体中的driver-settable字段必须在调用
+ 它之前设置。
+
+ * ::
+
+ int remove_watch_from_object(struct watch_list *wlist,
+ struct watch_queue *wqueue,
+ u64 id, false);
+
+ 从观测列表中删除一个观测,该观测必须与指定的观测队列(``wqueue``)和对象标识
+ 符(``id``)匹配。通知(``WATCH_META_REMOVAL_NOTIFICATION``)被发送到观测队列
+ 表示该观测已被删除。
+
+ * ``int remove_watch_from_object(struct watch_list *wlist, NULL, 0, true);``
+
+ 从观测列表中删除所有观测。预计这将被称为销毁前的准备工作,届时新的观测将无法
+ 访问观测列表。通知(``WATCH_META_REMOVAL_NOTIFICATION``)被发送到每个订阅观测
+ 的观测队列,以表明该观测已被删除。
+
+
+通知发布API
+===========
+
+要将通知发布到观测列表以便订阅的观测可以看到,应使用以下函数::
+
+ void post_watch_notification(struct watch_list *wlist,
+ struct watch_notification *n,
+ const struct cred *cred,
+ u64 id);
+
+应预先设置通知格式,并应传入一个指向头部(``n``)的指针。通知可能大于此值,并且缓
+冲槽为单位的大小在 ``n->info & WATCH_INFO_LENGTH`` 中注明。
+
+``cred`` 结构体表示源(对象)的证书,并传递给LSM,例如SELinux,以允许或禁止根据该队
+列(对象)的证书在每个单独队列中记录注释。
+
+``id`` 是源对象ID(如密钥上的序列号)。只有设置相同ID的观测才能看到这个通知。
+
+
+观测源
+======
+
+任何特定的缓冲区都可以从多个源获取信息。 这些源包括:
+
+ * WATCH_TYPE_KEY_NOTIFY
+
+ 这种类型的通知表示密钥和密钥环的变化,包括密钥环内容或密钥属性的变化。
+
+ 更多信息请参见Documentation/security/keys/core.rst。
+
+
+事件过滤
+========
+
+当创建观测队列后,我们可以应用一组过滤器以限制接收的事件::
+
+ struct watch_notification_filter filter = {
+ ...
+ };
+ ioctl(fd, IOC_WATCH_QUEUE_SET_FILTER, &filter)
+
+过滤器的描述的类型变量是::
+
+ struct watch_notification_filter {
+ __u32 nr_filters;
+ __u32 __reserved;
+ struct watch_notification_type_filter filters[];
+ };
+
+其中“nr_filters”表示filters[]数组中过滤器的数量,而“__reserved”应为0。
+“filter”数组有以下类型的元素::
+
+ struct watch_notification_type_filter {
+ __u32 type;
+ __u32 info_filter;
+ __u32 info_mask;
+ __u32 subtype_filter[8];
+ };
+
+其中:
+
+ * ``type`` 是过滤的事件类型,应类似于“WATCH_TYPE_KEY_NOTIFY”。
+
+ * ``info_filter`` 与 ``info_mask`` 充当通知记录的信息字段的过滤器,只有在以下情
+ 况,通知才会写入缓冲区::
+
+ (watch.info & info_mask) == info_filter
+
+ 例如,这可以用于忽略不在一个挂载树上的观测点的事件。
+
+ * ``subtype_filter`` 是一个位掩码,表示感兴趣的子类型。subtype_filter[0]的
+ bit[0]对应子类型0,bit[1]对应子类型1,以此类推。
+
+若ioctl()的参数为NULL,则过滤器将被移除,并且来自观测源的所有事件都将通过。
+
+
+用户空间代码示例
+================
+
+缓冲区的创建如下所示::
+
+ pipe2(fds, O_TMPFILE);
+ ioctl(fds[1], IOC_WATCH_QUEUE_SET_SIZE, 256);
+
+它可以被设置成接收密钥环变化的通知::
+
+ keyctl(KEYCTL_WATCH_KEY, KEY_SPEC_SESSION_KEYRING, fds[1], 0x01);
+
+然后,这些通知可以被如下方式所使用::
+
+ static void consumer(int rfd, struct watch_queue_buffer *buf)
+ {
+ unsigned char buffer[128];
+ ssize_t buf_len;
+
+ while (buf_len = read(rfd, buffer, sizeof(buffer)),
+ buf_len > 0
+ ) {
+ void *p = buffer;
+ void *end = buffer + buf_len;
+ while (p < end) {
+ union {
+ struct watch_notification n;
+ unsigned char buf1[128];
+ } n;
+ size_t largest, len;
+
+ largest = end - p;
+ if (largest > 128)
+ largest = 128;
+ memcpy(&n, p, largest);
+
+ len = (n->info & WATCH_INFO_LENGTH) >>
+ WATCH_INFO_LENGTH__SHIFT;
+ if (len == 0 || len > largest)
+ return;
+
+ switch (n.n.type) {
+ case WATCH_TYPE_META:
+ got_meta(&n.n);
+ case WATCH_TYPE_KEY_NOTIFY:
+ saw_key_change(&n.n);
+ break;
+ }
+
+ p += len;
+ }
+ }
+ }
diff --git a/Documentation/translations/zh_CN/core-api/workqueue.rst b/Documentation/translations/zh_CN/core-api/workqueue.rst
new file mode 100644
index 000000000000..7fac6f75d078
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/workqueue.rst
@@ -0,0 +1,352 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/workqueue.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
+
+.. _cn_workqueue.rst:
+
+=========================
+并发管理的工作队列 (cmwq)
+=========================
+
+:日期: September, 2010
+:作者: Tejun Heo <tj@kernel.org>
+:作者: Florian Mickler <florian@mickler.org>
+
+
+简介
+====
+
+在很多情况下,需要一个异步进程的执行环境,工作队列(wq)API是这种情况下
+最常用的机制。
+
+当需要这样一个异步执行上下文时,一个描述将要执行的函数的工作项(work,
+即一个待执行的任务)被放在队列中。一个独立的线程作为异步执行环境。该队
+列被称为workqueue,线程被称为工作者(worker,即执行这一队列的线程)。
+
+当工作队列上有工作项时,工作者会一个接一个地执行与工作项相关的函数。当
+工作队列中没有任何工作项时,工作者就会变得空闲。当一个新的工作项被排入
+队列时,工作者又开始执行。
+
+
+为什么要cmwq?
+=============
+
+在最初的wq实现中,多线程(MT)wq在每个CPU上有一个工作者线程,而单线程
+(ST)wq在全系统有一个工作者线程。一个MT wq需要保持与CPU数量相同的工
+作者数量。这些年来,内核增加了很多MT wq的用户,随着CPU核心数量的不断
+增加,一些系统刚启动就达到了默认的32k PID的饱和空间。
+
+尽管MT wq浪费了大量的资源,但所提供的并发性水平却不能令人满意。这个限
+制在ST和MT wq中都有,只是在MT中没有那么严重。每个wq都保持着自己独立的
+工作者池。一个MT wq只能为每个CPU提供一个执行环境,而一个ST wq则为整个
+系统提供一个。工作项必须竞争这些非常有限的执行上下文,从而导致各种问题,
+包括在单一执行上下文周围容易发生死锁。
+
+(MT wq)所提供的并发性水平和资源使用之间的矛盾也迫使其用户做出不必要的权衡,比
+如libata选择使用ST wq来轮询PIO,并接受一个不必要的限制,即没有两个轮
+询PIO可以同时进行。由于MT wq并没有提供更好的并发性,需要更高层次的并
+发性的用户,如async或fscache,不得不实现他们自己的线程池。
+
+并发管理工作队列(cmwq)是对wq的重新实现,重点是以下目标。
+
+* 保持与原始工作队列API的兼容性。
+
+* 使用由所有wq共享的每CPU统一的工作者池,在不浪费大量资源的情况下按
+* 需提供灵活的并发水平。
+
+* 自动调节工作者池和并发水平,使API用户不需要担心这些细节。
+
+
+设计
+====
+
+为了简化函数的异步执行,引入了一个新的抽象概念,即工作项。
+
+一个工作项是一个简单的结构,它持有一个指向将被异步执行的函数的指针。
+每当一个驱动程序或子系统希望一个函数被异步执行时,它必须建立一个指
+向该函数的工作项,并在工作队列中排队等待该工作项。(就是挂到workqueue
+队列里面去)
+
+特定目的线程,称为工作线程(工作者),一个接一个地执行队列中的功能。
+如果没有工作项排队,工作者线程就会闲置。这些工作者线程被管理在所谓
+的工作者池中。
+
+cmwq设计区分了面向用户的工作队列,子系统和驱动程序在上面排队工作,
+以及管理工作者池和处理排队工作项的后端机制。
+
+每个可能的CPU都有两个工作者池,一个用于正常的工作项,另一个用于高
+优先级的工作项,还有一些额外的工作者池,用于服务未绑定工作队列的工
+作项目——这些后备池的数量是动态的。
+
+当他们认为合适的时候,子系统和驱动程序可以通过特殊的
+``workqueue API`` 函数创建和排队工作项。他们可以通过在工作队列上
+设置标志来影响工作项执行方式的某些方面,他们把工作项放在那里。这些
+标志包括诸如CPU定位、并发限制、优先级等等。要获得详细的概述,请参
+考下面的 ``alloc_workqueue()`` 的 API 描述。
+
+当一个工作项被排入一个工作队列时,目标工作池将根据队列参数和工作队
+列属性确定,并被附加到工作池的共享工作列表上。例如,除非特别重写,
+否则一个绑定的工作队列的工作项将被排在与发起线程运行的CPU相关的普
+通或高级工作工作者池的工作项列表中。
+
+对于任何工作者池的实施,管理并发水平(有多少执行上下文处于活动状
+态)是一个重要问题。最低水平是为了节省资源,而饱和水平是指系统被
+充分使用。
+
+每个与实际CPU绑定的worker-pool通过钩住调度器来实现并发管理。每当
+一个活动的工作者被唤醒或睡眠时,工作者池就会得到通知,并跟踪当前可
+运行的工作者的数量。一般来说,工作项不会占用CPU并消耗很多周期。这
+意味着保持足够的并发性以防止工作处理停滞应该是最优的。只要CPU上有
+一个或多个可运行的工作者,工作者池就不会开始执行新的工作,但是,当
+最后一个运行的工作者进入睡眠状态时,它会立即安排一个新的工作者,这
+样CPU就不会在有待处理的工作项目时闲置。这允许在不损失执行带宽的情
+况下使用最少的工作者。
+
+除了kthreads的内存空间外,保留空闲的工作者并没有其他成本,所以cmwq
+在杀死它们之前会保留一段时间的空闲。
+
+对于非绑定的工作队列,后备池的数量是动态的。可以使用
+``apply_workqueue_attrs()`` 为非绑定工作队列分配自定义属性,
+workqueue将自动创建与属性相匹配的后备工作者池。调节并发水平的责任在
+用户身上。也有一个标志可以将绑定的wq标记为忽略并发管理。
+详情请参考API部分。
+
+前进进度的保证依赖于当需要更多的执行上下文时可以创建工作者,这也是
+通过使用救援工作者来保证的。所有可能在处理内存回收的代码路径上使用
+的工作项都需要在wq上排队,wq上保留了一个救援工作者,以便在内存有压
+力的情况下下执行。否则,工作者池就有可能出现死锁,等待执行上下文释
+放出来。
+
+
+应用程序编程接口 (API)
+======================
+
+``alloc_workqueue()`` 分配了一个wq。原来的 ``create_*workqueue()``
+函数已被废弃,并计划删除。 ``alloc_workqueue()`` 需要三个
+参数 - ``@name`` , ``@flags`` 和 ``@max_active`` 。
+``@name`` 是wq的名称,如果有的话,也用作救援线程的名称。
+
+一个wq不再管理执行资源,而是作为前进进度保证、刷新(flush)和
+工作项属性的域。 ``@flags`` 和 ``@max_active`` 控制着工作
+项如何被分配执行资源、安排和执行。
+
+
+``flags``
+---------
+
+``WQ_UNBOUND``
+ 排队到非绑定wq的工作项由特殊的工作者池提供服务,这些工作者不
+ 绑定在任何特定的CPU上。这使得wq表现得像一个简单的执行环境提
+ 供者,没有并发管理。非绑定工作者池试图尽快开始执行工作项。非
+ 绑定的wq牺牲了局部性,但在以下情况下是有用的。
+
+ * 预计并发水平要求会有很大的波动,使用绑定的wq最终可能会在不
+ 同的CPU上产生大量大部分未使用的工作者,因为发起线程在不同
+ 的CPU上跳转。
+
+ * 长期运行的CPU密集型工作负载,可以由系统调度器更好地管理。
+
+``WQ_FREEZABLE``
+ 一个可冻结的wq参与了系统暂停操作的冻结阶段。wq上的工作项被
+ 排空,在解冻之前没有新的工作项开始执行。
+
+``WQ_MEM_RECLAIM``
+ 所有可能在内存回收路径中使用的wq都必须设置这个标志。无论内
+ 存压力如何,wq都能保证至少有一个执行上下文。
+
+``WQ_HIGHPRI``
+ 高优先级wq的工作项目被排到目标cpu的高优先级工作者池中。高
+ 优先级的工作者池由具有较高级别的工作者线程提供服务。
+
+ 请注意,普通工作者池和高优先级工作者池之间并不相互影响。他
+ 们各自维护其独立的工作者池,并在其工作者之间实现并发管理。
+
+``WQ_CPU_INTENSIVE``
+ CPU密集型wq的工作项对并发水平没有贡献。换句话说,可运行的
+ CPU密集型工作项不会阻止同一工作者池中的其他工作项开始执行。
+ 这对于那些预计会占用CPU周期的绑定工作项很有用,这样它们的
+ 执行就会受到系统调度器的监管。
+
+ 尽管CPU密集型工作项不会对并发水平做出贡献,但它们的执行开
+ 始仍然受到并发管理的管制,可运行的非CPU密集型工作项会延迟
+ CPU密集型工作项的执行。
+
+ 这个标志对于未绑定的wq来说是没有意义的。
+
+
+``max_active``
+--------------
+
+``@max_active`` 决定了每个CPU可以分配给wq的工作项的最大执行上
+下文数量。例如,如果 ``@max_active为16`` ,每个CPU最多可以同
+时执行16个wq的工作项。
+
+目前,对于一个绑定的wq, ``@max_active`` 的最大限制是512,当指
+定为0时使用的默认值是256。对于非绑定的wq,其限制是512和
+4 * ``num_possible_cpus()`` 中的较高值。这些值被选得足够高,所
+以它们不是限制性因素,同时会在失控情况下提供保护。
+
+一个wq的活动工作项的数量通常由wq的用户来调节,更具体地说,是由用
+户在同一时间可以排列多少个工作项来调节。除非有特定的需求来控制活动
+工作项的数量,否则建议指定 为"0"。
+
+一些用户依赖于ST wq的严格执行顺序。 ``@max_active`` 为1和 ``WQ_UNBOUND``
+的组合用来实现这种行为。这种wq上的工作项目总是被排到未绑定的工作池
+中,并且在任何时候都只有一个工作项目处于活动状态,从而实现与ST wq相
+同的排序属性。
+
+在目前的实现中,上述配置只保证了特定NUMA节点内的ST行为。相反,
+``alloc_ordered_workqueue()`` 应该被用来实现全系统的ST行为。
+
+
+执行场景示例
+============
+
+下面的示例执行场景试图说明cmwq在不同配置下的行为。
+
+ 工作项w0、w1、w2被排到同一个CPU上的一个绑定的wq q0上。w0
+ 消耗CPU 5ms,然后睡眠10ms,然后在完成之前再次消耗CPU 5ms。
+
+忽略所有其他的任务、工作和处理开销,并假设简单的FIFO调度,
+下面是一个高度简化的原始wq的可能事件序列的版本。::
+
+ TIME IN MSECS EVENT
+ 0 w0 starts and burns CPU
+ 5 w0 sleeps
+ 15 w0 wakes up and burns CPU
+ 20 w0 finishes
+ 20 w1 starts and burns CPU
+ 25 w1 sleeps
+ 35 w1 wakes up and finishes
+ 35 w2 starts and burns CPU
+ 40 w2 sleeps
+ 50 w2 wakes up and finishes
+
+And with cmwq with ``@max_active`` >= 3, ::
+
+ TIME IN MSECS EVENT
+ 0 w0 starts and burns CPU
+ 5 w0 sleeps
+ 5 w1 starts and burns CPU
+ 10 w1 sleeps
+ 10 w2 starts and burns CPU
+ 15 w2 sleeps
+ 15 w0 wakes up and burns CPU
+ 20 w0 finishes
+ 20 w1 wakes up and finishes
+ 25 w2 wakes up and finishes
+
+如果 ``@max_active`` == 2, ::
+
+ TIME IN MSECS EVENT
+ 0 w0 starts and burns CPU
+ 5 w0 sleeps
+ 5 w1 starts and burns CPU
+ 10 w1 sleeps
+ 15 w0 wakes up and burns CPU
+ 20 w0 finishes
+ 20 w1 wakes up and finishes
+ 20 w2 starts and burns CPU
+ 25 w2 sleeps
+ 35 w2 wakes up and finishes
+
+现在,我们假设w1和w2被排到了不同的wq q1上,这个wq q1
+有 ``WQ_CPU_INTENSIVE`` 设置::
+
+ TIME IN MSECS EVENT
+ 0 w0 starts and burns CPU
+ 5 w0 sleeps
+ 5 w1 and w2 start and burn CPU
+ 10 w1 sleeps
+ 15 w2 sleeps
+ 15 w0 wakes up and burns CPU
+ 20 w0 finishes
+ 20 w1 wakes up and finishes
+ 25 w2 wakes up and finishes
+
+
+指南
+====
+
+* 如果一个wq可能处理在内存回收期间使用的工作项目,请不
+ 要忘记使用 ``WQ_MEM_RECLAIM`` 。每个设置了
+ ``WQ_MEM_RECLAIM`` 的wq都有一个为其保留的执行环境。
+ 如果在内存回收过程中使用的多个工作项之间存在依赖关系,
+ 它们应该被排在不同的wq中,每个wq都有 ``WQ_MEM_RECLAIM`` 。
+
+* 除非需要严格排序,否则没有必要使用ST wq。
+
+* 除非有特殊需要,建议使用0作为@max_active。在大多数使用情
+ 况下,并发水平通常保持在默认限制之下。
+
+* 一个wq作为前进进度保证(WQ_MEM_RECLAIM,冲洗(flush)和工
+ 作项属性的域。不涉及内存回收的工作项,不需要作为工作项组的一
+ 部分被刷新,也不需要任何特殊属性,可以使用系统中的一个wq。使
+ 用专用wq和系统wq在执行特性上没有区别。
+
+* 除非工作项预计会消耗大量的CPU周期,否则使用绑定的wq通常是有
+ 益的,因为wq操作和工作项执行中的定位水平提高了。
+
+
+调试
+====
+
+因为工作函数是由通用的工作者线程执行的,所以需要一些手段来揭示一些行为不端的工作队列用户。
+
+工作者线程在进程列表中显示为: ::
+
+ root 5671 0.0 0.0 0 0 ? S 12:07 0:00 [kworker/0:1]
+ root 5672 0.0 0.0 0 0 ? S 12:07 0:00 [kworker/1:2]
+ root 5673 0.0 0.0 0 0 ? S 12:12 0:00 [kworker/0:0]
+ root 5674 0.0 0.0 0 0 ? S 12:13 0:00 [kworker/1:0]
+
+如果kworkers失控了(使用了太多的cpu),有两类可能的问题:
+
+ 1. 正在迅速调度的事情
+ 2. 一个消耗大量cpu周期的工作项。
+
+第一个可以用追踪的方式进行跟踪: ::
+
+ $ echo workqueue:workqueue_queue_work > /sys/kernel/tracing/set_event
+ $ cat /sys/kernel/tracing/trace_pipe > out.txt
+ (wait a few secs)
+
+如果有什么东西在工作队列上忙着做循环,它就会主导输出,可以用工作项函数确定违规者。
+
+对于第二类问题,应该可以只检查违规工作者线程的堆栈跟踪。 ::
+
+ $ cat /proc/THE_OFFENDING_KWORKER/stack
+
+工作项函数在堆栈追踪中应该是微不足道的。
+
+不可重入条件
+============
+
+工作队列保证,如果在工作项排队后满足以下条件,则工作项不能重入:
+
+
+ 1. 工作函数没有被改变。
+ 2. 没有人将该工作项排到另一个工作队列中。
+ 3. 该工作项尚未被重新启动。
+
+换言之,如果上述条件成立,则保证在任何给定时间最多由一个系统范围内的工作程序执行
+该工作项。
+
+请注意,在self函数中将工作项重新排队(到同一队列)不会破坏这些条件,因此可以安全
+地执行此操作。否则在破坏工作函数内部的条件时需要小心。
+
+
+内核内联文档参考
+================
+
+该API在以下内核代码中:
+
+include/linux/workqueue.h
+
+kernel/workqueue.c
diff --git a/Documentation/translations/zh_CN/core-api/xarray.rst b/Documentation/translations/zh_CN/core-api/xarray.rst
new file mode 100644
index 000000000000..fb19324966ce
--- /dev/null
+++ b/Documentation/translations/zh_CN/core-api/xarray.rst
@@ -0,0 +1,373 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/xarray.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
+
+:校译:
+
+
+
+.. _cn_core-api_xarray:
+
+======
+XArray
+======
+
+:作者: Matthew Wilcox
+
+概览
+====
+
+XArray是一个抽象的数据类型,它的行为就像一个非常大的指针数组。它满足了许多与哈
+希或传统可调整大小的数组相同的需求。与哈希不同的是,它允许你以一种高效的缓存方
+式合理地转到下一个或上一个条目。与可调整大小的数组相比,不需要复制数据或改变MMU
+的映射来增加数组。与双链表相比,它的内存效率更高,可并行,对缓存更友好。它利用
+RCU的优势来执行查找而不需要锁定。
+
+当使用的索引是密集聚集的时候,XArray的实现是有效的;而哈希对象并使用哈希作为索引
+将不会有好的表现。XArray对小的索引进行了优化,不过对大的索引仍有良好的性能。如果
+你的索引可以大于 ``ULONG_MAX`` ,那么XArray就不适合你的数据类型。XArray最重要
+的用户是页面高速缓存。
+
+普通指针可以直接存储在XArray中。它们必须是4字节对齐的,这对任何从kmalloc()和
+alloc_page()返回的指针来说都是如此。这对任意的用户空间指针和函数指针来说都不是
+真的。你可以存储指向静态分配对象的指针,只要这些对象的对齐方式至少是4(字节)。
+
+你也可以在XArray中存储0到 ``LONG_MAX`` 之间的整数。你必须首先使用xa_mk_value()
+将其转换为一个条目。当你从XArray中检索一个条目时,你可以通过调用xa_is_value()检
+查它是否是一个值条目,并通过调用xa_to_value()将它转换回一个整数。
+
+一些用户希望对他们存储在XArray中的指针进行标记。你可以调用xa_tag_pointer()来创建
+一个带有标签的条目,xa_untag_pointer()将一个有标签的条目转回一个无标签的指针,
+xa_pointer_tag()来检索一个条目的标签。标签指针使用相同的位,用于区分值条目和普通
+指针,所以你必须决定他们是否要在任何特定的XArray中存储值条目或标签指针。
+
+XArray不支持存储IS_ERR()指针,因为有些指针与值条目或内部条目冲突。
+
+XArray的一个不寻常的特点是能够创建占据一系列索引的条目。一旦存储到其中,查询该范围
+内的任何索引将返回与查询该范围内任何其他索引相同的条目。存储到任何索引都会存储所有
+的索引条目。多索引条目可以明确地分割成更小的条目,或者将其存储 ``NULL`` 到任何条目中
+都会使XArray忘记范围。
+
+普通API
+=======
+
+首先初始化一个XArray,对于静态分配的XArray可以用DEFINE_XARRAY(),对于动态分配的
+XArray可以用xa_init()。一个新初始化的XArray在每个索引处都包含一个 ``NULL`` 指针。
+
+然后你可以用xa_store()来设置条目,用xa_load()来获取条目。xa_store将用新的条目覆盖任
+何条目,并返回存储在该索引的上一个条目。你可以使用xa_erase()来代替调用xa_store()的
+``NULL`` 条目。一个从未被存储过的条目、一个被擦除的条目和一个最近被存储过 ``NULL`` 的
+条目之间没有区别。
+
+你可以通过使用xa_cmpxchg()有条件地替换一个索引中的条目。和cmpxchg()一样,它只有在该索
+引的条目有 ‘旧‘ 值时才会成功。它也会返回该索引上的条目;如果它返回与传递的 ‘旧‘ 相同的条
+目,那么xa_cmpxchg()就成功了。
+
+如果你只想在某个索引的当前条目为 ``NULL`` 时将一个新条目存储到该索引,你可以使用xa_insert(),
+如果该条目不是空的,则返回 ``-EBUSY`` 。
+
+你可以通过调用xa_extract()将条目从XArray中复制到一个普通数组中。或者你可以通过调用
+xa_for_each()、xa_for_each_start()或xa_for_each_range()来遍历XArray中的现有条目。你
+可能更喜欢使用xa_find()或xa_find_after()来移动到XArray中的下一个当前条目。
+
+调用xa_store_range()可以在一个索引范围内存储同一个条目。如果你这样做,其他的一些操作将以
+一种稍微奇怪的方式进行。例如,在一个索引上标记条目可能会导致该条目在一些,但不是所有其他索
+引上被标记。储存到一个索引中可能会导致由一些,但不是所有其他索引检索的条目发生变化。
+
+有时你需要确保对xa_store()的后续调用将不需要分配内存。xa_reserve()函数将在指定索引处存储
+一个保留条目。普通API的用户将看到这个条目包含 ``NULL`` 。如果你不需要使用保留的条目,你可
+以调用xa_release()来删除这个未使用的条目。如果在此期间有其他用户存储到该条目,xa_release()
+将不做任何事情;相反,如果你想让该条目变成 ``NULL`` ,你应该使用xa_erase()。在一个保留的条
+目上使用xa_insert()将会失败。
+
+如果数组中的所有条目都是 ``NULL`` ,xa_empty()函数将返回 ``true`` 。
+
+最后,你可以通过调用xa_destroy()删除XArray中的所有条目。如果XArray的条目是指针,你可能希望
+先释放这些条目。你可以通过使用xa_for_each()迭代器遍历XArray中所有存在的条目来实现这一目的。
+
+搜索标记
+--------
+
+数组中的每个条目都有三个与之相关的位,称为标记。每个标记可以独立于其他标记被设置或清除。你可以
+通过使用xa_for_each_marked()迭代器来迭代有标记的条目。
+
+你可以通过使用xa_get_mark()来查询某个条目是否设置了标记。如果该条目不是 ``NULL`` ,你可以通过
+使用xa_set_mark()来设置一个标记,并通过调用xa_clear_mark()来删除条目上的标记。你可以通过调用
+xa_marked()来询问XArray中的任何条目是否有一个特定的标记被设置。从XArray中删除一个条目会导致与
+该条目相关的所有标记被清除。
+
+在一个多索引条目的任何索引上设置或清除标记将影响该条目所涵盖的所有索引。查询任何索引上的标记将返
+回相同的结果。
+
+没有办法对没有标记的条目进行迭代;数据结构不允许有效地实现这一点。目前没有迭代器来搜索比特的逻辑
+组合(例如迭代所有同时设置了 ``XA_MARK_1`` 和 ``XA_MARK_2`` 的条目,或者迭代所有设置了
+``XA_MARK_0`` 或 ``XA_MARK_2`` 的条目)。如果有用户需要,可以增加这些内容。
+
+分配XArrays
+-----------
+
+如果你使用DEFINE_XARRAY_ALLOC()来定义XArray,或者通过向xa_init_flags()传递 ``XA_FLAGS_ALLOC``
+来初始化它,XArray会改变以跟踪条目是否被使用。
+
+你可以调用xa_alloc()将条目存储在XArray中一个未使用的索引上。如果你需要从中断上下文中修改数组,你
+可以使用xa_alloc_bh()或xa_alloc_irq(),在分配ID的同时禁用中断。
+
+使用xa_store()、xa_cmpxchg()或xa_insert()也将标记该条目为正在分配。与普通的XArray不同,存储 ``NULL``
+将标记该条目为正在使用中,就像xa_reserve()。要释放一个条目,请使用xa_erase()(或者xa_release(),
+如果你只想释放一个 ``NULL`` 的条目)。
+
+默认情况下,最低的空闲条目从0开始分配。如果你想从1开始分配条目,使用DEFINE_XARRAY_ALLOC1()或
+``XA_FLAGS_ALLOC1`` 会更有效。如果你想分配ID到一个最大值,然后绕回最低的空闲ID,你可以使用
+xa_alloc_cyclic()。
+
+你不能在分配的XArray中使用 ``XA_MARK_0`` ,因为这个标记是用来跟踪一个条目是否是空闲的。其他的
+标记可以供你使用。
+
+内存分配
+--------
+
+xa_store(), xa_cmpxchg(), xa_alloc(), xa_reserve()和xa_insert()函数接受一个gfp_t参数,以
+防XArray需要分配内存来存储这个条目。如果该条目被删除,则不需要进行内存分配,指定的GFP标志将被忽
+略。
+
+没有内存可供分配是可能的,特别是如果你传递了一组限制性的GFP标志。在这种情况下,这些函数会返回一
+个特殊的值,可以用xa_err()把它变成一个错误值。如果你不需要确切地知道哪个错误发生,使用xa_is_err()
+会更有效一些。
+
+锁
+--
+
+当使用普通API时,你不必担心锁的问题。XArray使用RCU和一个内部自旋锁来同步访问:
+
+不需要锁:
+ * xa_empty()
+ * xa_marked()
+
+采取RCU读锁:
+ * xa_load()
+ * xa_for_each()
+ * xa_for_each_start()
+ * xa_for_each_range()
+ * xa_find()
+ * xa_find_after()
+ * xa_extract()
+ * xa_get_mark()
+
+内部使用xa_lock:
+ * xa_store()
+ * xa_store_bh()
+ * xa_store_irq()
+ * xa_insert()
+ * xa_insert_bh()
+ * xa_insert_irq()
+ * xa_erase()
+ * xa_erase_bh()
+ * xa_erase_irq()
+ * xa_cmpxchg()
+ * xa_cmpxchg_bh()
+ * xa_cmpxchg_irq()
+ * xa_store_range()
+ * xa_alloc()
+ * xa_alloc_bh()
+ * xa_alloc_irq()
+ * xa_reserve()
+ * xa_reserve_bh()
+ * xa_reserve_irq()
+ * xa_destroy()
+ * xa_set_mark()
+ * xa_clear_mark()
+
+假设进入时持有xa_lock:
+ * __xa_store()
+ * __xa_insert()
+ * __xa_erase()
+ * __xa_cmpxchg()
+ * __xa_alloc()
+ * __xa_set_mark()
+ * __xa_clear_mark()
+
+如果你想利用锁来保护你存储在XArray中的数据结构,你可以在调用xa_load()之前调用xa_lock(),然后在
+调用xa_unlock()之前对你找到的对象进行一个引用计数。这将防止存储操作在查找对象和增加refcount期间
+从数组中删除对象。你也可以使用RCU来避免解除对已释放内存的引用,但对这一点的解释已经超出了本文的范
+围。
+
+在修改数组时,XArray不会禁用中断或softirqs。从中断或softirq上下文中读取XArray是安全的,因为RCU锁
+提供了足够的保护。
+
+例如,如果你想在进程上下文中存储XArray中的条目,然后在softirq上下文中擦除它们,你可以这样做::
+
+ void foo_init(struct foo *foo)
+ {
+ xa_init_flags(&foo->array, XA_FLAGS_LOCK_BH);
+ }
+
+ int foo_store(struct foo *foo, unsigned long index, void *entry)
+ {
+ int err;
+
+ xa_lock_bh(&foo->array);
+ err = xa_err(__xa_store(&foo->array, index, entry, GFP_KERNEL));
+ if (!err)
+ foo->count++;
+ xa_unlock_bh(&foo->array);
+ return err;
+ }
+
+ /* foo_erase()只在软中断上下文中调用 */
+ void foo_erase(struct foo *foo, unsigned long index)
+ {
+ xa_lock(&foo->array);
+ __xa_erase(&foo->array, index);
+ foo->count--;
+ xa_unlock(&foo->array);
+ }
+
+如果你要从中断或softirq上下文中修改XArray,你需要使用xa_init_flags()初始化数组,传递
+``XA_FLAGS_LOCK_IRQ`` 或 ``XA_FLAGS_LOCK_BH`` (参数)。
+
+上面的例子还显示了一个常见的模式,即希望在存储端扩展xa_lock的覆盖范围,以保护与数组相关的一些统计
+数据。
+
+与中断上下文共享XArray也是可能的,可以在中断处理程序和进程上下文中都使用xa_lock_irqsave(),或者
+在进程上下文中使用xa_lock_irq(),在中断处理程序中使用xa_lock()。一些更常见的模式有一些辅助函数,
+如xa_store_bh()、xa_store_irq()、xa_erase_bh()、xa_erase_irq()、xa_cmpxchg_bh() 和xa_cmpxchg_irq()。
+
+有时你需要用一个mutex来保护对XArray的访问,因为这个锁在锁的层次结构中位于另一个mutex之上。这并不
+意味着你有权使用像__xa_erase()这样的函数而不占用xa_lock;xa_lock是用来进行lockdep验证的,将来也
+会用于其他用途。
+
+__xa_set_mark() 和 __xa_clear_mark() 函数也适用于你查找一个条目并想原子化地设置或清除一个标记的
+情况。在这种情况下,使用高级API可能更有效,因为它将使你免于走两次树。
+
+高级API
+=======
+
+高级API提供了更多的灵活性和更好的性能,但代价是接口可能更难使用,保障措施更少。高级API没有为你加锁,
+你需要在修改数组的时候使用xa_lock。在对数组进行只读操作时,你可以选择使用xa_lock或RCU锁。你可以在
+同一个数组上混合使用高级和普通操作;事实上,普通API是以高级API的形式实现的。高级API只对具有GPL兼容
+许可证的模块可用。
+
+高级API是基于xa_state的。这是一个不透明的数据结构,你使用XA_STATE()宏在堆栈中声明。这个宏初始化了
+xa_state,准备开始在XArray上移动。它被用作一个游标来保持在XArray中的位置,并让你把各种操作组合在一
+起,而不必每次都从头开始。xa_state的内容受rcu_read_lock()或xas_lock()的保护。如果需要删除保护状态
+和树的这些锁中的任何一个,你必须调用xas_pause()以便将来的调用不会依赖于状态中未受保护的部分。
+
+xa_state也被用来存储错误(store errors)。你可以调用xas_error()来检索错误。所有的操作在进行之前都
+会检查xa_state是否处于错误状态,所以你没有必要在每次调用之后检查错误;你可以连续进行多次调用,只在
+方便的时候检查。目前XArray代码本身产生的错误只有 ``ENOMEM`` 和 ``EINVAL`` ,但它支持任意的错误,
+以防你想自己调用xas_set_err()。
+
+如果xa_state持有 ``ENOMEM`` 错误,调用xas_nomem()将尝试使用指定的gfp标志分配更多的内存,并将其缓
+存在xa_state中供下一次尝试。这个想法是,你拿着xa_lock,尝试操作,然后放弃锁。该操作试图在持有锁的情
+况下分配内存,但它更有可能失败。一旦你放弃了锁,xas_nomem()可以更努力地尝试分配更多内存。如果值得重
+试该操作,它将返回 ``true`` (即出现了内存错误,分配了更多的内存)。如果它之前已经分配了内存,并且
+该内存没有被使用,也没有错误(或者一些不是 ``ENOMEM`` 的错误),那么它将释放之前分配的内存。
+
+内部条目
+--------
+
+XArray为它自己的目的保留了一些条目。这些条目从未通过正常的API暴露出来,但是当使用高级API时,有可能看
+到它们。通常,处理它们的最好方法是把它们传递给xas_retry(),如果它返回 ``true`` ,就重试操作。
+
+.. flat-table::
+ :widths: 1 1 6
+
+ * - 名称
+ - 检测
+ - 用途
+
+ * - Node
+ - xa_is_node()
+ - 一个XArray节点。 在使用多索引xa_state时可能是可见的。
+
+ * - Sibling
+ - xa_is_sibling()
+ - 一个多索引条目的非典型条目。该值表示该节点中的哪个槽有典型条目。
+
+ * - Retry
+ - xa_is_retry()
+ - 这个条目目前正在被一个拥有xa_lock的线程修改。在这个RCU周期结束时,包含该条目的节点可能会被释放。
+ 你应该从数组的头部重新开始查找。
+
+ * - Zero
+ - xa_is_zero()
+ - Zero条目通过普通API显示为 ``NULL`` ,但在XArray中占有一个条目,可用于保留索引供将来使用。这是
+ 通过为分配的条目分配XArrays来使用的,这些条目是 ``NULL`` 。
+
+其他内部条目可能会在未来被添加。在可能的情况下,它们将由xas_retry()处理。
+
+附加函数
+--------
+
+xas_create_range()函数分配了所有必要的内存来存储一个范围内的每一个条目。如果它不能分配内存,它将在
+xa_state中设置ENOMEM。
+
+你可以使用xas_init_marks()将一个条目上的标记重置为默认状态。这通常是清空所有标记,除非XArray被标记
+为 ``XA_FLAGS_TRACK_FREE`` ,在这种情况下,标记0被设置,所有其他标记被清空。使用xas_store()将一个
+条目替换为另一个条目不会重置该条目上的标记;如果你想重置标记,你应该明确地这样做。
+
+xas_load()会尽可能地将xa_state移动到该条目附近。如果你知道xa_state已经移动到了该条目,并且需要检查
+该条目是否有变化,你可以使用xas_reload()来保存一个函数调用。
+
+如果你需要移动到XArray中的不同索引,可以调用xas_set()。这可以将光标重置到树的顶端,这通常会使下一个
+操作将光标移动到树中想要的位置。如果你想移动到下一个或上一个索引,调用xas_next()或xas_prev()。设置
+索引不会使光标在数组中移动,所以不需要锁,而移动到下一个或上一个索引则需要锁。
+
+你可以使用xas_find()搜索下一个当前条目。这相当于xa_find()和xa_find_after();如果光标已经移动到了
+一个条目,那么它将找到当前引用的条目之后的下一个条目。如果没有,它将返回xa_state索引处的条目。使用
+xas_next_entry()而不是xas_find()来移动到下一个当前条目,在大多数情况下会节省一个函数调用,但代价
+是发出更多内联代码。
+
+xas_find_marked()函数也是如此。如果xa_state没有被移动过,它将返回xa_state的索引处的条目,如果它
+被标记了。否则,它将返回xa_state所引用的条目之后的第一个被标记的条目。xas_next_marked()函数等同
+于xas_next_entry()。
+
+当使用xas_for_each()或xas_for_each_marked()在XArray的某个范围内进行迭代时,可能需要暂时停止迭代。
+xas_pause()函数的存在就是为了这个目的。在你完成了必要的工作并希望恢复后,xa_state处于适当的状态,在
+你最后处理的条目后继续迭代。如果你在迭代时禁用了中断,那么暂停迭代并在每一个 ``XA_CHECK_SCHED`` 条目
+中重新启用中断是很好的做法。
+
+xas_get_mark(), xas_set_mark()和xas_clear_mark()函数要求xa_state光标已经被移动到XArray中的适当位
+置;如果你在之前调用了xas_pause()或xas_set(),它们将不会有任何作用。
+
+你可以调用xas_set_update(),让XArray每次更新一个节点时都调用一个回调函数。这被页面缓存的workingset
+代码用来维护其只包含阴影项的节点列表。
+
+多索引条目
+----------
+
+XArray有能力将多个索引联系在一起,因此对一个索引的操作会影响到所有的索引。例如,存储到任何索引将改变
+从任何索引检索的条目的值。在任何索引上设置或清除一个标记,都会在每个被绑在一起的索引上设置或清除该标
+记。目前的实现只允许将2的整数倍的范围绑在一起;例如指数64-127可以绑在一起,但2-6不能。这可以节省大量
+的内存;例如,将512个条目绑在一起可以节省4kB以上的内存。
+
+你可以通过使用XA_STATE_ORDER()或xas_set_order(),然后调用xas_store()来创建一个多索引条目。用一个
+多索引的xa_state调用xas_load()会把xa_state移动到树中的正确位置,但是返回值没有意义,有可能是一个内
+部条目或 ``NULL`` ,即使在范围内有一个条目存储。调用xas_find_conflict()将返回该范围内的第一个条目,
+如果该范围内没有条目,则返回 ``NULL`` 。xas_for_each_conflict()迭代器将遍历每个与指定范围重叠的条目。
+
+如果xas_load()遇到一个多索引条目,xa_state中的xa_index将不会被改变。当遍历一个XArray或者调用xas_find()
+时,如果初始索引在一个多索引条目的中间,它将不会被改变。随后的调用或迭代将把索引移到范围内的第一个索引。
+每个条目只会被返回一次,不管它占据了多少个索引。
+
+不支持使用xas_next()或xas_prev()来处理一个多索引的xa_state。在一个多索引的条目上使用这两个函数中的任
+何一个都会显示出同级的条目;这些条目应该被调用者跳过。
+
+在一个多索引条目的任何一个索引中存储 ``NULL`` ,将把每个索引的条目设置为 ``NULL`` ,并解除绑定。通过调
+用xas_split_alloc(),在没有xa_lock的情况下,可以将一个多索引条目分割成占据较小范围的条目,然后再取锁并
+调用xas_split()。
+
+函数和结构体
+============
+
+该API在以下内核代码中:
+
+include/linux/xarray.h
+
+lib/xarray.c
diff --git a/Documentation/translations/zh_CN/cpu-freq/core.rst b/Documentation/translations/zh_CN/cpu-freq/core.rst
new file mode 100644
index 000000000000..b3c095306ffe
--- /dev/null
+++ b/Documentation/translations/zh_CN/cpu-freq/core.rst
@@ -0,0 +1,109 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/cpu-freq/core.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+====================================
+CPUFreq核心和CPUFreq通知器的通用说明
+====================================
+
+作者:
+ - Dominik Brodowski <linux@brodo.de>
+ - David Kimdon <dwhedon@debian.org>
+ - Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ - Viresh Kumar <viresh.kumar@linaro.org>
+
+.. 目录:
+
+ 1. CPUFreq核心和接口
+ 2. CPUFreq通知器
+ 3. 含有Operating Performance Point (OPP)的CPUFreq表的生成
+
+1. CPUFreq核心和接口
+======================
+
+cpufreq核心代码位于drivers/cpufreq/cpufreq.c中。这些cpufreq代码为CPUFreq架构的驱
+动程序(那些执行硬件频率切换的代码)以及 "通知器" 提供了一个标准化的接口。
+包括设备驱动程序;需要了解策略变化(如 ACPI 热量管理),或所有频率变化(如计时代码),
+甚至需要强制限制为指定频率(如 ARM 架构上的 LCD 驱动程序)的其它内核组件。
+此外,内核 "常数" loops_per_jiffy 会根据频率变化而更新。
+
+cpufreq策略的引用计数由 cpufreq_cpu_get 和 cpufreq_cpu_put 来完成,以确保 cpufreq 驱
+动程序被正确地注册到核心中,并且驱动程序在 cpufreq_put_cpu 被调用之前不会被卸载。这也保证
+了每个CPU核的cpufreq 策略在使用期间不会被释放。
+
+2. CPUFreq 通知器
+====================
+
+CPUFreq通知器遵循标准的内核通知器接口。
+关于通知器的细节请参阅 linux/include/linux/notifier.h。
+
+这里有两个不同的CPUfreq通知器 - 策略通知器和转换通知器。
+
+
+2.1 CPUFreq策略通知器
+----------------------------
+
+当创建或移除策略时,这些都会被通知。
+
+阶段是在通知器的第二个参数中指定的。当第一次创建策略时,阶段是CPUFREQ_CREATE_POLICY,当
+策略被移除时,阶段是CPUFREQ_REMOVE_POLICY。
+
+第三个参数 ``void *pointer`` 指向一个结构体cpufreq_policy,其包括min,max(新策略的下限和
+上限(单位为kHz))这几个值。
+
+
+2.2 CPUFreq转换通知器
+--------------------------------
+
+当CPUfreq驱动切换CPU核心频率时,策略中的每个在线CPU都会收到两次通知,这些变化没有任何外部干
+预。
+
+第二个参数指定阶段 - CPUFREQ_PRECHANGE or CPUFREQ_POSTCHANGE.
+
+第三个参数是一个包含如下值的结构体cpufreq_freqs:
+
+====== ===============================
+policy 指向struct cpufreq_policy的指针
+old 旧频率
+new 新频率
+flags cpufreq驱动的标志
+====== ===============================
+
+3. 含有Operating Performance Point (OPP)的CPUFreq表的生成
+==================================================================
+关于OPP的细节请参阅 Documentation/power/opp.rst
+
+dev_pm_opp_init_cpufreq_table -
+ 这个函数提供了一个随时可用的转换例程,用来将OPP层关于可用频率的内部信息翻译成一种
+ cpufreq易于处理的格式。
+
+ .. Warning::
+
+ 不要在中断上下文中使用此函数。
+
+ 例如::
+
+ soc_pm_init()
+ {
+ /* Do things */
+ r = dev_pm_opp_init_cpufreq_table(dev, &freq_table);
+ if (!r)
+ policy->freq_table = freq_table;
+ /* Do other things */
+ }
+
+ .. note::
+
+ 该函数只有在CONFIG_PM_OPP之外还启用了CONFIG_CPU_FREQ时才可用。
+
+dev_pm_opp_free_cpufreq_table
+ 释放dev_pm_opp_init_cpufreq_table分配的表。
diff --git a/Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst b/Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst
new file mode 100644
index 000000000000..2ca92042767b
--- /dev/null
+++ b/Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst
@@ -0,0 +1,257 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/cpu-freq/cpu-drivers.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+=======================================
+如何实现一个新的CPUFreq处理器驱动程序?
+=======================================
+
+作者:
+
+
+ - Dominik Brodowski <linux@brodo.de>
+ - Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ - Viresh Kumar <viresh.kumar@linaro.org>
+
+.. Contents
+
+ 1. 怎么做?
+ 1.1 初始化
+ 1.2 Per-CPU 初始化
+ 1.3 验证
+ 1.4 target/target_index 或 setpolicy?
+ 1.5 target/target_index
+ 1.6 setpolicy
+ 1.7 get_intermediate 与 target_intermediate
+ 2. 频率表助手
+
+
+
+1. 怎么做?
+===========
+
+如果,你刚刚得到了一个全新的CPU/芯片组及其数据手册,并希望为这个CPU/芯片组添加cpufreq
+支持?很好,这里有一些至关重要的提示:
+
+
+1.1 初始化
+----------
+
+首先,在 __initcall level 7 (module_init())或更靠后的函数中检查这个内核是否
+运行在正确的CPU和正确的芯片组上。如果是,则使用cpufreq_register_driver()向
+CPUfreq核心层注册一个cpufreq_driver结构体。
+
+结构体cpufreq_driver应该包含什么成员?
+
+ .name - 驱动的名字。
+
+ .init - 一个指向per-policy初始化函数的指针。
+
+ .verify - 一个指向"verification"函数的指针。
+
+ .setpolicy 或 .fast_switch 或 .target 或 .target_index - 差异见
+ 下文。
+
+其它可选成员
+
+ .flags - 给cpufreq核心的提示。
+
+ .driver_data - cpufreq驱动程序的特有数据。
+
+ .get_intermediate 和 target_intermediate - 用于在改变CPU频率时切换到稳定
+ 的频率。
+
+ .get - 返回CPU的当前频率。
+
+ .bios_limit - 返回HW/BIOS对CPU的最大频率限制值。
+
+ .exit - 一个指向per-policy清理函数的指针,该函数在CPU热插拔过程的CPU_POST_DEAD
+ 阶段被调用。
+
+ .suspend - 一个指向per-policy暂停函数的指针,该函数在关中断且在该策略的调节器停止
+ 后被调用。
+
+ .resume - 一个指向per-policy恢复函数的指针,该函数在关中断且在调节器再一次启动前被
+ 调用。
+
+ .ready - 一个指向per-policy准备函数的指针,该函数在策略完全初始化之后被调用。
+
+ .attr - 一个指向NULL结尾的"struct freq_attr"列表的指针,该列表允许导出值到
+ sysfs。
+
+ .boost_enabled - 如果设置,则启用提升(boost)频率。
+
+ .set_boost - 一个指向per-policy函数的指针,该函数用来开启/关闭提升(boost)频率功能。
+
+
+1.2 Per-CPU 初始化
+------------------
+
+每当一个新的CPU被注册到设备模型中,或者当cpufreq驱动注册自身之后,如果此CPU的cpufreq策
+略不存在,则会调用per-policy的初始化函数cpufreq_driver.init。请注意,.init()和.exit()例程
+只为某个策略调用一次,而不是对该策略管理的每个CPU调用一次。它需要一个 ``struct cpufreq_policy
+*policy`` 作为参数。现在该怎么做呢?
+
+如果有必要,请在你的CPU上激活CPUfreq功能支持。
+
+然后,驱动程序必须填写以下值:
+
++-----------------------------------+--------------------------------------+
+|policy->cpuinfo.min_freq和 | 该CPU支持的最低和最高频率(kHz) |
+|policy->cpuinfo.max_freq | |
+| | |
++-----------------------------------+--------------------------------------+
+|policy->cpuinfo.transition_latency | CPU在两个频率之间切换所需的时间,以 |
+| | 纳秒为单位(如不适用,设定为 |
+| | CPUFREQ_ETERNAL) |
+| | |
++-----------------------------------+--------------------------------------+
+|policy->cur | 该CPU当前的工作频率(如适用) |
+| | |
++-----------------------------------+--------------------------------------+
+|policy->min, | 必须包含该CPU的"默认策略"。稍后 |
+|policy->max, | 会用这些值调用 |
+|policy->policy and, if necessary, | cpufreq_driver.verify和下面函数 |
+|policy->governor | 之一:cpufreq_driver.setpolicy或 |
+| | cpufreq_driver.target/target_index |
+| | |
++-----------------------------------+--------------------------------------+
+|policy->cpus | 该policy通过DVFS框架影响的全部CPU |
+| | (即与本CPU共享"时钟/电压"对)构成 |
+| | 掩码(同时包含在线和离线CPU),用掩码 |
+| | 更新本字段 |
+| | |
++-----------------------------------+--------------------------------------+
+
+对于设置其中的一些值(cpuinfo.min[max]_freq, policy->min[max]),频率表辅助函数可能会有帮
+助。关于它们的更多信息,请参见第2节。
+
+
+1.3 验证
+--------
+
+当用户决定设置一个新的策略(由"policy,governor,min,max组成")时,必须对这个策略进行验证,
+以便纠正不兼容的值。为了验证这些值,cpufreq_verify_within_limits(``struct cpufreq_policy
+*policy``, ``unsigned int min_freq``, ``unsigned int max_freq``)函数可能会有帮助。
+关于频率表辅助函数的详细内容请参见第2节。
+
+您需要确保至少有一个有效频率(或工作范围)在 policy->min 和 policy->max 范围内。如果有必
+要,先增大policy->max,只有在没有解决方案的情况下,才减小policy->min。
+
+
+1.4 target 或 target_index 或 setpolicy 或 fast_switch?
+-------------------------------------------------------
+
+大多数cpufreq驱动甚至大多数CPU频率升降算法只允许将CPU频率设置为预定义的固定值。对于这些,你
+可以使用->target(),->target_index()或->fast_switch()回调。
+
+有些具有硬件调频能力的处理器可以自行依据某些限制来切换CPU频率。它们应使用->setpolicy()回调。
+
+
+1.5. target/target_index
+------------------------
+
+target_index调用有两个参数: ``struct cpufreq_policy * policy`` 和 ``unsigned int``
+索引(用于索引频率表项)。
+
+当调用这里时,CPUfreq驱动必须设置新的频率。实际频率必须由freq_table[index].frequency决定。
+
+在发生错误的情况下总是应该恢复到之前的频率(即policy->restore_freq),即使我们已经切换到了
+中间频率。
+
+已弃用
+----------
+target调用有三个参数。``struct cpufreq_policy * policy``, unsigned int target_frequency,
+unsigned int relation.
+
+CPUfreq驱动在调用这里时必须设置新的频率。实际的频率必须使用以下规则来确定。
+
+- 尽量贴近"目标频率"。
+- policy->min <= new_freq <= policy->max (这必须是有效的!!!)
+- 如果 relation==CPUFREQ_REL_L,尝试选择一个高于或等于 target_freq 的 new_freq。("L代表
+ 最低,但不能低于")
+- 如果 relation==CPUFREQ_REL_H,尝试选择一个低于或等于 target_freq 的 new_freq。("H代表
+ 最高,但不能高于")
+
+这里,频率表辅助函数可能会帮助你 -- 详见第2节。
+
+1.6. fast_switch
+----------------
+
+这个函数用于从调度器的上下文进行频率切换。并非所有的驱动都要实现它,因为不允许在这个回调中睡眠。这
+个回调必须经过高度优化,以尽可能快地进行切换。
+
+这个函数有两个参数: ``struct cpufreq_policy *policy`` 和 ``unsigned int target_frequency``。
+
+
+1.7 setpolicy
+-------------
+
+setpolicy调用只需要一个 ``struct cpufreq_policy * policy`` 作为参数。需要将处理器内或芯片组内动态频
+率切换的下限设置为policy->min,上限设置为policy->max,如果支持的话,当policy->policy为
+CPUFREQ_POLICY_PERFORMANCE时选择面向性能的设置,为CPUFREQ_POLICY_POWERSAVE时选择面向省电的设置。
+也可以查看drivers/cpufreq/longrun.c中的参考实现。
+
+1.8 get_intermediate 和 target_intermediate
+--------------------------------------------
+
+仅适用于未设置 target_index() 和 CPUFREQ_ASYNC_NOTIFICATION 的驱动。
+
+get_intermediate应该返回一个平台想要切换到的稳定的中间频率,target_intermediate()应该将CPU设置为
+该频率,然后再跳转到'index'对应的频率。cpufreq核心会负责发送通知,驱动不必在
+target_intermediate()或target_index()中处理它们。
+
+在驱动程序不想为某个目标频率切换到中间频率的情况下,它们可以让get_intermediate()返回'0'。
+在这种情况下,cpufreq核心将直接调用->target_index()。
+
+注意:->target_index()应该在发生失败的情况下将频率恢复到policy->restore_freq,
+因为cpufreq核心会为此发送通知。
+
+
+2. 频率表辅助函数
+=================
+
+由于大多数支持cpufreq的处理器只允许被设置为几个特定的频率,因此,"频率表"和一些相关函数可能会辅助处理器驱动
+程序的一些工作。这样的"频率表"是一个由struct cpufreq_frequency_table的条目构成的数组,"driver_data"成员包
+含驱动程序的专用值,"frequency"成员包含了相应的频率,此外还有标志成员。在表的最后,需要添加一个
+cpufreq_frequency_table条目,频率设置为CPUFREQ_TABLE_END。如果想跳过表中的一个条目,则将频率设置为
+CPUFREQ_ENTRY_INVALID。这些条目不需要按照任何特定的顺序排序,如果排序了,cpufreq核心执行DVFS会更快一点,
+因为搜索最佳匹配会更快。
+
+如果在policy->freq_table字段中包含一个有效的频率表指针,频率表就会被cpufreq核心自动验证。
+
+cpufreq_frequency_table_verify()保证至少有一个有效的频率在policy->min和policy->max范围内,并且所有其他
+准则都被满足。这对->verify调用很有帮助。
+
+cpufreq_frequency_table_target()是对应于->target阶段的频率表辅助函数。只要把值传递给这个函数,这个函数就会返
+回包含CPU要设置的频率的频率表条目。
+
+以下宏可以作为cpufreq_frequency_table的迭代器。
+
+cpufreq_for_each_entry(pos, table) - 遍历频率表的所有条目。
+
+cpufreq_for_each_valid_entry(pos, table) - 该函数遍历所有条目,不包括CPUFREQ_ENTRY_INVALID频率。
+使用参数"pos" -- 一个 ``cpufreq_frequency_table *`` 作为循环指针,使用参数"table" -- 作为你想迭代
+的 ``cpufreq_frequency_table *`` 。
+
+例如::
+
+ struct cpufreq_frequency_table *pos, *driver_freq_table;
+
+ cpufreq_for_each_entry(pos, driver_freq_table) {
+ /* Do something with pos */
+ pos->frequency = ...
+ }
+
+如果你需要在driver_freq_table中处理pos的位置,不要做指针减法,因为它的代价相当高。作为替代,使用宏
+cpufreq_for_each_entry_idx() 和 cpufreq_for_each_valid_entry_idx() 。
diff --git a/Documentation/translations/zh_CN/cpu-freq/cpufreq-stats.rst b/Documentation/translations/zh_CN/cpu-freq/cpufreq-stats.rst
new file mode 100644
index 000000000000..e8fdba923cd5
--- /dev/null
+++ b/Documentation/translations/zh_CN/cpu-freq/cpufreq-stats.rst
@@ -0,0 +1,133 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/cpu-freq/cpufreq-stats.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+==========================================
+sysfs CPUFreq Stats的一般说明
+==========================================
+
+为使用者准备的信息
+
+
+作者: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+
+.. Contents
+
+ 1. 简介
+ 2. 提供的统计数据(举例说明)
+ 3. 配置cpufreq-stats
+
+
+1. 简介
+===============
+
+cpufreq-stats是一种为每个CPU提供CPU频率统计的驱动。
+这些统计数据以/sysfs中一系列只读接口的形式呈现。cpufreq-stats接口(若已配置)将为每个CPU生成
+/sysfs(<sysfs root>/devices/system/cpu/cpuX/cpufreq/stats/)中cpufreq目录下的stats目录。
+各项统计数据将在stats目录下形成对应的只读文件。
+
+此驱动是以独立于任何可能运行在你所用CPU上的特定cpufreq_driver的方式设计的。因此,它将能和任何
+cpufreq_driver协同工作。
+
+
+2. 已提供的统计数据(有例子)
+=====================================
+
+cpufreq stats提供了以下统计数据(在下面详细解释)。
+
+- time_in_state
+- total_trans
+- trans_table
+
+所有统计数据来自以下时间范围:从统计驱动被加载的时间(或统计数据被重置的时间)开始,到某一统计数据被读取的时间为止。
+显然,统计驱动不会保存它被加载之前的任何频率转换信息。
+
+::
+
+ <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # ls -l
+ total 0
+ drwxr-xr-x 2 root root 0 May 14 16:06 .
+ drwxr-xr-x 3 root root 0 May 14 15:58 ..
+ --w------- 1 root root 4096 May 14 16:06 reset
+ -r--r--r-- 1 root root 4096 May 14 16:06 time_in_state
+ -r--r--r-- 1 root root 4096 May 14 16:06 total_trans
+ -r--r--r-- 1 root root 4096 May 14 16:06 trans_table
+
+- **reset**
+
+只写属性,可用于重置统计计数器。这对于评估不同调节器的系统行为非常有用,且无需重启。
+
+
+- **time_in_state**
+
+此文件给出了在本CPU支持的每个频率上分别花费的时间。cat输出的每一行都是一个"<frequency>
+<time>"对,表示这个CPU在<frequency>上花费了<time>个usertime单位的时间。输出的每一行对应
+一个CPU支持的频率。这里usertime单位是10mS(类似于/proc导出的其它时间)。
+
+::
+
+ <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat time_in_state
+ 3600000 2089
+ 3400000 136
+ 3200000 34
+ 3000000 67
+ 2800000 172488
+
+
+- **total_trans**
+
+此文件给出了这个CPU频率转换的总次数。cat的输出是一个计数值,它就是频率转换的总次数。
+
+::
+
+ <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat total_trans
+ 20
+
+- **trans_table**
+
+本文件提供所有CPU频率转换的细粒度信息。这里的cat输出是一个二维矩阵,其中一个条目<i, j>(第
+i行,第j列)代表从Freq_i到Freq_j的转换次数。Freq_i行和Freq_j列遵循驱动最初提供给cpufreq
+核心的频率表的排列顺序,因此可以已排序(升序或降序)或未排序。这里的输出也包含了实际
+频率值,分别按行和按列显示,以便更好地阅读。
+
+如果转换表大于PAGE_SIZE,读取时将返回一个-EFBIG错误。
+
+::
+
+ <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat trans_table
+ From : To
+ : 3600000 3400000 3200000 3000000 2800000
+ 3600000: 0 5 0 0 0
+ 3400000: 4 0 2 0 0
+ 3200000: 0 1 0 2 0
+ 3000000: 0 0 1 0 3
+ 2800000: 0 0 0 2 0
+
+3. 配置cpufreq-stats
+============================
+
+按以下方式在你的内核中配置cpufreq-stats::
+
+ Config Main Menu
+ Power management options (ACPI, APM) --->
+ CPU Frequency scaling --->
+ [*] CPU Frequency scaling
+ [*] CPU frequency translation statistics
+
+
+"CPU Frequency scaling" (CONFIG_CPU_FREQ) 应该被启用,以支持配置cpufreq-stats。
+
+"CPU frequency translation statistics" (CONFIG_CPU_FREQ_STAT)提供了包括
+time_in_state、total_trans和trans_table的统计数据。
+
+一旦启用了这个选项,并且你的CPU支持cpufrequency,你就可以在/sysfs中看到CPU频率统计。
diff --git a/Documentation/translations/zh_CN/cpu-freq/index.rst b/Documentation/translations/zh_CN/cpu-freq/index.rst
new file mode 100644
index 000000000000..c6e50963cd33
--- /dev/null
+++ b/Documentation/translations/zh_CN/cpu-freq/index.rst
@@ -0,0 +1,47 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/cpu-freq/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_index.rst:
+
+=======================================================
+Linux CPUFreq - Linux(TM)内核中的CPU频率和电压升降代码
+=======================================================
+
+Author: Dominik Brodowski <linux@brodo.de>
+
+ 时钟升降允许你在运行中改变CPU的时钟速度。这是一个很好的节省电池电量的方法,因为时
+ 钟速度越低,CPU消耗的电量越少。
+
+
+.. toctree::
+ :maxdepth: 1
+
+ core
+ cpu-drivers
+ cpufreq-stats
+
+邮件列表
+------------
+这里有一个 CPU 频率变化的 CVS 提交和通用列表,您可以在这里报告bug、问题或提交补丁。要发
+布消息,请发送电子邮件到 linux-pm@vger.kernel.org。
+
+链接
+-----
+FTP档案:
+* ftp://ftp.linux.org.uk/pub/linux/cpufreq/
+
+如何访问CVS仓库:
+* http://cvs.arm.linux.org.uk/
+
+CPUFreq邮件列表:
+* http://vger.kernel.org/vger-lists.html#linux-pm
+
+SA-1100的时钟和电压标度:
+* http://www.lartmaker.nl/projects/scaling
diff --git a/Documentation/translations/zh_CN/dev-tools/gcov.rst b/Documentation/translations/zh_CN/dev-tools/gcov.rst
new file mode 100644
index 000000000000..3158c9da1318
--- /dev/null
+++ b/Documentation/translations/zh_CN/dev-tools/gcov.rst
@@ -0,0 +1,264 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/dev-tools/gcov.rst
+:Translator: 赵军奎 Bernard Zhao <bernard@vivo.com>
+
+在Linux内核里使用gcov做代码覆盖率检查
+=====================================
+
+gcov分析核心支持在Linux内核中启用GCC的覆盖率测试工具 gcov_ ,Linux内核
+运行时的代码覆盖率数据会以gcov兼容的格式导出到“gcov”debugfs目录中,可
+以通过gcov的 ``-o`` 选项(如下示例)获得指定文件的代码运行覆盖率统计数据
+(需要跳转到内核编译路径下并且要有root权限)::
+
+ # cd /tmp/linux-out
+ # gcov -o /sys/kernel/debug/gcov/tmp/linux-out/kernel spinlock.c
+
+这将在当前目录中创建带有执行计数注释的源代码文件。
+在获得这些统计文件后,可以使用图形化的gcov前端工具(比如 lcov_ ),来实现
+自动化处理Linux内核的覆盖率运行数据,同时生成易于阅读的HTML格式文件。
+
+可能的用途:
+
+* 调试(用来判断每一行的代码是否已经运行过)
+* 测试改进(如何修改测试代码,尽可能地覆盖到没有运行过的代码)
+* 内核最小化配置(对于某一个选项配置,如果关联的代码从来没有运行过,
+ 是否还需要这个配置)
+
+.. _gcov: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html
+.. _lcov: http://ltp.sourceforge.net/coverage/lcov.php
+
+
+准备
+----
+
+内核打开如下配置::
+
+ CONFIG_DEBUG_FS=y
+ CONFIG_GCOV_KERNEL=y
+
+获取整个内核的覆盖率数据,还需要打开::
+
+ CONFIG_GCOV_PROFILE_ALL=y
+
+需要注意的是,整个内核开启覆盖率统计会造成内核镜像文件尺寸的增大,
+同时内核运行也会变慢一些。
+另外,并不是所有的架构都支持整个内核开启覆盖率统计。
+
+代码运行覆盖率数据只在debugfs挂载完成后才可以访问::
+
+ mount -t debugfs none /sys/kernel/debug
+
+
+定制化
+------
+
+如果要单独针对某一个路径或者文件进行代码覆盖率统计,可以在内核相应路
+径的Makefile中增加如下的配置:
+
+- 单独统计单个文件(例如main.o)::
+
+ GCOV_PROFILE_main.o := y
+
+- 单独统计某一个路径::
+
+ GCOV_PROFILE := y
+
+如果要在整个内核的覆盖率统计(开启CONFIG_GCOV_PROFILE_ALL)中单独排除
+某一个文件或者路径,可以使用如下的方法::
+
+ GCOV_PROFILE_main.o := n
+
+和::
+
+ GCOV_PROFILE := n
+
+此机制仅支持链接到内核镜像或编译为内核模块的文件。
+
+
+相关文件
+--------
+
+gcov功能需要在debugfs中创建如下文件:
+
+``/sys/kernel/debug/gcov``
+ gcov相关功能的根路径
+
+``/sys/kernel/debug/gcov/reset``
+ 全局复位文件:向该文件写入数据后会将所有的gcov统计数据清0
+
+``/sys/kernel/debug/gcov/path/to/compile/dir/file.gcda``
+ gcov工具可以识别的覆盖率统计数据文件,向该文件写入数据后
+ 会将本文件的gcov统计数据清0
+
+``/sys/kernel/debug/gcov/path/to/compile/dir/file.gcno``
+ gcov工具需要的软连接文件(指向编译时生成的信息统计文件),这个文件是
+ 在gcc编译时如果配置了选项 ``-ftest-coverage`` 时生成的。
+
+
+针对模块的统计
+--------------
+
+内核中的模块会动态的加载和卸载,模块卸载时对应的数据会被清除掉。
+gcov提供了一种机制,通过保留相关数据的副本来收集这部分卸载模块的覆盖率数据。
+模块卸载后这些备份数据在debugfs中会继续存在。
+一旦这个模块重新加载,模块关联的运行统计会被初始化成debugfs中备份的数据。
+
+可以通过对内核参数gcov_persist的修改来停用gcov对模块的备份机制::
+
+ gcov_persist = 0
+
+在运行时,用户还可以通过写入模块的数据文件或者写入gcov复位文件来丢弃已卸
+载模块的数据。
+
+
+编译机和测试机分离
+------------------
+
+gcov的内核分析插桩支持内核的编译和运行是在同一台机器上,也可以编译和运
+行是在不同的机器上。
+如果内核编译和运行是不同的机器,那么需要额外的准备工作,这取决于gcov工具
+是在哪里使用的:
+
+.. _gcov-test_zh:
+
+a) 若gcov运行在测试机上
+
+ 测试机上面gcov工具的版本必须要跟内核编译机器使用的gcc版本相兼容,
+ 同时下面的文件要从编译机拷贝到测试机上:
+
+ 从源代码中:
+ - 所有的C文件和头文件
+
+ 从编译目录中:
+ - 所有的C文件和头文件
+ - 所有的.gcda文件和.gcno文件
+ - 所有目录的链接
+
+ 特别需要注意,测试机器上面的目录结构跟编译机器上面的目录机构必须
+ 完全一致。
+ 如果文件是软链接,需要替换成真正的目录文件(这是由make的当前工作
+ 目录变量CURDIR引起的)。
+
+.. _gcov-build_zh:
+
+b) 若gcov运行在编译机上
+
+ 测试用例运行结束后,如下的文件需要从测试机中拷贝到编译机上:
+
+ 从sysfs中的gcov目录中:
+ - 所有的.gcda文件
+ - 所有的.gcno文件软链接
+
+ 这些文件可以拷贝到编译机的任意目录下,gcov使用-o选项指定拷贝的
+ 目录。
+
+ 比如一个是示例的目录结构如下::
+
+ /tmp/linux: 内核源码目录
+ /tmp/out: 内核编译文件路径(make O=指定)
+ /tmp/coverage: 从测试机器上面拷贝的数据文件路径
+
+ [user@build] cd /tmp/out
+ [user@build] gcov -o /tmp/coverage/tmp/out/init main.c
+
+
+关于编译器的注意事项
+--------------------
+
+GCC和LLVM gcov工具不一定兼容。
+如果编译器是GCC,使用 gcov_ 来处理.gcno和.gcda文件,如果是Clang编译器,
+则使用 llvm-cov_ 。
+
+.. _gcov: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html
+.. _llvm-cov: https://llvm.org/docs/CommandGuide/llvm-cov.html
+
+GCC和Clang gcov之间的版本差异由Kconfig处理的。
+kconfig会根据编译工具链的检查自动选择合适的gcov格式。
+
+问题定位
+--------
+
+可能出现的问题1
+ 编译到链接阶段报错终止
+
+问题原因
+ 分析标志指定在了源文件但是没有链接到主内核,或者客制化了链接程序
+
+解决方法
+ 通过在相应的Makefile中使用 ``GCOV_PROFILE := n``
+ 或者 ``GCOV_PROFILE_basename.o := n`` 来将链接报错的文件排除掉
+
+可能出现的问题2
+ 从sysfs复制的文件显示为空或不完整
+
+问题原因
+ 由于seq_file的工作方式,某些工具(例如cp或tar)可能无法正确地从
+ sysfs复制文件。
+
+解决方法
+ 使用 ``cat`` 读取 ``.gcda`` 文件,使用 ``cp -d`` 复制链接,或者使用附录B
+ 中所示的机制。
+
+
+附录A:collect_on_build.sh
+--------------------------
+
+用于在编译机上收集覆盖率元文件的示例脚本
+(见 :ref:`编译机和测试机分离 a. <gcov-test_zh>` )
+
+.. code-block:: sh
+
+ #!/bin/bash
+
+ KSRC=$1
+ KOBJ=$2
+ DEST=$3
+
+ if [ -z "$KSRC" ] || [ -z "$KOBJ" ] || [ -z "$DEST" ]; then
+ echo "Usage: $0 <ksrc directory> <kobj directory> <output.tar.gz>" >&2
+ exit 1
+ fi
+
+ KSRC=$(cd $KSRC; printf "all:\n\t@echo \${CURDIR}\n" | make -f -)
+ KOBJ=$(cd $KOBJ; printf "all:\n\t@echo \${CURDIR}\n" | make -f -)
+
+ find $KSRC $KOBJ \( -name '*.gcno' -o -name '*.[ch]' -o -type l \) -a \
+ -perm /u+r,g+r | tar cfz $DEST -P -T -
+
+ if [ $? -eq 0 ] ; then
+ echo "$DEST successfully created, copy to test system and unpack with:"
+ echo " tar xfz $DEST -P"
+ else
+ echo "Could not create file $DEST"
+ fi
+
+
+附录B:collect_on_test.sh
+-------------------------
+
+用于在测试机上收集覆盖率数据文件的示例脚本
+(见 :ref:`编译机和测试机分离 b. <gcov-build_zh>` )
+
+.. code-block:: sh
+
+ #!/bin/bash -e
+
+ DEST=$1
+ GCDA=/sys/kernel/debug/gcov
+
+ if [ -z "$DEST" ] ; then
+ echo "Usage: $0 <output.tar.gz>" >&2
+ exit 1
+ fi
+
+ TEMPDIR=$(mktemp -d)
+ echo Collecting data..
+ find $GCDA -type d -exec mkdir -p $TEMPDIR/\{\} \;
+ find $GCDA -name '*.gcda' -exec sh -c 'cat < $0 > '$TEMPDIR'/$0' {} \;
+ find $GCDA -name '*.gcno' -exec sh -c 'cp -d $0 '$TEMPDIR'/$0' {} \;
+ tar czf $DEST -C $TEMPDIR sys
+ rm -rf $TEMPDIR
+
+ echo "$DEST successfully created, copy to build system and unpack with:"
+ echo " tar xfz $DEST"
diff --git a/Documentation/translations/zh_CN/dev-tools/gdb-kernel-debugging.rst b/Documentation/translations/zh_CN/dev-tools/gdb-kernel-debugging.rst
new file mode 100644
index 000000000000..17b5ce85a90c
--- /dev/null
+++ b/Documentation/translations/zh_CN/dev-tools/gdb-kernel-debugging.rst
@@ -0,0 +1,167 @@
+.. highlight:: none
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/dev-tools/gdb-kernel-debugging.rst
+:Translator: 高超 gao chao <gaochao49@huawei.com>
+
+通过gdb调试内核和模块
+=====================
+
+Kgdb内核调试器、QEMU等虚拟机管理程序或基于JTAG的硬件接口,支持在运行时使用gdb
+调试Linux内核及其模块。Gdb提供了一个强大的python脚本接口,内核也提供了一套
+辅助脚本以简化典型的内核调试步骤。本文档为如何启用和使用这些脚本提供了一个简要的教程。
+此教程基于QEMU/KVM虚拟机,但文中示例也适用于其他gdb stub。
+
+
+环境配置要求
+------------
+
+- gdb 7.2+ (推荐版本: 7.4+) 且开启python支持 (通常发行版上都已支持)
+
+设置
+----
+
+- 创建一个QEMU/KVM的linux虚拟机(详情请参考 www.linux-kvm.org 和 www.qemu.org )。
+ 对于交叉开发,https://landley.net/aboriginal/bin 提供了一些镜像和工具链,
+ 可以帮助搭建交叉开发环境。
+
+- 编译内核时开启CONFIG_GDB_SCRIPTS,关闭CONFIG_DEBUG_INFO_REDUCED。
+ 如果架构支持CONFIG_FRAME_POINTER,请保持开启。
+
+- 在guest环境上安装该内核。如有必要,通过在内核command line中添加“nokaslr”来关闭KASLR。
+ 此外,QEMU允许通过-kernel、-append、-initrd这些命令行选项直接启动内核。
+ 但这通常仅在不依赖内核模块时才有效。有关此模式的更多详细信息,请参阅QEMU文档。
+ 在这种情况下,如果架构支持KASLR,应该在禁用CONFIG_RANDOMIZE_BASE的情况下构建内核。
+
+- 启用QEMU/KVM的gdb stub,可以通过如下方式实现
+
+ - 在VM启动时,通过在QEMU命令行中添加“-s”参数
+
+ 或
+
+ - 在运行时通过从QEMU监视控制台发送“gdbserver”
+
+- 切换到/path/to/linux-build(内核源码编译)目录
+
+- 启动gdb:gdb vmlinux
+
+ 注意:某些发行版可能会将gdb脚本的自动加载限制在已知的安全目录中。
+ 如果gdb报告拒绝加载vmlinux-gdb.py(相关命令找不到),请将::
+
+ add-auto-load-safe-path /path/to/linux-build
+
+ 添加到~/.gdbinit。更多详细信息,请参阅gdb帮助信息。
+
+- 连接到已启动的guest环境::
+
+ (gdb) target remote :1234
+
+
+使用Linux提供的gdb脚本的示例
+----------------------------
+
+- 加载模块(以及主内核)符号::
+
+ (gdb) lx-symbols
+ loading vmlinux
+ scanning for modules in /home/user/linux/build
+ loading @0xffffffffa0020000: /home/user/linux/build/net/netfilter/xt_tcpudp.ko
+ loading @0xffffffffa0016000: /home/user/linux/build/net/netfilter/xt_pkttype.ko
+ loading @0xffffffffa0002000: /home/user/linux/build/net/netfilter/xt_limit.ko
+ loading @0xffffffffa00ca000: /home/user/linux/build/net/packet/af_packet.ko
+ loading @0xffffffffa003c000: /home/user/linux/build/fs/fuse/fuse.ko
+ ...
+ loading @0xffffffffa0000000: /home/user/linux/build/drivers/ata/ata_generic.ko
+
+- 对一些尚未加载的模块中的函数函数设置断点,例如::
+
+ (gdb) b btrfs_init_sysfs
+ Function "btrfs_init_sysfs" not defined.
+ Make breakpoint pending on future shared library load? (y or [n]) y
+ Breakpoint 1 (btrfs_init_sysfs) pending.
+
+- 继续执行::
+
+ (gdb) c
+
+- 加载模块并且能观察到正在加载的符号以及断点命中::
+
+ loading @0xffffffffa0034000: /home/user/linux/build/lib/libcrc32c.ko
+ loading @0xffffffffa0050000: /home/user/linux/build/lib/lzo/lzo_compress.ko
+ loading @0xffffffffa006e000: /home/user/linux/build/lib/zlib_deflate/zlib_deflate.ko
+ loading @0xffffffffa01b1000: /home/user/linux/build/fs/btrfs/btrfs.ko
+
+ Breakpoint 1, btrfs_init_sysfs () at /home/user/linux/fs/btrfs/sysfs.c:36
+ 36 btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj);
+
+- 查看内核的日志缓冲区::
+
+ (gdb) lx-dmesg
+ [ 0.000000] Initializing cgroup subsys cpuset
+ [ 0.000000] Initializing cgroup subsys cpu
+ [ 0.000000] Linux version 3.8.0-rc4-dbg+ (...
+ [ 0.000000] Command line: root=/dev/sda2 resume=/dev/sda1 vga=0x314
+ [ 0.000000] e820: BIOS-provided physical RAM map:
+ [ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
+ [ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
+ ....
+
+- 查看当前task struct结构体的字段(仅x86和arm64支持)::
+
+ (gdb) p $lx_current().pid
+ $1 = 4998
+ (gdb) p $lx_current().comm
+ $2 = "modprobe\000\000\000\000\000\000\000"
+
+- 对当前或指定的CPU使用per-cpu函数::
+
+ (gdb) p $lx_per_cpu("runqueues").nr_running
+ $3 = 1
+ (gdb) p $lx_per_cpu("runqueues", 2).nr_running
+ $4 = 0
+
+- 使用container_of查看更多hrtimers信息::
+
+ (gdb) set $next = $lx_per_cpu("hrtimer_bases").clock_base[0].active.next
+ (gdb) p *$container_of($next, "struct hrtimer", "node")
+ $5 = {
+ node = {
+ node = {
+ __rb_parent_color = 18446612133355256072,
+ rb_right = 0x0 <irq_stack_union>,
+ rb_left = 0x0 <irq_stack_union>
+ },
+ expires = {
+ tv64 = 1835268000000
+ }
+ },
+ _softexpires = {
+ tv64 = 1835268000000
+ },
+ function = 0xffffffff81078232 <tick_sched_timer>,
+ base = 0xffff88003fd0d6f0,
+ state = 1,
+ start_pid = 0,
+ start_site = 0xffffffff81055c1f <hrtimer_start_range_ns+20>,
+ start_comm = "swapper/2\000\000\000\000\000\000"
+ }
+
+
+命令和辅助调试功能列表
+----------------------
+
+命令和辅助调试功能可能会随着时间的推移而改进,此文显示的是初始版本的部分示例::
+
+ (gdb) apropos lx
+ function lx_current -- Return current task
+ function lx_module -- Find module by name and return the module variable
+ function lx_per_cpu -- Return per-cpu variable
+ function lx_task_by_pid -- Find Linux task by PID and return the task_struct variable
+ function lx_thread_info -- Calculate Linux thread_info from task variable
+ lx-dmesg -- Print Linux kernel log buffer
+ lx-lsmod -- List currently loaded modules
+ lx-symbols -- (Re-)load symbols of Linux kernel and currently loaded modules
+
+可以通过“help <command-name>”或“help function <function-name>”命令
+获取指定命令或指定调试功能的更多详细信息。
diff --git a/Documentation/translations/zh_CN/dev-tools/index.rst b/Documentation/translations/zh_CN/dev-tools/index.rst
new file mode 100644
index 000000000000..c2db3e566b1b
--- /dev/null
+++ b/Documentation/translations/zh_CN/dev-tools/index.rst
@@ -0,0 +1,37 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/dev-tools/index.rst
+:Translator: 赵军奎 Bernard Zhao <bernard@vivo.com>
+
+============
+内核开发工具
+============
+
+本文档是有关内核开发工具文档的合集。
+目前这些文档已经整理在一起,不需要再花费额外的精力。
+欢迎任何补丁。
+
+有关测试专用工具的简要概述,参见
+Documentation/translations/zh_CN/dev-tools/testing-overview.rst
+
+.. toctree::
+ :caption: 目录
+ :maxdepth: 2
+
+ testing-overview
+ sparse
+ gcov
+ kasan
+ gdb-kernel-debugging
+
+Todolist:
+
+ - coccinelle
+ - kcov
+ - ubsan
+ - kmemleak
+ - kcsan
+ - kfence
+ - kgdb
+ - kselftest
+ - kunit/index
diff --git a/Documentation/translations/zh_CN/dev-tools/kasan.rst b/Documentation/translations/zh_CN/dev-tools/kasan.rst
new file mode 100644
index 000000000000..8fdb20c9665b
--- /dev/null
+++ b/Documentation/translations/zh_CN/dev-tools/kasan.rst
@@ -0,0 +1,462 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/dev-tools/kasan.rst
+:Translator: 万家兵 Wan Jiabing <wanjiabing@vivo.com>
+
+内核地址消毒剂(KASAN)
+=====================
+
+概述
+----
+
+Kernel Address SANitizer(KASAN)是一种动态内存安全错误检测工具,主要功能是
+检查内存越界访问和使用已释放内存的问题。
+
+KASAN有三种模式:
+
+1. 通用KASAN
+2. 基于软件标签的KASAN
+3. 基于硬件标签的KASAN
+
+用CONFIG_KASAN_GENERIC启用的通用KASAN,是用于调试的模式,类似于用户空
+间的ASan。这种模式在许多CPU架构上都被支持,但它有明显的性能和内存开销。
+
+基于软件标签的KASAN或SW_TAGS KASAN,通过CONFIG_KASAN_SW_TAGS启用,
+可以用于调试和自我测试,类似于用户空间HWASan。这种模式只支持arm64,但其
+适度的内存开销允许在内存受限的设备上用真实的工作负载进行测试。
+
+基于硬件标签的KASAN或HW_TAGS KASAN,用CONFIG_KASAN_HW_TAGS启用,被
+用作现场内存错误检测器或作为安全缓解的模式。这种模式只在支持MTE(内存标签
+扩展)的arm64 CPU上工作,但它的内存和性能开销很低,因此可以在生产中使用。
+
+关于每种KASAN模式的内存和性能影响的细节,请参见相应的Kconfig选项的描述。
+
+通用模式和基于软件标签的模式通常被称为软件模式。基于软件标签的模式和基于
+硬件标签的模式被称为基于标签的模式。
+
+支持
+----
+
+体系架构
+~~~~~~~~
+
+在x86_64、arm、arm64、powerpc、riscv、s390、xtensa和loongarch上支持通用KASAN,
+而基于标签的KASAN模式只在arm64上支持。
+
+编译器
+~~~~~~
+
+软件KASAN模式使用编译时工具在每个内存访问之前插入有效性检查,因此需要一个
+提供支持的编译器版本。基于硬件标签的模式依靠硬件来执行这些检查,但仍然需要
+一个支持内存标签指令的编译器版本。
+
+通用KASAN需要GCC 8.3.0版本或更高版本,或者内核支持的任何Clang版本。
+
+基于软件标签的KASAN需要GCC 11+或者内核支持的任何Clang版本。
+
+基于硬件标签的KASAN需要GCC 10+或Clang 12+。
+
+内存类型
+~~~~~~~~
+
+通用KASAN支持在所有的slab、page_alloc、vmap、vmalloc、堆栈和全局内存
+中查找错误。
+
+基于软件标签的KASAN支持slab、page_alloc、vmalloc和堆栈内存。
+
+基于硬件标签的KASAN支持slab、page_alloc和不可执行的vmalloc内存。
+
+对于slab,两种软件KASAN模式都支持SLUB和SLAB分配器,而基于硬件标签的
+KASAN只支持SLUB。
+
+用法
+----
+
+要启用KASAN,请使用以下命令配置内核::
+
+ CONFIG_KASAN=y
+
+同时在 ``CONFIG_KASAN_GENERIC`` (启用通用KASAN模式), ``CONFIG_KASAN_SW_TAGS``
+(启用基于硬件标签的KASAN模式),和 ``CONFIG_KASAN_HW_TAGS`` (启用基于硬件标签
+的KASAN模式)之间进行选择。
+
+对于软件模式,还可以在 ``CONFIG_KASAN_OUTLINE`` 和 ``CONFIG_KASAN_INLINE``
+之间进行选择。outline和inline是编译器插桩类型。前者产生较小的二进制文件,
+而后者快2倍。
+
+要将受影响的slab对象的alloc和free堆栈跟踪包含到报告中,请启用
+``CONFIG_STACKTRACE`` 。要包括受影响物理页面的分配和释放堆栈跟踪的话,
+请启用 ``CONFIG_PAGE_OWNER`` 并使用 ``page_owner=on`` 进行引导。
+
+启动参数
+~~~~~~~~
+
+KASAN受到通用 ``panic_on_warn`` 命令行参数的影响。当它被启用时,KASAN
+在打印出错误报告后会使内核恐慌。
+
+默认情况下,KASAN只对第一个无效的内存访问打印错误报告。使用
+``kasan_multi_shot``,KASAN对每一个无效的访问都打印一份报告。这会禁用
+了KASAN报告的 ``panic_on_warn``。
+
+另外,独立于 ``panic_on_warn`` 、 ``kasan.fault=`` boot参数可以用
+来控制恐慌和报告行为。
+
+- ``kasan.fault=report`` 或 ``=panic`` 控制是否只打印KASAN report或
+ 同时使内核恐慌(默认: ``report`` )。即使 ``kasan_multi_shot`` 被
+ 启用,恐慌也会发生。
+
+基于软件和硬件标签的KASAN模式(见下面关于各种模式的部分)支持改变堆栈跟
+踪收集行为:
+
+- ``kasan.stacktrace=off`` 或 ``=on`` 禁用或启用分配和释放堆栈痕
+ 迹的收集(默认: ``on`` )。
+
+- ``kasan.stack_ring_size=<number of entries>`` 指定堆栈环的条
+ 目数(默认: ``32768`` )。
+
+基于硬件标签的KASAN模式是为了在生产中作为一种安全缓解措施使用。因此,它
+支持额外的启动参数,允许完全禁用KASAN或控制其功能。
+
+- ``kasan=off`` 或 ``=on`` 控制KASAN是否被启用(默认: ``on`` )。
+
+- ``kasan.mode=sync``, ``=async`` or ``=asymm`` 控制KASAN是否
+ 被配置为同步、异步或非对称的执行模式(默认: ``同步`` )。
+ 同步模式:当标签检查异常发生时,会立即检测到不良访问。
+ 异步模式:不良访问的检测是延迟的。当标签检查异常发生时,信息被存储在硬
+ 件中(对于arm64来说是在TFSR_EL1寄存器中)。内核周期性地检查硬件,并\
+ 且只在这些检查中报告标签异常。
+ 非对称模式:读取时同步检测不良访问,写入时异步检测。
+
+- ``kasan.vmalloc=off`` or ``=on`` 禁用或启用vmalloc分配的标记(默认: ``on`` )。
+
+错误报告
+~~~~~~~~
+
+典型的KASAN报告如下所示::
+
+ ==================================================================
+ BUG: KASAN: slab-out-of-bounds in kmalloc_oob_right+0xa8/0xbc [test_kasan]
+ Write of size 1 at addr ffff8801f44ec37b by task insmod/2760
+
+ CPU: 1 PID: 2760 Comm: insmod Not tainted 4.19.0-rc3+ #698
+ Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014
+ Call Trace:
+ dump_stack+0x94/0xd8
+ print_address_description+0x73/0x280
+ kasan_report+0x144/0x187
+ __asan_report_store1_noabort+0x17/0x20
+ kmalloc_oob_right+0xa8/0xbc [test_kasan]
+ kmalloc_tests_init+0x16/0x700 [test_kasan]
+ do_one_initcall+0xa5/0x3ae
+ do_init_module+0x1b6/0x547
+ load_module+0x75df/0x8070
+ __do_sys_init_module+0x1c6/0x200
+ __x64_sys_init_module+0x6e/0xb0
+ do_syscall_64+0x9f/0x2c0
+ entry_SYSCALL_64_after_hwframe+0x44/0xa9
+ RIP: 0033:0x7f96443109da
+ RSP: 002b:00007ffcf0b51b08 EFLAGS: 00000202 ORIG_RAX: 00000000000000af
+ RAX: ffffffffffffffda RBX: 000055dc3ee521a0 RCX: 00007f96443109da
+ RDX: 00007f96445cff88 RSI: 0000000000057a50 RDI: 00007f9644992000
+ RBP: 000055dc3ee510b0 R08: 0000000000000003 R09: 0000000000000000
+ R10: 00007f964430cd0a R11: 0000000000000202 R12: 00007f96445cff88
+ R13: 000055dc3ee51090 R14: 0000000000000000 R15: 0000000000000000
+
+ Allocated by task 2760:
+ save_stack+0x43/0xd0
+ kasan_kmalloc+0xa7/0xd0
+ kmem_cache_alloc_trace+0xe1/0x1b0
+ kmalloc_oob_right+0x56/0xbc [test_kasan]
+ kmalloc_tests_init+0x16/0x700 [test_kasan]
+ do_one_initcall+0xa5/0x3ae
+ do_init_module+0x1b6/0x547
+ load_module+0x75df/0x8070
+ __do_sys_init_module+0x1c6/0x200
+ __x64_sys_init_module+0x6e/0xb0
+ do_syscall_64+0x9f/0x2c0
+ entry_SYSCALL_64_after_hwframe+0x44/0xa9
+
+ Freed by task 815:
+ save_stack+0x43/0xd0
+ __kasan_slab_free+0x135/0x190
+ kasan_slab_free+0xe/0x10
+ kfree+0x93/0x1a0
+ umh_complete+0x6a/0xa0
+ call_usermodehelper_exec_async+0x4c3/0x640
+ ret_from_fork+0x35/0x40
+
+ The buggy address belongs to the object at ffff8801f44ec300
+ which belongs to the cache kmalloc-128 of size 128
+ The buggy address is located 123 bytes inside of
+ 128-byte region [ffff8801f44ec300, ffff8801f44ec380)
+ The buggy address belongs to the page:
+ page:ffffea0007d13b00 count:1 mapcount:0 mapping:ffff8801f7001640 index:0x0
+ flags: 0x200000000000100(slab)
+ raw: 0200000000000100 ffffea0007d11dc0 0000001a0000001a ffff8801f7001640
+ raw: 0000000000000000 0000000080150015 00000001ffffffff 0000000000000000
+ page dumped because: kasan: bad access detected
+
+ Memory state around the buggy address:
+ ffff8801f44ec200: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb
+ ffff8801f44ec280: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
+ >ffff8801f44ec300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03
+ ^
+ ffff8801f44ec380: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb
+ ffff8801f44ec400: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
+ ==================================================================
+
+报告标题总结了发生的错误类型以及导致该错误的访问类型。紧随其后的是错误访问的
+堆栈跟踪、所访问内存分配位置的堆栈跟踪(对于访问了slab对象的情况)以及对象
+被释放的位置的堆栈跟踪(对于访问已释放内存的问题报告)。接下来是对访问的
+slab对象的描述以及关于访问的内存页的信息。
+
+最后,报告展示了访问地址周围的内存状态。在内部,KASAN单独跟踪每个内存颗粒的
+内存状态,根据KASAN模式分为8或16个对齐字节。报告的内存状态部分中的每个数字
+都显示了围绕访问地址的其中一个内存颗粒的状态。
+
+对于通用KASAN,每个内存颗粒的大小为8个字节。每个颗粒的状态被编码在一个影子字节
+中。这8个字节可以是可访问的,部分访问的,已释放的或成为Redzone的一部分。KASAN
+对每个影子字节使用以下编码:00表示对应内存区域的所有8个字节都可以访问;数字N
+(1 <= N <= 7)表示前N个字节可访问,其他(8 - N)个字节不可访问;任何负值都表示
+无法访问整个8字节。KASAN使用不同的负值来区分不同类型的不可访问内存,如redzones
+或已释放的内存(参见 mm/kasan/kasan.h)。
+
+在上面的报告中,箭头指向影子字节 ``03`` ,表示访问的地址是部分可访问的。
+
+对于基于标签的KASAN模式,报告最后的部分显示了访问地址周围的内存标签
+(参考 `实施细则`_ 章节)。
+
+请注意,KASAN错误标题(如 ``slab-out-of-bounds`` 或 ``use-after-free`` )
+是尽量接近的:KASAN根据其拥有的有限信息打印出最可能的错误类型。错误的实际类型
+可能会有所不同。
+
+通用KASAN还报告两个辅助调用堆栈跟踪。这些堆栈跟踪指向代码中与对象交互但不直接
+出现在错误访问堆栈跟踪中的位置。目前,这包括 call_rcu() 和排队的工作队列。
+
+实施细则
+--------
+
+通用KASAN
+~~~~~~~~~
+
+软件KASAN模式使用影子内存来记录每个内存字节是否可以安全访问,并使用编译时工具
+在每次内存访问之前插入影子内存检查。
+
+通用KASAN将1/8的内核内存专用于其影子内存(16TB以覆盖x86_64上的128TB),并使用
+具有比例和偏移量的直接映射将内存地址转换为其相应的影子地址。
+
+这是将地址转换为其相应影子地址的函数::
+
+ static inline void *kasan_mem_to_shadow(const void *addr)
+ {
+ return (void *)((unsigned long)addr >> KASAN_SHADOW_SCALE_SHIFT)
+ + KASAN_SHADOW_OFFSET;
+ }
+
+在这里 ``KASAN_SHADOW_SCALE_SHIFT = 3`` 。
+
+编译时工具用于插入内存访问检查。编译器在每次访问大小为1、2、4、8或16的内存之前
+插入函数调用( ``__asan_load*(addr)`` , ``__asan_store*(addr)``)。这些函数通过
+检查相应的影子内存来检查内存访问是否有效。
+
+使用inline插桩,编译器不进行函数调用,而是直接插入代码来检查影子内存。此选项
+显著地增大了内核体积,但与outline插桩内核相比,它提供了x1.1-x2的性能提升。
+
+通用KASAN是唯一一种通过隔离延迟重新使用已释放对象的模式
+(参见 mm/kasan/quarantine.c 以了解实现)。
+
+基于软件标签的KASAN模式
+~~~~~~~~~~~~~~~~~~~~~~~
+
+基于软件标签的KASAN使用软件内存标签方法来检查访问有效性。目前仅针对arm64架构实现。
+
+基于软件标签的KASAN使用arm64 CPU的顶部字节忽略(TBI)特性在内核指针的顶部字节中
+存储一个指针标签。它使用影子内存来存储与每个16字节内存单元相关的内存标签(因此,
+它将内核内存的1/16专用于影子内存)。
+
+在每次内存分配时,基于软件标签的KASAN都会生成一个随机标签,用这个标签标记分配
+的内存,并将相同的标签嵌入到返回的指针中。
+
+基于软件标签的KASAN使用编译时工具在每次内存访问之前插入检查。这些检查确保正在
+访问的内存的标签等于用于访问该内存的指针的标签。如果标签不匹配,基于软件标签
+的KASAN会打印错误报告。
+
+基于软件标签的KASAN也有两种插桩模式(outline,发出回调来检查内存访问;inline,
+执行内联的影子内存检查)。使用outline插桩模式,会从执行访问检查的函数打印错误
+报告。使用inline插桩,编译器会发出 ``brk`` 指令,并使用专用的 ``brk`` 处理程序
+来打印错误报告。
+
+基于软件标签的KASAN使用0xFF作为匹配所有指针标签(不检查通过带有0xFF指针标签
+的指针进行的访问)。值0xFE当前保留用于标记已释放的内存区域。
+
+
+基于硬件标签的KASAN模式
+~~~~~~~~~~~~~~~~~~~~~~~
+
+基于硬件标签的KASAN在概念上类似于软件模式,但它是使用硬件内存标签作为支持而
+不是编译器插桩和影子内存。
+
+基于硬件标签的KASAN目前仅针对arm64架构实现,并且基于ARMv8.5指令集架构中引入
+的arm64内存标记扩展(MTE)和最高字节忽略(TBI)。
+
+特殊的arm64指令用于为每次内存分配指定内存标签。相同的标签被指定给指向这些分配
+的指针。在每次内存访问时,硬件确保正在访问的内存的标签等于用于访问该内存的指针
+的标签。如果标签不匹配,则会生成故障并打印报告。
+
+基于硬件标签的KASAN使用0xFF作为匹配所有指针标签(不检查通过带有0xFF指针标签的
+指针进行的访问)。值0xFE当前保留用于标记已释放的内存区域。
+
+如果硬件不支持MTE(ARMv8.5之前),则不会启用基于硬件标签的KASAN。在这种情况下,
+所有KASAN引导参数都将被忽略。
+
+请注意,启用CONFIG_KASAN_HW_TAGS始终会导致启用内核中的TBI。即使提供了
+``kasan.mode=off`` 或硬件不支持MTE(但支持TBI)。
+
+基于硬件标签的KASAN只报告第一个发现的错误。之后,MTE标签检查将被禁用。
+
+影子内存
+--------
+
+本节的内容只适用于软件KASAN模式。
+
+内核将内存映射到地址空间的几个不同部分。内核虚拟地址的范围很大:没有足够的真实
+内存来支持内核可以访问的每个地址的真实影子区域。因此,KASAN只为地址空间的某些
+部分映射真实的影子。
+
+默认行为
+~~~~~~~~
+
+默认情况下,体系结构仅将实际内存映射到用于线性映射的阴影区域(以及可能的其他
+小区域)。对于所有其他区域 —— 例如vmalloc和vmemmap空间 —— 一个只读页面被映射
+到阴影区域上。这个只读的影子页面声明所有内存访问都是允许的。
+
+这给模块带来了一个问题:它们不存在于线性映射中,而是存在于专用的模块空间中。
+通过连接模块分配器,KASAN临时映射真实的影子内存以覆盖它们。例如,这允许检测
+对模块全局变量的无效访问。
+
+这也造成了与 ``VMAP_STACK`` 的不兼容:如果堆栈位于vmalloc空间中,它将被分配
+只读页面的影子内存,并且内核在尝试为堆栈变量设置影子数据时会出错。
+
+CONFIG_KASAN_VMALLOC
+~~~~~~~~~~~~~~~~~~~~
+
+使用 ``CONFIG_KASAN_VMALLOC`` ,KASAN可以以更大的内存使用为代价覆盖vmalloc
+空间。目前,这在arm64、x86、riscv、s390和powerpc上受支持。
+
+这通过连接到vmalloc和vmap并动态分配真实的影子内存来支持映射。
+
+vmalloc空间中的大多数映射都很小,需要不到一整页的阴影空间。因此,为每个映射
+分配一个完整的影子页面将是一种浪费。此外,为了确保不同的映射使用不同的影子
+页面,映射必须与 ``KASAN_GRANULE_SIZE * PAGE_SIZE`` 对齐。
+
+相反,KASAN跨多个映射共享后备空间。当vmalloc空间中的映射使用影子区域的特定
+页面时,它会分配一个后备页面。此页面稍后可以由其他vmalloc映射共享。
+
+KASAN连接到vmap基础架构以懒清理未使用的影子内存。
+
+为了避免交换映射的困难,KASAN预测覆盖vmalloc空间的阴影区域部分将不会被早期
+的阴影页面覆盖,但是将不会被映射。这将需要更改特定于arch的代码。
+
+这允许在x86上支持 ``VMAP_STACK`` ,并且可以简化对没有固定模块区域的架构的支持。
+
+对于开发者
+----------
+
+忽略访问
+~~~~~~~~
+
+软件KASAN模式使用编译器插桩来插入有效性检查。此类检测可能与内核的某些部分
+不兼容,因此需要禁用。
+
+内核的其他部分可能会访问已分配对象的元数据。通常,KASAN会检测并报告此类访问,
+但在某些情况下(例如,在内存分配器中),这些访问是有效的。
+
+对于软件KASAN模式,要禁用特定文件或目录的检测,请将 ``KASAN_SANITIZE`` 添加
+到相应的内核Makefile中:
+
+- 对于单个文件(例如,main.o)::
+
+ KASAN_SANITIZE_main.o := n
+
+- 对于一个目录下的所有文件::
+
+ KASAN_SANITIZE := n
+
+对于软件KASAN模式,要在每个函数的基础上禁用检测,请使用KASAN特定的
+``__no_sanitize_address`` 函数属性或通用的 ``noinstr`` 。
+
+请注意,禁用编译器插桩(基于每个文件或每个函数)会使KASAN忽略在软件KASAN模式
+的代码中直接发生的访问。当访问是间接发生的(通过调用检测函数)或使用没有编译器
+插桩的基于硬件标签的模式时,它没有帮助。
+
+对于软件KASAN模式,要在当前任务的一部分内核代码中禁用KASAN报告,请使用
+``kasan_disable_current()``/``kasan_enable_current()`` 部分注释这部分代码。
+这也会禁用通过函数调用发生的间接访问的报告。
+
+对于基于标签的KASAN模式,要禁用访问检查,请使用 ``kasan_reset_tag()`` 或
+``page_kasan_tag_reset()`` 。请注意,通过 ``page_kasan_tag_reset()``
+临时禁用访问检查需要通过 ``page_kasan_tag`` / ``page_kasan_tag_set`` 保
+存和恢复每页KASAN标签。
+
+测试
+~~~~
+
+有一些KASAN测试可以验证KASAN是否正常工作并可以检测某些类型的内存损坏。
+测试由两部分组成:
+
+1. 与KUnit测试框架集成的测试。使用 ``CONFIG_KASAN_KUNIT_TEST`` 启用。
+这些测试可以通过几种不同的方式自动运行和部分验证;请参阅下面的说明。
+
+2. 与KUnit不兼容的测试。使用 ``CONFIG_KASAN_MODULE_TEST`` 启用并且只能作为模块
+运行。这些测试只能通过加载内核模块并检查内核日志以获取KASAN报告来手动验证。
+
+如果检测到错误,每个KUnit兼容的KASAN测试都会打印多个KASAN报告之一,然后测试打印
+其编号和状态。
+
+当测试通过::
+
+ ok 28 - kmalloc_double_kzfree
+
+当由于 ``kmalloc`` 失败而导致测试失败时::
+
+ # kmalloc_large_oob_right: ASSERTION FAILED at lib/test_kasan.c:163
+ Expected ptr is not null, but is
+ not ok 4 - kmalloc_large_oob_right
+
+当由于缺少KASAN报告而导致测试失败时::
+
+ # kmalloc_double_kzfree: EXPECTATION FAILED at lib/test_kasan.c:974
+ KASAN failure expected in "kfree_sensitive(ptr)", but none occurred
+ not ok 44 - kmalloc_double_kzfree
+
+
+最后打印所有KASAN测试的累积状态。成功::
+
+ ok 1 - kasan
+
+或者,如果其中一项测试失败::
+
+ not ok 1 - kasan
+
+有几种方法可以运行与KUnit兼容的KASAN测试。
+
+1. 可加载模块
+
+ 启用 ``CONFIG_KUNIT`` 后,KASAN-KUnit测试可以构建为可加载模块,并通过使用
+ ``insmod`` 或 ``modprobe`` 加载 ``test_kasan.ko`` 来运行。
+
+2. 内置
+
+ 通过内置 ``CONFIG_KUNIT`` ,也可以内置KASAN-KUnit测试。在这种情况下,
+ 测试将在启动时作为后期初始化调用运行。
+
+3. 使用kunit_tool
+
+ 通过内置 ``CONFIG_KUNIT`` 和 ``CONFIG_KASAN_KUNIT_TEST`` ,还可以使用
+ ``kunit_tool`` 以更易读的方式查看KUnit测试结果。这不会打印通过测试
+ 的KASAN报告。有关 ``kunit_tool`` 更多最新信息,请参阅
+ `KUnit文档 <https://www.kernel.org/doc/html/latest/dev-tools/kunit/index.html>`_ 。
+
+.. _KUnit: https://www.kernel.org/doc/html/latest/dev-tools/kunit/index.html
diff --git a/Documentation/translations/zh_CN/sparse.txt b/Documentation/translations/zh_CN/dev-tools/sparse.rst
index 0f444b83d639..0664c634bc4f 100644
--- a/Documentation/translations/zh_CN/sparse.txt
+++ b/Documentation/translations/zh_CN/dev-tools/sparse.rst
@@ -1,34 +1,34 @@
-Chinese translated version of Documentation/dev-tools/sparse.rst
+Copyright 2004 Linus Torvalds
+Copyright 2004 Pavel Machek <pavel@ucw.cz>
+Copyright 2006 Bob Copeland <me@bobcopeland.com>
-If you have any comment or update to the content, please contact the
-original document maintainer directly. However, if you have a problem
-communicating in English you can also ask the Chinese maintainer for
-help. Contact the Chinese maintainer if this translation is outdated
-or if there is a problem with the translation.
+.. include:: ../disclaimer-zh_CN.rst
-Chinese maintainer: Li Yang <leoyang.li@nxp.com>
----------------------------------------------------------------------
-Documentation/dev-tools/sparse.rst 的中文翻译
+:Original: Documentation/dev-tools/sparse.rst
-如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
-交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
-译存在问题,请联系中文版维护者。
+:翻译:
-中文版维护者: 李阳 Li Yang <leoyang.li@nxp.com>
-中文版翻译者: 李阳 Li Yang <leoyang.li@nxp.com>
+ Li Yang <leoyang.li@nxp.com>
+:校译:
-以下为正文
----------------------------------------------------------------------
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
-Copyright 2004 Linus Torvalds
-Copyright 2004 Pavel Machek <pavel@ucw.cz>
-Copyright 2006 Bob Copeland <me@bobcopeland.com>
+.. _cn_sparse:
+
+Sparse
+======
+
+Sparse是一个C程序的语义检查器;它可以用来发现内核代码的一些潜在问题。 关
+于sparse的概述,请参见https://lwn.net/Articles/689907/;本文档包含
+一些针对内核的sparse信息。
+关于sparse的更多信息,主要是关于它的内部结构,可以在它的官方网页上找到:
+https://sparse.docs.kernel.org。
使用 sparse 工具做类型检查
~~~~~~~~~~~~~~~~~~~~~~~~~~
-"__bitwise" 是一种类型属性,所以你应该这样使用它:
+"__bitwise" 是一种类型属性,所以你应该这样使用它::
typedef int __bitwise pm_request_t;
@@ -48,7 +48,7 @@ Copyright 2006 Bob Copeland <me@bobcopeland.com>
坦白来说,你并不需要使用枚举类型。上面那些实际都可以浓缩成一个特殊的"int
__bitwise"类型。
-所以更简单的办法只要这样做:
+所以更简单的办法只要这样做::
typedef int __bitwise pm_request_t;
@@ -60,25 +60,42 @@ __bitwise"类型。
一个小提醒:常数整数"0"是特殊的。你可以直接把常数零当作位方式整数使用而
不用担心 sparse 会抱怨。这是因为"bitwise"(恰如其名)是用来确保不同位方
式类型不会被弄混(小尾模式,大尾模式,cpu尾模式,或者其他),对他们来说
-常数"0"确实是特殊的。
+常数"0"确实 **是** 特殊的。
+
+使用sparse进行锁检查
+--------------------
+
+下面的宏对于 gcc 来说是未定义的,在 sparse 运行时定义,以使用sparse的“上下文”
+跟踪功能,应用于锁定。 这些注释告诉 sparse 什么时候有锁,以及注释的函数的进入和
+退出。
+
+__must_hold - 指定的锁在函数进入和退出时被持有。
+
+__acquires - 指定的锁在函数退出时被持有,但在进入时不被持有。
+
+__releases - 指定的锁在函数进入时被持有,但在退出时不被持有。
+
+如果函数在不持有锁的情况下进入和退出,在函数内部以平衡的方式获取和释放锁,则不
+需要注释。
+上面的三个注释是针对sparse否则会报告上下文不平衡的情况。
获取 sparse 工具
~~~~~~~~~~~~~~~~
你可以从 Sparse 的主页获取最新的发布版本:
- http://www.kernel.org/pub/linux/kernel/people/josh/sparse/
+ https://www.kernel.org/pub/software/devel/sparse/dist/
或者,你也可以使用 git 克隆最新的 sparse 开发版本:
- git://git.kernel.org/pub/scm/linux/kernel/git/josh/sparse.git
+ git://git.kernel.org/pub/scm/devel/sparse/sparse.git
一旦你下载了源码,只要以普通用户身份运行:
make
make install
-它将会被自动安装到你的 ~/bin 目录下。
+如果是标准的用户,它将会被自动安装到你的~/bin目录下。
使用 sparse 工具
~~~~~~~~~~~~~~~~
@@ -89,3 +106,5 @@ __bitwise"类型。
make 的可选变量 CHECKFLAGS 可以用来向 sparse 工具传递参数。编译系统会自
动向 sparse 工具传递 -Wbitwise 参数。
+
+注意sparse定义了__CHECKER__预处理器符号。 \ No newline at end of file
diff --git a/Documentation/translations/zh_CN/dev-tools/testing-overview.rst b/Documentation/translations/zh_CN/dev-tools/testing-overview.rst
new file mode 100644
index 000000000000..c91f9b60f9f1
--- /dev/null
+++ b/Documentation/translations/zh_CN/dev-tools/testing-overview.rst
@@ -0,0 +1,161 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/dev-tools/testing-overview.rst
+:Translator: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+============
+内核测试指南
+============
+
+有许多不同的工具可以用于测试Linux内核,因此了解什么时候使用它们可能
+很困难。本文档粗略概述了它们之间的区别,并阐释了它们是怎样糅合在一起
+的。
+
+编写和运行测试
+==============
+
+大多数内核测试都是用kselftest或KUnit框架之一编写的。它们都让运行测试
+更加简化,并为编写新测试提供帮助。
+
+如果你想验证内核的行为——尤其是内核的特定部分——那你就要使用kUnit或
+kselftest。
+
+KUnit和kselftest的区别
+----------------------
+
+.. note::
+ 由于本文段中部分术语尚无较好的对应中文释义,可能导致与原文含义
+ 存在些许差异,因此建议读者结合原文
+ (Documentation/dev-tools/testing-overview.rst)辅助阅读。
+ 如对部分翻译有异议或有更好的翻译意见,欢迎联系译者进行修订。
+
+KUnit(Documentation/dev-tools/kunit/index.rst)是用于“白箱”测
+试的一个完整的内核内部系统:因为测试代码是内核的一部分,所以它能够访
+问用户空间不能访问到的内部结构和功能。
+
+因此,KUnit测试最好针对内核中较小的、自包含的部分,以便能够独立地测
+试。“单元”测试的概念亦是如此。
+
+比如,一个KUnit测试可能测试一个单独的内核功能(甚至通过一个函数测试
+一个单一的代码路径,例如一个错误处理案例),而不是整个地测试一个特性。
+
+这也使得KUnit测试构建和运行非常地快,从而能够作为开发流程的一部分被
+频繁地运行。
+
+有关更详细的介绍,请参阅KUnit测试代码风格指南
+Documentation/dev-tools/kunit/style.rst
+
+kselftest(Documentation/dev-tools/kselftest.rst),相对来说,大量用
+于用户空间,并且通常测试用户空间的脚本或程序。
+
+这使得编写复杂的测试,或者需要操作更多全局系统状态的测试更加容易(诸
+如生成进程之类)。然而,从kselftest直接调用内核函数是不行的。这也就
+意味着只有通过某种方式(如系统调用、驱动设备、文件系统等)导出到了用
+户空间的内核功能才能使用kselftest来测试。为此,有些测试包含了一个伴
+生的内核模块用于导出更多的信息和功能。不过,对于基本上或者完全在内核
+中运行的测试,KUnit可能是更佳工具。
+
+kselftest也因此非常适合于全部功能的测试,因为这些功能会将接口暴露到
+用户空间,从而能够被测试,而不是展现实现细节。“system”测试和
+“end-to-end”测试亦是如此。
+
+比如,一个新的系统调用应该伴随有新的kselftest测试。
+
+代码覆盖率工具
+==============
+
+支持两种不同代码之间的覆盖率测量工具。它们可以用来验证一项测试执行的
+确切函数或代码行。这有助于决定内核被测试了多少,或用来查找合适的测试
+中没有覆盖到的极端情况。
+
+Documentation/translations/zh_CN/dev-tools/gcov.rst 是GCC的覆盖率测试
+工具,能用于获取内核的全局或每个模块的覆盖率。与KCOV不同的是,这个工具
+不记录每个任务的覆盖率。覆盖率数据可以通过debugfs读取,并通过常规的
+gcov工具进行解释。
+
+Documentation/dev-tools/kcov.rst 是能够构建在内核之中,用于在每个任务
+的层面捕捉覆盖率的一个功能。因此,它对于模糊测试和关于代码执行期间信
+息的其它情况非常有用,比如在一个单一系统调用里使用它就很有用。
+
+动态分析工具
+============
+
+内核也支持许多动态分析工具,用以检测正在运行的内核中出现的多种类型的
+问题。这些工具通常每个去寻找一类不同的缺陷,比如非法内存访问,数据竞
+争等并发问题,或整型溢出等其他未定义行为。
+
+如下所示:
+
+* kmemleak检测可能的内存泄漏。参阅
+ Documentation/dev-tools/kmemleak.rst
+* KASAN检测非法内存访问,如数组越界和释放后重用(UAF)。参阅
+ Documentation/dev-tools/kasan.rst
+* UBSAN检测C标准中未定义的行为,如整型溢出。参阅
+ Documentation/dev-tools/ubsan.rst
+* KCSAN检测数据竞争。参阅 Documentation/dev-tools/kcsan.rst
+* KFENCE是一个低开销的内存问题检测器,比KASAN更快且能被用于批量构建。
+ 参阅 Documentation/dev-tools/kfence.rst
+* lockdep是一个锁定正确性检测器。参阅
+ Documentation/locking/lockdep-design.rst
+* 除此以外,在内核中还有一些其它的调试工具,大多数能在
+ lib/Kconfig.debug 中找到。
+
+这些工具倾向于对内核进行整体测试,并且不像kselftest和KUnit一样“传递”。
+它们可以通过在启用这些工具时运行内核测试以与kselftest或KUnit结合起来:
+之后你就能确保这些错误在测试过程中都不会发生了。
+
+一些工具与KUnit和kselftest集成,并且在检测到问题时会自动打断测试。
+
+静态分析工具
+============
+
+除了测试运行中的内核,我们还可以使用**静态分析**工具直接分析内核的源代
+码(**在编译时**)。内核中常用的工具允许人们检查整个源代码树或其中的特
+定文件。它们使得在开发过程中更容易发现和修复问题。
+
+ Sparse可以通过执行类型检查、锁检查、值范围检查来帮助测试内核,此外还
+ 可以在检查代码时报告各种错误和警告。关于如何使用它的细节,请参阅
+ Documentation/translations/zh_CN/dev-tools/sparse.rst。
+
+ Smatch扩展了Sparse,并提供了对编程逻辑错误的额外检查,如开关语句中
+ 缺少断点,错误检查中未使用的返回值,忘记在错误路径的返回中设置错误代
+ 码等。Smatch也有针对更严重问题的测试,如整数溢出、空指针解除引用和内
+ 存泄漏。见项目页面http://smatch.sourceforge.net/。
+
+ Coccinelle是我们可以使用的另一个静态分析器。Coccinelle经常被用来
+ 帮助源代码的重构和并行演化,但它也可以帮助避免常见代码模式中出现的某
+ 些错误。可用的测试类型包括API测试、内核迭代器的正确使用测试、自由操
+ 作的合理性检查、锁定行为的分析,以及已知的有助于保持内核使用一致性的
+ 进一步测试。详情请见Documentation/dev-tools/coccinelle.rst。
+
+ 不过要注意的是,静态分析工具存在**假阳性**的问题。在试图修复错误和警
+ 告之前,需要仔细评估它们。
+
+何时使用Sparse和Smatch
+----------------------
+
+Sparse做类型检查,例如验证注释的变量不会导致无符号的错误,检测
+``__user`` 指针使用不当的地方,以及分析符号初始化器的兼容性。
+
+Smatch进行流程分析,如果允许建立函数数据库,它还会进行跨函数分析。
+Smatch试图回答一些问题,比如这个缓冲区是在哪里分配的?它有多大?这
+个索引可以由用户控制吗?这个变量比那个变量大吗?
+
+一般来说,在Smatch中写检查比在Sparse中写检查要容易。尽管如此,
+Sparse和Smatch的检查还是有一些重叠的地方。
+
+Smatch和Coccinelle的强项
+------------------------
+
+Coccinelle可能是最容易写检查的。它在预处理器之前工作,所以用Coccinelle
+检查宏中的错误更容易。Coccinelle还能为你创建补丁,这是其他工具无法做到的。
+
+例如,用Coccinelle你可以从 ``kmalloc_array(x, size, GFP_KERNEL)``
+到 ``kmalloc_array(x, size, GFP_KERNEL)`` 进行大规模转换,这真的很
+有用。如果你只是创建一个Smatch警告,并试图把转换的工作推给维护者,他们会很
+恼火。你将不得不为每个警告争论是否真的可以溢出。
+
+Coccinelle不对变量值进行分析,而这正是Smatch的强项。另一方面,Coccinelle
+允许你用简单的方法做简单的事情。
diff --git a/Documentation/translations/zh_CN/devicetree/changesets.rst b/Documentation/translations/zh_CN/devicetree/changesets.rst
new file mode 100644
index 000000000000..3df1b03c5695
--- /dev/null
+++ b/Documentation/translations/zh_CN/devicetree/changesets.rst
@@ -0,0 +1,37 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/devicetree/changesets.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+============
+设备树变更集
+============
+
+设备树变更集是一种方法,它允许人们以这样一种方式在实时树中使用变化,即要么使用全部的
+变化,要么不使用。如果在使用变更集的过程中发生错误,那么树将被回滚到之前的状态。一个
+变更集也可以在使用后被删除。
+
+当一个变更集被使用时,所有的改变在发出OF_RECONFIG通知器之前被一次性使用到树上。这是
+为了让接收者在收到通知时看到一个完整的、一致的树的状态。
+
+一个变化集的顺序如下。
+
+1. of_changeset_init() - 初始化一个变更集。
+
+2. 一些DT树变化的调用,of_changeset_attach_node(), of_changeset_detach_node(),
+ of_changeset_add_property(), of_changeset_remove_property,
+ of_changeset_update_property()来准备一组变更。此时不会对活动树做任何变更。所有
+ 的变更操作都记录在of_changeset的 `entries` 列表中。
+
+3. of_changeset_apply() - 将变更使用到树上。要么整个变更集被使用,要么如果有错误,
+ 树会被恢复到之前的状态。核心通过锁确保正确的顺序。如果需要的话,可以使用一个解锁的
+ __of_changeset_apply版本。
+
+如果一个成功使用的变更集需要被删除,可以用of_changeset_revert()来完成。
diff --git a/Documentation/translations/zh_CN/devicetree/dynamic-resolution-notes.rst b/Documentation/translations/zh_CN/devicetree/dynamic-resolution-notes.rst
new file mode 100644
index 000000000000..6dfd946d7093
--- /dev/null
+++ b/Documentation/translations/zh_CN/devicetree/dynamic-resolution-notes.rst
@@ -0,0 +1,31 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/devicetree/dynamic-resolution-notes.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+========================
+Devicetree动态解析器说明
+========================
+
+本文描述了内核内DeviceTree解析器的实现,它位于drivers/of/resolver.c中。
+
+解析器如何工作?
+----------------
+
+解析器被赋予一个任意的树作为输入,该树用适当的dtc选项编译,并有一个/plugin/标签。这就产
+生了适当的__fixups__和__local_fixups__节点。
+
+解析器依次通过以下步骤工作:
+
+1. 从实时树中获取最大的设备树phandle值 + 1.
+2. 调整树的所有本地 phandles,以解决这个量。
+3. 使用 __local__fixups__ 节点信息以相同的量调整所有本地引用。
+4. 对于__fixups__节点中的每个属性,找到它在实时树中引用的节点。这是用来标记该节点的标签。
+5. 检索fixup的目标的phandle。
+6. 对于属性中的每个fixup,找到节点:属性:偏移的位置,并用phandle值替换它。
diff --git a/Documentation/translations/zh_CN/devicetree/index.rst b/Documentation/translations/zh_CN/devicetree/index.rst
new file mode 100644
index 000000000000..7451dbfdd3e5
--- /dev/null
+++ b/Documentation/translations/zh_CN/devicetree/index.rst
@@ -0,0 +1,45 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/devicetree/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+=============================
+Open Firmware 和 Devicetree
+=============================
+
+该文档是整个设备树文档的总目录,标题中多是业内默认的术语,初见就翻译成中文,
+晦涩难懂,因此尽量保留,后面翻译其子文档时,可能会根据语境,灵活地翻译为中文。
+
+内核Devicetree的使用
+=======================
+.. toctree::
+ :maxdepth: 1
+
+ usage-model
+ of_unittest
+ kernel-api
+
+Devicetree Overlays
+===================
+.. toctree::
+ :maxdepth: 1
+
+ changesets
+ dynamic-resolution-notes
+ overlay-notes
+
+Devicetree Bindings
+===================
+.. toctree::
+ :maxdepth: 1
+
+Todolist:
+
+* bindings/index
diff --git a/Documentation/translations/zh_CN/devicetree/kernel-api.rst b/Documentation/translations/zh_CN/devicetree/kernel-api.rst
new file mode 100644
index 000000000000..2fb729368b40
--- /dev/null
+++ b/Documentation/translations/zh_CN/devicetree/kernel-api.rst
@@ -0,0 +1,58 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/devicetree/kernel-api.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+=================
+内核中的设备树API
+=================
+
+核心函数
+--------
+
+该API在以下内核代码中:
+
+drivers/of/base.c
+
+include/linux/of.h
+
+drivers/of/property.c
+
+include/linux/of_graph.h
+
+drivers/of/address.c
+
+drivers/of/irq.c
+
+drivers/of/fdt.c
+
+驱动模型函数
+------------
+
+该API在以下内核代码中:
+
+include/linux/of_device.h
+
+drivers/of/device.c
+
+include/linux/of_platform.h
+
+drivers/of/platform.c
+
+覆盖和动态DT函数
+----------------
+
+该API在以下内核代码中:
+
+drivers/of/resolver.c
+
+drivers/of/dynamic.c
+
+drivers/of/overlay.c
diff --git a/Documentation/translations/zh_CN/devicetree/of_unittest.rst b/Documentation/translations/zh_CN/devicetree/of_unittest.rst
new file mode 100644
index 000000000000..11eb08ca8866
--- /dev/null
+++ b/Documentation/translations/zh_CN/devicetree/of_unittest.rst
@@ -0,0 +1,189 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/devicetree/of_unittest.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+=================================
+Open Firmware Devicetree 单元测试
+=================================
+
+作者: Gaurav Minocha <gaurav.minocha.os@gmail.com>
+
+1. 概述
+=======
+
+本文档解释了执行 OF 单元测试所需的测试数据是如何动态地附加到实时树上的,与机器的架构无关。
+
+建议在继续读下去之前,先阅读以下文件。
+
+(1) Documentation/devicetree/usage-model.rst
+(2) http://www.devicetree.org/Device_Tree_Usage
+
+OF Selftest被设计用来测试提供给设备驱动开发者的接口(include/linux/of.h),以从未扁平
+化的设备树数据结构中获取设备信息等。这个接口被大多数设备驱动在各种使用情况下使用。
+
+
+2. 测试数据
+===========
+
+设备树源文件(drivers/of/unittest-data/testcases.dts)包含执行drivers/of/unittest.c
+中自动化单元测试所需的测试数据。目前,以下设备树源包含文件(.dtsi)被包含在testcases.dt中::
+
+ drivers/of/unittest-data/tests-interrupts.dtsi
+ drivers/of/unittest-data/tests-platform.dtsi
+ drivers/of/unittest-data/tests-phandle.dtsi
+ drivers/of/unittest-data/tests-match.dtsi
+
+当内核在启用OF_SELFTEST的情况下被构建时,那么下面的make规则::
+
+ $(obj)/%.dtb: $(src)/%.dts FORCE
+ $(call if_changed_dep, dtc)
+
+用于将DT源文件(testcases.dts)编译成二进制blob(testcases.dtb),也被称为扁平化的DT。
+
+之后,使用以下规则将上述二进制blob包装成一个汇编文件(testcases.dtb.S)::
+
+ $(obj)/%.dtb.S: $(obj)/%.dtb
+ $(call cmd, dt_S_dtb)
+
+汇编文件被编译成一个对象文件(testcases.dtb.o),并被链接到内核镜像中。
+
+
+2.1. 添加测试数据
+-----------------
+
+未扁平化的设备树结构体:
+
+未扁平化的设备树由连接的设备节点组成,其树状结构形式如下所述::
+
+ // following struct members are used to construct the tree
+ struct device_node {
+ ...
+ struct device_node *parent;
+ struct device_node *child;
+ struct device_node *sibling;
+ ...
+ };
+
+图1描述了一个机器的未扁平化设备树的通用结构,只考虑了子节点和同级指针。存在另一个指针,
+``*parent`` ,用于反向遍历该树。因此,在一个特定的层次上,子节点和所有的兄弟姐妹节点将
+有一个指向共同节点的父指针(例如,child1、sibling2、sibling3、sibling4的父指针指向
+根节点)::
+
+ root ('/')
+ |
+ child1 -> sibling2 -> sibling3 -> sibling4 -> null
+ | | | |
+ | | | null
+ | | |
+ | | child31 -> sibling32 -> null
+ | | | |
+ | | null null
+ | |
+ | child21 -> sibling22 -> sibling23 -> null
+ | | | |
+ | null null null
+ |
+ child11 -> sibling12 -> sibling13 -> sibling14 -> null
+ | | | |
+ | | | null
+ | | |
+ null null child131 -> null
+ |
+ null
+
+Figure 1: 未扁平化的设备树的通用结构
+
+
+在执行OF单元测试之前,需要将测试数据附加到机器的设备树上(如果存在)。因此,当调用
+selftest_data_add()时,首先会读取通过以下内核符号链接到内核镜像中的扁平化设备树
+数据::
+
+ __dtb_testcases_begin - address marking the start of test data blob
+ __dtb_testcases_end - address marking the end of test data blob
+
+其次,它调用of_fdt_unflatten_tree()来解除扁平化的blob。最后,如果机器的设备树
+(即实时树)是存在的,那么它将未扁平化的测试数据树附加到实时树上,否则它将自己作为
+实时设备树附加。
+
+attach_node_and_children()使用of_attach_node()将节点附加到实时树上,如下所
+述。为了解释这一点,图2中描述的测试数据树被附加到图1中描述的实时树上::
+
+ root ('/')
+ |
+ testcase-data
+ |
+ test-child0 -> test-sibling1 -> test-sibling2 -> test-sibling3 -> null
+ | | | |
+ test-child01 null null null
+
+
+Figure 2: 将测试数据树附在实时树上的例子。
+
+根据上面的方案,实时树已经存在,所以不需要附加根('/')节点。所有其他节点都是通过在
+每个节点上调用of_attach_node()来附加的。
+
+在函数of_attach_node()中,新的节点被附在实时树中给定的父节点的子节点上。但是,如
+果父节点已经有了一个孩子,那么新节点就会取代当前的孩子,并将其变成其兄弟姐妹。因此,
+当测试案例的数据节点被连接到上面的实时树(图1)时,最终的结构如图3所示::
+
+ root ('/')
+ |
+ testcase-data -> child1 -> sibling2 -> sibling3 -> sibling4 -> null
+ | | | | |
+ (...) | | | null
+ | | child31 -> sibling32 -> null
+ | | | |
+ | | null null
+ | |
+ | child21 -> sibling22 -> sibling23 -> null
+ | | | |
+ | null null null
+ |
+ child11 -> sibling12 -> sibling13 -> sibling14 -> null
+ | | | |
+ null null | null
+ |
+ child131 -> null
+ |
+ null
+ -----------------------------------------------------------------------
+
+ root ('/')
+ |
+ testcase-data -> child1 -> sibling2 -> sibling3 -> sibling4 -> null
+ | | | | |
+ | (...) (...) (...) null
+ |
+ test-sibling3 -> test-sibling2 -> test-sibling1 -> test-child0 -> null
+ | | | |
+ null null null test-child01
+
+
+Figure 3: 附加测试案例数据后的实时设备树结构。
+
+
+聪明的读者会注意到,与先前的结构相比,test-child0节点成为最后一个兄弟姐妹(图2)。
+在连接了第一个test-child0节点之后,又连接了test-sibling1节点,该节点推动子节点
+(即test-child0)成为兄弟姐妹,并使自己成为子节点,如上所述。
+
+如果发现一个重复的节点(即如果一个具有相同full_name属性的节点已经存在于实时树中),
+那么该节点不会被附加,而是通过调用函数update_node_properties()将其属性更新到活
+树的节点中。
+
+
+2.2. 删除测试数据
+-----------------
+
+一旦测试用例执行完,selftest_data_remove被调用,以移除最初连接的设备节点(首先是
+叶子节点被分离,然后向上移动父节点被移除,最后是整个树)。selftest_data_remove()
+调用detach_node_and_children(),使用of_detach_node()将节点从实时设备树上分离。
+
+为了分离一个节点,of_detach_node()要么将给定节点的父节点的子节点指针更新为其同级节
+点,要么根据情况将前一个同级节点附在给定节点的同级节点上。就这样吧。 :)
diff --git a/Documentation/translations/zh_CN/devicetree/overlay-notes.rst b/Documentation/translations/zh_CN/devicetree/overlay-notes.rst
new file mode 100644
index 000000000000..43e3c0bc5a9f
--- /dev/null
+++ b/Documentation/translations/zh_CN/devicetree/overlay-notes.rst
@@ -0,0 +1,140 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/devicetree/overlay-notes.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+==============
+设备树覆盖说明
+==============
+
+本文档描述了drivers/of/overlay.c中的内核内设备树覆盖功能的实现,是
+Documentation/devicetree/dynamic-resolution-notes.rst[1]的配套文档。
+
+覆盖如何工作
+------------
+
+设备树覆盖的目的是修改内核的实时树,并使修改以反映变化的方式影响内核的状态。
+由于内核主要处理的是设备,任何新的设备节点如果导致一个活动的设备,就应该创建它,
+而如果设备节点被禁用或被全部删除,受影响的设备应该被取消注册。
+
+让我们举个例子,我们有一个foo板,它的基本树形图如下::
+
+ ---- foo.dts ---------------------------------------------------------------
+ /* FOO平台 */
+ /dts-v1/;
+ / {
+ compatible = "corp,foo";
+
+ /* 共享的资源 */
+ res: res {
+ };
+
+ /* 芯片上的外围设备 */
+ ocp: ocp {
+ /* 总是被实例化的外围设备 */
+ peripheral1 { ... };
+ };
+ };
+ ---- foo.dts ---------------------------------------------------------------
+
+覆盖bar.dts,
+::
+
+ ---- bar.dts - 按标签覆盖目标位置 ----------------------------
+ /dts-v1/;
+ /插件/;
+ &ocp {
+ /* bar外围 */
+ bar {
+ compatible = "corp,bar";
+ ... /* 各种属性和子节点 */
+ };
+ };
+ ---- bar.dts ---------------------------------------------------------------
+
+当加载(并按照[1]中描述的方式解决)时,应该产生foo+bar.dts::
+
+ ---- foo+bar.dts -----------------------------------------------------------
+ /* FOO平台 + bar外围 */
+ / {
+ compatible = "corp,foo";
+
+ /* 共享资源 */
+ res: res {
+ };
+
+ /* 芯片上的外围设备 */
+ ocp: ocp {
+ /* 总是被实例化的外围设备 */
+ peripheral1 { ... };
+
+ /* bar外围 */
+ bar {
+ compatible = "corp,bar";
+ ... /* 各种属性和子节点 */
+ };
+ };
+ };
+ ---- foo+bar.dts -----------------------------------------------------------
+
+作为覆盖的结果,已经创建了一个新的设备节点(bar),因此将注册一个bar平台设备,
+如果加载了匹配的设备驱动程序,将按预期创建设备。
+
+如果基础DT不是用-@选项编译的,那么“&ocp”标签将不能用于将覆盖节点解析到基础
+DT中的适当位置。在这种情况下,可以提供目标路径。通过标签的目标位置的语法是比
+较好的,因为不管标签在DT中出现在哪里,覆盖都可以被应用到任何包含标签的基础DT上。
+
+上面的bar.dts例子被修改为使用目标路径语法,即为::
+
+ ---- bar.dts - 通过明确的路径覆盖目标位置 --------------------
+ /dts-v1/;
+ /插件/;
+ &{/ocp} {
+ /* bar外围 */
+ bar {
+ compatible = "corp,bar";
+ ... /* 各种外围设备和子节点 */
+ }
+ };
+ ---- bar.dts ---------------------------------------------------------------
+
+
+内核中关于覆盖的API
+-------------------
+
+该API相当容易使用。
+
+1) 调用of_overlay_fdt_apply()来创建和应用一个覆盖的变更集。返回值是一个
+ 错误或一个识别这个覆盖的cookie。
+
+2) 调用of_overlay_remove()来删除和清理先前通过调用of_overlay_fdt_apply()
+ 而创建的覆盖变更集。不允许删除一个被另一个覆盖的覆盖变化集。
+
+最后,如果你需要一次性删除所有的覆盖,只需调用of_overlay_remove_all(),
+它将以正确的顺序删除每一个覆盖。
+
+你可以选择注册在覆盖操作中被调用的通知器。详见
+of_overlay_notifier_register/unregister和enum of_overlay_notify_action。
+
+OF_OVERLAY_PRE_APPLY、OF_OVERLAY_POST_APPLY或OF_OVERLAY_PRE_REMOVE
+的通知器回调可以存储指向覆盖层中的设备树节点或其内容的指针,但这些指针不能持
+续到OF_OVERLAY_POST_REMOVE的通知器回调。在OF_OVERLAY_POST_REMOVE通
+知器被调用后,包含覆盖层的内存将被kfree()ed。请注意,即使OF_OVERLAY_POST_REMOVE
+的通知器返回错误,内存也会被kfree()ed。
+
+drivers/of/dynamic.c中的变更集通知器是第二种类型的通知器,可以通过应用或移除
+覆盖层来触发。这些通知器不允许在覆盖层或其内容中存储指向设备树节点的指针。当包含
+覆盖层的内存因移除覆盖层而被释放时,覆盖层代码并不能防止这类指针仍然有效。
+
+任何其他保留指向覆盖层节点或数据的指针的代码都被认为是一个错误,因为在移除覆盖层
+后,该指针将指向已释放的内存。
+
+覆盖层的用户必须特别注意系统上发生的整体操作,以确保其他内核代码不保留任何指向覆
+盖层节点或数据的指针。任何无意中使用这种指针的例子是,如果一个驱动或子系统模块在
+应用了覆盖后被加载,并且该驱动或子系统扫描了整个设备树或其大部分,包括覆盖节点。
diff --git a/Documentation/translations/zh_CN/devicetree/usage-model.rst b/Documentation/translations/zh_CN/devicetree/usage-model.rst
new file mode 100644
index 000000000000..19ba4ae0cd81
--- /dev/null
+++ b/Documentation/translations/zh_CN/devicetree/usage-model.rst
@@ -0,0 +1,330 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/devicetree/usage-model.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+===================
+Linux 和 Devicetree
+===================
+
+Linux对设备树数据的使用模型
+
+:作者: Grant Likely <grant.likely@secretlab.ca>
+
+这篇文章描述了Linux如何使用设备树。关于设备树数据格式的概述可以在
+devicetree.org\ [1]_ 的设备树使用页面上找到。
+
+.. [1] https://www.devicetree.org/specifications/
+
+"Open Firmware Device Tree",或简称为Devicetree(DT),是一种用于描述硬
+件的数据结构和语言。更确切地说,它是一种操作系统可读的硬件描述,这样操作系统就不
+需要对机器的细节进行硬编码。
+
+从结构上看,DT是一棵树,或者说是带有命名节点的无环图,节点可以有任意数量的命名
+属性来封装任意的数据。还存在一种机制,可以在自然的树状结构之外创建从一个节点到
+另一个节点的任意链接。
+
+从概念上讲,一套通用的使用惯例,称为 "bindings"(后文译为绑定),被定义为数据
+应该如何出现在树中,以描述典型的硬件特性,包括数据总线、中断线、GPIO连接和外围
+设备。
+
+尽可能使用现有的绑定来描述硬件,以最大限度地利用现有的支持代码,但由于属性和节
+点名称是简单的文本字符串,通过定义新的节点和属性来扩展现有的绑定或创建新的绑定
+很容易。然而,要警惕的是,在创建一个新的绑定之前,最好先对已经存在的东西做一些
+功课。目前有两种不同的、不兼容的i2c总线的绑定,这是因为在创建新的绑定时没有事先
+调查i2c设备在现有系统中是如何被枚举的。
+
+1. 历史
+-------
+DT最初是由Open Firmware创建的,作为将数据从Open Firmware传递给客户程序
+(如传递给操作系统)的通信方法的一部分。操作系统使用设备树在运行时探测硬件的拓
+扑结构,从而在没有硬编码信息的情况下支持大多数可用的硬件(假设所有设备的驱动程
+序都可用)。
+
+由于Open Firmware通常在PowerPC和SPARC平台上使用,长期以来,对这些架构的
+Linux支持一直使用设备树。
+
+2005年,当PowerPC Linux开始大规模清理并合并32位和64位支持时,决定在所有
+Powerpc平台上要求DT支持,无论它们是否使用Open Firmware。为了做到这一点,
+我们创建了一个叫做扁平化设备树(FDT)的DT表示法,它可以作为一个二进制的blob
+传递给内核,而不需要真正的Open Firmware实现。U-Boot、kexec和其他引导程序
+被修改,以支持传递设备树二进制(dtb)和在引导时修改dtb。DT也被添加到PowerPC
+引导包装器(arch/powerpc/boot/\*)中,这样dtb就可以被包裹在内核镜像中,以
+支持引导现有的非DT察觉的固件。
+
+一段时间后,FDT基础架构被普及到了所有的架构中。在写这篇文章的时候,6个主线架
+构(arm、microblaze、mips、powerpc、sparc和x86)和1个非主线架构(ios)
+有某种程度的DT支持。
+
+1. 数据模型
+-----------
+如果你还没有读过设备树用法\ [1]_页,那么现在就去读吧。没关系,我等着....
+
+2.1 高层次视角
+--------------
+最重要的是要明白,DT只是一个描述硬件的数据结构。它没有什么神奇之处,也不会神
+奇地让所有的硬件配置问题消失。它所做的是提供一种语言,将硬件配置与Linux内核
+(或任何其他操作系统)中的板卡和设备驱动支持解耦。使用它可以使板卡和设备支持
+变成数据驱动;根据传递到内核的数据做出设置决定,而不是根据每台机器的硬编码选
+择。
+
+理想情况下,数据驱动的平台设置应该导致更少的代码重复,并使其更容易用一个内核
+镜像支持各种硬件。
+
+Linux使用DT数据有三个主要目的:
+
+1) 平台识别。
+2) 运行时配置,以及
+3) 设备数量。
+
+2.2 平台识别
+------------
+首先,内核将使用DT中的数据来识别特定的机器。在一个理想的世界里,具体的平台对
+内核来说并不重要,因为所有的平台细节都会被设备树以一致和可靠的方式完美描述。
+但是,硬件并不完美,所以内核必须在早期启动时识别机器,以便有机会运行特定于机
+器的修复程序。
+
+在大多数情况下,机器的身份是不相关的,而内核将根据机器的核心CPU或SoC来选择
+设置代码。例如,在ARM上,arch/arm/kernel/setup.c中的setup_arch()将调
+用arch/arm/kernel/devtree.c中的setup_machine_fdt(),它通过
+machine_desc表搜索并选择与设备树数据最匹配的machine_desc。它通过查看根
+设备树节点中的'compatible'属性,并将其与struct machine_desc中的
+dt_compat列表(如果你好奇,该列表定义在arch/arm/include/asm/mach/arch.h
+中)进行比较,从而确定最佳匹配。
+
+“compatible” 属性包含一个排序的字符串列表,以机器的确切名称开始,后面是
+一个可选的与之兼容的板子列表,从最兼容到最不兼容排序。例如,TI BeagleBoard
+和它的后继者BeagleBoard xM板的根兼容属性可能看起来分别为::
+
+ compatible = "ti,omap3-beagleboard", "ti,omap3450", "ti,omap3";
+ compatible = "ti,omap3-beagleboard-xm", "ti,omap3450", "ti,omap3";
+
+其中 "ti,map3-beagleboard-xm "指定了确切的型号,它还声称它与OMAP 3450 SoC
+以及一般的OMP3系列SoC兼容。你会注意到,该列表从最具体的(确切的板子)到最
+不具体的(SoC系列)进行排序。
+
+聪明的读者可能会指出,Beagle xM也可以声称与原Beagle板兼容。然而,我们应
+该当心在板级上这样做,因为通常情况下,即使在同一产品系列中,每块板都有很高
+的变化,而且当一块板声称与另一块板兼容时,很难确定到底是什么意思。对于高层
+来说,最好是谨慎行事,不要声称一块板子与另一块板子兼容。值得注意的例外是,
+当一块板子是另一块板子的载体时,例如CPU模块连接到一个载体板上。
+
+关于兼容值还有一个注意事项。在兼容属性中使用的任何字符串都必须有文件说明它
+表示什么。在Documentation/devicetree/bindings中添加兼容字符串的文档。
+
+同样在ARM上,对于每个machine_desc,内核会查看是否有任何dt_compat列表条
+目出现在兼容属性中。如果有,那么该machine_desc就是驱动该机器的候选者。在搜索
+了整个machine_descs表之后,setup_machine_fdt()根据每个machine_desc
+在兼容属性中匹配的条目,返回 “最兼容” 的machine_desc。如果没有找到匹配
+的machine_desc,那么它将返回NULL。
+
+这个方案背后的原因是观察到,在大多数情况下,如果它们都使用相同的SoC或相同
+系列的SoC,一个machine_desc可以支持大量的电路板。然而,不可避免地会有一些例
+外情况,即特定的板子需要特殊的设置代码,这在一般情况下是没有用的。特殊情况
+可以通过在通用设置代码中明确检查有问题的板子来处理,但如果超过几个情况下,
+这样做很快就会变得很难看和/或无法维护。
+
+相反,兼容列表允许通用machine_desc通过在dt_compat列表中指定“不太兼容”的值
+来提供对广泛的通用板的支持。在上面的例子中,通用板支持可以声称与“ti,ompa3”
+或“ti,ompa3450”兼容。如果在最初的beagleboard上发现了一个bug,需要在
+早期启动时使用特殊的变通代码,那么可以添加一个新的machine_desc,实现变通,
+并且只在“ti,omap3-beagleboard”上匹配。
+
+PowerPC使用了一个稍微不同的方案,它从每个machine_desc中调用.probe()钩子,
+并使用第一个返回TRUE的钩子。然而,这种方法没有考虑到兼容列表的优先级,对于
+新的架构支持可能应该避免。
+
+2.3 运行时配置
+--------------
+在大多数情况下,DT是将数据从固件传递给内核的唯一方法,所以也被用来传递运行
+时和配置数据,如内核参数字符串和initrd镜像的位置。
+
+这些数据大部分都包含在/chosen节点中,当启动Linux时,它看起来就像这样::
+
+ chosen {
+ bootargs = "console=ttyS0,115200 loglevel=8";
+ initrd-start = <0xc8000000>;
+ initrd-end = <0xc8200000>;
+ };
+
+bootargs属性包含内核参数,initrd-\*属性定义initrd blob的地址和大小。注
+意initrd-end是initrd映像后的第一个地址,所以这与结构体资源的通常语义不一
+致。选择的节点也可以选择包含任意数量的额外属性,用于平台特定的配置数据。
+
+在早期启动过程中,架构设置代码通过不同的辅助回调函数多次调用
+of_scan_flat_dt()来解析设备树数据,然后进行分页设置。of_scan_flat_dt()
+代码扫描设备树,并使用辅助函数来提取早期启动期间所需的信息。通常情况下,
+early_init_dt_scan_chosen()辅助函数用于解析所选节点,包括内核参数,
+early_init_dt_scan_root()用于初始化DT地址空间模型,early_init_dt_scan_memory()
+用于确定可用RAM的大小和位置。
+
+在ARM上,函数setup_machine_fdt()负责在选择支持板子的正确machine_desc
+后,对设备树进行早期扫描。
+
+2.4 设备数量
+------------
+在电路板被识别后,在早期配置数据被解析后,内核初始化可以以正常方式进行。在
+这个过程中的某个时刻,unflatten_device_tree()被调用以将数据转换成更有
+效的运行时表示。这也是调用机器特定设置钩子的时候,比如ARM上的machine_desc
+.init_early()、.init_irq()和.init_machine()钩子。本节的其余部分使用
+了ARM实现的例子,但所有架构在使用DT时都会做几乎相同的事情。
+
+从名称上可以猜到,.init_early()用于在启动过程早期需要执行的任何机器特定设
+置,而.init_irq()则用于设置中断处理。使用DT并不会实质性地改变这两个函数的
+行为。如果提供了DT,那么.init_early()和.init_irq()都能调用任何一个DT查
+询函数(of_* in include/linux/of*.h),以获得关于平台的额外数据。
+
+DT上下文中最有趣的钩子是.init_machine(),它主要负责将平台的数据填充到
+Linux设备模型中。历史上,这在嵌入式平台上是通过在板卡support .c文件中定
+义一组静态时钟结构、platform_devices和其他数据,并在.init_machine()中
+大量注册来实现的。当使用DT时,就不用为每个平台的静态设备进行硬编码,可以通过
+解析DT获得设备列表,并动态分配设备结构体。
+
+最简单的情况是,.init_machine()只负责注册一个platform_devices。
+platform_device是Linux使用的一个概念,用于不能被硬件检测到的内存或I/O映
+射的设备,以及“复合”或 “虚拟”设备(后面会详细介绍)。虽然DT没有“平台设备”的
+术语,但平台设备大致对应于树根的设备节点和简单内存映射总线节点的子节点。
+
+现在是举例说明的好时机。下面是NVIDIA Tegra板的设备树的一部分::
+
+ /{
+ compatible = "nvidia,harmony", "nvidia,tegra20";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&intc>;
+
+ chosen { };
+ aliases { };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x40000000>;
+ };
+
+ soc {
+ compatible = "nvidia,tegra20-soc", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ intc: interrupt-controller@50041000 {
+ compatible = "nvidia,tegra20-gic";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x50041000 0x1000>, < 0x50040100 0x0100 >;
+ };
+
+ serial@70006300 {
+ compatible = "nvidia,tegra20-uart";
+ reg = <0x70006300 0x100>;
+ interrupts = <122>;
+ };
+
+ i2s1: i2s@70002800 {
+ compatible = "nvidia,tegra20-i2s";
+ reg = <0x70002800 0x100>;
+ interrupts = <77>;
+ codec = <&wm8903>;
+ };
+
+ i2c@7000c000 {
+ compatible = "nvidia,tegra20-i2c";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x7000c000 0x100>;
+ interrupts = <70>;
+
+ wm8903: codec@1a {
+ compatible = "wlf,wm8903";
+ reg = <0x1a>;
+ interrupts = <347>;
+ };
+ };
+ };
+
+ sound {
+ compatible = "nvidia,harmony-sound";
+ i2s-controller = <&i2s1>;
+ i2s-codec = <&wm8903>;
+ };
+ };
+
+在.init_machine()时,Tegra板支持代码将需要查看这个DT,并决定为哪些节点
+创建platform_devices。然而,看一下这个树,并不能立即看出每个节点代表什么
+类型的设备,甚至不能看出一个节点是否代表一个设备。/chosen、/aliases和
+/memory节点是信息节点,并不描述设备(尽管可以说内存可以被认为是一个设备)。
+/soc节点的子节点是内存映射的设备,但是codec@1a是一个i2c设备,而sound节
+点代表的不是一个设备,而是其他设备是如何连接在一起以创建音频子系统的。我知
+道每个设备是什么,因为我熟悉电路板的设计,但是内核怎么知道每个节点该怎么做?
+
+诀窍在于,内核从树的根部开始,寻找具有“兼容”属性的节点。首先,一般认为任何
+具有“兼容”属性的节点都代表某种设备;其次,可以认为树根的任何节点要么直接连
+接到处理器总线上,要么是无法用其他方式描述的杂项系统设备。对于这些节点中的
+每一个,Linux都会分配和注册一个platform_device,它又可能被绑定到一个
+platform_driver。
+
+为什么为这些节点使用platform_device是一个安全的假设?嗯,就Linux对设备
+的建模方式而言,几乎所有的总线类型都假定其设备是总线控制器的孩子。例如,每
+个i2c_client是i2c_master的一个子节点。每个spi_device都是SPI总线的一
+个子节点。类似的还有USB、PCI、MDIO等。同样的层次结构也出现在DT中,I2C设
+备节点只作为I2C总线节点的子节点出现。同理,SPI、MDIO、USB等等。唯一不需
+要特定类型的父设备的设备是platform_devices(和amba_devices,但后面会
+详细介绍),它们将愉快地运行在Linux/sys/devices树的底部。因此,如果一个
+DT节点位于树的根部,那么它真的可能最好注册为platform_device。
+
+Linux板支持代码调用of_platform_populate(NULL, NULL, NULL, NULL)来
+启动树根的设备发现。参数都是NULL,因为当从树的根部开始时,不需要提供一个起
+始节点(第一个NULL),一个父结构设备(最后一个NULL),而且我们没有使用匹配
+表(尚未)。对于只需要注册设备的板子,除了of_platform_populate()的调用,
+.init_machine()可以完全为空。
+
+在Tegra的例子中,这说明了/soc和/sound节点,但是SoC节点的子节点呢?它们
+不应该也被注册为平台设备吗?对于Linux DT支持,一般的行为是子设备在驱动
+.probe()时被父设备驱动注册。因此,一个i2c总线设备驱动程序将为每个子节点
+注册一个i2c_client,一个SPI总线驱动程序将注册其spi_device子节点,其他
+总线类型也是如此。根据该模型,可以编写一个与SoC节点绑定的驱动程序,并简单
+地为其每个子节点注册platform_device。板卡支持代码将分配和注册一个SoC设
+备,一个(理论上的)SoC设备驱动程序可以绑定到SoC设备,并在其.probe()钩
+中为/soc/interruptcontroller、/soc/serial、/soc/i2s和/soc/i2c注
+册platform_devices。很简单,对吗?
+
+实际上,事实证明,将一些platform_device的子设备注册为更多的platform_device
+是一种常见的模式,设备树支持代码反映了这一点,并使上述例子更简单。
+of_platform_populate()的第二个参数是一个of_device_id表,任何与该表
+中的条目相匹配的节点也将获得其子节点的注册。在Tegra的例子中,代码可以是
+这样的::
+
+ static void __init harmony_init_machine(void)
+ {
+ /* ... */
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+ }
+
+“simple-bus”在Devicetree规范中被定义为一个属性,意味着一个简单的内存映射
+的总线,所以of_platform_populate()代码可以被写成只是假设简单总线兼容的节
+点将总是被遍历。然而,我们把它作为一个参数传入,以便电路板支持代码可以随时覆
+盖默认行为。
+
+[需要添加关于添加i2c/spi/etc子设备的讨论] 。
+
+附录A:AMBA设备
+---------------
+
+ARM Primecell是连接到ARM AMBA总线的某种设备,它包括对硬件检测和电源管理
+的一些支持。在Linux中,amba_device和amba_bus_type结构体被用来表示
+Primecell设备。然而,棘手的一点是,AMBA总线上的所有设备并非都是Primecell,
+而且对于Linux来说,典型的情况是amba_device和platform_device实例都是同
+一总线段的同义词。
+
+当使用DT时,这给of_platform_populate()带来了问题,因为它必须决定是否将
+每个节点注册为platform_device或amba_device。不幸的是,这使设备创建模型
+变得有点复杂,但解决方案原来并不是太具有侵略性。如果一个节点与“arm,primecell”
+兼容,那么of_platform_populate()将把它注册为amba_device而不是
+platform_device。
diff --git a/Documentation/translations/zh_CN/disclaimer-zh_CN.rst b/Documentation/translations/zh_CN/disclaimer-zh_CN.rst
index dcf803ede85a..3c6db094a63c 100644
--- a/Documentation/translations/zh_CN/disclaimer-zh_CN.rst
+++ b/Documentation/translations/zh_CN/disclaimer-zh_CN.rst
@@ -6,4 +6,4 @@
.. note::
如果您发现本文档与原始文件有任何不同或者有翻译问题,请联系该文件的译者,
- 或者请求时奎亮的帮助:<alex.shi@linux.alibaba.com>。
+ 或者请求时奎亮的帮助:<alexs@kernel.org>。
diff --git a/Documentation/translations/zh_CN/doc-guide/contributing.rst b/Documentation/translations/zh_CN/doc-guide/contributing.rst
new file mode 100644
index 000000000000..394a13b438b0
--- /dev/null
+++ b/Documentation/translations/zh_CN/doc-guide/contributing.rst
@@ -0,0 +1,238 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/doc-guide/contributing.rst
+
+:译者: 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+如何帮助改进内核文档
+====================
+
+在任何软件开发项目中,文档都是重要组成部分。好的文档有助于引入新的开发人员,
+并帮助已有的开发人员更有效地工作。如果缺少高质量的文档,大量的时间就会浪费在
+代码的逆向工程和犯本可避免的错误上。
+
+不幸的是,内核的文档目前远远不能满足支持如此规模和重要性的项目的需要。
+
+本指南适用于希望帮助改善这种状况的贡献者。内核文档的改进可以由开发者在不同的
+技能层级上进行;这也是一条相对简单可以帮助您了解内核过程并在社区中找到一席之
+地的路径。下面的大部分内容是文档维护人员列出的最迫切需要完成的任务。
+
+文档待办事项列表
+----------------
+
+为了使我们的文档达到应有的水平,需要完成的任务数不胜数。此列表包含许多重要的
+项目,但还远远不够详尽;如果您知道改进文档的其他方法,请不要羞于启齿。
+
+消除警告(WARNING)
+~~~~~~~~~~~~~~~~~~~
+
+文档构建目前出现了数量惊人的警告。虱子多了不痒,债多了不愁;大伙儿忽略了它们,
+他们永远不会注意到他们的工作增加了新的警告。因此,消除警告是文档待办事项列表
+中优先级最高的任务之一。这项任务本身相当简单,但必须以正确的方式进行,才能取
+得成功。
+
+C代码编译器发出的警告常常会被视为误报,从而导致出现了旨在让编译器闭嘴的补丁。
+文档构建中的警告几乎总是指向真正的问题;要消除这些警告,需要理解问题并从源头上
+解决问题。因此,修复文档警告的补丁不应在标题中直接写“修复警告”;它们应该指明
+真正修复的问题。
+
+另一个重点是,文档警告常常由C代码里kernel-doc注释中的问题引起。虽然文档维护
+人员对收到这些修复补丁的副本表示感谢,但是文档树实际上通常并不适合接受这些
+补丁;它们应该被交给相关子系统的维护人员。
+
+例如,在一次文档构建中,我几乎是随意选取了一对警告::
+
+ ./drivers/devfreq/devfreq.c:1818: warning: bad line:
+ - Resource-managed devfreq_register_notifier()
+ ./drivers/devfreq/devfreq.c:1854: warning: bad line:
+ - Resource-managed devfreq_unregister_notifier()
+
+(作了断行以便于阅读)
+
+简单看一下上面给出的源文件,会发现几个kernel-doc注释,如下所示::
+
+ /**
+ * devm_devfreq_register_notifier()
+ - Resource-managed devfreq_register_notifier()
+ * @dev: The devfreq user device. (parent of devfreq)
+ * @devfreq: The devfreq object.
+ * @nb: The notifier block to be unregistered.
+ * @list: DEVFREQ_TRANSITION_NOTIFIER.
+ */
+
+问题在于缺了一个“*”,这不符合构建系统对C注释块的格式要求。此问题自2016年注释
+被添加以来一直存在——整整四年之久。修复它只需要添加丢失的星号。看一眼该文件的
+历史记录以了解主题行的常规格式是什么样,再使用 ``scripts/get_maintainer.pl``
+来搞清谁应当收到此补丁。生成的补丁如下所示::
+
+ [PATCH] PM / devfreq: Fix two malformed kerneldoc comments
+
+ Two kerneldoc comments in devfreq.c fail to adhere to the required format,
+ resulting in these doc-build warnings:
+
+ ./drivers/devfreq/devfreq.c:1818: warning: bad line:
+ - Resource-managed devfreq_register_notifier()
+ ./drivers/devfreq/devfreq.c:1854: warning: bad line:
+ - Resource-managed devfreq_unregister_notifier()
+
+ Add a couple of missing asterisks and make kerneldoc a little happier.
+
+ Signed-off-by: Jonathan Corbet <corbet@lwn.net>
+ ---
+ drivers/devfreq/devfreq.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+ diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
+ index 57f6944d65a6..00c9b80b3d33 100644
+ --- a/drivers/devfreq/devfreq.c
+ +++ b/drivers/devfreq/devfreq.c
+ @@ -1814,7 +1814,7 @@ static void devm_devfreq_notifier_release(struct device *dev, void *res)
+
+ /**
+ * devm_devfreq_register_notifier()
+ - - Resource-managed devfreq_register_notifier()
+ + * - Resource-managed devfreq_register_notifier()
+ * @dev: The devfreq user device. (parent of devfreq)
+ * @devfreq: The devfreq object.
+ * @nb: The notifier block to be unregistered.
+ @@ -1850,7 +1850,7 @@ EXPORT_SYMBOL(devm_devfreq_register_notifier);
+
+ /**
+ * devm_devfreq_unregister_notifier()
+ - - Resource-managed devfreq_unregister_notifier()
+ + * - Resource-managed devfreq_unregister_notifier()
+ * @dev: The devfreq user device. (parent of devfreq)
+ * @devfreq: The devfreq object.
+ * @nb: The notifier block to be unregistered.
+ --
+ 2.24.1
+
+整个过程只花了几分钟。当然,我后来发现有人在另一个树中修复了它,这亮出了另一
+个教训:在深入研究问题之前,一定要检查linux-next树,看看问题是否已经修复。
+
+其他修复可能需要更长的时间,尤其是那些与缺少文档的结构体成员或函数参数相关的
+修复。这种情况下,需要找出这些成员或参数的作用,并正确描述它们。总之,这种
+任务有时会有点乏味,但它非常重要。如果我们真的可以从文档构建中消除警告,那么
+我们就可以开始期望开发人员开始注意避免添加新的警告了。
+
+“迷失的”kernel-doc注释
+~~~~~~~~~~~~~~~~~~~~~~
+
+开发者被鼓励去为他们的代码写kernel-doc注释,但是许多注释从未被引入文档构建。
+这使得这些信息更难找到,例如使Sphinx无法生成指向该文档的链接。将 ``kernel-doc``
+指令添加到文档中以引入这些注释可以帮助社区获得为编写注释所做工作的全部价值。
+
+``scripts/find-unused-docs.sh`` 工具可以用来找到这些被忽略的评论。
+
+请注意,将导出的函数和数据结构引入文档是最有价值的。许多子系统还具有供内部
+使用的kernel-doc注释;除非这些注释放在专门针对相关子系统开发人员的文档中,
+否则不应将其引入文档构建中。
+
+
+修正错字
+~~~~~~~~
+
+
+修复文档中的排版或格式错误是一种快速学习如何创建和发送修补程序的方法,也是
+一项有用的服务。我总是愿意接受这样的补丁。这也意味着,一旦你修复了一些这种
+错误,请考虑转移到更高级的任务,留下一些拼写错误给下一个初学者解决。
+
+请注意,有些并 **不是** 拼写错误,不应该被“修复”:
+
+ - 内核文档中用美式和英式英语拼写皆可,没有必要互相倒换。
+
+ - 在内核文档中,没必要讨论句点后面应该跟一个还是两个空格的问题。其他一些有
+ 合理分歧的地方,比如“牛津逗号”,在这也是跑题的。
+
+与对任何项目的任何补丁一样,请考虑您的更改是否真的让事情变得更好。
+
+“上古”文档
+~~~~~~~~~~
+
+一些内核文档是最新的、被维护的,并且非常有用,有些文件确并非如此。尘封、陈旧
+和不准确的文档可能会误导读者,并对我们的整个文档产生怀疑。任何解决这些问题的
+事情都是非常受欢迎的。
+
+无论何时处理文档,请考虑它是否是最新的,是否需要更新,或者是否应该完全删除。
+您可以注意以下几个警告标志:
+
+ - 对2.x内核的引用
+ - 指向SourceForge存储库
+ - 历史记录除了拼写错误啥也没有持续几年
+ - 讨论Git之前时代的工作流
+
+当然,最好的办法是更新文档,添加所需的任何信息。这样的工作通常需要与熟悉相关
+子系统的开发人员合作。当有人善意地询问开发人员,并听取他们的回答然后采取
+行动时,开发人员通常更愿意与这些致力于改进文档的人员合作。
+
+有些文档已经没希望了;例如,我们偶尔会发现引用了很久以前从内核中删除的代码的
+文档。删除过时的文档会碰见令人惊讶的阻力,但我们无论如何都应该这样做。文档中
+多余的粗枝大叶对任何人都没有帮助。
+
+如果一个严重过时的文档中可能有一些有用的信息,而您又无法更新它,那么最好在
+开头添加一个警告。建议使用以下文本::
+
+ .. warning ::
+ This document is outdated and in need of attention. Please use
+ this information with caution, and please consider sending patches
+ to update it.
+
+这样的话,至少我们长期受苦的读者会得到文件可能会把他们引入歧途的警告。
+
+文档一致性
+~~~~~~~~~~
+
+这里的老前辈们会记得上世纪90年代出现在书架上的Linux书籍,它们只是从网上不同
+位置搜来的文档文件的集合。在此之后,(大部分)这些书都得到了改进,但是内核的
+文档仍然主要是建立在这种模型上。它有数千个文件,几乎每个文件都是与其他文件相
+独立编写的。我们没有一个连贯的内核文档;只有数千个独立的文档。
+
+我们一直试图通过编篡一套“书籍”来改善这种情况,以为特定读者提供成套文档。这
+包括:
+
+ - Documentation/translations/zh_CN/admin-guide/index.rst
+ - Documentation/core-api/index.rst
+ - Documentation/driver-api/index.rst
+ - Documentation/userspace-api/index.rst
+
+以及文档本身这本“书”。
+
+将文档移到适当的书中是一项重要的任务,需要继续进行。不过这项工作还是有一些
+挑战性。移动文档会给处理这些文档的人带来短期的痛苦;他们对这些更改无甚热情
+也是可以理解的。通常情况下,可以将一个文档移动一下;不过我们真的不想一直移动
+它们。
+
+即使所有文件都在正确的位置,我们也只是把一大堆文件变成一群小堆文件。试图将
+所有这些文件组合成一个整体的工作尚未开始。如果你对如何在这方面取得进展有好的
+想法,我们将很高兴了解。
+
+样式表(Stylesheet)改进
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+随着Sphinx的采用,我们得到了比以前更好的HTML输出。但它仍然需要很大的改进;
+Donald Knuth和Edward Tufte可能是映像平平的。这需要调整我们的样式表,以创建
+更具排版效果、可访问性和可读性的输出。
+
+请注意:如果你承担这个任务,你将进入经典的两难领域。即使是相对明显的变化,
+也会有很多意见和讨论。唉,这就是我们生活的世界的本质。
+
+无LaTeX的PDF构建
+~~~~~~~~~~~~~~~~
+
+对于拥有大量时间和Python技能的人来说,这绝对是一项不平凡的任务。Sphinx工具链
+相对较小且包含良好;很容易添加到开发系统中。但是构建PDF或EPUB输出需要安装
+LaTeX,它绝对称不上小或包含良好的。消除Latex将是一件很好的事情。
+
+最初是希望使用 `rst2pdf <https://rst2pdf.org/>`_ 工具来生成PDF,但结果发现
+无法胜任这项任务。不过rst2pdf的开发工作最近似乎又有了起色,这是个充满希望的
+迹象。如果有开发人员愿意与该项目合作,使rst2pdf可与内核文档构建一起工作,
+大家会非常感激。
+
+编写更多文档
+~~~~~~~~~~~~
+
+当然,内核中许多部分的文档严重不足。如果您有编写一个特定内核子系统文档的相应
+知识并愿意这样做,请不要犹豫,编写并向内核贡献结果吧!数不清的内核开发人员和
+用户会感谢你。
diff --git a/Documentation/translations/zh_CN/doc-guide/index.rst b/Documentation/translations/zh_CN/doc-guide/index.rst
new file mode 100644
index 000000000000..78c2e9a1697f
--- /dev/null
+++ b/Documentation/translations/zh_CN/doc-guide/index.rst
@@ -0,0 +1,27 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/doc-guide/index.rst
+
+:译者: 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+.. _doc_guide_zh:
+
+================
+如何编写内核文档
+================
+
+.. toctree::
+ :maxdepth: 1
+
+ sphinx
+ kernel-doc
+ parse-headers
+ contributing
+ maintainer-profile
+
+.. only:: subproject and html
+
+ 目录
+ ====
+
+ * :ref:`genindex`
diff --git a/Documentation/translations/zh_CN/doc-guide/kernel-doc.rst b/Documentation/translations/zh_CN/doc-guide/kernel-doc.rst
new file mode 100644
index 000000000000..ccfb9b8329c2
--- /dev/null
+++ b/Documentation/translations/zh_CN/doc-guide/kernel-doc.rst
@@ -0,0 +1,499 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/doc-guide/kernel-doc.rst
+
+:译者: 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+编写kernel-doc注释
+==================
+
+Linux内核源文件可以包含kernel-doc格式的结构化文档注释,用以描述代码的函数、
+类型和设计。将文档嵌入源文件更容易保持文档最新。
+
+.. note:: 内核文档格式与javadoc、gtk-doc或Doxygen看似很相似,但由于历史原因,
+ 实际有着明显的不同。内核源包含成千上万个kernel-doc注释。请坚持遵循
+ 此处描述的风格。
+
+.. note:: kernel-doc无法包含Rust代码:请参考 Documentation/rust/general-information.rst 。
+
+从注释中提取kernel-doc结构,并从中生成适当的 `Sphinx C 域`_ 函数和带有锚点的
+类型描述。这些注释将被过滤以生成特殊kernel-doc高亮和交叉引用。详见下文。
+
+.. _Sphinx C 域: http://www.sphinx-doc.org/en/stable/domains.html
+
+使用 ``EXPORT_SYMBOL`` 或 ``EXPORT_SYMBOL_GPL`` 导出到可加载模块的每个函数都
+应该有一个kernel-doc注释。模块使用的头文件中的函数和数据结构也应该有
+kernel-doc注释。
+
+对于其他内核文件(未标记为 ``static`` )中外部可见的函数,提供kernel-doc格式
+的文档是一个很好的实践。我们也建议为私有(文件 ``static`` )程序提供kernel-doc
+格式的文档,以确保内核源代码布局的一致性。此建议优先级较低,由内核源文件的
+维护者自行决定。
+
+如何格式化kernel-doc注释
+------------------------
+
+kernel-doc注释用 ``/**`` 作为开始标记。 ``kernel-doc`` 工具将提取以这种方式
+标记的注释。注释其余部分的格式类似于一个普通的多行注释,左侧有一列星号,以
+``*/`` 行结束。
+
+函数和类型的kernel-doc注释应该放在所描述的函数或类型之前,以便最大限度地提高
+更改代码的人同时更改文档的可能性。概述kernel-doc注释可以放在最顶部的任何地方。
+
+用详细模式和不生成实际输出来运行 ``kernel-doc`` 工具,可以验证文档注释的格式
+是否正确。例如::
+
+ scripts/kernel-doc -v -none drivers/foo/bar.c
+
+当请求执行额外的gcc检查时,内核构建将验证文档格式::
+
+ make W=n
+
+函数文档
+--------
+
+函数和函数式宏的kernel-doc注释的一般格式是::
+
+ /**
+ * 函数名() - 函数简要说明.
+ * @参数1: 描述第一个参数.
+ * @参数2: 描述第二个参数.
+ * 可以为参数提供一段
+ * 多行描述.
+ *
+ * 更详细的描述,进一步讨论函数 函数名(), 这可能对使用或修改它的人有用.
+ * 以空注释行开始, 内部可以包含空注释行.
+ *
+ * 详细描述可以有多个段落.
+ *
+ * Context: 描述函数是否可以休眠, 它需要、释放或期望持有什么锁.
+ * 可以写多行.
+ * Return: 描述函数返回值.
+ *
+ * 返回值描述也可以有多个段落,
+ * 并且应该放在注释块的末尾.
+ */
+
+函数名后面的简短描述可以跨多行,并以参数描述、空注释行或注释块结尾结束。
+
+函数参数
+~~~~~~~~
+
+每个函数参数都应该按照顺序描述,紧跟在函数简要说明之后。不要在函数描述和参数
+之间,也不要在参数之间留空。
+
+每个 ``@参数:`` 描述可以跨多行。
+
+.. note::
+
+ 如果 ``@参数`` 描述有多行,则说明的续行应该从上一行的同一列开始::
+
+ * @参数: 较长说明
+ * 的续行
+
+ 或::
+
+ * @参数:
+ * 较长说明
+ * 的续行
+
+如果函数的参数数目可变,则需用kernel-doc格式对其进行描述::
+
+ * @...: 描述
+
+函数上下文
+~~~~~~~~~~
+
+可调用函数的上下文应该在 ``Context`` 节中描述。此节应该包括函数是休眠的还是
+可以从中断上下文调用的,以及它需要什么锁、释放什么锁和期望它的调用者持有什么
+锁。
+
+例如::
+
+ * Context: Any context.
+ * Context: Any context. Takes and releases the RCU lock.
+ * Context: Any context. Expects <lock> to be held by caller.
+ * Context: Process context. May sleep if @gfp flags permit.
+ * Context: Process context. Takes and releases <mutex>.
+ * Context: Softirq or process context. Takes and releases <lock>, BH-safe.
+ * Context: Interrupt context.
+
+返回值
+~~~~~~
+
+如有返回值,应在 ``Return`` 节中描述。
+
+.. note::
+
+ #) 您提供的多行描述文本 *不会* 识别换行符,因此如果您想将某些文本预格式化,
+ 如::
+
+ * Return:
+ * 0 - OK
+ * -EINVAL - invalid argument
+ * -ENOMEM - out of memory
+
+ 它们在最终文档中变成一行::
+
+ Return: 0 - OK -EINVAL - invalid argument -ENOMEM - out of memory
+
+ 因此,为了在需要的地方换行,您需要使用ReST列表,例如::
+
+ * Return:
+ * * 0 - OK to runtime suspend the device
+ * * -EBUSY - Device should not be runtime suspended
+
+ #) 如果您提供的描述性文本中的行以某个后跟冒号的短语开头,则每一个这种短语
+ 都将被视为新的节标题,可能会产生意料不到的效果。
+
+结构体、共用体、枚举类型文档
+----------------------------
+
+结构体(struct)、共用体(union)、枚举(enum)类型kernel-doc注释的一般格式为::
+
+ /**
+ * struct 结构体名 - 简要描述.
+ * @成员1: 成员1描述.
+ * @成员2: 成员2描述.
+ * 可以为成员提供
+ * 多行描述.
+ *
+ * 结构体的描述.
+ */
+
+可以用 ``union`` 或 ``enum`` 替换上面示例中的 ``struct`` ,以描述共用体或枚举。
+``成员`` 用于表示枚举中的元素或共用体成员。
+
+结构体名称后面的简要说明可以跨多行,并以成员说明、空白注释行或注释块结尾结束。
+
+成员
+~~~~
+
+结构体、共用体和枚举的成员应以与函数参数相同的方式记录;它们后紧跟简短的描述,
+并且为多行。
+
+在结构体或共用体描述中,可以使用 ``private:`` 和 ``public:`` 注释标签。
+``private:`` 域内的字段不会列在生成的文档中。
+
+``private:`` 和 ``public:`` 标签必须紧跟在 ``/*`` 注释标记之后。可以选择是否
+在 ``:`` 和 ``*/`` 结束标记之间包含注释。
+
+例子::
+
+ /**
+ * struct 张三 - 简短描述
+ * @a: 第一个成员
+ * @b: 第二个成员
+ * @d: 第三个成员
+ *
+ * 详细描述
+ */
+ struct 张三 {
+ int a;
+ int b;
+ /* private: 仅内部使用 */
+ int c;
+ /* public: 下一个是公有的 */
+ int d;
+ };
+
+嵌套的结构体/共用体
+~~~~~~~~~~~~~~~~~~~
+
+嵌套的结构体/共用体可像这样记录::
+
+ /**
+ * struct nested_foobar - a struct with nested unions and structs
+ * @memb1: first member of anonymous union/anonymous struct
+ * @memb2: second member of anonymous union/anonymous struct
+ * @memb3: third member of anonymous union/anonymous struct
+ * @memb4: fourth member of anonymous union/anonymous struct
+ * @bar: non-anonymous union
+ * @bar.st1: struct st1 inside @bar
+ * @bar.st2: struct st2 inside @bar
+ * @bar.st1.memb1: first member of struct st1 on union bar
+ * @bar.st1.memb2: second member of struct st1 on union bar
+ * @bar.st2.memb1: first member of struct st2 on union bar
+ * @bar.st2.memb2: second member of struct st2 on union bar
+ */
+ struct nested_foobar {
+ /* Anonymous union/struct*/
+ union {
+ struct {
+ int memb1;
+ int memb2;
+ };
+ struct {
+ void *memb3;
+ int memb4;
+ };
+ };
+ union {
+ struct {
+ int memb1;
+ int memb2;
+ } st1;
+ struct {
+ void *memb1;
+ int memb2;
+ } st2;
+ } bar;
+ };
+
+.. note::
+
+ #) 在记录嵌套结构体或共用体时,如果结构体/共用体 ``张三`` 已命名,则其中
+ 的成员 ``李四`` 应记录为 ``@张三.李四:``
+
+ #) 当嵌套结构体/共用体是匿名的时,其中的成员 ``李四`` 应记录为 ``@李四:``
+
+行间注释文档
+~~~~~~~~~~~~
+
+结构成员也可在定义时以行间注释形式记录。有两种样式,一种是单行注释,其中开始
+``/**`` 和结束 ``*/`` 位于同一行;另一种是多行注释,开头结尾各自位于一行,就
+像所有其他核心文档注释一样::
+
+ /**
+ * struct 张三 - 简短描述.
+ * @张三: 成员张三.
+ */
+ struct 张三 {
+ int 张三;
+ /**
+ * @李四: 成员李四.
+ */
+ int 李四;
+ /**
+ * @王五: 成员王五.
+ *
+ * 此处,成员描述可以为好几段.
+ */
+ int 王五;
+ union {
+ /** @儿子: 单行描述. */
+ int 儿子;
+ };
+ /** @赵六: 描述@张三里面的结构体@赵六 */
+ struct {
+ /**
+ * @赵六.女儿: 描述@张三.赵六里面的@女儿
+ */
+ int 女儿;
+ } 赵六;
+ };
+
+Typedef文档
+-----------
+
+Typedef的kernel-doc文档注释的一般格式为::
+
+ /**
+ * typedef 类型名称 - 简短描述.
+ *
+ * 类型描述.
+ */
+
+还可以记录带有函数原型的typedef::
+
+ /**
+ * typedef 类型名称 - 简短描述.
+ * @参数1: 参数1的描述
+ * @参数2: 参数2的描述
+ *
+ * 类型描述.
+ *
+ * Context: 锁(Locking)上下文.
+ * Return: 返回值的意义.
+ */
+ typedef void (*类型名称)(struct v4l2_ctrl *参数1, void *参数2);
+
+高亮与交叉引用
+--------------
+
+在kernel-doc注释的描述文本中可以识别以下特殊模式,并将其转换为正确的
+reStructuredText标记和 `Sphinx C 域`_ 引用。
+
+.. attention:: 以下内容 **仅** 在kernel-doc注释中识别, **不会** 在普通的
+ reStructuredText文档中识别。
+
+``funcname()``
+ 函数引用。
+
+``@parameter``
+ 函数参数的名称(未交叉引用,仅格式化)。
+
+``%CONST``
+ 常量的名称(未交叉引用,仅格式化)。
+
+````literal````
+ 预格式化文本块。输出将使用等距字体。
+
+ 若你需要使用在kernel-doc脚本或reStructuredText中有特殊含义的字符,则此功能
+ 非常有用。
+
+ 若你需要在函数描述中使用类似于 ``%ph`` 的东西,这特别有用。
+
+``$ENVVAR``
+ 环境变量名称(未交叉引用,仅格式化)。
+
+``&struct name``
+ 结构体引用。
+
+``&enum name``
+ 枚举引用。
+
+``&typedef name``
+ Typedef引用。
+
+``&struct_name->member`` or ``&struct_name.member``
+ 结构体或共用体成员引用。交叉引用将链接到结构体或共用体定义,而不是直接到成员。
+
+``&name``
+ 泛类型引用。请首选上面描述的完整引用方式。此法主要是为了可能未描述的注释。
+
+从reStructuredText交叉引用
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+无需额外的语法来从reStructuredText文档交叉引用kernel-do注释中定义的函数和类型。
+只需以 ``()`` 结束函数名,并在类型之前写上 ``struct`` , ``union`` , ``enum``
+或 ``typedef`` 。
+例如::
+
+ See foo().
+ See struct foo.
+ See union bar.
+ See enum baz.
+ See typedef meh.
+
+若要在交叉引用链接中使用自定义文本,可以通过以下语法进行::
+
+ See :c:func:`my custom link text for function foo <foo>`.
+ See :c:type:`my custom link text for struct bar <bar>`.
+
+有关更多详细信息,请参阅 `Sphinx C 域`_ 文档。
+
+总述性文档注释
+--------------
+
+为了促进源代码和注释紧密联合,可以将kernel-doc文档块作为自由形式的注释,而
+不是函数、结构、联合、枚举或typedef的绑定kernel-doc。例如,这可以用于解释
+驱动程序或库代码的操作理论。
+
+这是通过使用带有节标题的 ``DOC:`` 节关键字来实现的。
+
+总述或高层级文档注释的一般格式为::
+
+ /**
+ * DOC: Theory of Operation
+ *
+ * The whizbang foobar is a dilly of a gizmo. It can do whatever you
+ * want it to do, at any time. It reads your mind. Here's how it works.
+ *
+ * foo bar splat
+ *
+ * The only drawback to this gizmo is that is can sometimes damage
+ * hardware, software, or its subject(s).
+ */
+
+``DOC:`` 后面的标题用作源文件中的标题,但也用作提取文档注释的标识符。因此,
+文件中的标题必须是唯一的。
+
+包含kernel-doc注释
+==================
+
+文档注释可以被包含在任何使用专用kernel-doc Sphinx指令扩展的reStructuredText
+文档中。
+
+kernel-doc指令的格式如下::
+
+ .. kernel-doc:: source
+ :option:
+
+*source* 是相对于内核源代码树的源文件路径。
+支持以下指令选项:
+
+export: *[source-pattern ...]*
+ 包括 *source* 中使用 ``EXPORT_SYMBOL`` 或 ``EXPORT_SYMBOL_GPL`` 导出的所有
+ 函数的文档,无论是在 *source* 中还是在 *source-pattern* 指定的任何文件中。
+
+ 当kernel-doc注释被放置在头文件中,而 ``EXPORT_SYMBOL`` 和 ``EXPORT_SYMBOL_GPL``
+ 位于函数定义旁边时, *source-pattern* 非常有用。
+
+ 例子::
+
+ .. kernel-doc:: lib/bitmap.c
+ :export:
+
+ .. kernel-doc:: include/net/mac80211.h
+ :export: net/mac80211/*.c
+
+internal: *[source-pattern ...]*
+ 包括 *source* 中所有在 *source* 或 *source-pattern* 的任何文件中都没有使用
+ ``EXPORT_SYMBOL`` 或 ``EXPORT_SYMBOL_GPL`` 导出的函数和类型的文档。
+
+ 例子::
+
+ .. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
+ :internal:
+
+identifiers: *[ function/type ...]*
+ 在 *source* 中包含每个 *function* 和 *type* 的文档。如果没有指定 *function* ,
+ 则 *source* 中所有函数和类型的文档都将包含在内。
+
+ 例子::
+
+ .. kernel-doc:: lib/bitmap.c
+ :identifiers: bitmap_parselist bitmap_parselist_user
+
+ .. kernel-doc:: lib/idr.c
+ :identifiers:
+
+no-identifiers: *[ function/type ...]*
+ 排除 *source* 中所有 *function* 和 *type* 的文档。
+
+ 例子::
+
+ .. kernel-doc:: lib/bitmap.c
+ :no-identifiers: bitmap_parselist
+
+functions: *[ function/type ...]*
+ 这是“identifiers”指令的别名,已弃用。
+
+doc: *title*
+ 包含 *source* 中由 *title* 标题标识的 ``DOC:`` 文档段落。 *title* 中允许
+ 空格;不要在 *title* 上加引号。 *title* 仅用作段落的标识符,不包含在输出中。
+ 请确保在所附的reStructuredText文档中有适当的标题。
+
+ 例子::
+
+ .. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
+ :doc: High Definition Audio over HDMI and Display Port
+
+如果没有选项,kernel-doc指令将包含源文件中的所有文档注释。
+
+kernel-doc扩展包含在内核源代码树中,位于 ``Documentation/sphinx/kerneldoc.py`` 。
+在内部,它使用 ``scripts/kernel-doc`` 脚本从源代码中提取文档注释。
+
+.. _kernel_doc_zh:
+
+如何使用kernel-doc生成手册(man)页
+-----------------------------------
+
+如果您只想使用kernel-doc生成手册页,可以从内核git树这样做::
+
+ $ scripts/kernel-doc -man \
+ $(git grep -l '/\*\*' -- :^Documentation :^tools) \
+ | scripts/split-man.pl /tmp/man
+
+一些旧版本的git不支持路径排除语法的某些变体。
+以下命令之一可能适用于这些版本::
+
+ $ scripts/kernel-doc -man \
+ $(git grep -l '/\*\*' -- . ':!Documentation' ':!tools') \
+ | scripts/split-man.pl /tmp/man
+
+ $ scripts/kernel-doc -man \
+ $(git grep -l '/\*\*' -- . ":(exclude)Documentation" ":(exclude)tools") \
+ | scripts/split-man.pl /tmp/man
+
diff --git a/Documentation/translations/zh_CN/doc-guide/maintainer-profile.rst b/Documentation/translations/zh_CN/doc-guide/maintainer-profile.rst
new file mode 100644
index 000000000000..35c88e5b3d83
--- /dev/null
+++ b/Documentation/translations/zh_CN/doc-guide/maintainer-profile.rst
@@ -0,0 +1,43 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/doc-guide/maintainer-profile.rst
+
+:译者: 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+文档子系统维护人员条目概述
+==========================
+
+文档“子系统”是内核文档和相关基础设施的中心协调点。它涵盖了 Documentation/ 下
+的文件层级(Documentation/devicetree 除外)、scripts/ 下的各种实用程序,并且
+在某些情况下的也包括 LICENSES/ 。
+
+不过值得注意的是,这个子系统的边界比通常更加模糊。许多其他子系统维护人员需要
+保持对 Documentation/ 某些部分的控制,以便于可以更自由地做更改。除此之外,
+许多内核文档都以kernel-doc注释的形式出现在源代码中;这些注释通常(但不总是)
+由相关的子系统维护人员维护。
+
+文档子系统的邮件列表是<linux-doc@vger.kernel.org>。
+补丁应尽量针对docs-next树。
+
+提交检查单补遗
+--------------
+
+在进行文档更改时,您应当构建文档以测试,并确保没有引入新的错误或警告。生成
+HTML文档并查看结果将有助于避免对文档渲染结果的不必要争执。
+
+开发周期的关键节点
+------------------
+
+补丁可以随时发送,但在合并窗口期间,响应将比通常慢。文档树往往在合并窗口打开
+之前关闭得比较晚,因为文档补丁导致回归的风险很小。
+
+审阅节奏
+--------
+
+我(译注:指Jonathan Corbet <corbet@lwn.net>)是文档子系统的唯一维护者,我在
+自己的时间里完成这项工作,所以对补丁的响应有时会很慢。当补丁被合并时(或当我
+决定拒绝合并补丁时),我都会发送通知。如果您在发送补丁后一周内没有收到回复,
+请不要犹豫,发送提醒就好。
+
diff --git a/Documentation/translations/zh_CN/doc-guide/parse-headers.rst b/Documentation/translations/zh_CN/doc-guide/parse-headers.rst
new file mode 100644
index 000000000000..a08819e904ed
--- /dev/null
+++ b/Documentation/translations/zh_CN/doc-guide/parse-headers.rst
@@ -0,0 +1,187 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/doc-guide/parse-headers.rst
+
+:译者: 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+=====================
+包含用户空间API头文件
+=====================
+
+有时,为了描述用户空间API并在代码和文档之间生成交叉引用,需要包含头文件和示例
+C代码。为用户空间API文件添加交叉引用还有一个好处:如果在文档中找不到相应符号,
+Sphinx将生成警告。这有助于保持用户空间API文档与内核更改同步。
+:ref:`parse_headers.pl <parse_headers_zh>` 提供了生成此类交叉引用的一种方法。
+在构建文档时,必须通过Makefile调用它。有关如何在内核树中使用它的示例,请参阅
+``Documentation/userspace-api/media/Makefile`` 。
+
+.. _parse_headers_zh:
+
+parse_headers.pl
+----------------
+
+脚本名称
+~~~~~~~~
+
+
+parse_headers.pl——解析一个C文件,识别函数、结构体、枚举、定义并对Sphinx文档
+创建交叉引用。
+
+
+用法概要
+~~~~~~~~
+
+
+\ **parse_headers.pl**\ [<选项>] <C文件> <输出文件> [<例外文件>]
+
+<选项> 可以是: --debug, --help 或 --usage 。
+
+
+选项
+~~~~
+
+
+
+\ **--debug**\
+
+ 开启脚本详细模式,在调试时很有用。
+
+
+\ **--usage**\
+
+ 打印简短的帮助信息并退出。
+
+
+
+\ **--help**\
+
+ 打印更详细的帮助信息并退出。
+
+
+说明
+~~~~
+
+通过C头文件或源文件(<C文件>)中为描述API的文档编写的带交叉引用的 ..预格式化
+文本 块将文件转换成重构文本(RST)。它接受一个可选的<例外文件>,其中描述了
+哪些元素将被忽略或指向非默认引用。
+
+输出被写入到<输出文件>。
+
+它能够识别定义、函数、结构体、typedef、枚举和枚举符号,并为它们创建交叉引用。
+它还能够区分用于指定Linux ioctl的 ``#define`` 。
+
+<例外文件> 包含两种类型的语句: \ **ignore**\ 或 \ **replace**\ .
+
+ignore标记的语法为:
+
+
+ignore \ **type**\ \ **name**\
+
+The \ **ignore**\ 意味着它不会为类型为 \ **type**\ 的 \ **name**\ 符号生成
+交叉引用。
+
+
+replace标记的语法为:
+
+
+replace \ **type**\ \ **name**\ \ **new_value**\
+
+The \ **replace**\ 味着它将为 \ **type**\ 类型的 \ **name**\ 符号生成交叉引
+用,但是它将使用 \ **new_value**\ 来取代默认的替换规则。
+
+
+这两种语句中, \ **type**\ 可以是以下任一项:
+
+
+\ **ioctl**\
+
+ ignore 或 replace 语句应用于ioctl定义,如:
+
+ #define VIDIOC_DBG_S_REGISTER _IOW('V', 79, struct v4l2_dbg_register)
+
+
+
+\ **define**\
+
+ ignore 或 replace 语句应用于在<C文件>中找到的任何其他 ``#define`` 。
+
+
+
+\ **typedef**\
+
+ ignore 和 replace 语句应用于<C文件>中的typedef语句。
+
+
+
+\ **struct**\
+
+ ignore 和 replace 语句应用于<C文件>中的结构体名称语句。
+
+
+
+\ **enum**\
+
+ ignore 和 replace 语句应用于<C文件>中的枚举名称语句。
+
+
+
+\ **symbol**\
+
+ ignore 和 replace 语句应用于<C文件>中的枚举值名称语句。
+
+ replace语句中, \ **new_value**\ 会自动使用 \ **typedef**\ , \ **enum**\
+ 和 \ **struct**\ 类型的 :c:type: 引用;以及 \ **ioctl**\ , \ **define**\ 和
+ \ **symbol**\ 类型的 :ref: 。引用的类型也可以在replace语句中显式定义。
+
+
+示例
+~~~~
+
+
+ignore define _VIDEODEV2_H
+
+
+忽略<C文件>中的 #define _VIDEODEV2_H 。
+
+ignore symbol PRIVATE
+
+
+如下结构体:
+
+enum foo { BAR1, BAR2, PRIVATE };
+
+不会为 \ **PRIVATE**\ 生成交叉引用。
+
+replace symbol BAR1 :c:type:\`foo\`
+replace symbol BAR2 :c:type:\`foo\`
+
+
+如下结构体:
+
+enum foo { BAR1, BAR2, PRIVATE };
+
+它会让BAR1和BAR2枚举符号交叉引用C域中的foo符号。
+
+
+
+缺陷
+~~~~
+
+
+请向Mauro Carvalho Chehab <mchehab@kernel.org>报告有关缺陷。
+
+中文翻译问题请找中文翻译维护者。
+
+
+版权
+~~~~
+
+
+版权所有 (c) 2016 Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
+
+许可证 GPLv2:GNU GPL version 2 <https://gnu.org/licenses/gpl.html>
+
+这是自由软件:你可以自由地修改和重新发布它。
+在法律允许的范围内,**不提供任何保证**。
diff --git a/Documentation/translations/zh_CN/doc-guide/sphinx.rst b/Documentation/translations/zh_CN/doc-guide/sphinx.rst
new file mode 100644
index 000000000000..23eac67fbc30
--- /dev/null
+++ b/Documentation/translations/zh_CN/doc-guide/sphinx.rst
@@ -0,0 +1,412 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/doc-guide/sphinx.rst
+
+:译者: 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+.. _sphinxdoc_zh:
+
+简介
+====
+
+Linux内核使用 `Sphinx <http://www.sphinx-doc.org/>`_ 来把 ``Documentation``
+下的 `reStructuredText <http://docutils.sourceforge.net/rst.html>`_ 文件转
+换成漂亮的文档。使用 ``make htmldocs`` 或 ``make pdfdocs`` 命令即可构建HTML
+或PDF格式的文档。生成的文档放在 ``Documentation/output`` 文件夹中。
+
+reStructuredText文件可能包含包含来自源文件的结构化文档注释或kernel-doc注释。
+通常它们用于描述代码的功能、类型和设计。kernel-doc注释有一些特殊的结构和
+格式,但除此之外,它们还被作为reStructuredText处理。
+
+最后,有成千上万的纯文本文档文件散布在 ``Documentation`` 里。随着时间推移,
+其中一些可能会转换为reStructuredText,但其中大部分仍保持纯文本。
+
+.. _sphinx_install_zh:
+
+安装Sphinx
+==========
+
+Documentation/ 下的ReST文件现在使用sphinx1.7或更高版本构建。
+
+这有一个脚本可以检查Sphinx的依赖项。更多详细信息见
+:ref:`sphinx-pre-install_zh` 。
+
+大多数发行版都附带了Sphinx,但是它的工具链比较脆弱,而且在您的机器上升级它
+或其他一些Python包导致文档构建中断的情况并不少见。
+
+避免此情况的一种方法是使用与发行版附带的不同的版本。因此,建议使用
+``virtualenv-3`` 或 ``virtualenv`` 在虚拟环境中安装Sphinx,具体取决于发行版
+如何打包Python3。
+
+.. note::
+
+ #) html输出建议使用RTD主题。根据Sphinx版本的不同,它应该用
+ ``pip install sphinx_rtd_theme`` 单独安装。
+
+ #) 一些ReST页面包含数学表达式。由于Sphinx的工作方式,这些表达式是使用 LaTeX
+ 编写的。它需要安装amsfonts和amsmath宏包,以便显示。
+
+总之,如您要安装Sphinx 2.4.4版本,应执行::
+
+ $ virtualenv sphinx_2.4.4
+ $ . sphinx_2.4.4/bin/activate
+ (sphinx_2.4.4) $ pip install -r Documentation/sphinx/requirements.txt
+
+在运行 ``. sphinx_2.4.4/bin/activate`` 之后,提示符将变化,以指示您正在使用新
+环境。如果您打开了一个新的shell,那么在构建文档之前,您需要重新运行此命令以再
+次进入虚拟环境中。
+
+图片输出
+--------
+
+内核文档构建系统包含一个扩展,可以处理GraphViz和SVG格式的图像(参见
+:ref:`sphinx_kfigure_zh` )。
+
+为了让它工作,您需要同时安装GraphViz和ImageMagick包。如果没有安装这些软件包,
+构建系统仍将构建文档,但不会在输出中包含任何图像。
+
+PDF和LaTeX构建
+--------------
+
+目前只有Sphinx 2.4及更高版本才支持这种构建。
+
+对于PDF和LaTeX输出,还需要 ``XeLaTeX`` 3.14159265版本。(译注:此版本号真实
+存在)
+
+根据发行版的不同,您可能还需要安装一系列 ``texlive`` 软件包,这些软件包提供了
+``XeLaTeX`` 工作所需的最小功能集。
+
+.. _sphinx-pre-install_zh:
+
+检查Sphinx依赖项
+----------------
+
+这有一个脚本可以自动检查Sphinx依赖项。如果它认得您的发行版,还会提示您所用发行
+版的安装命令::
+
+ $ ./scripts/sphinx-pre-install
+ Checking if the needed tools for Fedora release 26 (Twenty Six) are available
+ Warning: better to also install "texlive-luatex85".
+ You should run:
+
+ sudo dnf install -y texlive-luatex85
+ /usr/bin/virtualenv sphinx_2.4.4
+ . sphinx_2.4.4/bin/activate
+ pip install -r Documentation/sphinx/requirements.txt
+
+ Can't build as 1 mandatory dependency is missing at ./scripts/sphinx-pre-install line 468.
+
+默认情况下,它会检查html和PDF的所有依赖项,包括图像、数学表达式和LaTeX构建的
+需求,并假设将使用虚拟Python环境。html构建所需的依赖项被认为是必需的,其他依
+赖项则是可选的。
+
+它支持两个可选参数:
+
+``--no-pdf``
+
+ 禁用PDF检查;
+
+``--no-virtualenv``
+
+ 使用Sphinx的系统打包,而不是Python虚拟环境。
+
+Sphinx构建
+==========
+
+生成文档的常用方法是运行 ``make htmldocs`` 或 ``make pdfdocs`` 。还有其它可用
+的格式:请参阅 ``make help`` 的文档部分。生成的文档放在 ``Documentation/output``
+下相应格式的子目录中。
+
+要生成文档,显然必须安装Sphinx( ``sphinx-build`` )。要让HTML输出更漂亮,可以
+使用Read the Docs Sphinx主题( ``sphinx_rtd_theme`` )。对于PDF输出,您还需要
+``XeLaTeX`` 和来自ImageMagick(https://www.imagemagick.org)的 ``convert(1)`` 。
+所有这些软件在大多发行版中都可用或已打包。
+
+要传递额外的选项给Sphinx,可以使用make变量 ``SPHINXOPTS`` 。例如,使用
+``make SPHINXOPTS=-v htmldocs`` 获得更详细的输出。
+
+
+要删除生成的文档,请运行 ``make cleandocs`` 。
+
+编写文档
+========
+
+添加新文档很容易,只需:
+
+1. 在 ``Documentation`` 下某处添加一个新的 ``.rst`` 文件。
+2. 从 ``Documentation/index.rst`` 中的Sphinx `主目录树`_ 链接到它。
+
+.. _主目录树: http://www.sphinx-doc.org/en/stable/markup/toctree.html
+
+对于简单的文档(比如您现在正在阅读的文档),这通常已经足够好了,但是对于较大
+的文档,最好创建一个子目录(或者使用现有的子目录)。例如,图形子系统文档位于
+``Documentation/gpu`` 下,拆分为多个 ``.rst`` 文件,并具有从主目录链接来的单
+独索引 ``index.rst`` (有自己的目录树 ``toctree`` )。
+
+请参阅 `Sphinx <http://www.sphinx-doc.org/>`_ 和 `reStructuredText
+<http://docutils.sourceforge.net/rst.html>`_ 的文档,以了解如何使用它们。
+特别是Sphinx `reStructuredText 基础`_ 这是开始学习使用reStructuredText的
+好地方。还有一些 `Sphinx 特殊标记结构`_ 。
+
+.. _reStructuredText 基础: http://www.sphinx-doc.org/en/stable/rest.html
+.. _Sphinx 特殊标记结构: http://www.sphinx-doc.org/en/stable/markup/index.html
+
+内核文档的具体指南
+------------------
+
+这是一些内核文档的具体指南:
+
+* 请不要过于痴迷转换格式到reStructuredText。保持简单。在大多数情况下,文档
+ 应该是纯文本,格式应足够一致,以便可以转换为其他格式。
+
+* 将现有文档转换为reStructuredText时,请尽量减少格式更改。
+
+* 在转换文档时,还要更新内容,而不仅仅是格式。
+
+* 请遵循标题修饰符的顺序:
+
+ 1. ``=`` 文档标题,要有上线::
+
+ ========
+ 文档标题
+ ========
+
+ 2. ``=`` 章::
+
+ 章标题
+ ======
+
+ 3. ``-`` 节::
+
+ 节标题
+ ------
+
+ 4. ``~`` 小节::
+
+ 小节标题
+ ~~~~~~~~
+
+ 尽管RST没有规定具体的顺序(“没有强加一个固定数量和顺序的节标题装饰风格,最终
+ 按照的顺序将是实际遇到的顺序。”),但是拥有一个通用级别的文档更容易遵循。
+
+* 对于插入固定宽度的文本块(用于代码样例、用例等): ``::`` 用于语法高亮意义不
+ 大的内容,尤其是短代码段; ``.. code-block:: <language>`` 用于需要语法高亮的
+ 较长代码块。对于嵌入到文本中的简短代码片段,请使用 \`\` 。
+
+
+C域
+---
+
+**Sphinx C域(Domain)** (name c)适用于C API文档。例如,函数原型:
+
+.. code-block:: rst
+
+ .. c:function:: int ioctl( int fd, int request )
+
+内核文档的C域有一些附加特性。例如,您可以使用诸如 ``open`` 或 ``ioctl`` 这样的
+通用名称重命名函数的引用名称:
+
+.. code-block:: rst
+
+ .. c:function:: int ioctl( int fd, int request )
+ :name: VIDIOC_LOG_STATUS
+
+函数名称(例如ioctl)仍保留在输出中,但引用名称从 ``ioctl`` 变为
+``VIDIOC_LOG_STATUS`` 。此函数的索引项也变为 ``VIDIOC_LOG_STATUS`` 。
+
+请注意,不需要使用 ``c:func:`` 生成函数文档的交叉引用。由于一些Sphinx扩展的
+神奇力量,如果给定函数名的索引项存在,文档构建系统会自动将对 ``function()``
+的引用转换为交叉引用。如果在内核文档中看到 ``c:func:`` 的用法,请删除它。
+
+
+列表
+----
+
+我们建议使用 *列式表* 格式。 *列式表* 格式是二级列表。与ASCII艺术相比,它们对
+文本文件的读者来说可能没有那么舒适。但其优点是易于创建或修改,而且修改的差异
+(diff)更有意义,因为差异仅限于修改的内容。
+
+*平铺表* 也是一个二级列表,类似于 *列式表* ,但具有一些额外特性:
+
+* 列范围:使用 ``cspan`` 修饰,可以通过其他列扩展单元格
+
+* 行范围:使用 ``rspan`` 修饰,可以通过其他行扩展单元格
+
+* 自动将表格行最右边的单元格扩展到该行右侧空缺的单元格上。若使用
+ ``:fill-cells:`` 选项,此行为可以从 *自动合并* 更改为 *自动插入* ,自动
+ 插入(空)单元格,而不是扩展合并到最后一个单元格。
+
+选项:
+
+* ``:header-rows:`` [int] 标题行计数
+* ``:stub-columns:`` [int] 标题列计数
+* ``:widths:`` [[int] [int] ... ] 列宽
+* ``:fill-cells:`` 插入缺少的单元格,而不是自动合并缺少的单元格
+
+修饰:
+
+* ``:cspan:`` [int] 扩展列
+* ``:rspan:`` [int] 扩展行
+
+下面的例子演示了如何使用这些标记。分级列表的第一级是 *表格行* 。 *表格行* 中
+只允许一个标记,即该 *表格行* 中的单元格列表。 *comments* ( ``..`` )和
+*targets* 例外(例如引用 ``:ref:`最后一行 <last row_zh>``` / :ref:`最后一行
+<last row_zh>` )。
+
+.. code-block:: rst
+
+ .. flat-table:: 表格标题
+ :widths: 2 1 1 3
+
+ * - 表头 列1
+ - 表头 列2
+ - 表头 列3
+ - 表头 列4
+
+ * - 行1
+ - 字段1.1
+ - 字段1.2(自动扩展)
+
+ * - 行2
+ - 字段2.1
+ - :rspan:`1` :cspan:`1` 字段2.2~3.3
+
+ * .. _`last row_zh`:
+
+ - 行3
+
+渲染效果:
+
+ .. flat-table:: 表格标题
+ :widths: 2 1 1 3
+
+ * - 表头 列1
+ - 表头 列2
+ - 表头 列3
+ - 表头 列4
+
+ * - 行1
+ - 字段1.1
+ - 字段1.2(自动扩展)
+
+ * - 行2
+ - 字段2.1
+ - :rspan:`1` :cspan:`1` 字段2.2~3.3
+
+ * .. _`last row_zh`:
+
+ - 行3
+
+交叉引用
+--------
+
+从一页文档到另一页文档的交叉引用可以通过简单地写出文件路径来完成,无特殊格式
+要求。路径可以是绝对路径或相对路径。绝对路径从“Documentation/”开始。例如,要
+交叉引用此页,以下写法皆可,取决于具体的文档目录(注意 ``.rst`` 扩展名是可选
+的)::
+
+ 参见 Documentation/doc-guide/sphinx.rst 。此法始终可用。
+ 请查看 sphinx.rst ,仅在同级目录中有效。
+ 请阅读 ../sphinx.rst ,上级目录中的文件。
+
+如果要使用相对路径,则需要使用Sphinx的 ``doc`` 修饰。例如,从同一目录引用此页
+的操作如下::
+
+ 参见 :doc:`sphinx文档的自定义链接文本 <sphinx>`.
+
+对于大多数用例,前者是首选,因为它更干净,更适合阅读源文件的人。如果您遇到一
+个没有任何特殊作用的 ``:doc:`` 用法,请将其转换为文档路径。
+
+有关交叉引用kernel-doc函数或类型的信息,请参阅
+Documentation/doc-guide/kernel-doc.rst 。
+
+.. _sphinx_kfigure_zh:
+
+图形图片
+========
+
+如果要添加图片,应该使用 ``kernel-figure`` 和 ``kernel-image`` 指令。例如,
+要插入具有可缩放图像格式的图形,请使用SVG(:ref:`svg_image_example_zh` )::
+
+ .. kernel-figure:: ../../../doc-guide/svg_image.svg
+ :alt: 简易 SVG 图片
+
+ SVG 图片示例
+
+.. _svg_image_example_zh:
+
+.. kernel-figure:: ../../../doc-guide/svg_image.svg
+ :alt: 简易 SVG 图片
+
+ SVG 图片示例
+
+内核figure(和image)指令支持 DOT 格式文件,请参阅
+
+* DOT:http://graphviz.org/pdf/dotguide.pdf
+* Graphviz:http://www.graphviz.org/content/dot-language
+
+一个简单的例子(:ref:`hello_dot_file_zh` )::
+
+ .. kernel-figure:: ../../../doc-guide/hello.dot
+ :alt: 你好,世界
+
+ DOT 示例
+
+.. _hello_dot_file_zh:
+
+.. kernel-figure:: ../../../doc-guide/hello.dot
+ :alt: 你好,世界
+
+ DOT 示例
+
+嵌入的渲染标记(或语言),如Graphviz的 **DOT** 由 ``kernel-render`` 指令提供::
+
+ .. kernel-render:: DOT
+ :alt: 有向图
+ :caption: 嵌入式 **DOT** (Graphviz) 代码
+
+ digraph foo {
+ "五棵松" -> "国贸";
+ }
+
+如何渲染取决于安装的工具。如果安装了Graphviz,您将看到一个矢量图像。否则,原始
+标记将作为 *文字块* 插入(:ref:`hello_dot_render_zh` )。
+
+.. _hello_dot_render_zh:
+
+.. kernel-render:: DOT
+ :alt: 有向图
+ :caption: 嵌入式 **DOT** (Graphviz) 代码
+
+ digraph foo {
+ "五棵松" -> "国贸";
+ }
+
+*render* 指令包含 *figure* 指令中已知的所有选项,以及选项 ``caption`` 。如果
+``caption`` 有值,则插入一个 *figure* 节点,若无,则插入一个 *image* 节点。
+如果您想引用它,还需要一个 ``caption`` (:ref:`hello_svg_render_zh` )。
+
+嵌入式 **SVG**::
+
+ .. kernel-render:: SVG
+ :caption: 嵌入式 **SVG** 标记
+ :alt: 右上箭头
+
+ <?xml version="1.0" encoding="UTF-8"?>
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.1" ...>
+ ...
+ </svg>
+
+.. _hello_svg_render_zh:
+
+.. kernel-render:: SVG
+ :caption: 嵌入式 **SVG** 标记
+ :alt: 右上箭头
+
+ <?xml version="1.0" encoding="UTF-8"?>
+ <svg xmlns="http://www.w3.org/2000/svg"
+ version="1.1" baseProfile="full" width="70px" height="40px" viewBox="0 0 700 400">
+ <line x1="180" y1="370" x2="500" y2="50" stroke="black" stroke-width="15px"/>
+ <polygon points="585 0 525 25 585 50" transform="rotate(135 525 25)"/>
+ </svg>
+
diff --git a/Documentation/translations/zh_CN/driver-api/gpio/index.rst b/Documentation/translations/zh_CN/driver-api/gpio/index.rst
new file mode 100644
index 000000000000..9a6a14162a6c
--- /dev/null
+++ b/Documentation/translations/zh_CN/driver-api/gpio/index.rst
@@ -0,0 +1,68 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/driver-api/gpio/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+=======================
+通用型输入/输出(GPIO)
+=======================
+
+.. toctree::
+ :caption: 目录
+ :maxdepth: 2
+
+ legacy
+
+Todolist:
+
+* intro
+* using-gpio
+* driver
+* consumer
+* board
+* drivers-on-gpio
+* bt8xxgpio
+
+核心
+====
+
+该API在以下内核代码中:
+
+include/linux/gpio/driver.h
+
+drivers/gpio/gpiolib.c
+
+ACPI支持
+========
+
+该API在以下内核代码中:
+
+drivers/gpio/gpiolib-acpi.c
+
+设备树支持
+==========
+
+该API在以下内核代码中:
+
+drivers/gpio/gpiolib-of.c
+
+设备管理支持
+============
+
+该API在以下内核代码中:
+
+drivers/gpio/gpiolib-devres.c
+
+sysfs帮助(函数)
+=================
+
+该API在以下内核代码中:
+
+drivers/gpio/gpiolib-sysfs.c
diff --git a/Documentation/translations/zh_CN/gpio.txt b/Documentation/translations/zh_CN/driver-api/gpio/legacy.rst
index a23ee14fc927..aeccff777170 100644
--- a/Documentation/translations/zh_CN/gpio.txt
+++ b/Documentation/translations/zh_CN/driver-api/gpio/legacy.rst
@@ -1,39 +1,28 @@
-Chinese translated version of Documentation/admin-guide/gpio
+.. SPDX-License-Identifier: GPL-2.0
-If you have any comment or update to the content, please contact the
-original document maintainer directly. However, if you have a problem
-communicating in English you can also ask the Chinese maintainer for
-help. Contact the Chinese maintainer if this translation is outdated
-or if there is a problem with the translation.
+.. include:: ../../disclaimer-zh_CN.rst
-Maintainer: Grant Likely <grant.likely@secretlab.ca>
- Linus Walleij <linus.walleij@linaro.org>
-Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
----------------------------------------------------------------------
-Documentation/admin-guide/gpio 的中文翻译
+:Original: Documentation/driver-api/gpio/legacy.rst
-如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
-交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
-译存在问题,请联系中文版维护者。
-英文版维护者: Grant Likely <grant.likely@secretlab.ca>
- Linus Walleij <linus.walleij@linaro.org>
-中文版维护者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
-中文版翻译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
-中文版校译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
+:翻译:
+ 傅炜 Fu Wei <tekkamanninja@gmail.com>
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
-以下为正文
----------------------------------------------------------------------
-GPIO 接口
+:校译:
-本文档提供了一个在Linux下访问GPIO的公约概述。
+
+传统GPIO接口
+============
+
+本文档概述了Linux下的GPIO访问公约。
这些函数以 gpio_* 作为前缀。其他的函数不允许使用这样的前缀或相关的
__gpio_* 前缀。
-什么是GPIO?
-==========
+什么是GPIO?
+============
"通用输入/输出口"(GPIO)是一个灵活的由软件控制的数字信号。他们可
由多种芯片提供,且对于从事嵌入式和定制硬件的 Linux 开发者来说是
比较熟悉。每个GPIO 都代表一个连接到特定引脚或球栅阵列(BGA)封装中
@@ -99,6 +88,7 @@ GPIO 公约
标识 GPIO
---------
+
GPIO 是通过无符号整型来标识的,范围是 0 到 MAX_INT。保留“负”数
用于其他目的,例如标识信号“在这个板子上不可用”或指示错误。未接触底层
硬件的代码会忽略这些整数。
@@ -115,7 +105,7 @@ FPGA 的特定板子上使用 80-95。编号不一定要连续,那些平台中
如果你要初始化一个带有无效 GPIO 编号的结构体,可以使用一些负编码
(如"-EINVAL"),那将使其永远不会是有效。来测试这样一个结构体中的编号
-是否关联一个 GPIO,你可使用以下断言:
+是否关联一个 GPIO,你可使用以下断言::
int gpio_is_valid(int number);
@@ -128,11 +118,12 @@ FPGA 的特定板子上使用 80-95。编号不一定要连续,那些平台中
使用 GPIO
---------
+
对于一个 GPIO,系统应该做的第一件事情就是通过 gpio_request()
函数分配它,见下文。
接下来是设置I/O方向,这通常是在板级启动代码中为所使用的 GPIO 设置
-platform_device 时完成。
+platform_device 时完成::
/* 设置为输入或输出, 返回 0 或负的错误代码 */
int gpio_direction_input(unsigned gpio);
@@ -157,12 +148,12 @@ get/set(获取/设置)函数调用没法返回错误,且有可能是配置错误
访问自旋锁安全的 GPIO
--------------------
+---------------------
+
大多数 GPIO 控制器可以通过内存读/写指令来访问。这些指令不会休眠,可以
安全地在硬(非线程)中断例程和类似的上下文中完成。
-对于那些用 gpio_cansleep()测试总是返回失败的 GPIO(见下文),使用
-以下的函数访问:
+对于那些 GPIO,使用以下的函数访问::
/* GPIO 输入:返回零或非零 */
int gpio_get_value(unsigned gpio);
@@ -188,17 +179,13 @@ GPIO值是布尔值,零表示低电平,非零表示高电平。当读取一
访问可能休眠的 GPIO
------------------
+-------------------
+
某些 GPIO 控制器必须通过基于总线(如 I2C 或 SPI)的消息访问。读或写这些
GPIO 值的命令需要等待其信息排到队首才发送命令,再获得其反馈。期间需要
休眠,这不能在 IRQ 例程(中断上下文)中执行。
-支持此类 GPIO 的平台通过以下函数返回非零值来区分出这种 GPIO。(此函数需要
-一个之前通过 gpio_request 分配到的有效 GPIO 编号):
-
- int gpio_cansleep(unsigned gpio);
-
-为了访问这种 GPIO,内核定义了一套不同的函数:
+为了访问这种 GPIO,内核定义了一套不同的函数::
/* GPIO 输入:返回零或非零 ,可能会休眠 */
int gpio_get_value_cansleep(unsigned gpio);
@@ -206,7 +193,6 @@ GPIO 值的命令需要等待其信息排到队首才发送命令,再获得其
/* GPIO 输出,可能会休眠 */
void gpio_set_value_cansleep(unsigned gpio, int value);
-
访问这样的 GPIO 需要一个允许休眠的上下文,例如线程 IRQ 处理例程,并用以上的
访问函数替换那些没有 cansleep()后缀的自旋锁安全访问函数。
@@ -214,25 +200,25 @@ GPIO 值的命令需要等待其信息排到队首才发送命令,再获得其
事实,这些处理例程实际上和自旋锁安全的函数是一样的。
** 除此之外 ** 调用设置和配置此类 GPIO 的函数也必须在允许休眠的上下文中,
-因为它们可能也需要访问 GPIO 控制器芯片: (这些设置函数通常在板级启动代码或者
-驱动探测/断开代码中,所以这是一个容易满足的约束条件。)
+因为它们可能也需要访问 GPIO 控制器芯片 (这些设置函数通常在板级启动代码或者
+驱动探测/断开代码中,所以这是一个容易满足的约束条件。) ::
- gpio_direction_input()
- gpio_direction_output()
- gpio_request()
+ gpio_direction_input()
+ gpio_direction_output()
+ gpio_request()
-## gpio_request_one()
-## gpio_request_array()
-## gpio_free_array()
+ ## gpio_request_one()
+ ## gpio_request_array()
+ ## gpio_free_array()
- gpio_free()
- gpio_set_debounce()
+ gpio_free()
声明和释放 GPIO
-----------------------------
-为了有助于捕获系统配置错误,定义了两个函数。
+----------------
+
+为了有助于捕获系统配置错误,定义了两个函数::
/* 申请 GPIO, 返回 0 或负的错误代码.
* 非空标签可能有助于诊断.
@@ -256,9 +242,9 @@ GPIO 值的命令需要等待其信息排到队首才发送命令,再获得其
某些平台可能也使用 GPIO 作为电源管理激活信号(例如通过关闭未使用芯片区和
简单地关闭未使用时钟)。
-对于 GPIO 使用 pinctrl 子系统已知的引脚,子系统应该被告知其使用情况;
+对于 GPIO 使用引脚控制子系统已知的引脚,子系统应该被告知其使用情况;
一个 gpiolib 驱动的 .request()操作应调用 pinctrl_gpio_request(),
-而 gpiolib 驱动的 .free()操作应调用 pinctrl_gpio_free()。pinctrl
+而 gpiolib 驱动的 .free()操作应调用 pinctrl_gpio_free()。引脚控制
子系统允许 pinctrl_gpio_request()在某个引脚或引脚组以复用形式“属于”
一个设备时都成功返回。
@@ -270,7 +256,7 @@ GPIO 值的命令需要等待其信息排到队首才发送命令,再获得其
某些平台允许部分或所有 GPIO 信号使用不同的引脚。类似的,GPIO 或引脚的
其他方面也需要配置,如上拉/下拉。平台软件应该在对这些 GPIO 调用
-gpio_request()前将这类细节配置好,例如使用 pinctrl 子系统的映射表,
+gpio_request()前将这类细节配置好,例如使用引脚控制子系统的映射表,
使得 GPIO 的用户无须关注这些细节。
还有一个值得注意的是在释放 GPIO 前,你必须停止使用它。
@@ -278,7 +264,7 @@ gpio_request()前将这类细节配置好,例如使用 pinctrl 子系统的映
注意:申请一个 GPIO 并没有以任何方式配置它,只不过标识那个 GPIO 处于使用
状态。必须有另外的代码来处理引脚配置(如控制 GPIO 使用的引脚、上拉/下拉)。
-考虑到大多数情况下声明 GPIO 之后就会立即配置它们,所以定义了以下三个辅助函数:
+考虑到大多数情况下声明 GPIO 之后就会立即配置它们,所以定义了以下三个辅助函数::
/* 申请一个 GPIO 信号, 同时通过特定的'flags'初始化配置,
* 其他和 gpio_request()的参数和返回值相同
@@ -301,11 +287,6 @@ gpio_request()前将这类细节配置好,例如使用 pinctrl 子系统的映
* GPIOF_INIT_LOW - 在作为输出时,初始值为低电平
* GPIOF_INIT_HIGH - 在作为输出时,初始值为高电平
- * GPIOF_OPEN_DRAIN - gpio引脚为开漏信号
- * GPIOF_OPEN_SOURCE - gpio引脚为源极开路信号
-
- * GPIOF_EXPORT_DIR_FIXED - 将 gpio 导出到 sysfs,并保持方向
- * GPIOF_EXPORT_DIR_CHANGEABLE - 同样是导出, 但允许改变方向
因为 GPIOF_INIT_* 仅有在配置为输出的时候才存在,所以有效的组合为:
@@ -313,20 +294,8 @@ gpio_request()前将这类细节配置好,例如使用 pinctrl 子系统的映
* GPIOF_OUT_INIT_LOW - 配置为输出,并初始化为低电平
* GPIOF_OUT_INIT_HIGH - 配置为输出,并初始化为高电平
-当设置 flag 为 GPIOF_OPEN_DRAIN 时,则假设引脚是开漏信号。这样的引脚
-将不会在输出模式下置1。这样的引脚需要连接上拉电阻。通过使能这个标志,gpio库
-将会在被要求输出模式下置1时将引脚变为输入状态来使引脚置高。引脚在输出模式下
-通过置0使其输出低电平。
-
-当设置 flag 为 GPIOF_OPEN_SOURCE 时,则假设引脚为源极开路信号。这样的引脚
-将不会在输出模式下置0。这样的引脚需要连接下拉电阻。通过使能这个标志,gpio库
-将会在被要求输出模式下置0时将引脚变为输入状态来使引脚置低。引脚在输出模式下
-通过置1使其输出高电平。
-
-将来这些标志可能扩展到支持更多的属性。
-
更进一步,为了更简单地声明/释放多个 GPIO,'struct gpio'被引进来封装所有
-这三个领域:
+这三个领域::
struct gpio {
unsigned gpio;
@@ -334,7 +303,7 @@ gpio_request()前将这类细节配置好,例如使用 pinctrl 子系统的映
const char *label;
};
-一个典型的用例:
+一个典型的用例::
static struct gpio leds_gpios[] = {
{ 32, GPIOF_OUT_INIT_HIGH, "Power LED" }, /* 默认开启 */
@@ -356,16 +325,14 @@ gpio_request()前将这类细节配置好,例如使用 pinctrl 子系统的映
GPIO 映射到 IRQ
---------------------
+----------------
+
GPIO 编号是无符号整数;IRQ 编号也是。这些构成了两个逻辑上不同的命名空间
-(GPIO 0 不一定使用 IRQ 0)。你可以通过以下函数在它们之间实现映射:
+(GPIO 0 不一定使用 IRQ 0)。你可以通过以下函数在它们之间实现映射::
/* 映射 GPIO 编号到 IRQ 编号 */
int gpio_to_irq(unsigned gpio);
- /* 映射 IRQ 编号到 GPIO 编号 (尽量避免使用) */
- int irq_to_gpio(unsigned irq);
-
它们的返回值为对应命名空间的相关编号,或是负的错误代码(如果无法映射)。
(例如,某些 GPIO 无法做为 IRQ 使用。)以下的编号错误是未经检测的:使用一个
未通过 gpio_direction_input()配置为输入的 GPIO 编号,或者使用一个
@@ -378,13 +345,10 @@ gpio_to_irq()返回的非错误值可以传递给 request_irq()或者 free_irq()
触发选项是 IRQ 接口的一部分,如 IRQF_TRIGGER_FALLING,系统唤醒能力
也是如此。
-irq_to_gpio()返回的非错误值大多数通常可以被 gpio_get_value()所使用,
-比如在 IRQ 是沿触发时初始化或更新驱动状态。注意某些平台不支持反映射,所以
-你应该尽量避免使用它。
-
模拟开漏信号
-----------------------------
+------------
+
有时在只有低电平信号作为实际驱动结果(译者注:多个输出连接于一点,逻辑电平
结果为所有输出的逻辑与)的时候,共享的信号线需要使用“开漏”信号。(该术语
适用于 CMOS 管;而 TTL 用“集电极开路”。)一个上拉电阻使信号为高电平。这
@@ -408,9 +372,44 @@ irq_to_gpio()返回的非错误值大多数通常可以被 gpio_get_value()所
这不一定是错误的。一个常见的例子就是 I2C 时钟的延长:一个需要较慢时钟的
从设备延迟 SCK 的上升沿,而 I2C 主设备相应地调整其信号传输速率。
+GPIO控制器和引脚控制子系统
+--------------------------
+
+SOC上的GPIO控制器可能与引脚控制子系统紧密结合,即引脚可以与可选的gpio功
+能一起被其他功能使用。我们已经涵盖了这样的情况,例如一个GPIO控制器需要保
+留一个引脚或通过调用以下任何一个引脚来设置其方向::
+
+ pinctrl_gpio_request()
+ pinctrl_gpio_free()
+ pinctrl_gpio_direction_input()
+ pinctrl_gpio_direction_output()
+
+但是,引脚控制子系统是如何将GPIO号码(这是一个全局事项)与某个引脚控制器
+上的某个引脚交叉关联的?
+
+这是通过注册引脚的“范围”来实现的,这基本上是交叉参考表。这些描述是在
+Documentation/driver-api/pin-control.rst
+
+虽然引脚分配完全由引脚控制子系统管理,但gpio(在gpiolib下)仍由gpio驱动
+维护。可能发生的情况是,SoC中的不同引脚范围由不同的gpio驱动器管理。
+
+这使得在调用 "pinctrl_gpio_request" 之前,让gpio驱动向pin ctrl子系
+统宣布它们的引脚范围是合理的,以便在使用任何gpio之前要求引脚控制子系统准
+备相应的引脚。
+
+为此,gpio控制器可以用引脚控制子系统注册其引脚范围。目前有两种方法:有或
+无DT。
+
+关于对DT的支持,请参考 Documentation/devicetree/bindings/gpio/gpio.txt.
+
+对于非DT支持,用户可以用适当的参数调用gpiochip_add_pin_range(),将一
+系列的gpio引脚注册到引脚控制驱动上。为此,必须将引脚控制设备的名称字符串
+作为参数之一传给这个程序。
+
+
+这些公约忽略了什么?
+====================
-这些公约忽略了什么?
-================
这些公约忽略的最大一件事就是引脚复用,因为这属于高度芯片特定的属性且
没有可移植性。某个平台可能不需要明确的复用信息;有的对于任意给定的引脚
可能只有两个功能选项;有的可能每个引脚有八个功能选项;有的可能可以将
@@ -433,8 +432,9 @@ Linux 的系统。)
当前,动态定义 GPIO 并不是标准的,例如作为配置一个带有某些 GPIO 扩展器的
附加电路板的副作用。
-GPIO 实现者的框架 (可选)
-=====================
+GPIO 实现者的框架(可选)
+=========================
+
前面提到了,有一个可选的实现框架,让平台使用相同的编程接口,更加简单地支持
不同种类的 GPIO 控制器。这个框架称为"gpiolib"。
@@ -444,15 +444,16 @@ GPIO 实现者的框架 (可选)
控制器驱动: gpio_chip
--------------------
+---------------------
+
在框架中每个 GPIO 控制器都包装为一个 "struct gpio_chip",他包含了
该类型的每个控制器的常用信息:
- - 设置 GPIO 方向的方法
- - 用于访问 GPIO 值的方法
- - 告知调用其方法是否可能休眠的标志
- - 可选的 debugfs 信息导出方法 (显示类似上拉配置一样的额外状态)
- - 诊断标签
+ - 设置 GPIO 方向的方法
+ - 用于访问 GPIO 值的方法
+ - 告知调用其方法是否可能休眠的标志
+ - 可选的 debugfs 信息导出方法 (显示类似上拉配置一样的额外状态)
+ - 诊断标签
也包含了来自 device.platform_data 的每个实例的数据:它第一个 GPIO 的
编号和它可用的 GPIO 的数量。
@@ -471,11 +472,12 @@ GPIO 实现者的框架 (可选)
平台支持
--------
+--------
+
为了支持这个框架,一个平台的 Kconfig 文件将会 "select"(选择)
ARCH_REQUIRE_GPIOLIB 或 ARCH_WANT_OPTIONAL_GPIOLIB,并让它的
-<asm/gpio.h> 包含 <asm-generic/gpio.h>,同时定义三个方法:
-gpio_get_value()、gpio_set_value()和 gpio_cansleep()。
+<asm/gpio.h> 包含 <asm-generic/gpio.h>,同时定义两个方法:
+gpio_get_value()、gpio_set_value()。
它也应提供一个 ARCH_NR_GPIOS 的定义值,这样可以更好地反映该平台 GPIO
的实际数量,节省静态表的空间。(这个定义值应该包含片上系统内建 GPIO 和
@@ -489,11 +491,10 @@ ARCH_WANT_OPTIONAL_GPIOLIB 意味着 gpiolib 核心默认关闭,且用户可以
如果这些选项都没被选择,该平台就不通过 GPIO-lib 支持 GPIO,且代码不可以
被用户使能。
-以下这些方法的实现可以直接使用框架代码,并总是通过 gpio_chip 调度:
+以下这些方法的实现可以直接使用框架代码,并总是通过 gpio_chip 调度::
#define gpio_get_value __gpio_get_value
#define gpio_set_value __gpio_set_value
- #define gpio_cansleep __gpio_cansleep
这些定义可以用更理想的实现方法替代,那就是使用经过逻辑优化的内联函数来访问
基于特定片上系统的 GPIO。例如,若引用的 GPIO (寄存器位偏移)是常量“12”,
@@ -508,7 +509,8 @@ arch_initcall()或者更早的地方集成进平台初始化代码,使这些 G
且他们通常可以作为 IRQ 使用。
板级支持
--------
+--------
+
对于外部 GPIO 控制器(例如 I2C 或 SPI 扩展器、专用芯片、多功能器件、FPGA
或 CPLD),大多数常用板级特定代码都可以注册控制器设备,并保证他们的驱动知道
gpiochip_add()所使用的 GPIO 编号。他们的起始编号通常跟在平台特定的 GPIO
@@ -526,8 +528,9 @@ GPIO 可以工作之后才可被注册。解决这类依赖的的一种方法是
设备变成无效时移除它们。
-用户空间的 Sysfs 接口(可选)
-========================
+用户空间的 Sysfs 接口(可选)
+=============================
+
使用“gpiolib”实现框架的平台可以选择配置一个 GPIO 的 sysfs 用户接口。
这不同于 debugfs 接口,因为它提供的是对 GPIO方向和值的控制,而不只显示
一个GPIO 的状态摘要。此外,它可以出现在没有调试支持的产品级系统中。
@@ -548,6 +551,7 @@ GPIO 可以工作之后才可被注册。解决这类依赖的的一种方法是
Sysfs 中的路径
--------------
+
在/sys/class/gpio 中有 3 类入口:
- 用于在用户空间控制 GPIO 的控制接口;
@@ -624,27 +628,7 @@ GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO
确定给定信号所用的 GPIO 编号。
-从内核代码中导出
--------------
-内核代码可以明确地管理那些已通过 gpio_request()申请的 GPIO 的导出:
-
- /* 导出 GPIO 到用户空间 */
- int gpio_export(unsigned gpio, bool direction_may_change);
-
- /* gpio_export()的逆操作 */
- void gpio_unexport();
-
- /* 创建一个 sysfs 连接到已导出的 GPIO 节点 */
- int gpio_export_link(struct device *dev, const char *name,
- unsigned gpio)
-
-在一个内核驱动申请一个 GPIO 之后,它可以通过 gpio_export()使其在 sysfs
-接口中可见。该驱动可以控制信号方向是否可修改。这有助于防止用户空间代码无意间
-破坏重要的系统状态。
-
-这个明确的导出有助于(通过使某些实验更容易来)调试,也可以提供一个始终存在的接口,
-与文档配合作为板级支持包的一部分。
+API参考
+=======
-在 GPIO 被导出之后,gpio_export_link()允许在 sysfs 文件系统的任何地方
-创建一个到这个 GPIO sysfs 节点的符号链接。这样驱动就可以通过一个描述性的
-名字,在 sysfs 中他们所拥有的设备下提供一个(到这个 GPIO sysfs 节点的)接口。
+本节中列出的函数已被废弃。在新的代码中应该使用基于GPIO描述符的API。
diff --git a/Documentation/translations/zh_CN/driver-api/index.rst b/Documentation/translations/zh_CN/driver-api/index.rst
new file mode 100644
index 000000000000..92ff1b7fc3d3
--- /dev/null
+++ b/Documentation/translations/zh_CN/driver-api/index.rst
@@ -0,0 +1,129 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/driver-api/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+========================
+Linux驱动实现者的API指南
+========================
+
+内核提供了各种各样的接口来支持设备驱动的开发。这份文档只是对其中一些接口进行了
+一定程度的整理——希望随着时间的推移,它能变得更好!可用的小节可以在下面看到。
+
+.. toctree::
+ :caption: 目录列表
+ :maxdepth: 2
+
+ gpio/index
+ io_ordering
+
+Todolist:
+
+* driver-model/index
+* basics
+* infrastructure
+* ioctl
+* early-userspace/index
+* pm/index
+* clk
+* device-io
+* dma-buf
+* device_link
+* component
+* message-based
+* infiniband
+* aperture
+* frame-buffer
+* regulator
+* reset
+* iio/index
+* input
+* usb/index
+* firewire
+* pci/index
+* cxl/index
+* spi
+* i2c
+* ipmb
+* ipmi
+* i3c/index
+* interconnect
+* devfreq
+* hsi
+* edac
+* scsi
+* libata
+* target
+* mailbox
+* mtdnand
+* miscellaneous
+* mei/index
+* mtd/index
+* mmc/index
+* nvdimm/index
+* w1
+* rapidio/index
+* s390-drivers
+* vme
+* 80211/index
+* uio-howto
+* firmware/index
+* pin-control
+* md/index
+* media/index
+* misc_devices
+* nfc/index
+* dmaengine/index
+* slimbus
+* soundwire/index
+* thermal/index
+* fpga/index
+* acpi/index
+* auxiliary_bus
+* backlight/lp855x-driver.rst
+* connector
+* console
+* dcdbas
+* eisa
+* isa
+* isapnp
+* io-mapping
+* generic-counter
+* memory-devices/index
+* men-chameleon-bus
+* ntb
+* nvmem
+* parport-lowlevel
+* pps
+* ptp
+* phy/index
+* pwm
+* pldmfw/index
+* rfkill
+* serial/index
+* sm501
+* surface_aggregator/index
+* switchtec
+* sync_file
+* tty/index
+* vfio-mediated-device
+* vfio
+* vfio-pci-device-specific-driver-acceptance
+* xilinx/index
+* xillybus
+* zorro
+* hte/index
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
diff --git a/Documentation/translations/zh_CN/driver-api/io_ordering.rst b/Documentation/translations/zh_CN/driver-api/io_ordering.rst
new file mode 100644
index 000000000000..4dbfa4ce92a0
--- /dev/null
+++ b/Documentation/translations/zh_CN/driver-api/io_ordering.rst
@@ -0,0 +1,60 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/driver-api/io_ordering.rst
+
+:翻译:
+
+ 林永听 Lin Yongting <linyongting@gmail.com>
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+===========================
+对内存映射地址的I/O写入排序
+===========================
+
+在某些平台上,所谓的内存映射I/O是弱顺序。在这些平台上,驱动开发者有责任
+保证I/O内存映射地址的写操作按程序图意的顺序达到设备。通常读取一个“安全”
+设备寄存器或桥寄存器,触发IO芯片清刷未处理的写操作到达设备后才处理读操作,
+而达到保证目的。驱动程序通常在spinlock保护的临界区退出之前使用这种技术。
+这也可以保证后面的写操作只在前面的写操作之后到达设备(这非常类似于内存
+屏障操作,mb(),不过仅适用于I/O)。
+
+假设一个设备驱动程的具体例子::
+
+ ...
+ CPU A: spin_lock_irqsave(&dev_lock, flags)
+ CPU A: val = readl(my_status);
+ CPU A: ...
+ CPU A: writel(newval, ring_ptr);
+ CPU A: spin_unlock_irqrestore(&dev_lock, flags)
+ ...
+ CPU B: spin_lock_irqsave(&dev_lock, flags)
+ CPU B: val = readl(my_status);
+ CPU B: ...
+ CPU B: writel(newval2, ring_ptr);
+ CPU B: spin_unlock_irqrestore(&dev_lock, flags)
+ ...
+
+上述例子中,设备可能会先接收到newval2的值,然后接收到newval的值,问题就
+发生了。不过很容易通过下面方法来修复::
+
+ ...
+ CPU A: spin_lock_irqsave(&dev_lock, flags)
+ CPU A: val = readl(my_status);
+ CPU A: ...
+ CPU A: writel(newval, ring_ptr);
+ CPU A: (void)readl(safe_register); /* 配置寄存器?*/
+ CPU A: spin_unlock_irqrestore(&dev_lock, flags)
+ ...
+ CPU B: spin_lock_irqsave(&dev_lock, flags)
+ CPU B: val = readl(my_status);
+ CPU B: ...
+ CPU B: writel(newval2, ring_ptr);
+ CPU B: (void)readl(safe_register); /* 配置寄存器?*/
+ CPU B: spin_unlock_irqrestore(&dev_lock, flags)
+
+在解决方案中,读取safe_register寄存器,触发IO芯片清刷未处理的写操作,
+再处理后面的读操作,防止引发数据不一致问题。
diff --git a/Documentation/translations/zh_CN/filesystems/debugfs.rst b/Documentation/translations/zh_CN/filesystems/debugfs.rst
new file mode 100644
index 000000000000..4981a82dd651
--- /dev/null
+++ b/Documentation/translations/zh_CN/filesystems/debugfs.rst
@@ -0,0 +1,221 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/filesystems/debugfs.rst
+
+=======
+Debugfs
+=======
+
+译者
+::
+
+ 中文版维护者: 罗楚成 Chucheng Luo <luochucheng@vivo.com>
+ 中文版翻译者: 罗楚成 Chucheng Luo <luochucheng@vivo.com>
+ 中文版校译者: 罗楚成 Chucheng Luo <luochucheng@vivo.com>
+
+
+
+版权所有2020 罗楚成 <luochucheng@vivo.com>
+
+
+Debugfs是内核开发人员在用户空间获取信息的简单方法。与/proc不同,proc只提供进程
+信息。也不像sysfs,具有严格的“每个文件一个值“的规则。debugfs根本没有规则,开发
+人员可以在这里放置他们想要的任何信息。debugfs文件系统也不能用作稳定的ABI接口。
+从理论上讲,debugfs导出文件的时候没有任何约束。但是[1]实际情况并不总是那么
+简单。即使是debugfs接口,也最好根据需要进行设计,并尽量保持接口不变。
+
+
+Debugfs通常使用以下命令安装::
+
+ mount -t debugfs none /sys/kernel/debug
+
+(或等效的/etc/fstab行)。
+debugfs根目录默认仅可由root用户访问。要更改对文件树的访问,请使用“ uid”,“ gid”
+和“ mode”挂载选项。请注意,debugfs API仅按照GPL协议导出到模块。
+
+使用debugfs的代码应包含<linux/debugfs.h>。然后,首先是创建至少一个目录来保存
+一组debugfs文件::
+
+ struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
+
+如果成功,此调用将在指定的父目录下创建一个名为name的目录。如果parent参数为空,
+则会在debugfs根目录中创建。创建目录成功时,返回值是一个指向dentry结构体的指针。
+该dentry结构体的指针可用于在目录中创建文件(以及最后将其清理干净)。ERR_PTR
+(-ERROR)返回值表明出错。如果返回ERR_PTR(-ENODEV),则表明内核是在没有debugfs
+支持的情况下构建的,并且下述函数都不会起作用。
+
+在debugfs目录中创建文件的最通用方法是::
+
+ struct dentry *debugfs_create_file(const char *name, umode_t mode,
+ struct dentry *parent, void *data,
+ const struct file_operations *fops);
+
+在这里,name是要创建的文件的名称,mode描述了访问文件应具有的权限,parent指向
+应该保存文件的目录,data将存储在产生的inode结构体的i_private字段中,而fops是
+一组文件操作函数,这些函数中实现文件操作的具体行为。至少,read()和/或
+write()操作应提供;其他可以根据需要包括在内。同样的,返回值将是指向创建文件
+的dentry指针,错误时返回ERR_PTR(-ERROR),系统不支持debugfs时返回值为ERR_PTR
+(-ENODEV)。创建一个初始大小的文件,可以使用以下函数代替::
+
+ 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);
+
+file_size是初始文件大小。其他参数跟函数debugfs_create_file的相同。
+
+在许多情况下,没必要自己去创建一组文件操作;对于一些简单的情况,debugfs代码提供
+了许多帮助函数。包含单个整数值的文件可以使用以下任何一项创建::
+
+ void debugfs_create_u8(const char *name, umode_t mode,
+ struct dentry *parent, u8 *value);
+ void 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);
+ void debugfs_create_u64(const char *name, umode_t mode,
+ struct dentry *parent, u64 *value);
+
+这些文件支持读取和写入给定值。如果某个文件不支持写入,只需根据需要设置mode
+参数位。这些文件中的值以十进制表示;如果需要使用十六进制,可以使用以下函数
+替代::
+
+ void debugfs_create_x8(const char *name, umode_t mode,
+ struct dentry *parent, u8 *value);
+ void debugfs_create_x16(const char *name, umode_t mode,
+ struct dentry *parent, u16 *value);
+ void debugfs_create_x32(const char *name, umode_t mode,
+ struct dentry *parent, u32 *value);
+ void debugfs_create_x64(const char *name, umode_t mode,
+ struct dentry *parent, u64 *value);
+
+这些功能只有在开发人员知道导出值的大小的时候才有用。某些数据类型在不同的架构上
+有不同的宽度,这样会使情况变得有些复杂。在这种特殊情况下可以使用以下函数::
+
+ void debugfs_create_size_t(const char *name, umode_t mode,
+ struct dentry *parent, size_t *value);
+
+不出所料,此函数将创建一个debugfs文件来表示类型为size_t的变量。
+
+同样地,也有导出无符号长整型变量的函数,分别以十进制和十六进制表示如下::
+
+ struct dentry *debugfs_create_ulong(const char *name, umode_t mode,
+ struct dentry *parent,
+ unsigned long *value);
+ void debugfs_create_xul(const char *name, umode_t mode,
+ struct dentry *parent, unsigned long *value);
+
+布尔值可以通过以下方式放置在debugfs中::
+
+ struct dentry *debugfs_create_bool(const char *name, umode_t mode,
+ struct dentry *parent, bool *value);
+
+
+读取结果文件将产生Y(对于非零值)或N,后跟换行符写入的时候,它只接受大写或小写
+值或1或0。任何其他输入将被忽略。
+
+同样,atomic_t类型的值也可以放置在debugfs中::
+
+ void debugfs_create_atomic_t(const char *name, umode_t mode,
+ struct dentry *parent, atomic_t *value)
+
+读取此文件将获得atomic_t值,写入此文件将设置atomic_t值。
+
+另一个选择是通过以下结构体和函数导出一个任意二进制数据块::
+
+ struct debugfs_blob_wrapper {
+ void *data;
+ unsigned long size;
+ };
+
+ struct dentry *debugfs_create_blob(const char *name, umode_t mode,
+ struct dentry *parent,
+ struct debugfs_blob_wrapper *blob);
+
+读取此文件将返回由指针指向debugfs_blob_wrapper结构体的数据。一些驱动使用“blobs”
+作为一种返回几行(静态)格式化文本的简单方法。这个函数可用于导出二进制信息,但
+似乎在主线中没有任何代码这样做。请注意,使用debugfs_create_blob()命令创建的
+所有文件是只读的。
+
+如果您要转储一个寄存器块(在开发过程中经常会这么做,但是这样的调试代码很少上传
+到主线中。Debugfs提供两个函数:一个用于创建仅寄存器文件,另一个把一个寄存器块
+插入一个顺序文件中::
+
+ struct debugfs_reg32 {
+ char *name;
+ unsigned long offset;
+ };
+
+ struct debugfs_regset32 {
+ struct debugfs_reg32 *regs;
+ int nregs;
+ void __iomem *base;
+ };
+
+ 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, struct debugfs_reg32 *regs,
+ int nregs, void __iomem *base, char *prefix);
+
+“base”参数可能为0,但您可能需要使用__stringify构建reg32数组,实际上有许多寄存器
+名称(宏)是寄存器块在基址上的字节偏移量。
+
+如果要在debugfs中转储u32数组,可以使用以下函数创建文件::
+
+ void debugfs_create_u32_array(const char *name, umode_t mode,
+ struct dentry *parent,
+ u32 *array, u32 elements);
+
+“array”参数提供数据,而“elements”参数为数组中元素的数量。注意:数组创建后,数组
+大小无法更改。
+
+有一个函数来创建与设备相关的seq_file::
+
+ struct dentry *debugfs_create_devm_seqfile(struct device *dev,
+ const char *name,
+ struct dentry *parent,
+ int (*read_fn)(struct seq_file *s,
+ void *data));
+
+“dev”参数是与此debugfs文件相关的设备,并且“read_fn”是一个函数指针,这个函数在
+打印seq_file内容的时候被回调。
+
+还有一些其他的面向目录的函数::
+
+ struct dentry *debugfs_rename(struct dentry *old_dir,
+ struct dentry *old_dentry,
+ struct dentry *new_dir,
+ const char *new_name);
+
+ struct dentry *debugfs_create_symlink(const char *name,
+ struct dentry *parent,
+ const char *target);
+
+调用debugfs_rename()将为现有的debugfs文件重命名,可能同时切换目录。 new_name
+函数调用之前不能存在;返回值为old_dentry,其中包含更新的信息。可以使用
+debugfs_create_symlink()创建符号链接。
+
+所有debugfs用户必须考虑的一件事是:
+
+debugfs不会自动清除在其中创建的任何目录。如果一个模块在不显式删除debugfs目录的
+情况下卸载模块,结果将会遗留很多野指针,从而导致系统不稳定。因此,所有debugfs
+用户-至少是那些可以作为模块构建的用户-必须做模块卸载的时候准备删除在此创建的
+所有文件和目录。一份文件可以通过以下方式删除::
+
+ void debugfs_remove(struct dentry *dentry);
+
+dentry值可以为NULL或错误值,在这种情况下,不会有任何文件被删除。
+
+很久以前,内核开发者使用debugfs时需要记录他们创建的每个dentry指针,以便最后所有
+文件都可以被清理掉。但是,现在debugfs用户能调用以下函数递归清除之前创建的文件::
+
+ void debugfs_remove_recursive(struct dentry *dentry);
+
+如果将对应顶层目录的dentry传递给以上函数,则该目录下的整个层次结构将会被删除。
+
+注释:
+[1] http://lwn.net/Articles/309298/
diff --git a/Documentation/translations/zh_CN/filesystems/index.rst b/Documentation/translations/zh_CN/filesystems/index.rst
new file mode 100644
index 000000000000..9f2a8b003778
--- /dev/null
+++ b/Documentation/translations/zh_CN/filesystems/index.rst
@@ -0,0 +1,29 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: :ref:`Documentation/filesystems/index.rst <filesystems_index>`
+:Translator: Wang Wenhu <wenhu.wang@vivo.com>
+
+.. _cn_filesystems_index:
+
+========================
+Linux Kernel中的文件系统
+========================
+
+这份正在开发的手册或许在未来某个辉煌的日子里以易懂的形式将Linux虚拟\
+文件系统(VFS)层以及基于其上的各种文件系统如何工作呈现给大家。当前\
+可以看到下面的内容。
+
+文件系统
+========
+
+文件系统实现文档。
+
+.. toctree::
+ :maxdepth: 2
+
+ virtiofs
+ debugfs
+ tmpfs
+
diff --git a/Documentation/translations/zh_CN/filesystems/sysfs.txt b/Documentation/translations/zh_CN/filesystems/sysfs.txt
index ee1f37da5b23..547062759e60 100644
--- a/Documentation/translations/zh_CN/filesystems/sysfs.txt
+++ b/Documentation/translations/zh_CN/filesystems/sysfs.txt
@@ -1,4 +1,4 @@
-Chinese translated version of Documentation/filesystems/sysfs.txt
+Chinese translated version of Documentation/filesystems/sysfs.rst
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
@@ -10,7 +10,7 @@ Maintainer: Patrick Mochel <mochel@osdl.org>
Mike Murphy <mamurph@cs.clemson.edu>
Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
---------------------------------------------------------------------
-Documentation/filesystems/sysfs.txt 的中文翻译
+Documentation/filesystems/sysfs.rst 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
@@ -40,7 +40,7 @@ sysfs 是一个最初基于 ramfs 且位于内存的文件系统。它提供导
数据结构及其属性,以及它们之间的关联到用户空间的方法。
sysfs 始终与 kobject 的底层结构紧密相关。请阅读
-Documentation/kobject.txt 文档以获得更多关于 kobject 接口的
+Documentation/core-api/kobject.rst 文档以获得更多关于 kobject 接口的
信息。
@@ -154,14 +154,13 @@ sysfs 会为这个类型调用适当的方法。当一个文件被读写时,
示例:
-#define to_dev(obj) container_of(obj, struct device, kobj)
#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 = to_dev(kobj);
+ struct device *dev = kobj_to_dev(kobj);
ssize_t ret = -EIO;
if (dev_attr->show)
@@ -213,10 +212,12 @@ Sysfs 将会为每次读写操作调用一次这个方法。这使得这些方
- 缓冲区应总是 PAGE_SIZE 大小。对于i386,这个值为4096。
-- show() 方法应该返回写入缓冲区的字节数,也就是 snprintf()的
+- show() 方法应该返回写入缓冲区的字节数,也就是 scnprintf()的
返回值。
-- show() 应始终使用 snprintf()。
+- show() 方法在将格式化返回值返回用户空间的时候,禁止使用snprintf()。
+ 如果可以保证不会发生缓冲区溢出,可以使用sprintf(),否则必须使用
+ scnprintf()。
- store() 应返回缓冲区的已用字节数。如果整个缓存都已填满,只需返回
count 参数。
@@ -281,7 +282,7 @@ drivers/ 包含了每个已为特定总线上的设备而挂载的驱动程序
假定驱动没有跨越多个总线类型)。
fs/ 包含了一个为文件系统设立的目录。现在每个想要导出属性的文件系统必须
-在 fs/ 下创建自己的层次结构(参见Documentation/filesystems/fuse.txt)。
+在 fs/ 下创建自己的层次结构(参见Documentation/filesystems/fuse.rst)。
dev/ 包含两个子目录: char/ 和 block/。在这两个子目录中,有以
<major>:<minor> 格式命名的符号链接。这些符号链接指向 sysfs 目录
@@ -328,8 +329,8 @@ void device_remove_file(struct device *dev, const struct device_attribute * attr
struct bus_attribute {
struct attribute attr;
- ssize_t (*show)(struct bus_type *, char * buf);
- ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
+ ssize_t (*show)(const struct bus_type *, char * buf);
+ ssize_t (*store)(const struct bus_type *, const char * buf, size_t count);
};
声明:
diff --git a/Documentation/translations/zh_CN/filesystems/tmpfs.rst b/Documentation/translations/zh_CN/filesystems/tmpfs.rst
new file mode 100644
index 000000000000..6fd9d83b2db5
--- /dev/null
+++ b/Documentation/translations/zh_CN/filesystems/tmpfs.rst
@@ -0,0 +1,146 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/filesystems/tmpfs.rst
+
+translated by Wang Qing<wangqing@vivo.com>
+
+=====
+Tmpfs
+=====
+
+Tmpfs是一个将所有文件都保存在虚拟内存中的文件系统。
+
+tmpfs中的所有内容都是临时的,也就是说没有任何文件会在硬盘上创建。
+如果卸载tmpfs实例,所有保存在其中的文件都会丢失。
+
+tmpfs将所有文件保存在内核缓存中,随着文件内容增长或缩小可以将不需要的
+页面swap出去。它具有最大限制,可以通过“mount -o remount ...”调整。
+
+和ramfs(创建tmpfs的模板)相比,tmpfs包含交换和限制检查。和tmpfs相似的另
+一个东西是RAM磁盘(/dev/ram*),可以在物理RAM中模拟固定大小的硬盘,并在
+此之上创建一个普通的文件系统。Ramdisks无法swap,因此无法调整它们的大小。
+
+由于tmpfs完全保存于页面缓存和swap中,因此所有tmpfs页面将在/proc/meminfo
+中显示为“Shmem”,而在free(1)中显示为“Shared”。请注意,这些计数还包括
+共享内存(shmem,请参阅ipcs(1))。获得计数的最可靠方法是使用df(1)和du(1)。
+
+tmpfs具有以下用途:
+
+1) 内核总有一个无法看到的内部挂载,用于共享匿名映射和SYSV共享内存。
+
+ 挂载不依赖于CONFIG_TMPFS。如果CONFIG_TMPFS未设置,tmpfs对用户不可见。
+ 但是内部机制始终存在。
+
+2) glibc 2.2及更高版本期望将tmpfs挂载在/dev/shm上以用于POSIX共享内存
+ (shm_open,shm_unlink)。添加内容到/etc/fstab应注意如下:
+
+ tmpfs /dev/shm tmpfs defaults 0 0
+
+ 使用时需要记住创建挂载tmpfs的目录。
+
+ SYSV共享内存无需挂载,内部已默认支持。(在2.3内核版本中,必须挂载
+ tmpfs的前身(shm fs)才能使用SYSV共享内存)
+
+3) 很多人(包括我)都觉的在/tmp和/var/tmp上挂载非常方便,并具有较大的
+ swap分区。目前循环挂载tmpfs可以正常工作,所以大多数发布都应当可以
+ 使用mkinitrd通过/tmp访问/tmp。
+
+4) 也许还有更多我不知道的地方:-)
+
+
+tmpfs有三个用于调整大小的挂载选项:
+
+========= ===========================================================
+size tmpfs实例分配的字节数限制。默认值是不swap时物理RAM的一半。
+ 如果tmpfs实例过大,机器将死锁,因为OOM处理将无法释放该内存。
+nr_blocks 与size相同,但以PAGE_SIZE为单位。
+nr_inodes tmpfs实例的最大inode个数。默认值是物理内存页数的一半,或者
+ (有高端内存的机器)低端内存RAM的页数,二者以较低者为准。
+========= ===========================================================
+
+这些参数接受后缀k,m或g表示千,兆和千兆字节,可以在remount时更改。
+size参数也接受后缀%用来限制tmpfs实例占用物理RAM的百分比:
+未指定size或nr_blocks时,默认值为size=50%
+
+如果nr_blocks=0(或size=0),block个数将不受限制;如果nr_inodes=0,
+inode个数将不受限制。这样挂载通常是不明智的,因为它允许任何具有写权限的
+用户通过访问tmpfs耗尽机器上的所有内存;但同时这样做也会增强在多个CPU的
+场景下的访问。
+
+tmpfs具有为所有文件设置NUMA内存分配策略挂载选项(如果启用了CONFIG_NUMA),
+可以通过“mount -o remount ...”调整
+
+======================== =========================
+mpol=default 采用进程分配策略
+ (请参阅 set_mempolicy(2))
+mpol=prefer:Node 倾向从给定的节点分配
+mpol=bind:NodeList 只允许从指定的链表分配
+mpol=interleave 倾向于依次从每个节点分配
+mpol=interleave:NodeList 依次从每个节点分配
+mpol=local 优先本地节点分配内存
+======================== =========================
+
+NodeList格式是以逗号分隔的十进制数字表示大小和范围,最大和最小范围是用-
+分隔符的十进制数来表示。例如,mpol=bind0-3,5,7,9-15
+
+带有有效NodeList的内存策略将按指定格式保存,在创建文件时使用。当任务在该
+文件系统上创建文件时,会使用到挂载时的内存策略NodeList选项,如果设置的话,
+由调用任务的cpuset[请参见Documentation/admin-guide/cgroup-v1/cpusets.rst]
+以及下面列出的可选标志约束。如果NodeLists为设置为空集,则文件的内存策略将
+恢复为“默认”策略。
+
+NUMA内存分配策略有可选标志,可以用于模式结合。在挂载tmpfs时指定这些可选
+标志可以在NodeList之前生效。
+Documentation/admin-guide/mm/numa_memory_policy.rst列出所有可用的内存
+分配策略模式标志及其对内存策略。
+
+::
+
+ =static 相当于 MPOL_F_STATIC_NODES
+ =relative 相当于 MPOL_F_RELATIVE_NODES
+
+例如,mpol=bind=staticNodeList相当于MPOL_BIND|MPOL_F_STATIC_NODES的分配策略
+
+请注意,如果内核不支持NUMA,那么使用mpol选项挂载tmpfs将会失败;nodelist指定不
+在线的节点也会失败。如果您的系统依赖于此,但内核会运行不带NUMA功能(也许是安全
+revocery内核),或者具有较少的节点在线,建议从自动模式中省略mpol选项挂载选项。
+可以在以后通过“mount -o remount,mpol=Policy:NodeList MountPoint”添加到挂载点。
+
+要指定初始根目录,可以使用如下挂载选项:
+
+==== ====================
+模式 权限用八进制数字表示
+uid 用户ID
+gid 组ID
+==== ====================
+
+这些选项对remount没有任何影响。您可以通过chmod(1),chown(1)和chgrp(1)的更改
+已经挂载的参数。
+
+tmpfs具有选择32位还是64位inode的挂载选项:
+
+======= =============
+inode64 使用64位inode
+inode32 使用32位inode
+======= =============
+
+在32位内核上,默认是inode32,挂载时指定inode64会被拒绝。
+在64位内核上,默认配置是CONFIG_TMPFS_INODE64。inode64避免了单个设备上可能有多个
+具有相同inode编号的文件;比如32位应用程序使用glibc如果长期访问tmpfs,一旦达到33
+位inode编号,就有EOVERFLOW失败的危险,无法打开大于2GiB的文件,并返回EINVAL。
+
+所以'mount -t tmpfs -o size=10G,nr_inodes=10k,mode=700 tmpfs /mytmpfs'将在
+/mytmpfs上挂载tmpfs实例,分配只能由root用户访问的10GB RAM/SWAP,可以有10240个
+inode的实例。
+
+
+:作者:
+ Christoph Rohland <cr@sap.com>, 1.12.01
+:更新:
+ Hugh Dickins, 4 June 2007
+:更新:
+ KOSAKI Motohiro, 16 Mar 2010
+:更新:
+ Chris Down, 13 July 2020
diff --git a/Documentation/translations/zh_CN/filesystems/virtiofs.rst b/Documentation/translations/zh_CN/filesystems/virtiofs.rst
new file mode 100644
index 000000000000..09bc9e012e2a
--- /dev/null
+++ b/Documentation/translations/zh_CN/filesystems/virtiofs.rst
@@ -0,0 +1,58 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: :ref:`Documentation/filesystems/virtiofs.rst <virtiofs_index>`
+
+译者
+::
+
+ 中文版维护者: 王文虎 Wang Wenhu <wenhu.wang@vivo.com>
+ 中文版翻译者: 王文虎 Wang Wenhu <wenhu.wang@vivo.com>
+ 中文版校译者: 王文虎 Wang Wenhu <wenhu.wang@vivo.com>
+
+===========================================
+virtiofs: virtio-fs 主机<->客机共享文件系统
+===========================================
+
+- Copyright (C) 2020 Vivo Communication Technology Co. Ltd.
+
+介绍
+====
+Linux的virtiofs文件系统实现了一个半虚拟化VIRTIO类型“virtio-fs”设备的驱动,通过该\
+类型设备实现客机<->主机文件系统共享。它允许客机挂载一个已经导出到主机的目录。
+
+客机通常需要访问主机或者远程系统上的文件。使用场景包括:在新客机安装时让文件对其\
+可见;从主机上的根文件系统启动;对无状态或临时客机提供持久存储和在客机之间共享目录。
+
+尽管在某些任务可能通过使用已有的网络文件系统完成,但是却需要非常难以自动化的配置\
+步骤,且将存储网络暴露给客机。而virtio-fs设备通过提供不经过网络的文件系统访问文件\
+的设计方式解决了这些问题。
+
+另外,virto-fs设备发挥了主客机共存的优点提高了性能,并且提供了网络文件系统所不具备
+的一些语义功能。
+
+用法
+====
+以``myfs``标签将文件系统挂载到``/mnt``:
+
+.. code-block:: sh
+
+ guest# mount -t virtiofs myfs /mnt
+
+请查阅 https://virtio-fs.gitlab.io/ 了解配置QEMU和virtiofsd守护程序的详细信息。
+
+内幕
+====
+由于virtio-fs设备将FUSE协议用于文件系统请求,因此Linux的virtiofs文件系统与FUSE文\
+件系统客户端紧密集成在一起。客机充当FUSE客户端而主机充当FUSE服务器,内核与用户空\
+间之间的/dev/fuse接口由virtio-fs设备接口代替。
+
+FUSE请求被置于虚拟队列中由主机处理。主机填充缓冲区中的响应部分,而客机处理请求的完成部分。
+
+将/dev/fuse映射到虚拟队列需要解决/dev/fuse和虚拟队列之间语义上的差异。每次读取\
+/dev/fuse设备时,FUSE客户端都可以选择要传输的请求,从而可以使某些请求优先于其他\
+请求。虚拟队列有其队列语义,无法更改已入队请求的顺序。在虚拟队列已满的情况下尤
+其关键,因为此时不可能加入高优先级的请求。为了解决此差异,virtio-fs设备采用“hiprio”\
+(高优先级)虚拟队列,专门用于有别于普通请求的高优先级请求。
+
diff --git a/Documentation/translations/zh_CN/glossary.rst b/Documentation/translations/zh_CN/glossary.rst
new file mode 100644
index 000000000000..24f094df97cd
--- /dev/null
+++ b/Documentation/translations/zh_CN/glossary.rst
@@ -0,0 +1,36 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+术语表
+======
+
+这不是一个完善的术语表,我们只是将有争议的和陌生的翻译词汇记录于此,
+它的篇幅应该根据内核文档翻译的需求而增加。新词条最好随翻译补丁一起
+提交,且仅在以下情况下收录新词条:
+
+ - 在翻译过程中遇到陌生词汇,且尚无翻译先例的;
+ - 在审阅过程中,针对某词条出现了不同的翻译意见;
+ - 使用频率不高的词条和首字母缩写类型的词条;
+ - 已经存在且有歧义的词条翻译。
+
+
+* atomic: 原子的,一般指不可中断的极小的临界区操作。
+* DVFS: 动态电压频率升降。(Dynamic Voltage and Frequency Scaling)
+* EAS: 能耗感知调度。(Energy Aware Scheduling)
+* flush: 刷新,一般指对cache的冲洗操作。
+* fork: 创建, 通常指父进程创建子进程。
+* futex: 快速用户互斥锁。(fast user mutex)
+* guest halt polling: 客户机停机轮询机制。
+* HugePage: 巨页。
+* hypervisor: 虚拟机超级管理器。
+* memory barriers: 内存屏障。
+* MIPS: 每秒百万指令。(Millions of Instructions Per Second),注意与mips指令集区分开。
+* mutex: 互斥锁。
+* NUMA: 非统一内存访问。
+* OpenCAPI: 开放相干加速器处理器接口。(Open Coherent Accelerator Processor Interface)
+* OPP: 操作性能值。
+* overhead: 开销,一般指需要消耗的计算机资源。
+* PELT: 实体负载跟踪。(Per-Entity Load Tracking)
+* sched domain: 调度域。
+* semaphores: 信号量。
+* spinlock: 自旋锁。
+* watermark: 水位,一般指页表的消耗水平。
diff --git a/Documentation/translations/zh_CN/iio/ep93xx_adc.rst b/Documentation/translations/zh_CN/iio/ep93xx_adc.rst
new file mode 100644
index 000000000000..64f3f3508353
--- /dev/null
+++ b/Documentation/translations/zh_CN/iio/ep93xx_adc.rst
@@ -0,0 +1,48 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/iio/ep93xx_adc.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_iio_ep93xx_adc:
+
+==================================
+思睿逻辑 EP93xx 模拟数字转换器驱动
+==================================
+
+1. 概述
+=======
+
+该驱动同时适用于具有5通道模拟数字转换器的低端 (EP9301, Ep9302) 设备和10通道
+触摸屏/模拟数字转换器的高端设备(EP9307, EP9312, EP9315)。
+
+2. 通道编号
+===========
+
+EP9301和EP9302数据表定义了通道0..4的编号方案。虽然EP9307, EP9312和EP9315多
+了3个通道(一共8个),但是编号并没有定义。所以说最后三个通道是随机编号的。
+
+如果ep93xx_adc是IIO设备0,您将在以下位置找到条目
+/sys/bus/iio/devices/iio:device0/:
+
+ +-----------------+---------------+
+ | sysfs 入口 | ball/pin 名称 |
+ +=================+===============+
+ | in_voltage0_raw | YM |
+ +-----------------+---------------+
+ | in_voltage1_raw | SXP |
+ +-----------------+---------------+
+ | in_voltage2_raw | SXM |
+ +-----------------+---------------+
+ | in_voltage3_raw | SYP |
+ +-----------------+---------------+
+ | in_voltage4_raw | SYM |
+ +-----------------+---------------+
+ | in_voltage5_raw | XP |
+ +-----------------+---------------+
+ | in_voltage6_raw | XM |
+ +-----------------+---------------+
+ | in_voltage7_raw | YP |
+ +-----------------+---------------+
diff --git a/Documentation/translations/zh_CN/iio/iio_configfs.rst b/Documentation/translations/zh_CN/iio/iio_configfs.rst
new file mode 100644
index 000000000000..eccaf1c644b4
--- /dev/null
+++ b/Documentation/translations/zh_CN/iio/iio_configfs.rst
@@ -0,0 +1,106 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/iio/iio_configfs.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_iio_configfs:
+
+=====================
+工业 IIO configfs支持
+=====================
+
+1. 概述
+=======
+
+Configfs是一种内核对象的基于文件系统的管理系统,IIO使用一些可以通过
+configfs轻松配置的对象(例如:设备,触发器)。
+
+关于configfs是如何运行的,请查阅Documentation/filesystems/configfs.rst
+了解更多信息。
+
+2. 用法
+=======
+为了使configfs支持IIO,我们需要在编译时选中config的CONFIG_IIO_CONFIGFS
+选项。
+
+然后,挂载configfs文件系统(通常在 /config directory目录下)::
+
+ $ mkdir/config
+ $ mount -t configfs none/config
+
+此时,将创建所有默认IIO组,并可以在/ config / iio下对其进行访问。 下一章
+将介绍可用的IIO配置对象。
+
+3. 软件触发器
+=============
+
+IIO默认configfs组之一是“触发器”组。挂载configfs后可以自动访问它,并且可
+以在/config/iio/triggers下找到。
+
+IIO软件触发器为创建多种触发器类型提供了支持。通常在include/linux/iio
+/sw_trigger.h:中的接口下将新的触发器类型实现为单独的内核模块:
+::
+
+ /*
+ * drivers/iio/trigger/iio-trig-sample.c
+ * 一种新触发器类型的内核模块实例
+ */
+ #include <linux/iio/sw_trigger.h>
+
+
+ static struct iio_sw_trigger *iio_trig_sample_probe(const char *name)
+ {
+ /*
+ * 这将分配并注册一个IIO触发器以及其他触发器类型特性的初始化。
+ */
+ }
+
+ static int iio_trig_sample_remove(struct iio_sw_trigger *swt)
+ {
+ /*
+ * 这会废弃iio_trig_sample_probe中的操作
+ */
+ }
+
+ static const struct iio_sw_trigger_ops iio_trig_sample_ops = {
+ .probe = iio_trig_sample_probe,
+ .remove = iio_trig_sample_remove,
+ };
+
+ static struct iio_sw_trigger_type iio_trig_sample = {
+ .name = "trig-sample",
+ .owner = THIS_MODULE,
+ .ops = &iio_trig_sample_ops,
+ };
+
+ module_iio_sw_trigger_driver(iio_trig_sample);
+
+每种触发器类型在/config/iio/triggers下都有其自己的目录。加载iio-trig-sample
+模块将创建“trig-sample”触发器类型目录/config/iio/triggers/trig-sample.
+
+我们支持以下中断源(触发器类型)
+
+ * hrtimer,使用高分辨率定时器作为中断源
+
+3.1 Hrtimer触发器创建与销毁
+---------------------------
+
+加载iio-trig-hrtimer模块将注册hrtimer触发器类型,从而允许用户在
+/config/iio/triggers/hrtimer下创建hrtimer触发器。
+
+例如::
+
+ $ mkdir /config/iio/triggers/hrtimer/instance1
+ $ rmdir /config/iio/triggers/hrtimer/instance1
+
+每个触发器可以具有一个或多个独特的触发器类型的属性。
+
+3.2 "hrtimer" 触发器类型属性
+----------------------------
+
+"hrtimer”触发器类型没有来自/config dir的任何可配置属性。
+它确实引入了触发目录的sampling_frequency属性。
+该属性以Hz为单位设置轮询频率,精度为mHz。 \ No newline at end of file
diff --git a/Documentation/translations/zh_CN/iio/index.rst b/Documentation/translations/zh_CN/iio/index.rst
new file mode 100644
index 000000000000..32d69047b16a
--- /dev/null
+++ b/Documentation/translations/zh_CN/iio/index.rst
@@ -0,0 +1,22 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/iio/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_iio_index:
+
+========
+工业 I/O
+========
+
+.. toctree::
+ :maxdepth: 1
+
+ iio_configfs
+
+ ep93xx_adc
diff --git a/Documentation/translations/zh_CN/index.rst b/Documentation/translations/zh_CN/index.rst
index d3165535ec9e..6ccec9657cc6 100644
--- a/Documentation/translations/zh_CN/index.rst
+++ b/Documentation/translations/zh_CN/index.rst
@@ -1,21 +1,149 @@
+.. SPDX-License-Identifier: GPL-2.0
+
.. raw:: latex
\renewcommand\thesection*
\renewcommand\thesubsection*
+ \kerneldocCJKon
+ \kerneldocBeginSC{
+
+.. _linux_doc_zh:
中文翻译
========
-这些手册包含有关如何开发内核的整体信息。内核社区非常庞大,一年下来有数千名开发
-人员做出贡献。 与任何大型社区一样,知道如何完成任务将使得更改合并的过程变得更
-加容易。
+
+.. note::
+
+ **翻译计划:**
+ 内核中文文档欢迎任何翻译投稿,特别是关于内核用户和管理员指南部分。
+
+这是中文内核文档树的顶级目录。内核文档,就像内核本身一样,在很大程度上是一
+项正在进行的工作;当我们努力将许多分散的文件整合成一个连贯的整体时尤其如此。
+另外,随时欢迎您对内核文档进行改进;如果您想提供帮助,请加入vger.kernel.org
+上的linux-doc邮件列表。
+
+顺便说下,中文文档也需要遵守内核编码风格,风格中中文和英文的主要不同就是中文
+的字符标点占用两个英文字符宽度, 所以,当英文要求不要超过每行100个字符时,
+中文就不要超过50个字符。另外,也要注意'-','=' 等符号与相关标题的对齐。在将
+补丁提交到社区之前,一定要进行必要的 ``checkpatch.pl`` 检查和编译测试。
+
+与Linux 内核社区一起工作
+------------------------
+
+与内核开发社区进行协作并将工作推向上游的基本指南。
+
+.. toctree::
+ :maxdepth: 1
+
+ process/development-process
+ process/submitting-patches
+ 行为准则 <process/code-of-conduct>
+ maintainer/index
+ 完整开发流程文档 <process/index>
+
+内部API文档
+-----------
+
+开发人员使用的内核内部交互接口手册。
+
+.. toctree::
+ :maxdepth: 1
+
+ core-api/index
+ driver-api/index
+ subsystem-apis
+ 内核中的锁 <locking/index>
+
+开发工具和流程
+--------------
+
+为所有内核开发人员提供有用信息的各种其他手册。
+
+.. toctree::
+ :maxdepth: 1
+
+ process/license-rules
+ doc-guide/index
+ dev-tools/index
+ dev-tools/testing-overview
+ kernel-hacking/index
+ rust/index
+
+TODOList:
+
+* trace/index
+* fault-injection/index
+* livepatch/index
+
+面向用户的文档
+--------------
+
+下列手册针对
+希望内核在给定系统上以最佳方式工作的*用户*,
+和查找内核用户空间API信息的程序开发人员。
+
+.. toctree::
+ :maxdepth: 1
+
+ admin-guide/index
+ admin-guide/reporting-issues.rst
+ userspace-api/index
+
+TODOList:
+
+* 内核构建系统 <kbuild/index>
+* 用户空间工具 <tools/index>
+
+也可参考独立于内核文档的 `Linux 手册页 <https://www.kernel.org/doc/man-pages/>`_ 。
+
+固件相关文档
+------------
+
+下列文档描述了内核需要的平台固件相关信息。
+
+.. toctree::
+ :maxdepth: 2
+
+ devicetree/index
+
+TODOList:
+
+* firmware-guide/index
+
+体系结构文档
+------------
.. toctree::
:maxdepth: 2
- process/index
+ arch/index
+
+其他文档
+--------
-目录和表格
+有几份未分类的文档似乎不适合放在文档的其他部分,或者可能需要进行一些调整和/或
+转换为reStructureText格式,也有可能太旧。
+
+.. toctree::
+ :maxdepth: 2
+
+ staging/index
+
+术语表
+------
+
+.. toctree::
+ :maxdepth: 1
+
+ glossary
+
+
+索引和表格
----------
* :ref:`genindex`
+
+.. raw:: latex
+
+ }\kerneldocEndSC
diff --git a/Documentation/translations/zh_CN/infiniband/core_locking.rst b/Documentation/translations/zh_CN/infiniband/core_locking.rst
new file mode 100644
index 000000000000..42f08038d44b
--- /dev/null
+++ b/Documentation/translations/zh_CN/infiniband/core_locking.rst
@@ -0,0 +1,115 @@
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/infiniband/core_locking.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 王普宇 Puyu Wang <realpuyuwang@gmail.com>
+ 时奎亮 Alex Shi <alexs@kernel.org>
+
+.. _cn_infiniband_core_locking:
+
+==================
+infiniband中间层锁
+==================
+
+ 本指南试图明确infiniband中间层的锁假设。它描述了对位于中间层以下的低
+ 级驱动程序和使用中间层的上层协议的要求。
+
+睡眠和中断环境
+==============
+
+ 除了以下异常情况,ib_device结构体中所有方法的低级驱动实现都可以睡眠。
+ 这些异常情况是列表中的任意的方法:
+
+ - create_ah
+ - modify_ah
+ - query_ah
+ - destroy_ah
+ - post_send
+ - post_recv
+ - poll_cq
+ - req_notify_cq
+
+ 他们可能不可以睡眠,而且必须可以从任何上下文中调用。
+
+ 向上层协议使用者输出的相应函数:
+
+ - rdma_create_ah
+ - rdma_modify_ah
+ - rdma_query_ah
+ - rdma_destroy_ah
+ - ib_post_send
+ - ib_post_recv
+ - ib_req_notify_cq
+
+ 因此,在任何情况下都可以安全调用(它们)。
+
+ 此外,该函数
+
+ - ib_dispatch_event
+
+ 被底层驱动用来通过中间层调度异步事件的“A”,也可以从任何上下文中安全调
+ 用。
+
+可重入性
+--------
+
+ 由低级驱动程序导出的ib_device结构体中的所有方法必须是完全可重入的。
+ 即使使用同一对象的多个函数调用被同时运行,低级驱动程序也需要执行所有
+ 必要的同步以保持一致性。
+
+ IB中间层不执行任何函数调用的序列化。
+
+ 因为低级驱动程序是可重入的,所以不要求上层协议使用者任何顺序执行。然
+ 而,为了得到合理的结果,可能需要一些顺序。例如,一个使用者可以在多个
+ CPU上同时安全地调用ib_poll_cq()。然而,不同的ib_poll_cq()调用之间
+ 的工作完成信息的顺序没有被定义。
+
+回调
+----
+
+ 低级驱动程序不得直接从与ib_device方法调用相同的调用链中执行回调。例
+ 如,低级驱动程序不允许从post_send方法直接调用使用者的完成事件处理程
+ 序。相反,低级驱动程序应该推迟这个回调,例如,调度一个tasklet来执行
+ 这个回调。
+
+ 低层驱动负责确保同一CQ的多个完成事件处理程序不被同时调用。驱动程序必
+ 须保证一个给定的CQ的事件处理程序在同一时间只有一个在运行。换句话说,
+ 以下情况是不允许的::
+
+ CPU1 CPU2
+
+ low-level driver ->
+ consumer CQ event callback:
+ /* ... */
+ ib_req_notify_cq(cq, ...);
+ low-level driver ->
+ /* ... */ consumer CQ event callback:
+ /* ... */
+ return from CQ event handler
+
+ 完成事件和异步事件回调的运行环境没有被定义。 根据低级别的驱动程序,它可能是
+ 进程上下文、softirq上下文或中断上下文。上层协议使用者可能不会在回调中睡眠。
+
+热插拔
+------
+
+ 当一个低级驱动程序调用ib_register_device()时,它宣布一个设备已经
+ 准备好供使用者使用,所有的初始化必须在这个调用之前完成。设备必须保
+ 持可用,直到驱动对ib_unregister_device()的调用返回。
+
+ 低级驱动程序必须从进程上下文调用ib_register_device()和
+ ib_unregister_device()。如果使用者在这些调用中回调到驱动程序,它
+ 不能持有任何可能导致死锁的semaphores。
+
+ 一旦其结构体ib_client的add方法被调用,上层协议使用者就可以开始使用
+ 一个IB设备。使用者必须在从移除方法返回之前完成所有的清理工作并释放
+ 与设备相关的所有资源。
+
+ 使用者被允许在其添加和删除方法中睡眠。
diff --git a/Documentation/translations/zh_CN/infiniband/index.rst b/Documentation/translations/zh_CN/infiniband/index.rst
new file mode 100644
index 000000000000..5634cc48379f
--- /dev/null
+++ b/Documentation/translations/zh_CN/infiniband/index.rst
@@ -0,0 +1,40 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/infiniband/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 王普宇 Puyu Wang <realpuyuwang@gmail.com>
+ 时奎亮 Alex Shi <alexs@kernel.org>
+
+.. _cn_infiniband_index:
+
+==========
+infiniband
+==========
+
+.. toctree::
+ :maxdepth: 1
+
+ core_locking
+ ipoib
+ opa_vnic
+ sysfs
+ tag_matching
+ user_mad
+ user_verbs
+
+
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
diff --git a/Documentation/translations/zh_CN/infiniband/ipoib.rst b/Documentation/translations/zh_CN/infiniband/ipoib.rst
new file mode 100644
index 000000000000..56517ea5fe9d
--- /dev/null
+++ b/Documentation/translations/zh_CN/infiniband/ipoib.rst
@@ -0,0 +1,111 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/infiniband/ipoib.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 王普宇 Puyu Wang <realpuyuwang@gmail.com>
+ 时奎亮 Alex Shi <alexs@kernel.org>
+
+.. _cn_infiniband_ipoib:
+
+=========================
+infiniband上的IP(IPoIB)
+=========================
+
+ ib_ipoib驱动是IETF ipoib工作组发布的RFC 4391和4392所规定的
+ infiniband上IP协议的一个实现。它是一个“本地”实现,即把接口类型设置为
+ ARPHRD_INFINIBAND,硬件地址长度为20(早期的专有实现向内核伪装为以太网
+ 接口)。
+
+分区和P_Keys
+============
+
+ 当IPoIB驱动被加载时,它会使用索引为0的P_Key给每个端口创建一个接口。要用
+ 不同的P_Key创建一个接口,将所需的P_Key写入主接口的
+ /sys/class/net/<intf name>/create_child文件里面。比如说::
+
+ echo 0x8001 > /sys/class/net/ib0/create_child
+
+ 这将用P_Key 0x8001创建一个名为ib0.8001的接口。要删除一个子接口,使用
+ ``delete_child`` 文件::
+
+ echo 0x8001 > /sys/class/net/ib0/delete_child
+
+ 任何接口的P_Key都由“pkey”文件给出,而子接口的主接口在“parent”中。
+
+ 子接口的创建/删除也可以使用IPoIB的rtnl_link_ops来完成,使用两种
+ 方式创建的子接口的行为是一样的。
+
+数据报与连接模式
+================
+
+ IPoIB驱动支持两种操作模式:数据报和连接。模式是通过接口的
+ /sys/class/net/<intf name>/mode文件设置和读取的。
+
+ 在数据报模式下,使用IB UD(不可靠数据报)传输,因此接口MTU等于IB L2 MTU
+ 减去IPoIB封装头(4字节)。例如,在一个典型的具有2K MTU的IB结构中,IPoIB
+ MTU将是2048 - 4 = 2044字节。
+
+ 在连接模式下,使用IB RC(可靠的连接)传输。连接模式利用IB传输的连接特性,
+ 允许MTU达到最大的IP包大小64K,这减少了处理大型UDP数据包、TCP段等所需的
+ IP包数量,提高了大型信息的性能。
+
+ 在连接模式下,接口的UD QP仍被用于组播和与不支持连接模式的对等体的通信。
+ 在这种情况下,ICMP PMTU数据包的RX仿真被用来使网络堆栈对这些邻居使用较
+ 小的UD MTU。
+
+无状态卸载
+==========
+
+ 如果IB HW支持IPoIB无状态卸载,IPoIB会向网络堆栈广播TCP/IP校验和/或大量
+ 传送(LSO)负载转移能力。
+
+ 大量传送(LSO)负载转移也已实现,可以使用ethtool调用打开/关闭。目前,LRO
+ 只支持具有校验和卸载能力的设备。
+
+ 无状态卸载只在数据报模式下支持。
+
+中断管理
+========
+
+ 如果底层IB设备支持CQ事件管理,可以使用ethtool来设置中断缓解参数,从而减少
+ 处理中断产生的开销。IPoIB的主要代码路径不使用TX完成信号的事件,所以只支持
+ RX管理。
+
+调试信息
+========
+
+ 通过将CONFIG_INFINIBAND_IPOIB_DEBUG设置为“y”来编译IPoIB驱动,跟踪信
+ 息被编译到驱动中。通过将模块参数debug_level和mcast_debug_level设置为1来
+ 打开它们。这些参数可以在运行时通过/sys/module/ib_ipoib/的文件来控制。
+
+ CONFIG_INFINIBAND_IPOIB_DEBUG也启用debugfs虚拟文件系统中的文件。通过挂
+ 载这个文件系统,例如用::
+
+ mount -t debugfs none /sys/kernel/debug
+
+ 可以从/sys/kernel/debug/ipoib/ib0_mcg等文件中获得关于多播组的统计数据。
+
+ 这个选项对性能的影响可以忽略不计,所以在正常运行时,在debug_level设置为
+ 0的情况下启用这个选项是安全的。
+
+ CONFIG_INFINIBAND_IPOIB_DEBUG_DATA当data_debug_level设置为1时,可以
+ 在数据路径中启用更多的调试输出。 然而,即使禁用输出,启用这个配置选项也
+ 会影响性能,因为它在快速路径中增加了测试。
+
+引用
+====
+
+ 在InfiniBand上传输IP(IPoIB)(RFC 4391)。
+ http://ietf.org/rfc/rfc4391.txt
+
+ infiniband上的IP:上的IP架构(RFC 4392)。
+ http://ietf.org/rfc/rfc4392.txt
+
+ infiniband上的IP: 连接模式 (RFC 4755)
+ http://ietf.org/rfc/rfc4755.txt
diff --git a/Documentation/translations/zh_CN/infiniband/opa_vnic.rst b/Documentation/translations/zh_CN/infiniband/opa_vnic.rst
new file mode 100644
index 000000000000..12b147fbf792
--- /dev/null
+++ b/Documentation/translations/zh_CN/infiniband/opa_vnic.rst
@@ -0,0 +1,156 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/infiniband/opa_vnic.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 王普宇 Puyu Wang <realpuyuwang@gmail.com>
+ 时奎亮 Alex Shi <alexs@kernel.org>
+
+.. _cn_infiniband_opa_vnic:
+
+=============================================
+英特尔全路径(OPA)虚拟网络接口控制器(VNIC)
+=============================================
+
+英特尔全路径(OPA)虚拟网络接口控制器(VNIC)功能通过封装HFI节点之间的以
+太网数据包,支持Omni-Path结构上的以太网功能。
+
+体系结构
+========
+
+Omni-Path封装的以太网数据包的交换模式涉及Omni-Path结构拓扑上覆盖的一个或
+多个虚拟以太网交换机。Omni-Path结构上的HFI节点的一个子集被允许在特定的虚
+拟以太网交换机上交换封装的以太网数据包。虚拟以太网交换机是通过配置结构上的
+HFI节点实现的逻辑抽象,用于生成和处理报头。在最简单的配置中,整个结构的所有
+HFI节点通过一个虚拟以太网交换机交换封装的以太网数据包。一个虚拟以太网交换机,
+实际上是一个独立的以太网网络。该配置由以太网管理器(EM)执行,它是可信的结
+构管理器(FM)应用程序的一部分。HFI节点可以有多个VNIC,每个连接到不同的虚
+拟以太网交换机。下图介绍了两个虚拟以太网交换机与两个HFI节点的情况::
+
+ +-------------------+
+ | 子网/ |
+ | 以太网 |
+ | 管理 |
+ +-------------------+
+ / /
+ / /
+ / /
+ / /
+ +-----------------------------+ +------------------------------+
+ | 虚拟以太网切换 | | 虚拟以太网切换 |
+ | +---------+ +---------+ | | +---------+ +---------+ |
+ | | VPORT | | VPORT | | | | VPORT | | VPORT | |
+ +--+---------+----+---------+-+ +-+---------+----+---------+---+
+ | \ / |
+ | \ / |
+ | \/ |
+ | / \ |
+ | / \ |
+ +-----------+------------+ +-----------+------------+
+ | VNIC | VNIC | | VNIC | VNIC |
+ +-----------+------------+ +-----------+------------+
+ | HFI | | HFI |
+ +------------------------+ +------------------------+
+
+
+Omni-Path封装的以太网数据包格式如下所述。
+
+==================== ================================
+位 域
+==================== ================================
+Quad Word 0:
+0-19 SLID (低20位)
+20-30 长度 (以四字为单位)
+31 BECN 位
+32-51 DLID (低20位)
+52-56 SC (服务级别)
+57-59 RC (路由控制)
+60 FECN 位
+61-62 L2 (=10, 16B 格式)
+63 LT (=1, 链路传输头 Flit)
+
+Quad Word 1:
+0-7 L4 type (=0x78 ETHERNET)
+8-11 SLID[23:20]
+12-15 DLID[23:20]
+16-31 PKEY
+32-47 熵
+48-63 保留
+
+Quad Word 2:
+0-15 保留
+16-31 L4 头
+32-63 以太网数据包
+
+Quad Words 3 to N-1:
+0-63 以太网数据包 (pad拓展)
+
+Quad Word N (last):
+0-23 以太网数据包 (pad拓展)
+24-55 ICRC
+56-61 尾
+62-63 LT (=01, 链路传输尾 Flit)
+==================== ================================
+
+以太网数据包在传输端被填充,以确保VNIC OPA数据包是四字对齐的。“尾”字段
+包含填充的字节数。在接收端,“尾”字段被读取,在将数据包向上传递到网络堆
+栈之前,填充物被移除(与ICRC、尾和OPA头一起)。
+
+L4头字段包含VNIC端口所属的虚拟以太网交换机ID。在接收端,该字段用于将收
+到的VNIC数据包去多路复用到不同的VNIC端口。
+
+驱动设计
+========
+
+英特尔OPA VNIC的软件设计如下图所示。OPA VNIC功能有一个依赖于硬件的部分
+和一个独立于硬件的部分。
+
+对IB设备分配和释放RDMA netdev设备的支持已经被加入。RDMA netdev支持与
+网络堆栈的对接,从而创建标准的网络接口。OPA_VNIC是一个RDMA netdev设备
+类型。
+
+依赖于HW的VNIC功能是HFI1驱动的一部分。它实现了分配和释放OPA_VNIC RDMA
+netdev的动作。它涉及VNIC功能的HW资源分配/管理。它与网络堆栈接口并实现所
+需的net_device_ops功能。它在传输路径中期待Omni-Path封装的以太网数据包,
+并提供对它们的HW访问。在将数据包向上传递到网络堆栈之前,它把Omni-Path头
+从接收的数据包中剥离。它还实现了RDMA netdev控制操作。
+
+OPA VNIC模块实现了独立于硬件的VNIC功能。它由两部分组成。VNIC以太网管理
+代理(VEMA)作为一个IB客户端向IB核心注册,并与IB MAD栈接口。它与以太网
+管理器(EM)和VNIC netdev交换管理信息。VNIC netdev部分分配和释放OPA_VNIC
+RDMA netdev设备。它在需要时覆盖由依赖HW的VNIC驱动设置的net_device_ops函数,
+以适应任何控制操作。它还处理以太网数据包的封装,在传输路径中使用Omni-Path头。
+对于每个VNIC接口,封装所需的信息是由EM通过VEMA MAD接口配置的。它还通过调用
+RDMA netdev控制操作将任何控制信息传递给依赖于HW的驱动程序::
+
+ +-------------------+ +----------------------+
+ | | | Linux |
+ | IB MAD | | 网络 |
+ | | | 栈 |
+ +-------------------+ +----------------------+
+ | | |
+ | | |
+ +----------------------------+ |
+ | | |
+ | OPA VNIC 模块 | |
+ | (OPA VNIC RDMA Netdev | |
+ | & EMA 函数) | |
+ | | |
+ +----------------------------+ |
+ | |
+ | |
+ +------------------+ |
+ | IB 核心 | |
+ +------------------+ |
+ | |
+ | |
+ +--------------------------------------------+
+ | |
+ | HFI1 驱动和 VNIC 支持 |
+ | |
+ +--------------------------------------------+
diff --git a/Documentation/translations/zh_CN/infiniband/sysfs.rst b/Documentation/translations/zh_CN/infiniband/sysfs.rst
new file mode 100644
index 000000000000..e9a48b0b2ba6
--- /dev/null
+++ b/Documentation/translations/zh_CN/infiniband/sysfs.rst
@@ -0,0 +1,21 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/infiniband/sysfs.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 王普宇 Puyu Wang <realpuyuwang@gmail.com>
+ 时奎亮 Alex Shi <alexs@kernel.org>
+
+.. _cn_infiniband_sysfs:
+
+=========
+Sysfs文件
+=========
+
+sysfs接口已移至
+Documentation/ABI/stable/sysfs-class-infiniband.
diff --git a/Documentation/translations/zh_CN/infiniband/tag_matching.rst b/Documentation/translations/zh_CN/infiniband/tag_matching.rst
new file mode 100644
index 000000000000..19b99587b862
--- /dev/null
+++ b/Documentation/translations/zh_CN/infiniband/tag_matching.rst
@@ -0,0 +1,63 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/infiniband/tag_matching.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 王普宇 Puyu Wang <realpuyuwang@gmail.com>
+ 时奎亮 Alex Shi <alexs@kernel.org>
+
+.. _cn_infiniband_tag_matching:
+
+============
+标签匹配逻辑
+============
+
+MPI标准定义了一套规则,称为标签匹配,用于将源发送操作与目的接收匹配。以下参数必
+须与以下源和目的参数相匹配:
+
+* 沟通者
+* 用户标签--通配符(wild card)可由接收方指定
+* 来源等级--通配符可由接收方指定
+* 目的地等级 – wild
+
+排序规则要求,当一对以上的发送和接收消息信封可能匹配时,包括最早发布-发送和最早
+发布-接收的一对是必须用来满足匹配操作的一对。然而,这并不意味着标签是按照它们被
+创建的顺序消耗的,例如,如果早期的标签不能用来满足匹配规则,那么后来生成的标签
+可能被消耗。
+
+当消息从发送方发送到接收方时,通信库可能试图在相应的匹配接收被发布之后或之前处
+理该操作。如果匹配的接收被发布,这就是一个预期的消息,否则就被称为一个意外的消
+息。实现时经常为这两种不同的匹配实例使用不同的匹配方案。
+
+为了减少MPI库的内存占用,MPI实现通常使用两种不同的协议来实现这一目的:
+
+1. Eager协议--当发送方处理完发送时,完整的信息就会被发送。在send_cq中会收到
+一个完成发送的通知,通知缓冲区可以被重新使用。
+
+2. Rendezvous协议--发送方在第一次通知接收方时发送标签匹配头,也许还有一部分
+数据。当相应的缓冲区被发布时,响应者将使用头中的信息,直接向匹配的缓冲区发起
+RDMA读取操作。为了使缓冲区得到重用,需要收到一个fin消息。
+
+标签匹配的实现
+==============
+
+使用的匹配对象有两种类型,即发布的接收列表和意外消息列表。应用程序通过调用发布
+的接收列表中的MPI接收例程发布接收缓冲区,并使用MPI发送例程发布发送消息。发布的
+接收列表的头部可以由硬件来维护,而软件则要对这个列表进行跟踪。
+
+当发送开始并到达接收端时,如果没有为这个到达的消息预先发布接收,它将被传递给软
+件并被放在意外(unexpect)消息列表中。否则,将对该匹配进行处理,包括交会处理,
+如果合适的话,将数据传送到指定的接收缓冲区。这允许接收方MPI标签匹配与计算重叠。
+
+当一个接收信息被发布时,通信库将首先检查软件的意外信息列表,以寻找一个匹配的接
+收信息。如果找到一个匹配的,数据就会被送到用户缓冲区,使用一个软件控制的协议。
+UCX的实现根据数据大小,使用急切或交会协议。如果没有找到匹配,整个预置的接收列
+表由硬件维护,并且有空间在这个列表中增加一个预置的接收,这个接收被传递给硬件。
+软件要对这个列表进行跟踪,以帮助处理MPI取消操作。此外,由于硬件和软件在标签匹
+配操作方面预计不会紧密同步,这个影子列表被用来检测预先发布的接收被传递到硬件的
+情况,因为匹配的意外消息正在从硬件传递到软件。
diff --git a/Documentation/translations/zh_CN/infiniband/user_mad.rst b/Documentation/translations/zh_CN/infiniband/user_mad.rst
new file mode 100644
index 000000000000..d9ab2edfb559
--- /dev/null
+++ b/Documentation/translations/zh_CN/infiniband/user_mad.rst
@@ -0,0 +1,164 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/infiniband/user_mad.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 王普宇 Puyu Wang <realpuyuwang@gmail.com>
+ 时奎亮 Alex Shi <alexs@kernel.org>
+
+.. _cn_infiniband_user_mad:
+
+===============
+用户空间MAD访问
+===============
+
+设备文件
+========
+
+ 每个InfiniBand设备的每个端口都有一个“umad”设备和一个“issm”设备连接。
+ 例如,一个双端口的HCA将有两个umad设备和两个issm设备,而一个交换机将
+ 有每个类型的一个设备(对于交换机端口0)。
+
+创建MAD代理
+===========
+
+ 一个MAD代理可以通过填写一个结构体ib_user_mad_reg_req来创建,然后在
+ 适当的设备文件的文件描述符上调用IB_USER_MAD_REGISTER_AGENT ioctl。
+ 如果注册请求成功,结构体中会返回一个32位的ID。比如说::
+
+ struct ib_user_mad_reg_req req = { /* ... */ };
+ ret = ioctl(fd, IB_USER_MAD_REGISTER_AGENT, (char *) &req);
+ if (!ret)
+ my_agent = req.id;
+ else
+ perror("agent register");
+
+ 代理可以通过IB_USER_MAD_UNREGISTER_AGENT ioctl取消注册。另外,所有
+ 通过文件描述符注册的代理在描述符关闭时将被取消注册。
+
+ 2014
+ 现在提供了一个新的注册IOctl,允许在注册时提供额外的字段。这个注册
+ 调用的用户隐含了对pkey_index的使用(见下文)。现在提供了一个新的
+ 注册IOctl,允许在注册时提供额外的字段。这个注册调用的用户隐含了对
+ pkey_index的使用(见下文)。
+
+接收MADs
+========
+
+ 使用read()接收MAD。现在接收端支持RMPP。传给read()的缓冲区必须至少是
+ 一个struct ib_user_mad + 256字节。比如说:
+
+ 如果传递的缓冲区不足以容纳收到的MAD(RMPP),errno被设置为ENOSPC,需
+ 要的缓冲区长度被设置在mad.length中。
+
+ 正常MAD(非RMPP)的读取示例::
+
+ struct ib_user_mad *mad;
+ mad = malloc(sizeof *mad + 256);
+ ret = read(fd, mad, sizeof *mad + 256);
+ if (ret != sizeof mad + 256) {
+ perror("read");
+ free(mad);
+ }
+
+ RMPP读取示例::
+
+ struct ib_user_mad *mad;
+ mad = malloc(sizeof *mad + 256);
+ ret = read(fd, mad, sizeof *mad + 256);
+ if (ret == -ENOSPC)) {
+ length = mad.length;
+ free(mad);
+ mad = malloc(sizeof *mad + length);
+ ret = read(fd, mad, sizeof *mad + length);
+ }
+ if (ret < 0) {
+ perror("read");
+ free(mad);
+ }
+
+ 除了实际的MAD内容外,其他结构体ib_user_mad字段将被填入收到的MAD的信
+ 息。例如,远程LID将在mad.lid中。
+
+ 如果发送超时,将产生一个接收,mad.status设置为ETIMEDOUT。否则,当一个
+ MAD被成功接收后,mad.status将是0。
+
+ poll()/select()可以用来等待一个MAD可以被读取。
+
+ poll()/select()可以用来等待,直到可以读取一个MAD。
+
+发送MADs
+========
+
+ MADs是用write()发送的。发送的代理ID应该填入MAD的id字段,目的地LID应该
+ 填入lid字段,以此类推。发送端确实支持RMPP,所以可以发送任意长度的MAD。
+ 比如说::
+
+ struct ib_user_mad *mad;
+
+ mad = malloc(sizeof *mad + mad_length);
+
+ /* fill in mad->data */
+
+ mad->hdr.id = my_agent; /* req.id from agent registration */
+ mad->hdr.lid = my_dest; /* in network byte order... */
+ /* etc. */
+
+ ret = write(fd, &mad, sizeof *mad + mad_length);
+ if (ret != sizeof *mad + mad_length)
+ perror("write");
+
+交换IDs
+=======
+
+ umad设备的用户可以在发送的MAD中使用交换ID字段的低32位(也就是网络字节顺序中
+ 最小有效的一半字段)来匹配请求/响应对。上面的32位是保留给内核使用的,在发送
+ MAD之前会被改写。
+
+P_Key索引处理
+=============
+
+ 旧的ib_umad接口不允许为发送的MAD设置P_Key索引,也没有提供获取接收的MAD的
+ P_Key索引的方法。一个带有pkey_index成员的struct ib_user_mad_hdr的新布局已
+ 经被定义;然而,为了保持与旧的应用程序的二进制兼容性,除非在文件描述符被用于
+ 其他用途之前调用IB_USER_MAD_ENABLE_PKEY或IB_USER_MAD_REGISTER_AGENT2 ioctl
+ 之一,否则不会使用这种新布局。
+
+ 在2008年9月,IB_USER_MAD_ABI_VERSION将被增加到6,默认使用新的ib_user_mad_hdr
+ 结构布局,并且IB_USER_MAD_ENABLE_PKEY ioctl将被删除。
+
+设置IsSM功能位
+==============
+
+ 要为一个端口设置IsSM功能位,只需打开相应的issm设备文件。如果IsSM位已经被设置,那
+ 么打开调用将阻塞,直到该位被清除(或者如果O_NONBLOCK标志被传递给open(),则立即返
+ 回,errno设置为EAGAIN)。当issm文件被关闭时,IsSM位将被清除。在issm文件上不能进
+ 行任何读、写或其他操作。
+
+/dev文件
+========
+
+为了用 udev自动创建相应的字符设备文件,一个类似::
+
+ KERNEL=="umad*", NAME="infiniband/%k"
+ KERNEL=="issm*", NAME="infiniband/%k"
+
+ 的规则可以被使用。它将创建节点的名字::
+
+ /dev/infiniband/umad0
+ /dev/infiniband/issm0
+
+ 为第一个端口,以此类推。与这些设备相关的infiniband设备和端口可以从以下文件中确定::
+
+ /sys/class/infiniband_mad/umad0/ibdev
+ /sys/class/infiniband_mad/umad0/port
+
+ 和::
+
+ /sys/class/infiniband_mad/issm0/ibdev
+ /sys/class/infiniband_mad/issm0/port
diff --git a/Documentation/translations/zh_CN/infiniband/user_verbs.rst b/Documentation/translations/zh_CN/infiniband/user_verbs.rst
new file mode 100644
index 000000000000..970bc1a4e396
--- /dev/null
+++ b/Documentation/translations/zh_CN/infiniband/user_verbs.rst
@@ -0,0 +1,72 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/infiniband/user_verbs.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 王普宇 Puyu Wang <realpuyuwang@gmail.com>
+ 时奎亮 Alex Shi <alexs@kernel.org>
+
+.. _cn_infiniband_user_verbs:
+
+=================
+用户空间verbs访问
+=================
+
+ ib_uverbs模块,通过启用CONFIG_INFINIBAND_USER_VERBS构建,使用户空间
+ 通过“verbs”直接访问IB硬件,如InfiniBand架构规范第11章所述。
+
+ 要使用verbs,需要libibverbs库,可从https://github.com/linux-rdma/rdma-core。
+ libibverbs包含一个独立于设备的API,用于使用ib_uverbs接口。libibverbs
+ 还需要为你的InfiniBand硬件提供适当的独立于设备的内核和用户空间驱动。例如,
+ 要使用Mellanox HCA,你需要安装ib_mthca内核模块和libmthca用户空间驱动。
+
+用户-内核通信
+=============
+
+ 用户空间通过/dev/infiniband/uverbsN字符设备与内核进行慢速路径、资源管理
+ 操作的通信。快速路径操作通常是通过直接写入硬件寄存器mmap()到用户空间来完成
+ 的,没有系统调用或上下文切换到内核。
+
+ 命令是通过在这些设备文件上的write()s发送给内核的。ABI在
+ drivers/infiniband/include/ib_user_verbs.h中定义。需要内核响应的命令的结
+ 构包含一个64位字段,用来传递一个指向输出缓冲区的指针。状态作为write()系统调
+ 用的返回值被返回到用户空间。
+
+资源管理
+========
+
+ 由于所有IB资源的创建和销毁都是通过文件描述符传递的命令完成的,所以内核可以跟
+ 踪那些被附加到给定用户空间上下文的资源。ib_uverbs模块维护着idr表,用来在
+ 内核指针和不透明的用户空间句柄之间进行转换,这样内核指针就不会暴露给用户空间,
+ 而用户空间也无法欺骗内核去跟踪一个假的指针。
+
+ 这也允许内核在一个进程退出时进行清理,并防止一个进程触及另一个进程的资源。
+
+内存固定
+========
+
+ 直接的用户空间I/O要求与作为潜在I/O目标的内存区域保持在同一物理地址上。ib_uverbs
+ 模块通过get_user_pages()和put_page()调用来管理内存区域的固定和解除固定。它还核
+ 算进程的pinned_vm中被固定的内存量,并检查非特权进程是否超过其RLIMIT_MEMLOCK限制。
+
+ 被多次固定的页面在每次被固定时都会被计数,所以pinned_vm的值可能会高估一个进程所
+ 固定的页面数量。
+
+/dev文件
+========
+
+ 要想用udev自动创建适当的字符设备文件,可以采用如下规则::
+
+ KERNEL=="uverbs*", NAME="infiniband/%k"
+
+ 可以使用。 这将创建设备节点,名为::
+
+ /dev/infiniband/uverbs0
+
+ 等等。由于InfiniBand的用户空间verbs对于非特权进程来说应该是安全的,因此在udev规
+ 则中加入适当的MODE或GROUP可能是有用的。
diff --git a/Documentation/translations/zh_CN/io_ordering.txt b/Documentation/translations/zh_CN/io_ordering.txt
deleted file mode 100644
index 1f8127bdd415..000000000000
--- a/Documentation/translations/zh_CN/io_ordering.txt
+++ /dev/null
@@ -1,67 +0,0 @@
-Chinese translated version of Documentation/io_ordering.txt
-
-If you have any comment or update to the content, please contact the
-original document maintainer directly. However, if you have a problem
-communicating in English you can also ask the Chinese maintainer for
-help. Contact the Chinese maintainer if this translation is outdated
-or if there is a problem with the translation.
-
-Chinese maintainer: Lin Yongting <linyongting@gmail.com>
----------------------------------------------------------------------
-Documentation/io_ordering.txt 的中文翻译
-
-如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
-交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
-译存在问题,请联系中文版维护者。
-
-中文版维护者: 林永听 Lin Yongting <linyongting@gmail.com>
-中文版翻译者: 林永听 Lin Yongting <linyongting@gmail.com>
-中文版校译者: 林永听 Lin Yongting <linyongting@gmail.com>
-
-
-以下为正文
----------------------------------------------------------------------
-
-在某些平台上,所谓的内存映射I/O是弱顺序。在这些平台上,驱动开发者有责任
-保证I/O内存映射地址的写操作按程序图意的顺序达到设备。通常读取一个“安全”
-设备寄存器或桥寄存器,触发IO芯片清刷未处理的写操作到达设备后才处理读操作,
-而达到保证目的。驱动程序通常在spinlock保护的临界区退出之前使用这种技术。
-这也可以保证后面的写操作只在前面的写操作之后到达设备(这非常类似于内存
-屏障操作,mb(),不过仅适用于I/O)。
-
-假设一个设备驱动程的具体例子:
-
- ...
-CPU A: spin_lock_irqsave(&dev_lock, flags)
-CPU A: val = readl(my_status);
-CPU A: ...
-CPU A: writel(newval, ring_ptr);
-CPU A: spin_unlock_irqrestore(&dev_lock, flags)
- ...
-CPU B: spin_lock_irqsave(&dev_lock, flags)
-CPU B: val = readl(my_status);
-CPU B: ...
-CPU B: writel(newval2, ring_ptr);
-CPU B: spin_unlock_irqrestore(&dev_lock, flags)
- ...
-
-上述例子中,设备可能会先接收到newval2的值,然后接收到newval的值,问题就
-发生了。不过很容易通过下面方法来修复:
-
- ...
-CPU A: spin_lock_irqsave(&dev_lock, flags)
-CPU A: val = readl(my_status);
-CPU A: ...
-CPU A: writel(newval, ring_ptr);
-CPU A: (void)readl(safe_register); /* 配置寄存器?*/
-CPU A: spin_unlock_irqrestore(&dev_lock, flags)
- ...
-CPU B: spin_lock_irqsave(&dev_lock, flags)
-CPU B: val = readl(my_status);
-CPU B: ...
-CPU B: writel(newval2, ring_ptr);
-CPU B: (void)readl(safe_register); /* 配置寄存器?*/
-CPU B: spin_unlock_irqrestore(&dev_lock, flags)
-
-在解决方案中,读取safe_register寄存器,触发IO芯片清刷未处理的写操作,
-再处理后面的读操作,防止引发数据不一致问题。
diff --git a/Documentation/translations/zh_CN/kernel-hacking/hacking.rst b/Documentation/translations/zh_CN/kernel-hacking/hacking.rst
new file mode 100644
index 000000000000..9112949b993c
--- /dev/null
+++ b/Documentation/translations/zh_CN/kernel-hacking/hacking.rst
@@ -0,0 +1,707 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/kernel-hacking/hacking.rst
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+==============
+内核骇客指北
+==============
+
+:作者: Rusty Russell
+
+引言
+=====
+
+欢迎咱优雅的读者们来阅读Rusty的非常不靠谱的Linux内核骇客(Hacking)指南。本文
+描述了内核代码的常见例程和一般要求:其目标是引导有经验的C程序员入门Linux内核
+开发。我回避了实现细节:这是代码要做的,也忽略了很多有用的例程。
+
+在你读这篇文章之前,请理解我从来没有想过要写这篇文章,因为我的资历太低了;
+但我一直想读这样的文章,自己写是唯一的方法。我希望它能成长为一个最佳实践、
+通用起点和其他信息的汇编。
+
+玩家
+=======
+
+在任何时候,系统中的每个CPU都可以:
+
+- 与任何进程无关,服务于硬件中断;
+
+- 与任何进程无关,服务于软件中断(softirq)或子任务(tasklet);
+
+- 运行于内核空间中,与进程(用户上下文)相关联;
+
+- 在用户空间中运行进程。
+
+它们之间有优先级顺序。最下面的两个可以互相抢占,但上面为严格的层次结构:
+每个层级只能被上方的抢占。例如,当一个软中断在CPU上运行时,没有其他软中断
+会抢占它,但是硬件中断可以抢占它。不过,系统中的任何其他CPU都是独立执行的。
+
+我们将会看到许多方法,用户上下文可以阻止中断,从而成为真正的不可抢占。
+
+用户上下文
+------------
+
+用户上下文是指当您从系统调用或其他陷阱进入时:就像用户空间一样,您可以被更
+重要的任务和中断抢占。您可以通过调用 :c:func:`schedule()` 进行睡眠。
+
+.. note::
+
+ 在模块加载和卸载以及块设备层上的操作时,你始终处于用户上下文中。
+
+在用户上下文中,当前 ``current`` 指针(指示我们当前正在执行的任务)是有效的,
+且 :c:func:`in_interrupt()` ( ``include/linux/preempt.h`` )值为非(false)。
+
+.. warning::
+
+ 请注意,如果您禁用了抢占或软中断(见下文),:c:func:`in_interrupt()` 会
+ 返回假阳性。
+
+硬件中断(Hard IRQs)
+----------------------
+
+像定时器、网卡和键盘等都是可能在任意时刻产生中断的真实硬件。内核运行中断
+处理程序,为硬件提供服务。内核确保处理程序永远不会重入:如果相同的中断到达,
+它将被排队(或丢弃)。因为它会关闭中断,所以处理程序必须很快:通常它只是
+确认中断,标记一个“软件中断”以执行并退出。
+
+您可以通过 in_hardirq() 返回真来判断您处于硬件中断状态。
+
+.. warning::
+
+ 请注意,如果中断被禁用,这将返回假阳性(见下文)。
+
+软件中断上下文:软中断(Softirqs)与子任务(Tasklets)
+-------------------------------------------------------
+
+当系统调用即将返回用户空间或硬件中断处理程序退出时,任何标记为挂起(通常通
+过硬件中断)的“软件中断”将运行( ``kernel/softirq.c`` )。
+
+此处完成了许多真正的中断处理工作。在向SMP过渡的早期,只有“bottom halves下半
+部”(BHs)机制,无法利用多个CPU的优势。在从那些一团糟的旧电脑切换过来后不久,
+我们放弃了这个限制,转而使用“软中断”。
+
+``include/linux/interrupt.h`` 列出了不同的软中断。定时器软中断是一个非常重要
+的软中断( ``include/linux/timer.h`` ):您可以注册它以在给定时间后为您调用
+函数。
+
+软中断通常是一个很难处理的问题,因为同一个软中断将同时在多个CPU上运行。因此,
+子任务( ``include/linux/interrupt.h`` )更常用:它们是动态可注册的(意味着
+您可以拥有任意数量),并且它们还保证任何子任务都只能在一个CPU上运行,不同的
+子任务也可以同时运行。
+
+.. warning::
+
+ “tasklet”这个名字是误导性的:它们与“任务”无关。
+
+你可以使用 :c:func:`in_softirq()` 宏( ``include/linux/preempt.h`` )来确认
+是否处于软中断(或子任务)中。
+
+.. warning::
+
+ 注意,如果持有 :ref:`bottom half lock <local_bh_disable_zh>` 锁,这将返回
+ 假阳性。
+
+一些基本规则
+================
+
+缺少内存保护
+ 如果你损坏了内存,无论是在用户上下文还是中断上下文中,整个机器都会崩溃。
+ 你确定你不能在用户空间里做你想做的事吗?
+
+缺少浮点或MMX
+ FPU上下文不会被保存;即使在用户上下文中,FPU状态也可能与当前进程不一致:
+ 您会弄乱某些用户进程的FPU状态。如果真的要这样做,就必须显式地保存/恢复
+ 完整的FPU状态(并避免上下文切换)。这通常不是个好主意;请优先用定点算法。
+
+严格的堆栈限制
+ 对于大多数32位体系结构,根据配置选项的不同内核堆栈大约为3K到6K;对于大
+ 多数64位机器,内核堆栈大约为14K,并且经常与中断共享,因此你无法使用全部。
+ 应避免深度递归和栈上的巨型本地数组(用动态分配它们来代替)。
+
+Linux内核是可移植的
+ 就这样吧。您的代码应该是纯64位的,并且不依赖于字节序(endian)。您还应该
+ 尽量减少CPU特定的东西,例如内联汇编(inline assembly)应该被干净地封装和
+ 最小化以便于移植。一般来说,它应该局限于内核树中有体系结构依赖的部分。
+
+输入输出控制(ioctls):避免编写新的系统调用
+==============================================
+
+系统调用(system call)通常看起来像这样::
+
+ asmlinkage long sys_mycall(int arg)
+ {
+ return 0;
+ }
+
+
+首先,在大多数情况下,您无需创建新的系统调用。创建一个字符设备并为其实现适当
+的输入输出控制(ioctls)。这比系统调用灵活得多,不必写进每个体系结构的
+``include/asm/unistd.h`` 和 ``arch/kernel/entry.S`` 文件里,而且更容易被Linus
+接受。
+
+如果您的程序所做的只是读取或写入一些参数,请考虑实现 :c:func:`sysfs()` 接口。
+
+在输入输出控制中,您处于进程的用户上下文。出现错误时,返回一个负的错误参数
+(errno,请参阅 ``include/uapi/asm-generic/errno-base.h`` 、
+``include/uapi/asm-generic/errno.h`` 和 ``include/linux/errno.h`` ),否则返
+回0。
+
+在睡眠之后,您应该检查是否出现了信号:Unix/Linux处理信号的方法是暂时退出系统
+调用,并返回 ``-ERESTARTSYS`` 错误。系统调用入口代码将切换回用户上下文,处理
+信号处理程序,然后系统调用将重新启动(除非用户禁用了该功能)。因此,您应该准
+备好处理重新启动,例如若您处理某些数据结构到一半。
+
+::
+
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
+
+如果你要做更长时间的计算:优先考虑用户空间。如果你真的想在内核中做这件事,你
+应该定期检查你是否需要让出CPU(请记得每个CPU都有协作多任务)。
+习惯用法::
+
+ cond_resched(); /* Will sleep */
+
+
+接口设计的小注释:UNIX系统调用的格言是“提供机制而不是策略
+Provide mechanism not policy”。
+
+死锁的“配方”
+====================
+
+您不能调用任何可能睡眠的程序,除非:
+
+- 您处于用户上下文中。
+
+- 你未拥有任何自旋锁。
+
+- 您已经启用中断(实际上,Andi Kleen说调度代码将为您启用它们,但这可能不是
+ 您想要的)。
+
+注意,有些函数可能隐式地睡眠:常见的是用户空间访问函数(\*_user)和没有
+``GFP_ATOMIC`` 的内存分配函数。
+
+您应该始终打开 ``CONFIG_DEBUG_ATOMIC_SLEEP`` 项来编译内核,如果您违反这些
+规则,它将警告您。如果你 **真的** 违反了规则,你最终会锁住你的电脑。
+
+真的会这样。
+
+
+常用函数/程序
+===============
+
+:c:func:`printk()`
+------------------
+
+定义于 ``include/linux/printk.h``
+
+:c:func:`printk()` 将内核消息提供给控制台、dmesg和syslog守护进程。它对于调
+试和报告错误很有用,并且可以在中断上下文中使用,但是使用时要小心:如果机器
+的控制台中充斥着printk消息则会无法使用。它使用与ANSI C printf基本兼容的格式
+字符串,并通过C字符串串联为其提供第一个“优先”参数::
+
+ printk(KERN_INFO "i = %u\n", i);
+
+
+参见 ``include/linux/kern_levels.h`` ;了解其他 ``KERN_`` 值;syslog将这些值
+解释为级别。特殊用法:打印IP地址使用::
+
+ __be32 ipaddress;
+ printk(KERN_INFO "my ip: %pI4\n", &ipaddress);
+
+
+:c:func:`printk()` 内部使用的1K缓冲区,不捕获溢出。请确保足够使用。
+
+.. note::
+
+ 当您开始在用户程序中将printf打成printk时,就知道自己是真正的内核程序员了
+ :)
+
+.. note::
+
+ 另一个注释:最初的unix第六版源代码在其printf函数的顶部有一个注释:“printf
+ 不应该用于叽叽喳喳”。你也应该遵循此建议。
+
+:c:func:`copy_to_user()` / :c:func:`copy_from_user()` / :c:func:`get_user()` / :c:func:`put_user()`
+---------------------------------------------------------------------------------------------------
+
+定义于 ``include/linux/uaccess.h`` / ``asm/uaccess.h``
+
+**[睡眠]**
+
+:c:func:`put_user()` 和 :c:func:`get_user()` 用于从用户空间中获取和向用户空
+间中传出单个值(如int、char或long)。指向用户空间的指针永远不应该直接取消
+引用:应该使用这些程序复制数据。两者都返回 ``-EFAULT`` 或 0。
+
+:c:func:`copy_to_user()` 和 :c:func:`copy_from_user()` 更通用:它们从/向用户
+空间复制任意数量的数据。
+
+.. warning::
+
+ 与 :c:func:`put_user()` 和 :c:func:`get_user()` 不同,它们返回未复制的
+ 数据量(即0仍然意味着成功)。
+
+【是的,这个讨厌的接口真心让我尴尬。火爆的口水仗大概每年都会发生。
+—— Rusty Russell】
+
+这些函数可以隐式睡眠。它不应该在用户上下文之外调用(没有意义)、调用时禁用中断
+或获得自旋锁。
+
+:c:func:`kmalloc()`/:c:func:`kfree()`
+-------------------------------------
+
+定义于 ``include/linux/slab.h``
+
+**[可能睡眠:见下]**
+
+这些函数用于动态请求指针对齐的内存块,类似用户空间中的malloc和free,但
+:c:func:`kmalloc()` 需要额外的标志词。重要的值:
+
+``GFP_KERNEL``
+ 可以睡眠和交换以释放内存。只允许在用户上下文中使用,但这是分配内存最可靠
+ 的方法。
+
+``GFP_ATOMIC``
+ 不会睡眠。较 ``GFP_KERNEL`` 更不可靠,但可以从中断上下文调用。你 **应该**
+ 有一个很好的内存不足错误处理策略。
+
+``GFP_DMA``
+ 分配低于16MB的ISA DMA。如果你不知道那是什么,那你就不需要了。非常不可靠。
+
+如果您看到一个从无效上下文警告消息调用的睡眠的函数,那么您可能在没有
+``GFP_ATOMIC`` 的情况下从中断上下文调用了一个睡眠的分配函数。你必须立即修复,
+快点!
+
+如果你要分配至少 ``PAGE_SIZE`` ( ``asm/page.h`` 或 ``asm/page_types.h`` )
+字节,请考虑使用 :c:func:`__get_free_pages()` ( ``include/linux/gfp.h`` )。
+它采用顺序参数(0表示页面大小,1表示双页,2表示四页……)和与上述相同的内存
+优先级标志字。
+
+如果分配的字节数超过一页,可以使用 :c:func:`vmalloc()` 。它将在内核映射中分
+配虚拟内存。此块在物理内存中不是连续的,但是MMU(内存管理单元)使它看起来像
+是为您准备好的连续空间(因此它只是看起来对cpu连续,对外部设备驱动程序则不然)。
+如果您真的需要为一些奇怪的设备提供大量物理上连续的内存,那么您就会遇到问题:
+Linux对此支持很差,因为正在运行的内核中的内存碎片化会使它变得很困难。最好的
+方法是在引导过程的早期通过 :c:func:`alloc_bootmem()` 函数分配。
+
+在创建自己的常用对象缓存之前,请考虑使用 ``include/linux/slab.h`` 中的slab
+缓存。
+
+:c:macro:`current`
+------------------
+
+定义于 ``include/asm/current.h``
+
+此全局变量(其实是宏)包含指向当前任务结构(task structure)的指针,因此仅在
+用户上下文中有效。例如,当进程进行系统调用时,这将指向调用进程的任务结构。
+在中断上下文中不为空(**not NULL**)。
+
+:c:func:`mdelay()`/:c:func:`udelay()`
+-------------------------------------
+
+定义于 ``include/asm/delay.h`` / ``include/linux/delay.h``
+
+:c:func:`udelay()` 和 :c:func:`ndelay()` 函数可被用于小暂停。不要对它们使用
+大的值,因为这样会导致溢出——帮助函数 :c:func:`mdelay()` 在这里很有用,或者
+考虑 :c:func:`msleep()`。
+
+:c:func:`cpu_to_be32()`/:c:func:`be32_to_cpu()`/:c:func:`cpu_to_le32()`/:c:func:`le32_to_cpu()`
+-----------------------------------------------------------------------------------------------
+
+定义于 ``include/asm/byteorder.h``
+
+:c:func:`cpu_to_be32()` 系列函数(其中“32”可以替换为64或16,“be”可以替换为
+“le”)是在内核中进行字节序转换的常用方法:它们返回转换后的值。所有的变体也
+提供反向转换函数:
+:c:func:`be32_to_cpu()` 等。
+
+这些函数有两个主要的变体:指针变体,例如 :c:func:`cpu_to_be32p()` ,它获取
+指向给定类型的指针,并返回转换后的值。另一个变体是“in-situ”系列,例如
+:c:func:`cpu_to_be32s()` ,它转换指针引用的值,并返回void。
+
+:c:func:`local_irq_save()`/:c:func:`local_irq_restore()`
+--------------------------------------------------------
+
+定义于 ``include/linux/irqflags.h``
+
+
+这些程序禁用本地CPU上的硬中断,并还原它们。它们是可重入的;在其一个
+``unsigned long flags`` 参数中保存以前的状态。如果您知道中断已启用,那么可
+直接使用 :c:func:`local_irq_disable()` 和 :c:func:`local_irq_enable()`。
+
+.. _local_bh_disable_zh:
+
+:c:func:`local_bh_disable()`/:c:func:`local_bh_enable()`
+--------------------------------------------------------
+
+定义于 ``include/linux/bottom_half.h``
+
+
+这些程序禁用本地CPU上的软中断,并还原它们。它们是可重入的;如果之前禁用了
+软中断,那么在调用这对函数之后仍然会禁用它们。它们阻止软中断和子任务在当前
+CPU上运行。
+
+:c:func:`smp_processor_id()`
+----------------------------
+
+定义于 ``include/linux/smp.h``
+
+:c:func:`get_cpu()` 禁用抢占(这样您就不会突然移动到另一个cpu)并返回当前
+处理器号,介于0和 ``NR_CPUS`` 之间。请注意,CPU编号不一定是连续的。完成后,
+使用 :c:func:`put_cpu()` 再次返回。
+
+如果您知道您不能被另一个任务抢占(即您处于中断上下文中,或已禁用抢占),您
+可以使用 :c:func:`smp_processor_id()`。
+
+``__init``/``__exit``/``__initdata``
+------------------------------------
+
+定义于 ``include/linux/init.h``
+
+引导之后,内核释放一个特殊的部分;用 ``__init`` 标记的函数和用 ``__initdata``
+标记的数据结构在引导完成后被丢弃:同样地,模块在初始化后丢弃此内存。
+``__exit`` 用于声明只在退出时需要的函数:如果此文件未编译为模块,则该函数将
+被删除。请参阅头文件以使用。请注意,使用 :c:func:`EXPORT_SYMBOL()` 或
+:c:func:`EXPORT_SYMBOL_GPL()` 将标记为 ``__init`` 的函数导出到模块是没有意义
+的——这将出问题。
+
+
+:c:func:`__initcall()`/:c:func:`module_init()`
+----------------------------------------------
+
+定义于 ``include/linux/init.h`` / ``include/linux/module.h``
+
+内核的许多部分都作为模块(内核的可动态加载部分)良好服务。使用
+:c:func:`module_init()` 和 :c:func:`module_exit()` 宏可以简化代码编写,无需
+``#ifdef`` ,即可以作为模块运行或内置在内核中。
+
+:c:func:`module_init()` 宏定义在模块插入时(如果文件编译为模块)或在引导时
+调用哪个函数:如果文件未编译为模块,:c:func:`module_init()` 宏将等效于
+:c:func:`__initcall()` ,它通过链接器的魔力确保在引导时调用该函数。
+
+该函数可以返回一个错误值,以导致模块加载失败(不幸的是,如果将模块编译到内核
+中,则此操作无效)。此函数在启用中断的用户上下文中调用,因此可以睡眠。
+
+:c:func:`module_exit()`
+-----------------------
+
+
+定义于 ``include/linux/module.h``
+
+这个宏定义了在模块删除时要调用的函数(如果是编译到内核中的文件,则无用武之地)。
+只有在模块使用计数到零时才会调用它。这个函数也可以睡眠,但不能失败:当它返回
+时,所有的东西都必须清理干净。
+
+注意,这个宏是可选的:如果它不存在,您的模块将不可移除(除非 ``rmmod -f`` )。
+
+:c:func:`try_module_get()`/:c:func:`module_put()`
+-------------------------------------------------
+
+定义于 ``include/linux/module.h``
+
+这些函数会操作模块使用计数,以防止删除(如果另一个模块使用其导出的符号之一,
+则无法删除模块,参见下文)。在调用模块代码之前,您应该在该模块上调用
+:c:func:`try_module_get()` :若失败,那么该模块将被删除,您应该将其视为不存在。
+若成功,您就可以安全地进入模块,并在完成后调用模块 :c:func:`module_put()` 。
+
+大多数可注册结构体都有所有者字段,例如在
+:c:type:`struct file_operations <file_operations>` 结构体中,此字段应设置为
+宏 ``THIS_MODULE`` 。
+
+等待队列 ``include/linux/wait.h``
+====================================
+
+**[睡眠]**
+
+等待队列用于等待某程序在条件为真时唤醒另一程序。必须小心使用,以确保没有竞争
+条件。先声明一个 :c:type:`wait_queue_head_t` ,然后对希望等待该条件的进程声明
+一个关于它们自己的 :c:type:`wait_queue_entry_t` ,并将其放入队列中。
+
+声明
+-----
+
+使用 :c:func:`DECLARE_WAIT_QUEUE_HEAD()` 宏声明一个 ``wait_queue_head_t`` ,
+或者在初始化代码中使用 :c:func:`init_waitqueue_head()` 程序。
+
+排队
+-----
+
+将自己放在等待队列中相当复杂,因为你必须在检查条件之前将自己放入队列中。有一
+个宏可以来执行此操作: :c:func:`wait_event_interruptible()`
+( ``include/linux/wait.h`` )第一个参数是等待队列头,第二个参数是计算的表达
+式;当该表达式为true时宏返回0,或者在接收到信号时返回 ``-ERESTARTSYS`` 。
+:c:func:`wait_event()` 版本会忽略信号。
+
+唤醒排队任务
+-------------
+
+调用 :c:func:`wake_up()` ( ``include/linux/wait.h`` ),它将唤醒队列中的所有
+进程。例外情况:如果有一个进程设置了 ``TASK_EXCLUSIVE`` ,队列的其余部分将不
+会被唤醒。这个基本函数的其他变体也可以在同一个头文件中使用。
+
+原子操作
+=========
+
+某些操作在所有平台上都有保证。第一类为操作 :c:type:`atomic_t`
+( ``include/asm/atomic.h`` )的函数;它包含一个有符号整数(至少32位长),
+您必须使用这些函数来操作或读取 :c:type:`atomic_t` 变量。
+:c:func:`atomic_read()` 和 :c:func:`atomic_set()` 获取并设置计数器,还有
+:c:func:`atomic_add()` ,:c:func:`atomic_sub()` ,:c:func:`atomic_inc()` ,
+:c:func:`atomic_dec()` 和 :c:func:`atomic_dec_and_test()` (如果递减为零,
+则返回true)。
+
+是的。它在原子变量为零时返回true(即!=0)。
+
+请注意,这些函数比普通的算术运算速度慢,因此不应过度使用。
+
+第二类原子操作是在 ``unsigned long`` ( ``include/linux/bitops.h`` )上的
+原子位操作。这些操作通常采用指向位模式(bit pattern)的指针,第0位是最低有效
+位。:c:func:`set_bit()`,:c:func:`clear_bit()` 和 :c:func:`change_bit()` 设置、
+清除和更改给定位。:c:func:`test_and_set_bit()` ,:c:func:`test_and_clear_bit()`
+和 :c:func:`test_and_change_bit()` 执行相同的操作,但如果之前设置了位,则返回
+true;这些对于原子设置标志特别有用。
+
+可以使用大于 ``BITS_PER_LONG`` 位的位索引调用这些操作。但结果在大端序平台上
+不太正常,所以最好不要这样做。
+
+符号
+=====
+
+在内核内部,正常的链接规则仍然适用(即除非用static关键字将符号声明为文件范围,
+否则它可以在内核中的任何位置使用)。但是对于模块,会保留一个特殊可导出符号表,
+该表将入口点限制为内核内部。模块也可以导出符号。
+
+:c:func:`EXPORT_SYMBOL()`
+-------------------------
+
+定义于 ``include/linux/export.h``
+
+这是导出符号的经典方法:动态加载的模块将能够正常使用符号。
+
+:c:func:`EXPORT_SYMBOL_GPL()`
+-----------------------------
+
+定义于 ``include/linux/export.h``
+
+
+类似于 :c:func:`EXPORT_SYMBOL()`,只是 :c:func:`EXPORT_SYMBOL_GPL()` 导出的
+符号只能由具有由 :c:func:`MODULE_LICENSE()` 指定GPL兼容许可证的模块看到。这
+意味着此函数被认为是一个内部实现问题,而不是一个真正的接口。一些维护人员和
+开发人员在添加一些新的API或功能时可能却需要导出 EXPORT_SYMBOL_GPL()。
+
+:c:func:`EXPORT_SYMBOL_NS()`
+----------------------------
+
+定义于 ``include/linux/export.h``
+
+这是 ``EXPORT_SYMBOL()`` 的变体,允许指定符号命名空间。符号名称空间记录于
+Documentation/core-api/symbol-namespaces.rst 。
+
+:c:func:`EXPORT_SYMBOL_NS_GPL()`
+--------------------------------
+
+定义于 ``include/linux/export.h``
+
+这是 ``EXPORT_SYMBOL_GPL()`` 的变体,允许指定符号命名空间。符号名称空间记录于
+Documentation/core-api/symbol-namespaces.rst 。
+
+程序与惯例
+===========
+
+双向链表 ``include/linux/list.h``
+-----------------------------------
+
+内核头文件中曾经有三组链表程序,但这一组是赢家。如果你对一个单链表没有特别迫切的
+需求,那么这是一个不错的选择。
+
+通常 :c:func:`list_for_each_entry()` 很有用。
+
+返回值惯例
+------------
+
+对于在用户上下文中调用的代码,违背C语言惯例是很常见的,即返回0表示成功,返回
+负错误值(例如 ``-EFAULT`` )表示失败。这在一开始可能是不直观的,但在内核中
+相当普遍。
+
+使用 :c:func:`ERR_PTR()` ( ``include/linux/err.h`` )将负错误值编码到指针中,
+然后使用 :c:func:`IS_ERR()` 和 :c:func:`PTR_ERR()` 将其再取出:避免为错误值
+使用单独的指针参数。挺讨厌的,但的确是个好方式。
+
+破坏编译
+----------
+
+Linus和其他开发人员有时会更改开发内核中的函数或结构体名称;这样做不仅是为了
+让每个人都保持警惕,还反映了一个重大的更改(例如,不能再在打开中断的情况下
+调用,或者执行额外的检查,或者不执行以前捕获的检查)。通常这会附带发送一个
+相当全面的注释到相应的内核邮件列表中;请搜索存档以查看。简单地对文件进行全局
+替换通常只会让事情变得 **更糟** 。
+
+初始化结构体成员
+------------------
+
+初始化结构体的首选方法是使用指定的初始化器,如ISO C99所述。
+例如::
+
+ static struct block_device_operations opt_fops = {
+ .open = opt_open,
+ .release = opt_release,
+ .ioctl = opt_ioctl,
+ .check_media_change = opt_media_change,
+ };
+
+
+这使得很容易查找(grep),并且可以清楚地看到设置了哪些结构字段。你应该这样做,
+因为它看起来很酷。
+
+GNU 扩展
+----------
+
+Linux内核中明确允许GNU扩展。请注意,由于缺乏通用性,一些更复杂的版本并没有
+得到很好的支持,但以下内容被认为是标准的(有关更多详细信息,请参阅GCC info页
+的“C 扩展”部分——是的,实际上是info页,手册页只是info中内容的简短摘要)。
+
+- 内联函数
+
+- 语句表达式(Statement expressions)(即({ 和 })结构)。
+
+
+- 声明函数/变量/类型的属性(__attribute__)
+
+- typeof
+
+- 零长度数组
+
+- 宏变量
+
+- 空指针运算
+
+- 非常量(Non-Constant)初始化程序
+
+- 汇编程序指令(在 arch/ 和 include/asm/ 之内)
+
+- 字符串函数名(__func__)。
+
+- __builtin_constant_p()
+
+在内核中使用long long时要小心,gcc为其生成的代码非常糟糕:除法和乘法在i386上
+不能工作,因为内核环境中缺少用于它的gcc运行时函数。
+
+C++
+---
+
+在内核中使用C++通常是个坏主意,因为内核不提供必要的运行时环境,并且不为其
+测试包含文件。不过这仍然是可能的,但不建议。如果你真的想这么做,至少别用
+异常处理(exceptions)。
+
+#if
+---
+
+通常认为,在头文件(或.c文件顶部)中使用宏来抽象函数比在源代码中使用“if”预
+处理器语句更干净。
+
+把你的东西放进内核里
+======================
+
+为了让你的东西更正式、补丁更整洁,还有一些工作要做:
+
+- 搞清楚你修改的代码属于谁。查看源文件的根目录、 ``MAINTAINERS`` 文件以及
+ ``CREDITS`` 文件的最后一部分。你应该和此人协调,确保你没有重新发明轮子,
+ 或者尝试一些已经被拒绝的东西。
+
+ 确保你把你的名字和电子邮件地址放在你创建或修改的任何文件的顶部。当人们发
+ 现一个缺陷,或者想要做出修改时,这是他们首先会看的地方。
+
+- 通常你需要一个配置选项来支持你的内核编程。在适当的目录中编辑 ``Kconfig`` 。
+ 配置语言很容易通过剪切和粘贴来使用,在
+ Documentation/kbuild/kconfig-language.rst 中有完整的文档。
+
+ 在您对选项的描述中,请确保同时照顾到了专家用户和对此功能一无所知的用户。
+ 在此说明任何不兼容和问题。结尾一定要写上“如有疑问,就选N”(或者是“Y”);
+ 这是针对那些看不懂你在说什么的人的。
+
+- 编辑 ``Makefile`` :配置变量在这里导出,因此通常你只需添加一行
+ “obj-$(CONFIG_xxx) += xxx.o”。语法记录在
+ Documentation/kbuild/makefiles.rst 。
+
+- 如果你认为自己做了一些有意义的事情,可以把自己放进 ``CREDITS`` ,通常不
+ 止一个文件(无论如何你的名字都应该在源文件的顶部)。 ``MAINTAINERS``
+ 意味着您希望在对子系统进行更改时得到询问,并了解缺陷;这意味着对某部分
+ 代码做出更多承诺。
+
+- 最后,别忘记去阅读 Documentation/process/submitting-patches.rst。
+
+Kernel 仙女棒
+===============
+
+浏览源代码时的一些收藏。请随意添加到此列表。
+
+``arch/x86/include/asm/delay.h``::
+
+ #define ndelay(n) (__builtin_constant_p(n) ? \
+ ((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \
+ __ndelay(n))
+
+
+``include/linux/fs.h``::
+
+ /*
+ * Kernel pointers have redundant information, so we can use a
+ * scheme where we can return either an error code or a dentry
+ * pointer with the same return value.
+ *
+ * This should be a per-architecture thing, to allow different
+ * error and pointer decisions.
+ */
+ #define ERR_PTR(err) ((void *)((long)(err)))
+ #define PTR_ERR(ptr) ((long)(ptr))
+ #define IS_ERR(ptr) ((unsigned long)(ptr) > (unsigned long)(-1000))
+
+``arch/x86/include/asm/uaccess_32.h:``::
+
+ #define copy_to_user(to,from,n) \
+ (__builtin_constant_p(n) ? \
+ __constant_copy_to_user((to),(from),(n)) : \
+ __generic_copy_to_user((to),(from),(n)))
+
+
+``arch/sparc/kernel/head.S:``::
+
+ /*
+ * Sun people can't spell worth damn. "compatibility" indeed.
+ * At least we *know* we can't spell, and use a spell-checker.
+ */
+
+ /* Uh, actually Linus it is I who cannot spell. Too much murky
+ * Sparc assembly will do this to ya.
+ */
+ C_LABEL(cputypvar):
+ .asciz "compatibility"
+
+ /* Tested on SS-5, SS-10. Probably someone at Sun applied a spell-checker. */
+ .align 4
+ C_LABEL(cputypvar_sun4m):
+ .asciz "compatible"
+
+
+``arch/sparc/lib/checksum.S:``::
+
+ /* Sun, you just can't beat me, you just can't. Stop trying,
+ * give up. I'm serious, I am going to kick the living shit
+ * out of you, game over, lights out.
+ */
+
+
+致谢
+=====
+
+感谢Andi Kleen提出点子,回答我的问题,纠正我的错误,充实内容等帮助。
+感谢Philipp Rumpf做了许多拼写和清晰度修复,以及一些优秀的不明显的点。
+感谢Werner Almesberger对 :c:func:`disable_irq()` 做了一个很好的总结,
+Jes Sorensen和Andrea Arcangeli补充了一些注意事项。
+感谢Michael Elizabeth Chastain检查并补充了配置部分。
+感谢Telsa Gwynne教我DocBook。
diff --git a/Documentation/translations/zh_CN/kernel-hacking/index.rst b/Documentation/translations/zh_CN/kernel-hacking/index.rst
new file mode 100644
index 000000000000..df530de2278d
--- /dev/null
+++ b/Documentation/translations/zh_CN/kernel-hacking/index.rst
@@ -0,0 +1,22 @@
+.. _kernel_hacking_zh:
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/kernel-hacking/index.rst
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+=============
+内核骇客指南
+=============
+
+.. toctree::
+ :maxdepth: 2
+
+ hacking
+
+TODO
+
+- locking
diff --git a/Documentation/translations/zh_CN/locking/index.rst b/Documentation/translations/zh_CN/locking/index.rst
new file mode 100644
index 000000000000..f0b10707668d
--- /dev/null
+++ b/Documentation/translations/zh_CN/locking/index.rst
@@ -0,0 +1,43 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/locking/index.rst
+
+:翻译:
+
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+==
+锁
+==
+
+.. toctree::
+ :maxdepth: 1
+
+ mutex-design
+ spinlocks
+
+TODOList:
+
+ * locktypes
+ * lockdep-design
+ * lockstat
+ * locktorture
+ * rt-mutex-design
+ * rt-mutex
+ * seqlock
+ * ww-mutex-design
+ * preempt-locking
+ * pi-futex
+ * futex-requeue-pi
+ * hwspinlock
+ * percpu-rw-semaphore
+ * robust-futexes
+ * robust-futex-ABI
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
diff --git a/Documentation/translations/zh_CN/locking/mutex-design.rst b/Documentation/translations/zh_CN/locking/mutex-design.rst
new file mode 100644
index 000000000000..6aad54372a6c
--- /dev/null
+++ b/Documentation/translations/zh_CN/locking/mutex-design.rst
@@ -0,0 +1,145 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/locking/mutex-design.rst
+
+:翻译:
+
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+================
+通用互斥锁子系统
+================
+
+:初稿:
+
+ Ingo Molnar <mingo@redhat.com>
+
+:更新:
+
+ Davidlohr Bueso <davidlohr@hp.com>
+
+什么是互斥锁?
+--------------
+
+在Linux内核中,互斥锁(mutex)指的是一个特殊的加锁原语,它在共享内存系统上
+强制保证序列化,而不仅仅是指在学术界或类似的理论教科书中出现的通用术语“相互
+排斥”。互斥锁是一种睡眠锁,它的行为类似于二进制信号量(semaphores),在
+2006年被引入时[1],作为后者的替代品。这种新的数据结构提供了许多优点,包括更
+简单的接口,以及在当时更少的代码量(见缺陷)。
+
+[1] https://lwn.net/Articles/164802/
+
+实现
+----
+
+互斥锁由“struct mutex”表示,在include/linux/mutex.h中定义,并在
+kernel/locking/mutex.c中实现。这些锁使用一个原子变量(->owner)来跟踪
+它们生命周期内的锁状态。字段owner实际上包含的是指向当前锁所有者的
+`struct task_struct *` 指针,因此如果无人持有锁,则它的值为空(NULL)。
+由于task_struct的指针至少按L1_CACHE_BYTES对齐,低位(3)被用来存储额外
+的状态(例如,等待者列表非空)。在其最基本的形式中,它还包括一个等待队列和
+一个确保对其序列化访问的自旋锁。此外,CONFIG_MUTEX_SPIN_ON_OWNER=y的
+系统使用一个自旋MCS锁(->osq,译注:MCS是两个人名的合并缩写),在下文的
+(ii)中描述。
+
+准备获得一把自旋锁时,有三种可能经过的路径,取决于锁的状态:
+
+(i) 快速路径:试图通过调用cmpxchg()修改锁的所有者为当前任务,以此原子化地
+ 获取锁。这只在无竞争的情况下有效(cmpxchg()检查值是否为0,所以3个状态
+ 比特必须为0)。如果锁处在竞争状态,代码进入下一个可能的路径。
+
+(ii) 中速路径:也就是乐观自旋,当锁的所有者正在运行并且没有其它优先级更高的
+ 任务(need_resched,需要重新调度)准备运行时,当前任务试图自旋来获得
+ 锁。原理是,如果锁的所有者正在运行,它很可能不久就会释放锁。互斥锁自旋体
+ 使用MCS锁排队,这样只有一个自旋体可以竞争互斥锁。
+
+ MCS锁(由Mellor-Crummey和Scott提出)是一个简单的自旋锁,它具有一些
+ 理想的特性,比如公平,以及每个CPU在试图获得锁时在一个本地变量上自旋。
+ 它避免了常见的“检测-设置”自旋锁实现导致的(CPU核间)缓存行回弹
+ (cacheline bouncing)这种昂贵的开销。一个类MCS锁是为实现睡眠锁的
+ 乐观自旋而专门定制的。这种定制MCS锁的一个重要特性是,它有一个额外的属性,
+ 当自旋体需要重新调度时,它们能够退出MCS自旋锁队列。这进一步有助于避免
+ 以下场景:需要重新调度的MCS自旋体将继续自旋等待自旋体所有者,即将获得
+ MCS锁时却直接进入慢速路径。
+
+(iii) 慢速路径:最后的手段,如果仍然无法获得锁,该任务会被添加到等待队列中,
+ 休眠直到被解锁路径唤醒。在通常情况下,它以TASK_UNINTERRUPTIBLE状态
+ 阻塞。
+
+虽然从形式上看,内核互斥锁是可睡眠的锁,路径(ii)使它实际上成为混合类型。通过
+简单地不中断一个任务并忙着等待几个周期,而不是立即睡眠,这种锁已经被认为显著
+改善一些工作负载的性能。注意,这种技术也被用于读写信号量(rw-semaphores)。
+
+语义
+----
+
+互斥锁子系统检查并强制执行以下规则:
+
+ - 每次只有一个任务可以持有该互斥锁。
+ - 只有锁的所有者可以解锁该互斥锁。
+ - 不允许多次解锁。
+ - 不允许递归加锁/解锁。
+ - 互斥锁只能通过API进行初始化(见下文)。
+ - 一个任务不能在持有互斥锁的情况下退出。
+ - 持有锁的内存区域不得被释放。
+ - 被持有的锁不能被重新初始化。
+ - 互斥锁不能用于硬件或软件中断上下文,如小任务(tasklet)和定时器。
+
+当CONFIG DEBUG_MUTEXES被启用时,这些语义将被完全强制执行。此外,互斥锁
+调试代码还实现了一些其它特性,使锁的调试更容易、更快速:
+
+ - 当打印到调试输出时,总是使用互斥锁的符号名称。
+ - 加锁点跟踪,函数名符号化查找,系统持有的全部锁的列表,打印出它们。
+ - 所有者跟踪。
+ - 检测自我递归的锁并打印所有相关信息。
+ - 检测多任务环形依赖死锁,并打印所有受影响的锁和任务(并且只限于这些任务)。
+
+
+接口
+----
+静态定义互斥锁::
+
+ DEFINE_MUTEX(name);
+
+动态初始化互斥锁::
+
+ mutex_init(mutex);
+
+以不可中断方式(uninterruptible)获取互斥锁::
+
+ void mutex_lock(struct mutex *lock);
+ void mutex_lock_nested(struct mutex *lock, unsigned int subclass);
+ int mutex_trylock(struct mutex *lock);
+
+以可中断方式(interruptible)获取互斥锁::
+
+ int mutex_lock_interruptible_nested(struct mutex *lock,
+ unsigned int subclass);
+ int mutex_lock_interruptible(struct mutex *lock);
+
+当原子变量减为0时,以可中断方式(interruptible)获取互斥锁::
+
+ int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);
+
+释放互斥锁::
+
+ void mutex_unlock(struct mutex *lock);
+
+检测是否已经获取互斥锁::
+
+ int mutex_is_locked(struct mutex *lock);
+
+缺陷
+----
+
+与它最初的设计和目的不同,'struct mutex' 是内核中最大的锁之一。例如:在
+x86-64上它是32字节,而 'struct semaphore' 是24字节,rw_semaphore是
+40字节。更大的结构体大小意味着更多的CPU缓存和内存占用。
+
+
+何时使用互斥锁
+--------------
+
+总是优先选择互斥锁而不是任何其它锁原语,除非互斥锁的严格语义不合适,和/或临界区
+阻止锁被共享。
diff --git a/Documentation/translations/zh_CN/locking/spinlocks.rst b/Documentation/translations/zh_CN/locking/spinlocks.rst
new file mode 100644
index 000000000000..2017c01f0a4b
--- /dev/null
+++ b/Documentation/translations/zh_CN/locking/spinlocks.rst
@@ -0,0 +1,149 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/locking/spinlocks.rst
+
+:翻译:
+
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+==========
+加锁的教训
+==========
+
+教训 1:自旋锁
+==============
+
+加锁最基本的原语是自旋锁(spinlock)::
+
+ static DEFINE_SPINLOCK(xxx_lock);
+
+ unsigned long flags;
+
+ spin_lock_irqsave(&xxx_lock, flags);
+ ... 这里是临界区 ..
+ spin_unlock_irqrestore(&xxx_lock, flags);
+
+上述代码总是安全的。自旋锁将在 _本地_ 禁用中断,但它本身将保证全局锁定。所以它
+将保证在该锁保护的区域内只有一个控制线程。即使在单处理器(UP)下也能很好的工作,
+所以代码 _不_ 需要担心UP还是SMP的问题:自旋锁在两种情况下都能正常工作。
+
+ 注意!自旋锁对内存的潜在影响由下述文档进一步描述:
+
+ Documentation/memory-barriers.txt
+
+ (5) ACQUIRE operations.
+
+ (6) RELEASE operations.
+
+上述代码通常非常简单(对大部分情况,你通常需要并且只希望有一个自旋锁——使用多个
+自旋锁会使事情变得更复杂,甚至更慢,而且通常仅仅在你 **理解的** 序列有被拆分的
+需求时才值得这么做:如果你不确定的话,请不惜一切代价避免这样做)。
+
+这是关于自旋锁的唯一真正困难的部分:一旦你开始使用自旋锁,它们往往会扩展到你以前
+可能没有注意到的领域,因为你必须确保自旋锁正确地保护共享数据结构 **每一处** 被
+使用的地方。自旋锁是最容易被添加到完全独立于其它代码的地方(例如,没有人访问的
+内部驱动数据结构)的。
+
+ 注意!仅当你在跨CPU核访问时使用 **同一把** 自旋锁,对它的使用才是安全的。
+ 这意味着所有访问共享变量的代码必须对它们想使用的自旋锁达成一致。
+
+----
+
+教训 2:读-写自旋锁
+===================
+
+如果你的数据访问有一个非常自然的模式,倾向于从共享变量中读取数据,读-写自旋锁
+(rw_lock)有时是有用的。它们允许多个读者同时出现在同一个临界区,但是如果有人想
+改变变量,它必须获得一个独占的写锁。
+
+ 注意!读-写自旋锁比原始自旋锁需要更多的原子内存操作。除非读者的临界区很长,
+ 否则你最好只使用原始自旋锁。
+
+例程看起来和上面一样::
+
+ rwlock_t xxx_lock = __RW_LOCK_UNLOCKED(xxx_lock);
+
+ unsigned long flags;
+
+ read_lock_irqsave(&xxx_lock, flags);
+ .. 仅读取信息的临界区 ...
+ read_unlock_irqrestore(&xxx_lock, flags);
+
+ write_lock_irqsave(&xxx_lock, flags);
+ .. 读取和独占写信息 ...
+ write_unlock_irqrestore(&xxx_lock, flags);
+
+上面这种锁对于复杂的数据结构如链表可能会有用,特别是在不改变链表的情况下搜索其中
+的条目。读锁允许许多并发的读者。任何希望 **修改** 链表的代码将必须先获取写锁。
+
+ 注意!RCU锁更适合遍历链表,但需要仔细注意设计细节(见Documentation/RCU/listRCU.rst)。
+
+另外,你不能把读锁“升级”为写锁,所以如果你在 _任何_ 时候需要做任何修改
+(即使你不是每次都这样做),你必须在一开始就获得写锁。
+
+ 注意!我们正在努力消除大多数情况下的读-写自旋锁的使用,所以请不要在没有达成
+ 共识的情况下增加一个新的(相反,请参阅Documentation/RCU/rcu.rst以获得完整
+ 信息)。
+
+----
+
+教训 3:重新审视自旋锁
+======================
+
+上述的自旋锁原语绝不是唯一的。它们是最安全的,在所有情况下都能正常工作,但部分
+**因为** 它们是安全的,它们也是相当慢的。它们比原本需要的更慢,因为它们必须要
+禁用中断(在X86上只是一条指令,但却是一条昂贵的指令——而在其他体系结构上,情况
+可能更糟)。
+
+如果你有必须保护跨CPU访问的数据结构且你想使用自旋锁的场景,你有可能使用代价小的
+自旋锁版本。当且仅当你知道某自旋锁永远不会在中断处理程序中使用,你可以使用非中断
+的版本::
+
+ spin_lock(&lock);
+ ...
+ spin_unlock(&lock);
+
+(当然,也可以使用相应的读-写锁版本)。这种自旋锁将同样可以保证独占访问,而且
+速度会快很多。如果你知道有关的数据只在“进程上下文”中被存取,即,不涉及中断,
+这种自旋锁就有用了。
+
+当这些版本的自旋锁涉及中断时,你不能使用的原因是会陷入死锁::
+
+ spin_lock(&lock);
+ ...
+ <- 中断来临:
+ spin_lock(&lock);
+
+一个中断试图对一个已经锁定的变量上锁。如果中断发生在另一个CPU上,不会有问题;
+但如果中断发生在已经持有自旋锁的同一个CPU上,将 _会_ 有问题,因为该锁显然永远
+不会被释放(因为中断正在等待该锁,而锁的持有者被中断打断,并且无法继续执行,
+直到中断处理结束)。
+
+(这也是自旋锁的中断版本只需要禁用 _本地_ 中断的原因——在发生于其它CPU的中断中
+使用同一把自旋锁是没问题的,因为发生于其它CPU的中断不会打断已经持锁的CPU,所以
+锁的持有者可以继续执行并最终释放锁)。
+
+ Linus
+
+----
+
+参考信息
+========
+
+对于动态初始化,使用spin_lock_init()或rwlock_init()是合适的::
+
+ spinlock_t xxx_lock;
+ rwlock_t xxx_rw_lock;
+
+ static int __init xxx_init(void)
+ {
+ spin_lock_init(&xxx_lock);
+ rwlock_init(&xxx_rw_lock);
+ ...
+ }
+
+ module_init(xxx_init);
+
+对于静态初始化,使用DEFINE_SPINLOCK() / DEFINE_RWLOCK()或
+__SPIN_LOCK_UNLOCKED() / __RW_LOCK_UNLOCKED()是合适的。
diff --git a/Documentation/translations/zh_CN/maintainer/configure-git.rst b/Documentation/translations/zh_CN/maintainer/configure-git.rst
new file mode 100644
index 000000000000..a45ea736f73b
--- /dev/null
+++ b/Documentation/translations/zh_CN/maintainer/configure-git.rst
@@ -0,0 +1,62 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/maintainer/configure-git.rst
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+.. _configuregit_zh:
+
+Git配置
+=======
+
+本章讲述了维护者级别的git配置。
+
+Documentation/maintainer/pull-requests.rst 中使用的标记分支应使用开发人员的
+GPG公钥进行签名。可以通过将 ``-u`` 标志传递给 ``git tag`` 来创建签名标记。
+但是,由于 *通常* 对同一项目使用同一个密钥,因此可以设置::
+
+ git config user.signingkey "keyname"
+
+或者手动编辑你的 ``.git/config`` 或 ``~/.gitconfig`` 文件::
+
+ [user]
+ name = Jane Developer
+ email = jd@domain.org
+ signingkey = jd@domain.org
+
+你可能需要告诉 ``git`` 去使用 ``gpg2``::
+
+ [gpg]
+ program = /path/to/gpg2
+
+你可能也需要告诉 ``gpg`` 去使用哪个 ``tty`` (添加到你的shell rc文件中)::
+
+ export GPG_TTY=$(tty)
+
+
+创建链接到lore.kernel.org的提交
+-------------------------------
+
+http://lore.kernel.org 网站是所有涉及或影响内核开发的邮件列表的总存档。在这里
+存储补丁存档是推荐的做法,当维护人员将补丁应用到子系统树时,最好提供一个指向
+lore存档链接的标签,以便浏览提交历史的人可以找到某个更改背后的相关讨论和基本
+原理。链接标签如下所示:
+
+ Link: https://lore.kernel.org/r/<message-id>
+
+通过在git中添加以下钩子,可以将此配置为在发布 ``git am`` 时自动执行:
+
+.. code-block:: none
+
+ $ git config am.messageid true
+ $ cat >.git/hooks/applypatch-msg <<'EOF'
+ #!/bin/sh
+ . git-sh-setup
+ perl -pi -e 's|^Message-Id:\s*<?([^>]+)>?$|Link: https://lore.kernel.org/r/$1|g;' "$1"
+ test -x "$GIT_DIR/hooks/commit-msg" &&
+ exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
+ :
+ EOF
+ $ chmod a+x .git/hooks/applypatch-msg
diff --git a/Documentation/translations/zh_CN/maintainer/index.rst b/Documentation/translations/zh_CN/maintainer/index.rst
new file mode 100644
index 000000000000..eb75ccea9a21
--- /dev/null
+++ b/Documentation/translations/zh_CN/maintainer/index.rst
@@ -0,0 +1,21 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/maintainer/index.rst
+
+==============
+内核维护者手册
+==============
+
+本文档本是内核维护者手册的首页。
+本手册还需要大量完善!请自由提出(和编写)本手册的补充内容。
+*译注:指英文原版*
+
+.. toctree::
+ :maxdepth: 2
+
+ configure-git
+ rebasing-and-merging
+ pull-requests
+ maintainer-entry-profile
+ modifying-patches
+
diff --git a/Documentation/translations/zh_CN/maintainer/maintainer-entry-profile.rst b/Documentation/translations/zh_CN/maintainer/maintainer-entry-profile.rst
new file mode 100644
index 000000000000..0f5acfb1012e
--- /dev/null
+++ b/Documentation/translations/zh_CN/maintainer/maintainer-entry-profile.rst
@@ -0,0 +1,92 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/maintainer/maintainer-entry-profile.rst
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+.. _maintainerentryprofile_zh:
+
+维护者条目概要
+==============
+
+维护人员条目概要补充了顶层过程文档(提交补丁,提交驱动程序……),增加了子系
+统/设备驱动程序本地习惯以及有关补丁提交生命周期的相关内容。贡献者使用此文档
+来调整他们的期望和避免常见错误;维护人员可以使用这些信息超越子系统层面查看
+是否有机会汇聚到通用实践中。
+
+
+总览
+----
+
+提供了子系统如何操作的介绍。MAINTAINERS文件告诉了贡献者应发送某文件的补丁到哪,
+但它没有传达其他子系统的本地基础设施和机制以协助开发。
+
+请考虑以下问题:
+
+- 当补丁被本地树接纳或合并到上游时是否有通知?
+- 子系统是否使用patchwork实例?Patchwork状态变更是否有通知?
+- 是否有任何机器人或CI基础设施监视列表,或子系统是否使用自动测试反馈以便把
+ 控接纳补丁?
+- 被拉入-next的Git分支是哪个?
+- 贡献者应针对哪个分支提交?
+- 是否链接到其他维护者条目概要?例如一个设备驱动可能指向其父子系统的条目。
+ 这使得贡献者意识到某维护者可能对提交链中其他维护者负有的义务。
+
+
+提交检查单补遗
+--------------
+
+列出强制性和咨询性标准,超出通用标准“提交检查表,以便维护者检查一个补丁是否
+足够健康。例如:“通过checkpatch.pl,没有错误、没有警告。通过单元测试详见某处”。
+
+提交检查单补遗还可以包括有关硬件规格状态的详细信息。例如,子系统接受补丁之前
+是否需要考虑在某个修订版上发布的规范。
+
+
+开发周期的关键日期
+------------------
+
+提交者常常会误以为补丁可以在合并窗口关闭之前的任何时间发送,且下一个-rc1时仍
+可以。事实上,大多数补丁都需要在下一个合并窗口打开之前提前进入linux-next中。
+向提交者澄清关键日期(以-rc发布周为标志)以明确什么时候补丁会被考虑合并以及
+何时需要等待下一个-rc。
+
+至少需要讲明:
+
+- 最后一个可以提交新功能的-rc:
+ 针对下一个合并窗口的新功能提交应该在此点之前首次发布以供考虑。在此时间点
+ 之后提交的补丁应该明确他们的目标为下下个合并窗口,或者给出应加快进度被接受
+ 的充足理由。通常新特性贡献者的提交应出现在-rc5之前。
+
+- 最后合并-rc:合并决策的最后期限。
+ 向贡献者指出尚未接受的补丁集需要等待下下个合并窗口。当然,维护者没有义务
+ 接受所有给定的补丁集,但是如果审阅在此时间点尚未结束,那么希望贡献者应该
+ 等待并在下一个合并窗口重新提交。
+
+可选项:
+
+- 开发基线分支的首个-rc,列在概述部分,视为已为新提交做好准备。
+
+
+审阅节奏
+--------
+
+贡献者最担心的问题之一是:补丁集已发布却未收到反馈,应在多久后发送提醒。除了
+指定在重新提交之前要等待多长时间,还可以指示更新的首选样式;例如,重新发送
+整个系列,或私下发送提醒邮件。本节也可以列出本区域的代码审阅方式,以及获取
+不能直接从维护者那里得到的反馈的方法。
+
+
+现有概要
+--------
+
+这里列出了现有的维护人员条目概要;我们可能会想要在不久的将来做一些不同的事情。
+
+.. toctree::
+ :maxdepth: 1
+
+ ../doc-guide/maintainer-profile
+ ../../../nvdimm/maintainer-entry-profile
+ ../../../arch/riscv/patch-acceptance
diff --git a/Documentation/translations/zh_CN/maintainer/modifying-patches.rst b/Documentation/translations/zh_CN/maintainer/modifying-patches.rst
new file mode 100644
index 000000000000..7f6326137f6b
--- /dev/null
+++ b/Documentation/translations/zh_CN/maintainer/modifying-patches.rst
@@ -0,0 +1,51 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/maintainer/modifying-patches.rst
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+.. _modifyingpatches_zh:
+
+修改补丁
+========
+
+如果你是子系统或者分支的维护者,由于代码在你的和提交者的树中并不完全相同,
+有时你需要稍微修改一下收到的补丁以合并它们。
+
+如果你严格遵守开发者来源证书的规则(c),你应该要求提交者重做,但这完全是会
+适得其反的时间、精力浪费。规则(b)允许你调整代码,但这样修改提交者的代码并
+让他背书你的错误是非常不礼貌的。为解决此问题,建议在你之前最后一个
+Signed-off-by标签和你的之间添加一行,以指示更改的性质。这没有强制性要求,最
+好在描述前面加上你的邮件和/或姓名,用方括号括住整行,以明显指出你对最后一刻
+的更改负责。例如::
+
+ Signed-off-by: Random J Developer <random@developer.example.org>
+ [lucky@maintainer.example.org: struct foo moved from foo.c to foo.h]
+ Signed-off-by: Lucky K Maintainer <lucky@maintainer.example.org>
+
+如果您维护着一个稳定的分支,并希望同时明确贡献、跟踪更改、合并修复,并保护
+提交者免受责难,这种做法尤其有用。请注意,在任何情况下都不得更改作者的身份
+(From头),因为它会在变更日志中显示。
+
+向后移植(back-port)人员特别要注意:为了便于跟踪,请在提交消息的顶部(即主题行
+之后)插入补丁的来源,这是一种常见而有用的做法。例如,我们可以在3.x稳定版本
+中看到以下内容::
+
+ Date: Tue Oct 7 07:26:38 2014 -0400
+
+ libata: Un-break ATA blacklist
+
+ commit 1c40279960bcd7d52dbdf1d466b20d24b99176c8 upstream.
+
+下面是一个旧的内核在某补丁被向后移植后会出现的::
+
+ Date: Tue May 13 22:12:27 2008 +0200
+
+ wireless, airo: waitbusy() won't delay
+
+ [backport of 2.6 commit b7acbdfbd1f277c1eb23f344f899cfa4cd0bf36a]
+
+不管什么格式,这些信息都为人们跟踪你的树,以及试图解决你树中的错误的人提供了
+有价值的帮助。
diff --git a/Documentation/translations/zh_CN/maintainer/pull-requests.rst b/Documentation/translations/zh_CN/maintainer/pull-requests.rst
new file mode 100644
index 000000000000..ce9725f4674c
--- /dev/null
+++ b/Documentation/translations/zh_CN/maintainer/pull-requests.rst
@@ -0,0 +1,148 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/maintainer/pull-requests.rst
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+.. _pullrequests_zh:
+
+如何创建拉取请求
+================
+
+本章描述维护人员如何创建并向其他维护人员提交拉取请求。这对将更改从一个维护者
+树转移到另一个维护者树非常有用。
+
+本文档由Tobin C. Harding(当时他尚不是一名经验丰富的维护人员)编写,内容主要
+来自Greg Kroah Hartman和Linus Torvalds在LKML上的评论。Jonathan Corbet和Mauro
+Carvalho Chehab提出了一些建议和修改。错误不可避免,如有问题,请找Tobin C.
+Harding <me@tobin.cc>。
+
+原始邮件线程::
+
+ https://lore.kernel.org/r/20171114110500.GA21175@kroah.com
+
+
+创建分支
+--------
+
+首先,您需要将希望包含拉取请求里的所有更改都放在单独分支中。通常您将基于某开发
+人员树的一个分支,一般是打算向其发送拉取请求的开发人员。
+
+为了创建拉取请求,您必须首先标记刚刚创建的分支。建议您选择一个有意义的标记名,
+以即使过了一段时间您和他人仍能理解的方式。在名称中包含源子系统和目标内核版本
+的指示也是一个好的做法。
+
+Greg提供了以下内容。对于一个含有drivers/char中混杂事项、将应用于4.15-rc1内核的
+拉取请求,可以命名为 ``char-misc-4.15-rc1`` 。如果要在 ``char-misc-next`` 分支
+上打上此标记,您可以使用以下命令::
+
+ git tag -s char-misc-4.15-rc1 char-misc-next
+
+这将在 ``char-misc-next`` 分支的最后一个提交上创建一个名为 ``char-misc-4.15-rc1``
+的标记,并用您的gpg密钥签名(参见 Documentation/maintainer/configure-git.rst )。
+
+Linus只接受基于签名过的标记的拉取请求。其他维护者可能会有所不同。
+
+当您运行上述命令时 ``git`` 会打开编辑器要求你描述一下这个标记。在本例中您需要
+描述拉取请求,所以请概述一下包含的内容,为什么要合并,是否完成任何测试。所有
+这些信息都将留在标记中,然后在维护者合并拉取请求时保留在合并提交中。所以把它
+写好,它将永远留在内核中。
+
+正如Linus所说::
+
+ 不管怎么样,至少对我来说,重要的是 *信息* 。我需要知道我在拉取什么、
+ 为什么我要拉取。我也希望将此消息用于合并消息,因此它不仅应该对我有
+ 意义,也应该可以成为一个有意义的历史记录。
+
+ 注意,如果拉取请求有一些不寻常的地方,请详细说明。如果你修改了并非
+ 由你维护的文件,请解释 **为什么** 。我总会在差异中看到的,如果你不
+ 提的话,我只会觉得分外可疑。当你在合并窗口后给我发新东西的时候,
+ (甚至是比较重大的错误修复),不仅需要解释做了什么、为什么这么做,
+ 还请解释一下 **时间问题** 。为什么错过了合并窗口……
+
+ 我会看你写在拉取请求邮件和签名标记里面的内容,所以根据你的工作流,
+ 你可以在签名标记里面描述工作内容(也会自动放进拉取请求邮件),也
+ 可以只在标记里面放个占位符,稍后在你实际发给我拉取请求时描述工作内容。
+
+ 是的,我会编辑这些消息。部分因为我需要做一些琐碎的格式调整(整体缩进、
+ 括号等),也因为此消息可能对我有意义(描述了冲突或一些个人问题)而对
+ 合并提交信息上下文没啥意义,因此我需要尽力让它有意义起来。我也会
+ 修复一些拼写和语法错误,特别是非母语者(母语者也是;^)。但我也会删掉
+ 或增加一些内容。
+
+ Linus
+
+Greg给出了一个拉取请求的例子::
+
+ Char/Misc patches for 4.15-rc1
+
+ Here is the big char/misc patch set for the 4.15-rc1 merge window.
+ Contained in here is the normal set of new functions added to all
+ of these crazy drivers, as well as the following brand new
+ subsystems:
+ - time_travel_controller: Finally a set of drivers for the
+ latest time travel bus architecture that provides i/o to
+ the CPU before it asked for it, allowing uninterrupted
+ processing
+ - relativity_shifters: due to the affect that the
+ time_travel_controllers have on the overall system, there
+ was a need for a new set of relativity shifter drivers to
+ accommodate the newly formed black holes that would
+ threaten to suck CPUs into them. This subsystem handles
+ this in a way to successfully neutralize the problems.
+ There is a Kconfig option to force these to be enabled
+ when needed, so problems should not occur.
+
+ All of these patches have been successfully tested in the latest
+ linux-next releases, and the original problems that it found have
+ all been resolved (apologies to anyone living near Canberra for the
+ lack of the Kconfig options in the earlier versions of the
+ linux-next tree creations.)
+
+ Signed-off-by: Your-name-here <your_email@domain>
+
+
+此标记消息格式就像一个git提交。顶部有一行“总结标题”, 一定要在下面sign-off。
+
+现在您已经有了一个本地签名标记,您需要将它推送到可以被拉取的位置::
+
+ git push origin char-misc-4.15-rc1
+
+
+创建拉取请求
+------------
+
+最后要做的是创建拉取请求消息。可以使用 ``git request-pull`` 命令让 ``git``
+为你做这件事,但它需要确定你想拉取什么,以及拉取针对的基础(显示正确的拉取
+更改和变更状态)。以下命令将生成一个拉取请求::
+
+ git request-pull master git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git/ char-misc-4.15-rc1
+
+引用Greg的话::
+
+ 此命令要求git比较从“char-misc-4.15-rc1”标记位置到“master”分支头(上述
+ 例子中指向了我从Linus的树分叉的地方,通常是-rc发布)的差异,并去使用
+ git:// 协议拉取。如果你希望使用 https:// 协议,也可以用在这里(但是请
+ 注意,部分人由于防火墙问题没法用https协议拉取)。
+
+ 如果char-misc-4.15-rc1标记没有出现在我要求拉取的仓库中,git会提醒
+ 它不在那里,所以记得推送到公开地方。
+
+ “git request-pull”会包含git树的地址和需要拉取的特定标记,以及标记
+ 描述全文(详尽描述标记)。同时它也会创建此拉取请求的差异状态和单个
+ 提交的缩短日志。
+
+Linus回复说他倾向于 ``git://`` 协议。其他维护者可能有不同的偏好。另外,请注意
+如果你创建的拉取请求没有签名标记, ``https://`` 可能是更好的选择。完整的讨论
+请看原邮件。
+
+
+提交拉取请求
+------------
+
+拉取请求的提交方式与普通补丁相同。向维护人员发送内联电子邮件并抄送LKML以及
+任何必要特定子系统的列表。对Linus的拉取请求通常有如下主题行::
+
+ [GIT PULL] <subsystem> changes for v4.15-rc1
diff --git a/Documentation/translations/zh_CN/maintainer/rebasing-and-merging.rst b/Documentation/translations/zh_CN/maintainer/rebasing-and-merging.rst
new file mode 100644
index 000000000000..83b7dabfe88b
--- /dev/null
+++ b/Documentation/translations/zh_CN/maintainer/rebasing-and-merging.rst
@@ -0,0 +1,165 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/maintainer/rebasing-and-merging.rst
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+==========
+变基与合并
+==========
+
+一般来说,维护子系统需要熟悉Git源代码管理系统。Git是一个功能强大的工具,有
+很多功能;就像这类工具常出现的情况一样,使用这些功能的方法有对有错。本文档
+特别介绍了变基与合并的用法。维护者经常在错误使用这些工具时遇到麻烦,但避免
+问题实际上并不那么困难。
+
+总的来说,需要注意的一点是:与许多其他项目不同,内核社区并不害怕在其开发历史
+中看到合并提交。事实上,考虑到该项目的规模,避免合并几乎是不可能的。维护者会
+在希望避免合并时遇到一些问题,而过于频繁的合并也会带来另一些问题。
+
+变基
+====
+
+“变基(Rebase)”是更改存储库中一系列提交的历史记录的过程。有两种不同型的操作
+都被称为变基,因为这两种操作都使用 ``git rebase`` 命令,但它们之间存在显著
+差异:
+
+ - 更改一系列补丁的父提交(起始提交)。例如,变基操作可以将基于上一内核版本
+ 的一个补丁集重建到当前版本上。在下面的讨论中,我们将此操作称为“变根”。
+
+ - 通过修复(或删除)损坏的提交、添加补丁、添加标记以更改一系列补丁的历史,
+ 来提交变更日志或更改已应用提交的顺序。在下文中,这种类型的操作称为“历史
+ 修改”
+
+术语“变基”将用于指代上述两种操作。如果使用得当,变基可以产生更清晰、更整洁的
+开发历史;如果使用不当,它可能会模糊历史并引入错误。
+
+以下一些经验法则可以帮助开发者避免最糟糕的变基风险:
+
+ - 已经发布到你私人系统之外世界的历史通常不应更改。其他人可能会拉取你的树
+ 的副本,然后基于它进行工作;修改你的树会给他们带来麻烦。如果工作需要变基,
+ 这通常是表明它还没有准备好提交到公共存储库的信号。
+
+ 但是,总有例外。有些树(linux-next是一个典型的例子)由于它们的需要经常
+ 变基,开发人员知道不要基于它们来工作。开发人员有时会公开一个不稳定的分支,
+ 供其他人或自动测试服务进行测试。如果您确实以这种方式公开了一个可能不稳定
+ 的分支,请确保潜在使用者知道不要基于它来工作。
+
+ - 不要在包含由他人创建的历史的分支上变基。如果你从别的开发者的仓库拉取了变更,
+ 那你现在就成了他们历史记录的保管人。你不应该改变它,除了少数例外情况。例如
+ 树中有问题的提交必须显式恢复(即通过另一个补丁修复),而不是通过修改历史而
+ 消失。
+
+ - 没有合理理由,不要对树变根。仅为了切换到更新的基或避免与上游储存库的合并
+ 通常不是合理理由。
+
+ - 如果你必须对储存库进行变根,请不要随机选取一个提交作为新基。在发布节点之间
+ 内核通常处于一个相对不稳定的状态;基于其中某点进行开发会增加遇到意外错误的
+ 几率。当一系列补丁必须移动到新基时,请选择移动到一个稳定节点(例如-rc版本
+ 节点)。
+
+ - 请知悉对补丁系列进行变根(或做明显的历史修改)会改变它们的开发环境,且很
+ 可能使做过的大部分测试失效。一般来说,变基后的补丁系列应当像新代码一样对
+ 待,并重新测试。
+
+合并窗口麻烦的一个常见原因是,Linus收到了一个明显在拉取请求发送之前不久才变根
+(通常是变根到随机的提交上)的补丁系列。这样一个系列被充分测试的可能性相对较
+低,拉取请求被接受的几率也同样较低。
+
+相反,如果变基仅限于私有树、提交基于一个通用的起点、且经过充分测试,则引起
+麻烦的可能性就很低。
+
+合并
+====
+
+内核开发过程中,合并是一个很常见的操作;5.1版本开发周期中有超过1126个合并
+——差不多占了整体的9%。内核开发工作积累在100多个不同的子系统树中,每个
+子系统树都可能包含多个主题分支;每个分支通常独立于其他分支进行开发。因此
+在任何给定分支进入上游储存库之前,至少需要一次合并。
+
+许多项目要求拉取请求中的分支基于当前主干,这样历史记录中就不会出现合并提交。
+内核并不是这样;任何为了避免合并而重新对分支变基都很可能导致麻烦。
+
+子系统维护人员发现他们必须进行两种类型的合并:从较低层级的子系统树和从其他
+子系统树(同级树或主线)进行合并。这两种情况下要遵循的最佳实践是不同的。
+
+合并较低层级树
+--------------
+
+较大的子系统往往有多个级别的维护人员,较低级别的维护人员向较高级别发送拉取
+请求。合并这样的请求执行几乎肯定会生成一个合并提交;这也是应该的。实际上,
+子系统维护人员可能希望在极少数快进合并情况下使用 ``-–no-ff`` 标志来强制添加
+合并提交,以便记录合并的原因。 **任何** 类型的合并的变更日志必须说明
+*为什么* 合并。对于较低级别的树,“为什么”通常是对该取所带来的变化的总结。
+
+各级维护人员都应在他们的拉取请求上使用经签名的标签,上游维护人员应在拉取分支
+时验证标签。不这样做会威胁整个开发过程的安全。
+
+根据上面列出的规则,一旦您将其他人的历史记录合并到树中,您就不得对该分支进行
+变基,即使您能够这样做。
+
+合并同级树或上游树
+------------------
+
+虽然来自下游的合并是常见且不起眼的,但当需要将一个分支推向上游时,其中来自
+其他树的合并往往是一个危险信号。这种合并需要仔细考虑并加以充分证明,否则后续
+的拉取请求很可能会被拒绝。
+
+想要将主分支合并到存储库中是很自然的;这种类型的合并通常被称为“反向合并”
+。反向合并有助于确保与并行的开发没有冲突,并且通常会给人一种温暖、舒服的
+感觉,即处于最新。但这种诱惑几乎总是应该避免的。
+
+为什么呢?反向合并将搅乱你自己分支的开发历史。它们会大大增加你遇到来自社区
+其他地方的错误的机会,且使你很难确保你所管理的工作稳定并准备好合入上游。
+频繁的合并还可以掩盖树中开发过程中的问题;它们会隐藏与其他树的交互,而这些
+交互不应该(经常)发生在管理良好的分支中。
+
+也就是说,偶尔需要进行反向合并;当这种情况发生时,一定要在提交信息中记录
+*为什么* 。同样,在一个众所周知的稳定点进行合并,而不是随机提交。即使这样,
+你也不应该反向合并一棵比你的直接上游树更高层级的树;如果确实需要更高级别的
+反向合并,应首先在上游树进行。
+
+导致合并相关问题最常见的原因之一是:在发送拉取请求之前维护者合并上游以解决
+合并冲突。同样,这种诱惑很容易理解,但绝对应该避免。对于最终拉取请求来说
+尤其如此:Linus坚信他更愿意看到合并冲突,而不是不必要的反向合并。看到冲突
+可以让他了解潜在的问题所在。他做过很多合并(在5.1版本开发周期中是382次),
+而且在解决冲突方面也很在行——通常比参与的开发人员要强。
+
+那么,当他们的子系统分支和主线之间发生冲突时,维护人员应该怎么做呢?最重要
+的一步是在拉取请求中提示Linus会发生冲突;如果啥都没说则表明您的分支可以正常
+合入。对于特别困难的冲突,创建并推送一个 *独立* 分支来展示你将如何解决问题。
+在拉取请求中提到该分支,但是请求本身应该针对未合并的分支。
+
+即使不存在已知冲突,在发送拉取请求之前进行合并测试也是个好主意。它可能会提醒
+您一些在linux-next树中没有发现的问题,并帮助您准确地理解您正在要求上游做什么。
+
+合并上游树或另一个子系统树的另一个原因是解决依赖关系。这些依赖性问题有时确实
+会发生,而且有时与另一棵树交叉合并是解决这些问题的最佳方法;同样,在这种情况
+下,合并提交应该解释为什么要进行合并。花点时间把它做好;会有人阅读这些变更
+日志。
+
+然而依赖性问题通常表明需要改变方法。合并另一个子系统树以解决依赖性风险会带来
+其他缺陷,几乎永远不应这样做。如果该子系统树无法被合到上游,那么它的任何问题
+也都会阻碍你的树合并。更可取的选择包括与维护人员达成一致意见,在其中一个树中
+同时进行两组更改;或者创建一个主题分支专门处理可以合并到两个树中的先决条件提交。
+如果依赖关系与主要的基础结构更改相关,正确的解决方案可能是将依赖提交保留一个
+开发周期,以便这些更改有时间在主线上稳定。
+
+最后
+====
+
+在开发周期的开头合并主线是比较常见的,可以获取树中其他地方的更改和修复。同样,
+这样的合并应该选择一个众所周知的发布点,而不是一些随机点。如果在合并窗口期间
+上游分支已完全清空到主线中,则可以使用以下命令向前拉取它::
+
+ git merge v5.2-rc1^0
+
+“^0”使Git执行快进合并(在这种情况下这应该可以),从而避免多余的虚假合并提交。
+
+上面列出的就是指导方针了。总是会有一些情况需要不同的解决方案,这些指导原则
+不应阻止开发人员在需要时做正确的事情。但是,我们应该时刻考虑是否真的出现了
+这样的需求,并准备好解释为什么需要做一些不寻常的事情。
diff --git a/Documentation/translations/zh_CN/mm/active_mm.rst b/Documentation/translations/zh_CN/mm/active_mm.rst
new file mode 100644
index 000000000000..c2816f523bd7
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/active_mm.rst
@@ -0,0 +1,85 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/mm/active_mm.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+=========
+Active MM
+=========
+
+这是一封linux之父回复开发者的一封邮件,所以翻译时我尽量保持邮件格式的完整。
+
+::
+
+ List: linux-kernel
+ Subject: Re: active_mm
+ From: Linus Torvalds <torvalds () transmeta ! com>
+ Date: 1999-07-30 21:36:24
+
+ 因为我并不经常写解释,所以已经抄送到linux-kernel邮件列表,而当我做这些,
+ 且更多的人在阅读它们时,我觉得棒极了。
+
+ 1999年7月30日 星期五, David Mosberger 写道:
+ >
+ > 是否有一个简短的描述,说明task_struct中的
+ > "mm" 和 "active_mm"应该如何使用? (如果
+ > 这个问题在邮件列表中讨论过,我表示歉意--我刚
+ > 刚度假回来,有一段时间没能关注linux-kernel了)。
+
+ 基本上,新的设定是:
+
+ - 我们有“真实地址空间”和“匿名地址空间”。区别在于,匿名地址空间根本不关心用
+ 户级页表,所以当我们做上下文切换到匿名地址空间时,我们只是让以前的地址空间
+ 处于活动状态。
+
+ 一个“匿名地址空间”的明显用途是任何不需要任何用户映射的线程--所有的内核线
+ 程基本上都属于这一类,但即使是“真正的”线程也可以暂时说在一定时间内它们不
+ 会对用户空间感兴趣,调度器不妨试着避免在切换VM状态上浪费时间。目前只有老
+ 式的bdflush sync能做到这一点。
+
+ - “tsk->mm” 指向 “真实地址空间”。对于一个匿名进程来说,tsk->mm将是NULL,
+ 其逻辑原因是匿名进程实际上根本就 “没有” 真正的地址空间。
+
+ - 然而,我们显然需要跟踪我们为这样的匿名用户“偷用”了哪个地址空间。为此,我们
+ 有 “tsk->active_mm”,它显示了当前活动的地址空间是什么。
+
+ 规则是,对于一个有真实地址空间的进程(即tsk->mm是 non-NULL),active_mm
+ 显然必须与真实的mm相同。
+
+ 对于一个匿名进程,tsk->mm == NULL,而tsk->active_mm是匿名进程运行时
+ “借用”的mm。当匿名进程被调度走时,借用的地址空间被返回并清除。
+
+ 为了支持所有这些,“struct mm_struct”现在有两个计数器:一个是 “mm_users”
+ 计数器,即有多少 “真正的地址空间用户”,另一个是 “mm_count”计数器,即 “lazy”
+ 用户(即匿名用户)的数量,如果有任何真正的用户,则加1。
+
+ 通常情况下,至少有一个真正的用户,但也可能是真正的用户在另一个CPU上退出,而
+ 一个lazy的用户仍在活动,所以你实际上得到的情况是,你有一个地址空间 **只**
+ 被lazy的用户使用。这通常是一个短暂的生命周期状态,因为一旦这个线程被安排给一
+ 个真正的线程,这个 “僵尸” mm就会被释放,因为 “mm_count”变成了零。
+
+ 另外,一个新的规则是,**没有人** 再把 “init_mm” 作为一个真正的MM了。
+ “init_mm”应该被认为只是一个 “没有其他上下文时的lazy上下文”,事实上,它主
+ 要是在启动时使用,当时还没有真正的VM被创建。因此,用来检查的代码
+
+ if (current->mm == &init_mm)
+
+ 一般来说,应该用
+
+ if (!current->mm)
+
+ 取代上面的写法(这更有意义--测试基本上是 “我们是否有一个用户环境”,并且通常
+ 由缺页异常处理程序和类似的东西来完成)。
+
+ 总之,我刚才在ftp.kernel.org上放了一个pre-patch-2.3.13-1,因为它稍微改
+ 变了接口以适配alpha(谁会想到呢,但alpha体系结构上下文切换代码实际上最终是
+ 最丑陋的之一--不像其他架构的MM和寄存器状态是分开的,alpha的PALcode将两者
+ 连接起来,你需要同时切换两者)。
+
+ (文档来源 http://marc.info/?l=linux-kernel&m=93337278602211&w=2)
diff --git a/Documentation/translations/zh_CN/mm/balance.rst b/Documentation/translations/zh_CN/mm/balance.rst
new file mode 100644
index 000000000000..6fd79209c307
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/balance.rst
@@ -0,0 +1,81 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/mm/balance.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+========
+内存平衡
+========
+
+2000年1月开始,作者:Kanoj Sarcar <kanoj@sgi.com>
+
+对于 !__GFP_HIGH 和 !__GFP_KSWAPD_RECLAIM 以及非 __GFP_IO 的分配,需要进行
+内存平衡。
+
+调用者避免回收的第一个原因是调用者由于持有自旋锁或处于中断环境中而无法睡眠。第二个
+原因可能是,调用者愿意在不产生页面回收开销的情况下分配失败。这可能发生在有0阶回退
+选项的机会主义高阶分配请求中。在这种情况下,调用者可能也希望避免唤醒kswapd。
+
+__GFP_IO分配请求是为了防止文件系统死锁。
+
+在没有非睡眠分配请求的情况下,做平衡似乎是有害的。页面回收可以被懒散地启动,也就是
+说,只有在需要的时候(也就是区域的空闲内存为0),而不是让它成为一个主动的过程。
+
+也就是说,内核应该尝试从直接映射池中满足对直接映射页的请求,而不是回退到dma池中,
+这样就可以保持dma池为dma请求(不管是不是原子的)所填充。类似的争论也适用于高内存
+和直接映射的页面。相反,如果有很多空闲的dma页,最好是通过从dma池中分配一个来满足
+常规的内存请求,而不是产生常规区域平衡的开销。
+
+在2.2中,只有当空闲页总数低于总内存的1/64时,才会启动内存平衡/页面回收。如果dma
+和常规内存的比例合适,即使dma区完全空了,也很可能不会进行平衡。2.2已经在不同内存
+大小的生产机器上运行,即使有这个问题存在,似乎也做得不错。在2.3中,由于HIGHMEM的
+存在,这个问题变得更加严重。
+
+在2.3中,区域平衡可以用两种方式之一来完成:根据区域的大小(可能是低级区域的大小),
+我们可以在初始化阶段决定在平衡任何区域时应该争取多少空闲页。好的方面是,在平衡的时
+候,我们不需要看低级区的大小,坏的方面是,我们可能会因为忽略低级区可能较低的使用率
+而做过于频繁的平衡。另外,只要对分配程序稍作修改,就有可能将memclass()宏简化为一
+个简单的等式。
+
+另一个可能的解决方案是,我们只在一个区 **和** 其所有低级区的空闲内存低于该区及其
+低级区总内存的1/64时进行平衡。这就解决了2.2的平衡问题,并尽可能地保持了与2.2行为
+的接近。另外,平衡算法在各种架构上的工作方式也是一样的,这些架构有不同数量和类型的
+内存区。如果我们想变得更花哨一点,我们可以在未来为不同区域的自由页面分配不同的权重。
+
+请注意,如果普通区的大小与dma区相比是巨大的,那么在决定是否平衡普通区的时候,考虑
+空闲的dma页就变得不那么重要了。那么第一个解决方案就变得更有吸引力。
+
+所附的补丁实现了第二个解决方案。它还 “修复”了两个问题:首先,在低内存条件下,kswapd
+被唤醒,就像2.2中的非睡眠分配。第二,HIGHMEM区也被平衡了,以便给replace_with_highmem()
+一个争取获得HIGHMEM页的机会,同时确保HIGHMEM分配不会落回普通区。这也确保了HIGHMEM
+页不会被泄露(例如,在一个HIGHMEM页在交换缓存中但没有被任何人使用的情况下)。
+
+kswapd还需要知道它应该平衡哪些区。kswapd主要是在无法进行平衡的情况下需要的,可能
+是因为所有的分配请求都来自中断上下文,而所有的进程上下文都在睡眠。对于2.3,
+kswapd并不真正需要平衡高内存区,因为中断上下文并不请求高内存页。kswapd看zone
+结构体中的zone_wake_kswapd字段来决定一个区是否需要平衡。
+
+如果从进程内存和shm中偷取页面可以减轻该页面节点中任何区的内存压力,而该区的内存压力
+已经低于其水位,则会进行偷取。
+
+watemark[WMARK_MIN/WMARK_LOW/WMARK_HIGH]/low_on_memory/zone_wake_kswapd:
+这些是每个区的字段,用于确定一个区何时需要平衡。当页面数低于水位[WMARK_MIN]时,
+hysteric 的字段low_on_memory被设置。这个字段会一直被设置,直到空闲页数变成水位
+[WMARK_HIGH]。当low_on_memory被设置时,页面分配请求将尝试释放该区域的一些页面(如果
+请求中设置了GFP_WAIT)。与此相反的是,决定唤醒kswapd以释放一些区的页。这个决定不是基于
+hysteresis 的,而是当空闲页的数量低于watermark[WMARK_LOW]时就会进行;在这种情况下,
+zone_wake_kswapd也被设置。
+
+
+我所听到的(超棒的)想法:
+
+1. 动态经历应该影响平衡:可以跟踪一个区的失败请求的数量,并反馈到平衡方案中(jalvo@mbay.net)。
+
+2. 实现一个类似于replace_with_highmem()的replace_with_regular(),以保留dma页面。
+ (lkd@tantalophile.demon.co.uk)
diff --git a/Documentation/translations/zh_CN/mm/damon/api.rst b/Documentation/translations/zh_CN/mm/damon/api.rst
new file mode 100644
index 000000000000..5593a83c86bc
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/damon/api.rst
@@ -0,0 +1,32 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+:Original: Documentation/mm/damon/api.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+=======
+API参考
+=======
+
+内核空间的程序可以使用下面的API来使用DAMON的每个功能。你所需要做的就是引用 ``damon.h`` ,
+它位于源代码树的include/linux/。
+
+结构体
+======
+
+该API在以下内核代码中:
+
+include/linux/damon.h
+
+
+函数
+====
+
+该API在以下内核代码中:
+
+mm/damon/core.c
diff --git a/Documentation/translations/zh_CN/mm/damon/design.rst b/Documentation/translations/zh_CN/mm/damon/design.rst
new file mode 100644
index 000000000000..16e3db34a7dd
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/damon/design.rst
@@ -0,0 +1,140 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+:Original: Documentation/mm/damon/design.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+====
+设计
+====
+
+可配置的层
+==========
+
+DAMON提供了数据访问监控功能,同时使其准确性和开销可控。基本的访问监控需要依赖于目标地址空间
+并为之优化的基元。另一方面,作为DAMON的核心,准确性和开销的权衡机制是在纯逻辑空间中。DAMON
+将这两部分分离在不同的层中,并定义了它的接口,以允许各种低层次的基元实现与核心逻辑的配置。
+
+由于这种分离的设计和可配置的接口,用户可以通过配置核心逻辑和适当的低级基元实现来扩展DAMON的
+任何地址空间。如果没有提供合适的,用户可以自己实现基元。
+
+例如,物理内存、虚拟内存、交换空间、那些特定的进程、NUMA节点、文件和支持的内存设备将被支持。
+另外,如果某些架构或设备支持特殊的优化访问检查基元,这些基元将很容易被配置。
+
+
+特定地址空间基元的参考实现
+==========================
+
+基本访问监测的低级基元被定义为两部分。:
+
+1. 确定地址空间的监测目标地址范围
+2. 目标空间中特定地址范围的访问检查。
+
+DAMON目前为物理和虚拟地址空间提供了基元的实现。下面两个小节描述了这些工作的方式。
+
+
+基于VMA的目标地址范围构造
+-------------------------
+
+这仅仅是针对虚拟地址空间基元的实现。对于物理地址空间,只是要求用户手动设置监控目标地址范围。
+
+在进程的超级巨大的虚拟地址空间中,只有小部分被映射到物理内存并被访问。因此,跟踪未映射的地
+址区域只是一种浪费。然而,由于DAMON可以使用自适应区域调整机制来处理一定程度的噪声,所以严
+格来说,跟踪每一个映射并不是必须的,但在某些情况下甚至会产生很高的开销。也就是说,监测目标
+内部过于巨大的未映射区域应该被移除,以不占用自适应机制的时间。
+
+出于这个原因,这个实现将复杂的映射转换为三个不同的区域,覆盖地址空间的每个映射区域。这三个
+区域之间的两个空隙是给定地址空间中两个最大的未映射区域。这两个最大的未映射区域是堆和最上面
+的mmap()区域之间的间隙,以及在大多数情况下最下面的mmap()区域和堆之间的间隙。因为这些间隙
+在通常的地址空间中是异常巨大的,排除这些间隙就足以做出合理的权衡。下面详细说明了这一点::
+
+ <heap>
+ <BIG UNMAPPED REGION 1>
+ <uppermost mmap()-ed region>
+ (small mmap()-ed regions and munmap()-ed regions)
+ <lowermost mmap()-ed region>
+ <BIG UNMAPPED REGION 2>
+ <stack>
+
+
+基于PTE访问位的访问检查
+-----------------------
+
+物理和虚拟地址空间的实现都使用PTE Accessed-bit进行基本访问检查。唯一的区别在于从地址中
+找到相关的PTE访问位的方式。虚拟地址的实现是为该地址的目标任务查找页表,而物理地址的实现则
+是查找与该地址有映射关系的每一个页表。通过这种方式,实现者找到并清除下一个采样目标地址的位,
+并检查该位是否在一个采样周期后再次设置。这可能会干扰其他使用访问位的内核子系统,即空闲页跟
+踪和回收逻辑。为了避免这种干扰,DAMON使其与空闲页面跟踪相互排斥,并使用 ``PG_idle`` 和
+``PG_young`` 页面标志来解决与回收逻辑的冲突,就像空闲页面跟踪那样。
+
+
+独立于地址空间的核心机制
+========================
+
+下面四个部分分别描述了DAMON的核心机制和五个监测属性,即 ``采样间隔`` 、 ``聚集间隔`` 、
+``更新间隔`` 、 ``最小区域数`` 和 ``最大区域数`` 。
+
+
+访问频率监测
+------------
+
+DAMON的输出显示了在给定的时间内哪些页面的访问频率是多少。访问频率的分辨率是通过设置
+``采样间隔`` 和 ``聚集间隔`` 来控制的。详细地说,DAMON检查每个 ``采样间隔`` 对每
+个页面的访问,并将结果汇总。换句话说,计算每个页面的访问次数。在每个 ``聚合间隔`` 过
+去后,DAMON调用先前由用户注册的回调函数,以便用户可以阅读聚合的结果,然后再清除这些结
+果。这可以用以下简单的伪代码来描述::
+
+ while monitoring_on:
+ for page in monitoring_target:
+ if accessed(page):
+ nr_accesses[page] += 1
+ if time() % aggregation_interval == 0:
+ for callback in user_registered_callbacks:
+ callback(monitoring_target, nr_accesses)
+ for page in monitoring_target:
+ nr_accesses[page] = 0
+ sleep(sampling interval)
+
+这种机制的监测开销将随着目标工作负载规模的增长而任意增加。
+
+
+基于区域的抽样调查
+------------------
+
+为了避免开销的无限制增加,DAMON将假定具有相同访问频率的相邻页面归入一个区域。只要保持
+这个假设(一个区域内的页面具有相同的访问频率),该区域内就只需要检查一个页面。因此,对
+于每个 ``采样间隔`` ,DAMON在每个区域中随机挑选一个页面,等待一个 ``采样间隔`` ,检
+查该页面是否同时被访问,如果被访问则增加该区域的访问频率。因此,监测开销是可以通过设置
+区域的数量来控制的。DAMON允许用户设置最小和最大的区域数量来进行权衡。
+
+然而,如果假设没有得到保证,这个方案就不能保持输出的质量。
+
+
+适应性区域调整
+--------------
+
+即使最初的监测目标区域被很好地构建以满足假设(同一区域内的页面具有相似的访问频率),数
+据访问模式也会被动态地改变。这将导致监测质量下降。为了尽可能地保持假设,DAMON根据每个
+区域的访问频率自适应地进行合并和拆分。
+
+对于每个 ``聚集区间`` ,它比较相邻区域的访问频率,如果频率差异较小,就合并这些区域。
+然后,在它报告并清除每个区域的聚合接入频率后,如果区域总数不超过用户指定的最大区域数,
+它将每个区域拆分为两个或三个区域。
+
+通过这种方式,DAMON提供了其最佳的质量和最小的开销,同时保持了用户为其权衡设定的界限。
+
+
+动态目标空间更新处理
+--------------------
+
+监测目标地址范围可以动态改变。例如,虚拟内存可以动态地被映射和解映射。物理内存可以被
+热插拔。
+
+由于在某些情况下变化可能相当频繁,DAMON允许监控操作检查动态变化,包括内存映射变化,
+并仅在用户指定的时间间隔( ``更新间隔`` )中的每个时间段,将其应用于监控操作相关的
+数据结构,如抽象的监控目标内存区。 \ No newline at end of file
diff --git a/Documentation/translations/zh_CN/mm/damon/faq.rst b/Documentation/translations/zh_CN/mm/damon/faq.rst
new file mode 100644
index 000000000000..de4be417494a
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/damon/faq.rst
@@ -0,0 +1,48 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+:Original: Documentation/mm/damon/faq.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+========
+常见问题
+========
+
+为什么是一个新的子系统,而不是扩展perf或其他用户空间工具?
+==========================================================
+
+首先,因为它需要尽可能的轻量级,以便可以在线使用,所以应该避免任何不必要的开销,如内核-用户
+空间的上下文切换成本。第二,DAMON的目标是被包括内核在内的其他程序所使用。因此,对特定工具
+(如perf)的依赖性是不可取的。这就是DAMON在内核空间实现的两个最大的原因。
+
+
+“闲置页面跟踪” 或 “perf mem” 可以替代DAMON吗?
+==============================================
+
+闲置页跟踪是物理地址空间访问检查的一个低层次的原始方法。“perf mem”也是类似的,尽管它可以
+使用采样来减少开销。另一方面,DAMON是一个更高层次的框架,用于监控各种地址空间。它专注于内
+存管理优化,并提供复杂的精度/开销处理机制。因此,“空闲页面跟踪” 和 “perf mem” 可以提供
+DAMON输出的一个子集,但不能替代DAMON。
+
+
+DAMON是否只支持虚拟内存?
+=========================
+
+不,DAMON的核心是独立于地址空间的。用户可以在DAMON核心上实现和配置特定地址空间的低级原始
+部分,包括监测目标区域的构造和实际的访问检查。通过这种方式,DAMON用户可以用任何访问检查技
+术来监测任何地址空间。
+
+尽管如此,DAMON默认为虚拟内存和物理内存提供了基于vma/rmap跟踪和PTE访问位检查的地址空间
+相关功能的实现,以供参考和方便使用。
+
+
+我可以简单地监测页面的粒度吗?
+==============================
+
+是的,你可以通过设置 ``min_nr_regions`` 属性高于工作集大小除以页面大小的值来实现。
+因为监视目标区域的大小被强制为 ``>=page size`` ,所以区域分割不会产生任何影响。
diff --git a/Documentation/translations/zh_CN/mm/damon/index.rst b/Documentation/translations/zh_CN/mm/damon/index.rst
new file mode 100644
index 000000000000..b03bf307204f
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/damon/index.rst
@@ -0,0 +1,32 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+:Original: Documentation/mm/damon/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+==========================
+DAMON:数据访问监视器
+==========================
+
+DAMON是Linux内核的一个数据访问监控框架子系统。DAMON的核心机制使其成为
+(该核心机制详见(Documentation/translations/zh_CN/mm/damon/design.rst))
+
+ - *准确度* (监测输出对DRAM级别的内存管理足够有用;但可能不适合CPU Cache级别),
+ - *轻量级* (监控开销低到可以在线应用),以及
+ - *可扩展* (无论目标工作负载的大小,开销的上限值都在恒定范围内)。
+
+因此,利用这个框架,内核的内存管理机制可以做出高级决策。会导致高数据访问监控开销的实
+验性内存管理优化工作可以再次进行。同时,在用户空间,有一些特殊工作负载的用户可以编写
+个性化的应用程序,以便更好地了解和优化他们的工作负载和系统。
+
+.. toctree::
+ :maxdepth: 2
+
+ faq
+ design
+ api
diff --git a/Documentation/translations/zh_CN/mm/free_page_reporting.rst b/Documentation/translations/zh_CN/mm/free_page_reporting.rst
new file mode 100644
index 000000000000..5bfd58014c94
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/free_page_reporting.rst
@@ -0,0 +1,38 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/mm/free_page_reporting.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+==========
+空闲页报告
+==========
+
+空闲页报告是一个API,设备可以通过它来注册接收系统当前未使用的页面列表。这在虚拟
+化的情况下是很有用的,客户机能够使用这些数据来通知管理器它不再使用内存中的某些页
+面。
+
+对于驱动,通常是气球驱动要使用这个功能,它将分配和初始化一个page_reporting_dev_info
+结构体。它要填充的结构体中的字段是用于处理散点列表的 "report" 函数指针。它还必
+须保证每次调用该函数时能处理至少相当于PAGE_REPORTING_CAPACITY的散点列表条目。
+假设没有其他页面报告设备已经注册, 对page_reporting_register的调用将向报告框
+架注册页面报告接口。
+
+一旦注册,页面报告API将开始向驱动报告成批的页面。API将在接口被注册后2秒开始报告
+页面,并在任何足够高的页面被释放之后2秒继续报告。
+
+报告的页面将被存储在传递给报告函数的散列表中,最后一个条目的结束位被设置在条目
+nent-1中。 当页面被报告函数处理时,分配器将无法访问它们。一旦报告函数完成,这些
+页将被返回到它们所获得的自由区域。
+
+在移除使用空闲页报告的驱动之前,有必要调用page_reporting_unregister,以移除
+目前被空闲页报告使用的page_reporting_dev_info结构体。这样做将阻止进一步的报
+告通过该接口发出。如果另一个驱动或同一驱动被注册,它就有可能恢复前一个驱动在报告
+空闲页方面的工作。
+
+
+Alexander Duyck, 2019年12月04日
diff --git a/Documentation/translations/zh_CN/mm/highmem.rst b/Documentation/translations/zh_CN/mm/highmem.rst
new file mode 100644
index 000000000000..2c0ee0cbf5c4
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/highmem.rst
@@ -0,0 +1,151 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/mm/highmem.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+==========
+高内存处理
+==========
+
+作者: Peter Zijlstra <a.p.zijlstra@chello.nl>
+
+.. contents:: :local:
+
+高内存是什么?
+==============
+
+当物理内存的大小接近或超过虚拟内存的最大大小时,就会使用高内存(highmem)。在这一点上,内
+核不可能在任何时候都保持所有可用的物理内存的映射。这意味着内核需要开始使用它想访问的物理内
+存的临时映射。
+
+没有被永久映射覆盖的那部分(物理)内存就是我们所说的 "高内存"。对于这个边界的确切位置,有
+各种架构上的限制。
+
+例如,在i386架构中,我们选择将内核映射到每个进程的虚拟空间,这样我们就不必为内核的进入/退
+出付出全部的TLB作废代价。这意味着可用的虚拟内存空间(i386上为4GiB)必须在用户和内核空间之
+间进行划分。
+
+使用这种方法的架构的传统分配方式是3:1,3GiB用于用户空间,顶部的1GiB用于内核空间。::
+
+ +--------+ 0xffffffff
+ | Kernel |
+ +--------+ 0xc0000000
+ | |
+ | User |
+ | |
+ +--------+ 0x00000000
+
+这意味着内核在任何时候最多可以映射1GiB的物理内存,但是由于我们需要虚拟地址空间来做其他事
+情--包括访问其余物理内存的临时映射--实际的直接映射通常会更少(通常在~896MiB左右)。
+
+其他有mm上下文标签的TLB的架构可以有独立的内核和用户映射。然而,一些硬件(如一些ARM)在使
+用mm上下文标签时,其虚拟空间有限。
+
+
+临时虚拟映射
+============
+
+内核包含几种创建临时映射的方法。下面的列表按照使用的优先顺序显示了它们。
+
+* kmap_local_page()。这个函数是用来要求短期映射的。它可以从任何上下文(包括中断)中调用,
+ 但是映射只能在获取它们的上下文中使用。
+
+ 在可行的情况下,这个函数应该比其他所有的函数优先使用。
+
+ 这些映射是线程本地和CPU本地的,这意味着映射只能从这个线程中访问,并且当映射处于活跃状
+ 态时,线程被绑定到CPU上。尽管这个函数从来没有禁用过抢占,但在映射被处理之前,CPU不能
+ 通过CPU-hotplug从系统中拔出。
+
+ 在本地的kmap区域中采取pagefaults是有效的,除非获取本地映射的上下文由于其他原因不允许
+ 这样做。
+
+ 如前所述,缺页异常和抢占从未被禁用。没有必要禁用抢占,因为当上下文切换到一个不同的任务
+ 时,离开的任务的映射被保存,而进入的任务的映射被恢复。
+
+ kmap_local_page()总是返回一个有效的虚拟地址,并且假定kunmap_local()不会失败。
+
+ 在CONFIG_HIGHMEM=n的内核中,对于低内存页,它返回直接映射的虚拟地址。只有真正的高内
+ 存页面才会被临时映射。因此,用户可以为那些已知不是来自ZONE_HIGHMEM的页面调用普通的
+ page_address()。然而,使用kmap_local_page() / kunmap_local()总是安全的。
+
+ 虽然它比kmap()快得多,但在高内存的情况下,它对指针的有效性有限制。与kmap()映射相反,
+ 本地映射只在调用者的上下文中有效,不能传递给其他上下文。这意味着用户必须绝对保证返回
+ 地址的使用只限于映射它的线程。
+
+ 大多数代码可以被设计成使用线程本地映射。因此,用户在设计他们的代码时,应该尽量避免使用
+ kmap(),将页面映射到将被使用的同一线程中,并优先使用kmap_local_page()。
+
+ 嵌套kmap_local_page()和kmap_atomic()映射在一定程度上是允许的(最多到KMAP_TYPE_NR),
+ 但是它们的调用必须严格排序,因为映射的实现是基于堆栈的。关于如何管理嵌套映射的细节,
+ 请参见kmap_local_page() kdocs(包含在 "函数 "部分)。
+
+* kmap_atomic(). 这允许对单个页面进行非常短的时间映射。由于映射被限制在发布它的CPU上,
+ 它表现得很好,但发布的任务因此被要求留在该CPU上直到它完成,以免其他任务取代它的映射。
+
+ kmap_atomic()也可以被中断上下文使用,因为它不睡眠,调用者也可能在调用kunmap_atomic()
+ 后才睡眠。
+
+ 内核中对kmap_atomic()的每次调用都会创建一个不可抢占的段,并禁用缺页异常。这可能是
+ 未预期延迟的来源之一。因此用户应该选择kmap_local_page()而不是kmap_atomic()。
+
+ 假设k[un]map_atomic()不会失败。
+
+* kmap()。这应该被用来对单个页面进行短时间的映射,对抢占或迁移没有限制。它会带来开销,
+ 因为映射空间是受限制的,并且受到全局锁的保护,以实现同步。当不再需要映射时,必须用
+ kunmap()释放该页被映射的地址。
+
+ 映射变化必须广播到所有CPU(核)上,kmap()还需要在kmap的池被回绕(TLB项用光了,需要从第
+ 一项复用)时进行全局TLB无效化,当映射空间被完全利用时,它可能会阻塞,直到有一个可用的
+ 槽出现。因此,kmap()只能从可抢占的上下文中调用。
+
+ 如果一个映射必须持续相对较长的时间,上述所有的工作都是必要的,但是内核中大部分的
+ 高内存映射都是短暂的,而且只在一个地方使用。这意味着在这种情况下,kmap()的成本大
+ 多被浪费了。kmap()并不是为长期映射而设计的,但是它已经朝着这个方向发展了,在较新
+ 的代码中强烈不鼓励使用它,前面的函数集应该是首选。
+
+ 在64位系统中,调用kmap_local_page()、kmap_atomic()和kmap()没有实际作用,因为64位
+ 地址空间足以永久映射所有物理内存页面。
+
+* vmap()。这可以用来将多个物理页长期映射到一个连续的虚拟空间。它需要全局同步来解除
+ 映射。
+
+临时映射的成本
+==============
+
+创建临时映射的代价可能相当高。体系架构必须操作内核的页表、数据TLB和/或MMU的寄存器。
+
+如果CONFIG_HIGHMEM没有被设置,那么内核会尝试用一点计算来创建映射,将页面结构地址转换成
+指向页面内容的指针,而不是去捣鼓映射。在这种情况下,解映射操作可能是一个空操作。
+
+如果CONFIG_MMU没有被设置,那么就不可能有临时映射和高内存。在这种情况下,也将使用计算方法。
+
+
+i386 PAE
+========
+
+在某些情况下,i386 架构将允许你在 32 位机器上安装多达 64GiB 的内存。但这有一些后果:
+
+* Linux需要为系统中的每个页面建立一个页帧结构,而且页帧需要驻在永久映射中,这意味着:
+
+* 你最多可以有896M/sizeof(struct page)页帧;由于页结构体是32字节的,所以最终会有
+ 112G的页;然而,内核需要在内存中存储更多的页帧......
+
+* PAE使你的页表变大--这使系统变慢,因为更多的数据需要在TLB填充等方面被访问。一个好处
+ 是,PAE有更多的PTE位,可以提供像NX和PAT这样的高级功能。
+
+一般的建议是,你不要在32位机器上使用超过8GiB的空间--尽管更多的空间可能对你和你的工作
+量有用,但你几乎是靠你自己--不要指望内核开发者真的会很关心事情的进展情况。
+
+函数
+====
+
+该API在以下内核代码中:
+
+include/linux/highmem.h
+
+include/linux/highmem-internal.h
diff --git a/Documentation/translations/zh_CN/mm/hmm.rst b/Documentation/translations/zh_CN/mm/hmm.rst
new file mode 100644
index 000000000000..babbbe756c0f
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/hmm.rst
@@ -0,0 +1,361 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/mm/hmm.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+==================
+异构内存管理 (HMM)
+==================
+
+提供基础设施和帮助程序以将非常规内存(设备内存,如板上 GPU 内存)集成到常规内核路径中,其
+基石是此类内存的专用struct page(请参阅本文档的第 5 至 7 节)。
+
+HMM 还为 SVM(共享虚拟内存)提供了可选的帮助程序,即允许设备透明地访问与 CPU 一致的程序
+地址,这意味着 CPU 上的任何有效指针也是该设备的有效指针。这对于简化高级异构计算的使用变得
+必不可少,其中 GPU、DSP 或 FPGA 用于代表进程执行各种计算。
+
+本文档分为以下部分:在第一部分中,我揭示了与使用特定于设备的内存分配器相关的问题。在第二
+部分中,我揭示了许多平台固有的硬件限制。第三部分概述了 HMM 设计。第四部分解释了 CPU 页
+表镜像的工作原理以及 HMM 在这种情况下的目的。第五部分处理内核中如何表示设备内存。最后,
+最后一节介绍了一个新的迁移助手,它允许利用设备 DMA 引擎。
+
+.. contents:: :local:
+
+使用特定于设备的内存分配器的问题
+================================
+
+具有大量板载内存(几 GB)的设备(如 GPU)历来通过专用驱动程序特定 API 管理其内存。这会
+造成设备驱动程序分配和管理的内存与常规应用程序内存(私有匿名、共享内存或常规文件支持内存)
+之间的隔断。从这里开始,我将把这个方面称为分割的地址空间。我使用共享地址空间来指代相反的情况:
+即,设备可以透明地使用任何应用程序内存区域。
+
+分割的地址空间的发生是因为设备只能访问通过设备特定 API 分配的内存。这意味着从设备的角度来
+看,程序中的所有内存对象并不平等,这使得依赖于广泛的库的大型程序变得复杂。
+
+具体来说,这意味着想要利用像 GPU 这样的设备的代码需要在通用分配的内存(malloc、mmap
+私有、mmap 共享)和通过设备驱动程序 API 分配的内存之间复制对象(这仍然以 mmap 结束,
+但是是设备文件)。
+
+对于平面数据集(数组、网格、图像……),这并不难实现,但对于复杂数据集(列表、树……),
+很难做到正确。复制一个复杂的数据集需要重新映射其每个元素之间的所有指针关系。这很容易出错,
+而且由于数据集和地址的重复,程序更难调试。
+
+分割地址空间也意味着库不能透明地使用它们从核心程序或另一个库中获得的数据,因此每个库可能
+不得不使用设备特定的内存分配器来重复其输入数据集。大型项目会因此受到影响,并因为各种内存
+拷贝而浪费资源。
+
+复制每个库的API以接受每个设备特定分配器分配的内存作为输入或输出,并不是一个可行的选择。
+这将导致库入口点的组合爆炸。
+
+最后,随着高级语言结构(在 C++ 中,当然也在其他语言中)的进步,编译器现在有可能在没有程
+序员干预的情况下利用 GPU 和其他设备。某些编译器识别的模式仅适用于共享地址空间。对所有
+其他模式,使用共享地址空间也更合理。
+
+
+I/O 总线、设备内存特性
+======================
+
+由于一些限制,I/O 总线削弱了共享地址空间。大多数 I/O 总线只允许从设备到主内存的基本
+内存访问;甚至缓存一致性通常是可选的。从 CPU 访问设备内存甚至更加有限。通常情况下,它
+不是缓存一致的。
+
+如果我们只考虑 PCIE 总线,那么设备可以访问主内存(通常通过 IOMMU)并与 CPU 缓存一
+致。但是,它只允许设备对主存储器进行一组有限的原子操作。这在另一个方向上更糟:CPU
+只能访问有限范围的设备内存,而不能对其执行原子操作。因此,从内核的角度来看,设备内存不
+能被视为与常规内存等同。
+
+另一个严重的因素是带宽有限(约 32GBytes/s,PCIE 4.0 和 16 通道)。这比最快的 GPU
+内存 (1 TBytes/s) 慢 33 倍。最后一个限制是延迟。从设备访问主内存的延迟比设备访问自
+己的内存时高一个数量级。
+
+一些平台正在开发新的 I/O 总线或对 PCIE 的添加/修改以解决其中一些限制
+(OpenCAPI、CCIX)。它们主要允许 CPU 和设备之间的双向缓存一致性,并允许架构支持的所
+有原子操作。遗憾的是,并非所有平台都遵循这一趋势,并且一些主要架构没有针对这些问题的硬
+件解决方案。
+
+因此,为了使共享地址空间有意义,我们不仅必须允许设备访问任何内存,而且还必须允许任何内
+存在设备使用时迁移到设备内存(在迁移时阻止 CPU 访问)。
+
+
+共享地址空间和迁移
+==================
+
+HMM 打算提供两个主要功能。第一个是通过复制cpu页表到设备页表中来共享地址空间,因此对
+于进程地址空间中的任何有效主内存地址,相同的地址指向相同的物理内存。
+
+为了实现这一点,HMM 提供了一组帮助程序来填充设备页表,同时跟踪 CPU 页表更新。设备页表
+更新不像 CPU 页表更新那么容易。要更新设备页表,您必须分配一个缓冲区(或使用预先分配的
+缓冲区池)并在其中写入 GPU 特定命令以执行更新(取消映射、缓存失效和刷新等)。这不能通
+过所有设备的通用代码来完成。因此,为什么HMM提供了帮助器,在把硬件的具体细节留给设备驱
+动程序的同时,把一切可以考虑的因素都考虑进去了。
+
+HMM 提供的第二种机制是一种新的 ZONE_DEVICE 内存,它允许为设备内存的每个页面分配一个
+struct page。这些页面很特殊,因为 CPU 无法映射它们。然而,它们允许使用现有的迁移机
+制将主内存迁移到设备内存,从 CPU 的角度来看,一切看起来都像是换出到磁盘的页面。使用
+struct page可以与现有的 mm 机制进行最简单、最干净的集成。再次,HMM 仅提供帮助程序,
+首先为设备内存热插拔新的 ZONE_DEVICE 内存,然后执行迁移。迁移内容和时间的策略决定留
+给设备驱动程序。
+
+请注意,任何 CPU 对设备页面的访问都会触发缺页异常并迁移回主内存。例如,当支持给定CPU
+地址 A 的页面从主内存页面迁移到设备页面时,对地址 A 的任何 CPU 访问都会触发缺页异常
+并启动向主内存的迁移。
+
+凭借这两个特性,HMM 不仅允许设备镜像进程地址空间并保持 CPU 和设备页表同步,而且还通
+过迁移设备正在使用的数据集部分来利用设备内存。
+
+
+地址空间镜像实现和API
+=====================
+
+地址空间镜像的主要目标是允许将一定范围的 CPU 页表复制到一个设备页表中;HMM 有助于
+保持两者同步。想要镜像进程地址空间的设备驱动程序必须从注册 mmu_interval_notifier
+开始::
+
+ int mmu_interval_notifier_insert(struct mmu_interval_notifier *interval_sub,
+ struct mm_struct *mm, unsigned long start,
+ unsigned long length,
+ const struct mmu_interval_notifier_ops *ops);
+
+在 ops->invalidate() 回调期间,设备驱动程序必须对范围执行更新操作(将范围标记为只
+读,或完全取消映射等)。设备必须在驱动程序回调返回之前完成更新。
+
+当设备驱动程序想要填充一个虚拟地址范围时,它可以使用::
+
+ int hmm_range_fault(struct hmm_range *range);
+
+如果请求写访问,它将在丢失或只读条目上触发缺页异常(见下文)。缺页异常使用通用的 mm 缺
+页异常代码路径,就像 CPU 缺页异常一样。
+
+这两个函数都将 CPU 页表条目复制到它们的 pfns 数组参数中。该数组中的每个条目对应于虚拟
+范围中的一个地址。HMM 提供了一组标志来帮助驱动程序识别特殊的 CPU 页表项。
+
+在 sync_cpu_device_pagetables() 回调中锁定是驱动程序必须尊重的最重要的方面,以保
+持事物正确同步。使用模式是::
+
+ int driver_populate_range(...)
+ {
+ struct hmm_range range;
+ ...
+
+ range.notifier = &interval_sub;
+ range.start = ...;
+ range.end = ...;
+ range.hmm_pfns = ...;
+
+ if (!mmget_not_zero(interval_sub->notifier.mm))
+ return -EFAULT;
+
+ again:
+ range.notifier_seq = mmu_interval_read_begin(&interval_sub);
+ mmap_read_lock(mm);
+ ret = hmm_range_fault(&range);
+ if (ret) {
+ mmap_read_unlock(mm);
+ if (ret == -EBUSY)
+ goto again;
+ return ret;
+ }
+ mmap_read_unlock(mm);
+
+ take_lock(driver->update);
+ if (mmu_interval_read_retry(&ni, range.notifier_seq) {
+ release_lock(driver->update);
+ goto again;
+ }
+
+ /* Use pfns array content to update device page table,
+ * under the update lock */
+
+ release_lock(driver->update);
+ return 0;
+ }
+
+driver->update 锁与驱动程序在其 invalidate() 回调中使用的锁相同。该锁必须在调用
+mmu_interval_read_retry() 之前保持,以避免与并发 CPU 页表更新发生任何竞争。
+
+利用 default_flags 和 pfn_flags_mask
+====================================
+
+hmm_range 结构有 2 个字段,default_flags 和 pfn_flags_mask,它们指定整个范围
+的故障或快照策略,而不必为 pfns 数组中的每个条目设置它们。
+
+例如,如果设备驱动程序需要至少具有读取权限的范围的页面,它会设置::
+
+ range->default_flags = HMM_PFN_REQ_FAULT;
+ range->pfn_flags_mask = 0;
+
+并如上所述调用 hmm_range_fault()。这将填充至少具有读取权限的范围内的所有页面。
+
+现在假设驱动程序想要做同样的事情,除了它想要拥有写权限的范围内的一页。现在驱动程序设
+置::
+
+ range->default_flags = HMM_PFN_REQ_FAULT;
+ range->pfn_flags_mask = HMM_PFN_REQ_WRITE;
+ range->pfns[index_of_write] = HMM_PFN_REQ_WRITE;
+
+有了这个,HMM 将在至少读取(即有效)的所有页面中异常,并且对于地址
+== range->start + (index_of_write << PAGE_SHIFT) 它将异常写入权限,即,如果
+CPU pte 没有设置写权限,那么HMM将调用handle_mm_fault()。
+
+hmm_range_fault 完成后,标志位被设置为页表的当前状态,即 HMM_PFN_VALID | 如果页
+面可写,将设置 HMM_PFN_WRITE。
+
+
+从核心内核的角度表示和管理设备内存
+==================================
+
+尝试了几种不同的设计来支持设备内存。第一个使用特定于设备的数据结构来保存有关迁移内存
+的信息,HMM 将自身挂接到 mm 代码的各个位置,以处理对设备内存支持的地址的任何访问。
+事实证明,这最终复制了 struct page 的大部分字段,并且还需要更新许多内核代码路径才
+能理解这种新的内存类型。
+
+大多数内核代码路径从不尝试访问页面后面的内存,而只关心struct page的内容。正因为如此,
+HMM 切换到直接使用 struct page 用于设备内存,这使得大多数内核代码路径不知道差异。
+我们只需要确保没有人试图从 CPU 端映射这些页面。
+
+移入和移出设备内存
+==================
+
+由于 CPU 无法直接访问设备内存,因此设备驱动程序必须使用硬件 DMA 或设备特定的加载/存
+储指令来迁移数据。migrate_vma_setup()、migrate_vma_pages() 和
+migrate_vma_finalize() 函数旨在使驱动程序更易于编写并集中跨驱动程序的通用代码。
+
+在将页面迁移到设备私有内存之前,需要创建特殊的设备私有 ``struct page`` 。这些将用
+作特殊的“交换”页表条目,以便 CPU 进程在尝试访问已迁移到设备专用内存的页面时会发生异常。
+
+这些可以通过以下方式分配和释放::
+
+ struct resource *res;
+ struct dev_pagemap pagemap;
+
+ res = request_free_mem_region(&iomem_resource, /* number of bytes */,
+ "name of driver resource");
+ pagemap.type = MEMORY_DEVICE_PRIVATE;
+ pagemap.range.start = res->start;
+ pagemap.range.end = res->end;
+ pagemap.nr_range = 1;
+ pagemap.ops = &device_devmem_ops;
+ memremap_pages(&pagemap, numa_node_id());
+
+ memunmap_pages(&pagemap);
+ release_mem_region(pagemap.range.start, range_len(&pagemap.range));
+
+还有devm_request_free_mem_region(), devm_memremap_pages(),
+devm_memunmap_pages() 和 devm_release_mem_region() 当资源可以绑定到 ``struct device``.
+
+整体迁移步骤类似于在系统内存中迁移 NUMA 页面(see Documentation/mm/page_migration.rst) ,
+但这些步骤分为设备驱动程序特定代码和共享公共代码:
+
+1. ``mmap_read_lock()``
+
+ 设备驱动程序必须将 ``struct vm_area_struct`` 传递给migrate_vma_setup(),
+ 因此需要在迁移期间保留 mmap_read_lock() 或 mmap_write_lock()。
+
+2. ``migrate_vma_setup(struct migrate_vma *args)``
+
+ 设备驱动初始化了 ``struct migrate_vma`` 的字段,并将该指针传递给
+ migrate_vma_setup()。``args->flags`` 字段是用来过滤哪些源页面应该被迁移。
+ 例如,设置 ``MIGRATE_VMA_SELECT_SYSTEM`` 将只迁移系统内存,设置
+ ``MIGRATE_VMA_SELECT_DEVICE_PRIVATE`` 将只迁移驻留在设备私有内存中的页
+ 面。如果后者被设置, ``args->pgmap_owner`` 字段被用来识别驱动所拥有的设备
+ 私有页。这就避免了试图迁移驻留在其他设备中的设备私有页。目前,只有匿名的私有VMA
+ 范围可以被迁移到系统内存和设备私有内存。
+
+ migrate_vma_setup()所做的第一步是用 ``mmu_notifier_invalidate_range_start()``
+ 和 ``mmu_notifier_invalidate_range_end()`` 调用来遍历设备周围的页表,使
+ 其他设备的MMU无效,以便在 ``args->src`` 数组中填写要迁移的PFN。
+ ``invalidate_range_start()`` 回调传递给一个``struct mmu_notifier_range`` ,
+ 其 ``event`` 字段设置为MMU_NOTIFY_MIGRATE, ``owner`` 字段设置为传递给
+ migrate_vma_setup()的 ``args->pgmap_owner`` 字段。这允许设备驱动跳过无
+ 效化回调,只无效化那些实际正在迁移的设备私有MMU映射。这一点将在下一节详细解释。
+
+
+ 在遍历页表时,一个 ``pte_none()`` 或 ``is_zero_pfn()`` 条目导致一个有效
+ 的 “zero” PFN 存储在 ``args->src`` 阵列中。这让驱动分配设备私有内存并清
+ 除它,而不是复制一个零页。到系统内存或设备私有结构页的有效PTE条目将被
+ ``lock_page()``锁定,与LRU隔离(如果系统内存和设备私有页不在LRU上),从进
+ 程中取消映射,并插入一个特殊的迁移PTE来代替原来的PTE。 migrate_vma_setup()
+ 还清除了 ``args->dst`` 数组。
+
+3. 设备驱动程序分配目标页面并将源页面复制到目标页面。
+
+ 驱动程序检查每个 ``src`` 条目以查看该 ``MIGRATE_PFN_MIGRATE`` 位是否已
+ 设置并跳过未迁移的条目。设备驱动程序还可以通过不填充页面的 ``dst`` 数组来选
+ 择跳过页面迁移。
+
+ 然后,驱动程序分配一个设备私有 struct page 或一个系统内存页,用 ``lock_page()``
+ 锁定该页,并将 ``dst`` 数组条目填入::
+
+ dst[i] = migrate_pfn(page_to_pfn(dpage));
+
+ 现在驱动程序知道这个页面正在被迁移,它可以使设备私有 MMU 映射无效并将设备私有
+ 内存复制到系统内存或另一个设备私有页面。由于核心 Linux 内核会处理 CPU 页表失
+ 效,因此设备驱动程序只需使其自己的 MMU 映射失效。
+
+ 驱动程序可以使用 ``migrate_pfn_to_page(src[i])`` 来获取源设备的
+ ``struct page`` 面,并将源页面复制到目标设备上,如果指针为 ``NULL`` ,意
+ 味着源页面没有被填充到系统内存中,则清除目标设备的私有内存。
+
+4. ``migrate_vma_pages()``
+
+ 这一步是实际“提交”迁移的地方。
+
+ 如果源页是 ``pte_none()`` 或 ``is_zero_pfn()`` 页,这时新分配的页会被插
+ 入到CPU的页表中。如果一个CPU线程在同一页面上发生异常,这可能会失败。然而,页
+ 表被锁定,只有一个新页会被插入。如果它失去了竞争,设备驱动将看到
+ ``MIGRATE_PFN_MIGRATE`` 位被清除。
+
+ 如果源页被锁定、隔离等,源 ``struct page`` 信息现在被复制到目标
+ ``struct page`` ,最终完成CPU端的迁移。
+
+5. 设备驱动为仍在迁移的页面更新设备MMU页表,回滚未迁移的页面。
+
+ 如果 ``src`` 条目仍然有 ``MIGRATE_PFN_MIGRATE`` 位被设置,设备驱动可以
+ 更新设备MMU,如果 ``MIGRATE_PFN_WRITE`` 位被设置,则设置写启用位。
+
+6. ``migrate_vma_finalize()``
+
+ 这一步用新页的页表项替换特殊的迁移页表项,并释放对源和目的 ``struct page``
+ 的引用。
+
+7. ``mmap_read_unlock()``
+
+ 现在可以释放锁了。
+
+独占访问存储器
+==============
+
+一些设备具有诸如原子PTE位的功能,可以用来实现对系统内存的原子访问。为了支持对一
+个共享的虚拟内存页的原子操作,这样的设备需要对该页的访问是排他的,而不是来自CPU
+的任何用户空间访问。 ``make_device_exclusive_range()`` 函数可以用来使一
+个内存范围不能从用户空间访问。
+
+这将用特殊的交换条目替换给定范围内的所有页的映射。任何试图访问交换条目的行为都会
+导致一个异常,该异常会通过用原始映射替换该条目而得到恢复。驱动程序会被通知映射已
+经被MMU通知器改变,之后它将不再有对该页的独占访问。独占访问被保证持续到驱动程序
+放弃页面锁和页面引用为止,这时页面上的任何CPU异常都可以按所述进行。
+
+内存 cgroup (memcg) 和 rss 统计
+===============================
+
+目前,设备内存被视为 rss 计数器中的任何常规页面(如果设备页面用于匿名,则为匿名,
+如果设备页面用于文件支持页面,则为文件,如果设备页面用于共享内存,则为 shmem)。
+这是为了保持现有应用程序的故意选择,这些应用程序可能在不知情的情况下开始使用设备
+内存,运行不受影响。
+
+一个缺点是 OOM 杀手可能会杀死使用大量设备内存而不是大量常规系统内存的应用程序,
+因此不会释放太多系统内存。在决定以不同方式计算设备内存之前,我们希望收集更多关
+于应用程序和系统在存在设备内存的情况下在内存压力下如何反应的实际经验。
+
+对内存 cgroup 做出了相同的决定。设备内存页面根据相同的内存 cgroup 计算,常规
+页面将被计算在内。这确实简化了进出设备内存的迁移。这也意味着从设备内存迁移回常规
+内存不会失败,因为它会超过内存 cgroup 限制。一旦我们对设备内存的使用方式及其对
+内存资源控制的影响有了更多的了解,我们可能会在后面重新考虑这个选择。
+
+请注意,设备内存永远不能由设备驱动程序或通过 GUP 固定,因此此类内存在进程退出时
+总是被释放的。或者在共享内存或文件支持内存的情况下,当删除最后一个引用时。
diff --git a/Documentation/translations/zh_CN/mm/hugetlbfs_reserv.rst b/Documentation/translations/zh_CN/mm/hugetlbfs_reserv.rst
new file mode 100644
index 000000000000..20947f8bd065
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/hugetlbfs_reserv.rst
@@ -0,0 +1,437 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/mm/hugetlbfs_reserv.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+==============
+Hugetlbfs 预留
+==============
+
+概述
+====
+
+Documentation/admin-guide/mm/hugetlbpage.rst
+中描述的巨页通常是预先分配给应用程序使用的 。如果VMA指
+示要使用巨页,这些巨页会在缺页异常时被实例化到任务的地址空间。如果在缺页异常
+时没有巨页存在,任务就会被发送一个SIGBUS,并经常不高兴地死去。在加入巨页支
+持后不久,人们决定,在mmap()时检测巨页的短缺情况会更好。这个想法是,如果
+没有足够的巨页来覆盖映射,mmap()将失败。这首先是在mmap()时在代码中做一个
+简单的检查,以确定是否有足够的空闲巨页来覆盖映射。就像内核中的大多数东西一
+样,代码随着时间的推移而不断发展。然而,基本的想法是在mmap()时 “预留”
+巨页,以确保巨页可以用于该映射中的缺页异常。下面的描述试图描述在v4.10内核
+中是如何进行巨页预留处理的。
+
+
+读者
+====
+这个描述主要是针对正在修改hugetlbfs代码的内核开发者。
+
+
+数据结构
+========
+
+resv_huge_pages
+ 这是一个全局的(per-hstate)预留的巨页的计数。预留的巨页只对预留它们的任
+ 务可用。因此,一般可用的巨页的数量被计算为(``free_huge_pages - resv_huge_pages``)。
+Reserve Map
+ 预留映射由以下结构体描述::
+
+ 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;
+ };
+
+ 系统中每个巨页映射都有一个预留映射。resv_map中的regions列表描述了映射中的
+ 区域。一个区域被描述为::
+
+ struct file_region {
+ struct list_head link;
+ long from;
+ long to;
+ };
+
+ file_region结构体的 ‘from’ 和 ‘to’ 字段是进入映射的巨页索引。根据映射的类型,在
+ reserv_map 中的一个区域可能表示该范围存在预留,或预留不存在。
+Flags for MAP_PRIVATE Reservations
+ 这些被存储在预留的映射指针的底部。
+
+ ``#define HPAGE_RESV_OWNER (1UL << 0)``
+ 表示该任务是与该映射相关的预留的所有者。
+ ``#define HPAGE_RESV_UNMAPPED (1UL << 1)``
+ 表示最初映射此范围(并创建储备)的任务由于COW失败而从该任务(子任务)中取消映
+ 射了一个页面。
+Page Flags
+ PagePrivate页面标志是用来指示在释放巨页时必须恢复巨页的预留。更多细节将在
+ “释放巨页” 一节中讨论。
+
+
+预留映射位置(私有或共享)
+==========================
+
+一个巨页映射或段要么是私有的,要么是共享的。如果是私有的,它通常只对一个地址空间
+(任务)可用。如果是共享的,它可以被映射到多个地址空间(任务)。对于这两种类型的映射,
+预留映射的位置和语义是明显不同的。位置的差异是:
+
+- 对于私有映射,预留映射挂在VMA结构体上。具体来说,就是vma->vm_private_data。这个保
+ 留映射是在创建映射(mmap(MAP_PRIVATE))时创建的。
+- 对于共享映射,预留映射挂在inode上。具体来说,就是inode->i_mapping->private_data。
+ 由于共享映射总是由hugetlbfs文件系统中的文件支持,hugetlbfs代码确保每个节点包含一个预
+ 留映射。因此,预留映射在创建节点时被分配。
+
+
+创建预留
+========
+当创建一个巨大的有页面支持的共享内存段(shmget(SHM_HUGETLB))或通过mmap(MAP_HUGETLB)
+创建一个映射时,就会创建预留。这些操作会导致对函数hugetlb_reserve_pages()的调用::
+
+ int hugetlb_reserve_pages(struct inode *inode,
+ long from, long to,
+ struct vm_area_struct *vma,
+ vm_flags_t vm_flags)
+
+hugetlb_reserve_pages()做的第一件事是检查在调用shmget()或mmap()时是否指定了NORESERVE
+标志。如果指定了NORESERVE,那么这个函数立即返回,因为不需要预留。
+
+参数'from'和'to'是映射或基础文件的巨页索引。对于shmget(),'from'总是0,'to'对应于段/映射
+的长度。对于mmap(),offset参数可以用来指定进入底层文件的偏移量。在这种情况下,'from'和'to'
+参数已经被这个偏移量所调整。
+
+PRIVATE和SHARED映射之间的一个很大的区别是预留在预留映射中的表示方式。
+
+- 对于共享映射,预留映射中的条目表示对应页面的预留存在或曾经存在。当预留被消耗时,预留映射不被
+ 修改。
+- 对于私有映射,预留映射中没有条目表示相应页面存在预留。随着预留被消耗,条目被添加到预留映射中。
+ 因此,预留映射也可用于确定哪些预留已被消耗。
+
+对于私有映射,hugetlb_reserve_pages()创建预留映射并将其挂在VMA结构体上。此外,
+HPAGE_RESV_OWNER标志被设置,以表明该VMA拥有预留。
+
+预留映射被查阅以确定当前映射/段需要多少巨页预留。对于私有映射,这始终是一个值(to - from)。
+然而,对于共享映射来说,一些预留可能已经存在于(to - from)的范围内。关于如何实现这一点的细节,
+请参见 :ref:`预留映射的修改 <resv_map_modifications>` 一节。
+
+该映射可能与一个子池(subpool)相关联。如果是这样,将查询子池以确保有足够的空间用于映射。子池
+有可能已经预留了可用于映射的预留空间。更多细节请参见 :ref: `子池预留 <sub_pool_resv>`
+一节。
+
+在咨询了预留映射和子池之后,就知道了需要的新预留数量。hugetlb_acct_memory()函数被调用以检查
+并获取所要求的预留数量。hugetlb_acct_memory()调用到可能分配和调整剩余页数的函数。然而,在这
+些函数中,代码只是检查以确保有足够的空闲的巨页来容纳预留。如果有的话,全局预留计数resv_huge_pages
+会被调整,如下所示::
+
+ if (resv_needed <= (resv_huge_pages - free_huge_pages))
+ resv_huge_pages += resv_needed;
+
+注意,在检查和调整这些计数器时,全局锁hugetlb_lock会被预留。
+
+如果有足够的空闲的巨页,并且全局计数resv_huge_pages被调整,那么与映射相关的预留映射被修改以
+反映预留。在共享映射的情况下,将存在一个file_region,包括'from'-'to'范围。对于私有映射,
+不对预留映射进行修改,因为没有条目表示存在预留。
+
+如果hugetlb_reserve_pages()成功,全局预留数和与映射相关的预留映射将根据需要被修改,以确保
+在'from'-'to'范围内存在预留。
+
+消耗预留/分配一个巨页
+===========================
+
+当与预留相关的巨页在相应的映射中被分配和实例化时,预留就被消耗了。该分配是在函数alloc_hugetlb_folio()
+中进行的::
+
+ struct folio *alloc_hugetlb_folio(struct vm_area_struct *vma,
+ unsigned long addr, int avoid_reserve)
+
+alloc_hugetlb_folio被传递给一个VMA指针和一个虚拟地址,因此它可以查阅预留映射以确定是否存在预留。
+此外,alloc_hugetlb_folio需要一个参数avoid_reserve,该参数表示即使看起来已经为指定的地址预留了
+预留,也不应该使用预留。avoid_reserve参数最常被用于写时拷贝和页面迁移的情况下,即现有页面的额
+外拷贝被分配。
+
+
+调用辅助函数vma_needs_reservation()来确定是否存在对映射(vma)中地址的预留。关于这个函数的详
+细内容,请参见 :ref:`预留映射帮助函数 <resv_map_helpers>` 一节。从
+vma_needs_reservation()返回的值通常为0或1。如果该地址存在预留,则为0,如果不存在预留,则为1。
+如果不存在预留,并且有一个与映射相关联的子池,则查询子池以确定它是否包含预留。如果子池包含预留,
+则可将其中一个用于该分配。然而,在任何情况下,avoid_reserve参数都会优先考虑为分配使用预留。在
+确定预留是否存在并可用于分配后,调用dequeue_huge_page_vma()函数。这个函数需要两个与预留有关
+的参数:
+
+- avoid_reserve,这是传递给alloc_hugetlb_folio()的同一个值/参数。
+- chg,尽管这个参数的类型是long,但只有0或1的值被传递给dequeue_huge_page_vma。如果该值为0,
+ 则表明存在预留(关于可能的问题,请参见 “预留和内存策略” 一节)。如果值
+ 为1,则表示不存在预留,如果可能的话,必须从全局空闲池中取出该页。
+
+与VMA的内存策略相关的空闲列表被搜索到一个空闲页。如果找到了一个页面,当该页面从空闲列表中移除时,
+free_huge_pages的值被递减。如果有一个与该页相关的预留,将进行以下调整::
+
+ SetPagePrivate(page); /* 表示分配这个页面消耗了一个预留,
+ * 如果遇到错误,以至于必须释放这个页面,预留将被
+ * 恢复。 */
+ resv_huge_pages--; /* 减少全局预留计数 */
+
+注意,如果找不到满足VMA内存策略的巨页,将尝试使用伙伴分配器分配一个。这就带来了超出预留范围
+的剩余巨页和超额分配的问题。即使分配了一个多余的页面,也会进行与上面一样的基于预留的调整:
+SetPagePrivate(page) 和 resv_huge_pages--.
+
+在获得一个新的巨页后,(folio)->_hugetlb_subpool被设置为与该页面相关的子池的值,如果它存在的话。当页
+面被释放时,这将被用于子池的计数。
+
+然后调用函数vma_commit_reservation(),根据预留的消耗情况调整预留映射。一般来说,这涉及
+到确保页面在区域映射的file_region结构体中被表示。对于预留存在的共享映射,预留映射中的条目
+已经存在,所以不做任何改变。然而,如果共享映射中没有预留,或者这是一个私有映射,则必须创建一
+个新的条目。
+
+注意,如果找不到满足VMA内存策略的巨页,将尝试使用伙伴分配器分配一个。这就带来了超出预留范围
+的剩余巨页和过度分配的问题。即使分配了一个多余的页面,也会进行与上面一样的基于预留的调整。
+SetPagePrivate(page)和resv_huge_pages-。
+
+在获得一个新的巨页后,(page)->private被设置为与该页面相关的子池的值,如果它存在的话。当页
+面被释放时,这将被用于子池的计数。
+
+然后调用函数vma_commit_reservation(),根据预留的消耗情况调整预留映射。一般来说,这涉及
+到确保页面在区域映射的file_region结构体中被表示。对于预留存在的共享映射,预留映射中的条目
+已经存在,所以不做任何改变。然而,如果共享映射中没有预留,或者这是一个私有映射,则必须创建
+一个新的条目。
+
+在alloc_hugetlb_folio()开始调用vma_needs_reservation()和页面分配后调用
+vma_commit_reservation()之间,预留映射有可能被改变。如果hugetlb_reserve_pages在共
+享映射中为同一页面被调用,这将是可能的。在这种情况下,预留计数和子池空闲页计数会有一个偏差。
+这种罕见的情况可以通过比较vma_needs_reservation和vma_commit_reservation的返回值来
+识别。如果检测到这种竞争,子池和全局预留计数将被调整以进行补偿。关于这些函数的更多信息,请
+参见 :ref:`预留映射帮助函数 <resv_map_helpers>` 一节。
+
+
+实例化巨页
+==========
+
+在巨页分配之后,页面通常被添加到分配任务的页表中。在此之前,共享映射中的页面被添加到页面缓
+存中,私有映射中的页面被添加到匿名反向映射中。在这两种情况下,PagePrivate标志被清除。因此,
+当一个已经实例化的巨页被释放时,不会对全局预留计数(resv_huge_pages)进行调整。
+
+
+释放巨页
+========
+
+巨页释放是由函数free_huge_folio()执行的。这个函数是hugetlbfs复合页的析构器。因此,它只传
+递一个指向页面结构体的指针。当一个巨页被释放时,可能需要进行预留计算。如果该页与包含保
+留的子池相关联,或者该页在错误路径上被释放,必须恢复全局预留计数,就会出现这种情况。
+
+page->private字段指向与该页相关的任何子池。如果PagePrivate标志被设置,它表明全局预留计数
+应该被调整(关于如何设置这些标志的信息,请参见
+:ref: `消耗预留/分配一个巨页 <consume_resv>` )。
+
+
+该函数首先调用hugepage_subpool_put_pages()来处理该页。如果这个函数返回一个0的值(不等于
+传递的1的值),它表明预留与子池相关联,这个新释放的页面必须被用来保持子池预留的数量超过最小值。
+因此,在这种情况下,全局resv_huge_pages计数器被递增。
+
+如果页面中设置了PagePrivate标志,那么全局resv_huge_pages计数器将永远被递增。
+
+子池预留
+========
+
+有一个结构体hstate与每个巨页尺寸相关联。hstate跟踪所有指定大小的巨页。一个子池代表一
+个hstate中的页面子集,它与一个已挂载的hugetlbfs文件系统相关
+
+当一个hugetlbfs文件系统被挂载时,可以指定min_size选项,它表示文件系统所需的最小的巨页数量。
+如果指定了这个选项,与min_size相对应的巨页的数量将被预留给文件系统使用。这个数字在结构体
+hugepage_subpool的min_hpages字段中被跟踪。在挂载时,hugetlb_acct_memory(min_hpages)
+被调用以预留指定数量的巨页。如果它们不能被预留,挂载就会失败。
+
+当从子池中获取或释放页面时,会调用hugepage_subpool_get/put_pages()函数。
+hugepage_subpool_get/put_pages被传递给巨页数量,以此来调整子池的 “已用页面” 计数
+(get为下降,put为上升)。通常情况下,如果子池中没有足够的页面,它们会返回与传递的相同的值或
+一个错误。
+
+然而,如果预留与子池相关联,可能会返回一个小于传递值的返回值。这个返回值表示必须进行的额外全局
+池调整的数量。例如,假设一个子池包含3个预留的巨页,有人要求5个。与子池相关的3个预留页可以用来
+满足部分请求。但是,必须从全局池中获得2个页面。为了向调用者转达这一信息,将返回值2。然后,调用
+者要负责从全局池中获取另外两个页面。
+
+
+COW和预留
+==========
+
+由于共享映射都指向并使用相同的底层页面,COW最大的预留问题是私有映射。在这种情况下,两个任务可
+以指向同一个先前分配的页面。一个任务试图写到该页,所以必须分配一个新的页,以便每个任务都指向它
+自己的页。
+
+当该页最初被分配时,该页的预留被消耗了。当由于COW而试图分配一个新的页面时,有可能没有空闲的巨
+页,分配会失败。
+
+当最初创建私有映射时,通过设置所有者的预留映射指针中的HPAGE_RESV_OWNER位来标记映射的所有者。
+由于所有者创建了映射,所有者拥有与映射相关的所有预留。因此,当一个写异常发生并且没有可用的页面
+时,对预留的所有者和非所有者采取不同的行动。
+
+在发生异常的任务不是所有者的情况下,异常将失败,该任务通常会收到一个SIGBUS。
+
+如果所有者是发生异常的任务,我们希望它能够成功,因为它拥有原始的预留。为了达到这个目的,该页被
+从非所有者任务中解映射出来。这样一来,唯一的引用就是来自拥有者的任务。此外,HPAGE_RESV_UNMAPPED
+位被设置在非拥有任务的预留映射指针中。如果非拥有者任务后来在一个不存在的页面上发生异常,它可能
+会收到一个SIGBUS。但是,映射/预留的原始拥有者的行为将与预期一致。
+
+预留映射的修改
+==============
+
+以下低级函数用于对预留映射进行修改。通常情况下,这些函数不会被直接调用。而是调用一个预留映射辅
+助函数,该函数调用这些低级函数中的一个。这些低级函数在源代码(mm/hugetlb.c)中得到了相当好的
+记录。这些函数是::
+
+ long region_chg(struct resv_map *resv, long f, long t);
+ long region_add(struct resv_map *resv, long f, long t);
+ void region_abort(struct resv_map *resv, long f, long t);
+ long region_count(struct resv_map *resv, long f, long t);
+
+在预留映射上的操作通常涉及两个操作:
+
+1) region_chg()被调用来检查预留映射,并确定在指定的范围[f, t]内有多少页目前没有被代表。
+
+ 调用代码执行全局检查和分配,以确定是否有足够的巨页使操作成功。
+
+2)
+ a) 如果操作能够成功,region_add()将被调用,以实际修改先前传递给region_chg()的相同范围
+ [f, t]的预留映射。
+ b) 如果操作不能成功,region_abort被调用,在相同的范围[f, t]内中止操作。
+
+注意,这是一个两步的过程, region_add()和 region_abort()在事先调用 region_chg()后保证
+成功。 region_chg()负责预先分配任何必要的数据结构以确保后续操作(特别是 region_add())的
+成功。
+
+如上所述,region_chg()确定该范围内当前没有在映射中表示的页面的数量。region_add()返回添加
+到映射中的范围内的页数。在大多数情况下, region_add() 的返回值与 region_chg() 的返回值相
+同。然而,在共享映射的情况下,有可能在调用 region_chg() 和 region_add() 之间对预留映射进
+行更改。在这种情况下,region_add()的返回值将与region_chg()的返回值不符。在这种情况下,全局计数
+和子池计数很可能是不正确的,需要调整。检查这种情况并进行适当的调整是调用者的责任。
+
+函数region_del()被调用以从预留映射中移除区域。
+它通常在以下情况下被调用:
+
+- 当hugetlbfs文件系统中的一个文件被删除时,该节点将被释放,预留映射也被释放。在释放预留映射
+ 之前,所有单独的file_region结构体必须被释放。在这种情况下,region_del的范围是[0, LONG_MAX]。
+- 当一个hugetlbfs文件正在被截断时。在这种情况下,所有在新文件大小之后分配的页面必须被释放。
+ 此外,预留映射中任何超过新文件大小的file_region条目必须被删除。在这种情况下,region_del
+ 的范围是[new_end_of_file, LONG_MAX]。
+- 当在一个hugetlbfs文件中打洞时。在这种情况下,巨页被一次次从文件的中间移除。当这些页被移除
+ 时,region_del()被调用以从预留映射中移除相应的条目。在这种情况下,region_del被传递的范
+ 围是[page_idx, page_idx + 1]。
+
+在任何情况下,region_del()都会返回从预留映射中删除的页面数量。在非常罕见的情况下,region_del()
+会失败。这只能发生在打洞的情况下,即它必须分割一个现有的file_region条目,而不能分配一个新的
+结构体。在这种错误情况下,region_del()将返回-ENOMEM。这里的问题是,预留映射将显示对该页有
+预留。然而,子池和全局预留计数将不反映该预留。为了处理这种情况,调用函数hugetlb_fix_reserve_counts()
+来调整计数器,使其与不能被删除的预留映射条目相对应。
+
+region_count()在解除私有巨页映射时被调用。在私有映射中,预留映射中没有条目表明存在一个预留。
+因此,通过计算预留映射中的条目数,我们知道有多少预留被消耗了,有多少预留是未完成的
+(Outstanding = (end - start) - region_count(resv, start, end))。由于映射正在消
+失,子池和全局预留计数被未完成的预留数量所减去。
+
+预留映射帮助函数
+================
+
+有几个辅助函数可以查询和修改预留映射。这些函数只对特定的巨页的预留感兴趣,所以它们只是传入一个
+地址而不是一个范围。此外,它们还传入相关的VMA。从VMA中,可以确定映射的类型(私有或共享)和预留
+映射的位置(inode或VMA)。这些函数只是调用 “预留映射的修改” 一节中描述的基础函数。然而,
+它们确实考虑到了私有和共享映射的预留映射条目的 “相反” 含义,并向调用者隐藏了这个细节::
+
+ long vma_needs_reservation(struct hstate *h,
+ struct vm_area_struct *vma,
+ unsigned long addr)
+
+该函数为指定的页面调用 region_chg()。如果不存在预留,则返回1。如果存在预留,则返回0::
+
+ long vma_commit_reservation(struct hstate *h,
+ struct vm_area_struct *vma,
+ unsigned long addr)
+
+这将调用 region_add(),用于指定的页面。与region_chg和region_add的情况一样,该函数应在
+先前调用的vma_needs_reservation后调用。它将为该页添加一个预留条目。如果预留被添加,它将
+返回1,如果没有则返回0。返回值应与之前调用vma_needs_reservation的返回值进行比较。如果出
+现意外的差异,说明在两次调用之间修改了预留映射::
+
+ void vma_end_reservation(struct hstate *h,
+ struct vm_area_struct *vma,
+ unsigned long addr)
+
+这将调用指定页面的 region_abort()。与region_chg和region_abort的情况一样,该函数应在
+先前调用的vma_needs_reservation后被调用。它将中止/结束正在进行的预留添加操作::
+
+ long vma_add_reservation(struct hstate *h,
+ struct vm_area_struct *vma,
+ unsigned long addr)
+
+这是一个特殊的包装函数,有助于在错误路径上清理预留。它只从repare_reserve_on_error()函数
+中调用。该函数与vma_needs_reservation一起使用,试图将一个预留添加到预留映射中。它考虑到
+了私有和共享映射的不同预留映射语义。因此,region_add被调用用于共享映射(因为映射中的条目表
+示预留),而region_del被调用用于私有映射(因为映射中没有条目表示预留)。关于在错误路径上需
+要做什么的更多信息,请参见 “错误路径中的预留清理” 。
+
+
+错误路径中的预留清理
+====================
+
+正如在:ref:`预留映射帮助函数<resv_map_helpers>` 一节中提到的,预留的修改分两步进行。首
+先,在分配页面之前调用vma_needs_reservation。如果分配成功,则调用vma_commit_reservation。
+如果不是,则调用vma_end_reservation。全局和子池的预留计数根据操作的成功或失败进行调整,
+一切都很好。
+
+此外,在一个巨页被实例化后,PagePrivate标志被清空,这样,当页面最终被释放时,计数是
+正确的。
+
+然而,有几种情况是,在一个巨页被分配后,但在它被实例化之前,就遇到了错误。在这种情况下,
+页面分配已经消耗了预留,并进行了适当的子池、预留映射和全局计数调整。如果页面在这个时候被释放
+(在实例化和清除PagePrivate之前),那么free_huge_folio将增加全局预留计数。然而,预留映射
+显示报留被消耗了。这种不一致的状态将导致预留的巨页的 “泄漏” 。全局预留计数将比它原本的要高,
+并阻止分配一个预先分配的页面。
+
+函数 restore_reserve_on_error() 试图处理这种情况。它有相当完善的文档。这个函数的目的
+是将预留映射恢复到页面分配前的状态。通过这种方式,预留映射的状态将与页面释放后的全局预留计
+数相对应。
+
+函数restore_reserve_on_error本身在试图恢复预留映射条目时可能会遇到错误。在这种情况下,
+它将简单地清除该页的PagePrivate标志。这样一来,当页面被释放时,全局预留计数将不会被递增。
+然而,预留映射将继续看起来像预留被消耗了一样。一个页面仍然可以被分配到该地址,但它不会像最
+初设想的那样使用一个预留页。
+
+有一些代码(最明显的是userfaultfd)不能调用restore_reserve_on_error。在这种情况下,
+它简单地修改了PagePrivate,以便在释放巨页时不会泄露预留。
+
+
+预留和内存策略
+==============
+当git第一次被用来管理Linux代码时,每个节点的巨页列表就存在于hstate结构中。预留的概念是
+在一段时间后加入的。当预留被添加时,没有尝试将内存策略考虑在内。虽然cpusets与内存策略不
+完全相同,但hugetlb_acct_memory中的这个注释总结了预留和cpusets/内存策略之间的相互作
+用::
+
+
+ /*
+ * 当cpuset被配置时,它打破了严格的hugetlb页面预留,因为计数是在一个全局变量上完
+ * 成的。在有cpuset的情况下,这样的预留完全是垃圾,因为预留没有根据当前cpuset的
+ * 页面可用性来检查。在任务所在的cpuset中缺乏空闲的htlb页面时,应用程序仍然有可能
+ * 被内核OOM'ed。试图用cpuset来执行严格的计数几乎是不可能的(或者说太难看了),因
+ * 为cpuset太不稳定了,任务或内存节点可以在cpuset之间动态移动。与cpuset共享
+ * hugetlb映射的语义变化是不可取的。然而,为了预留一些语义,我们退回到检查当前空闲
+ * 页的可用性,作为一种最好的尝试,希望能将cpuset改变语义的影响降到最低。
+ */
+
+添加巨页预留是为了防止在缺页异常时出现意外的页面分配失败(OOM)。然而,如果一个应用
+程序使用cpusets或内存策略,就不能保证在所需的节点上有巨页可用。即使有足够数量的全局
+预留,也是如此。
+
+Hugetlbfs回归测试
+=================
+
+最完整的hugetlb测试集在libhugetlbfs仓库。如果你修改了任何hugetlb相关的代码,请使用
+libhugetlbfs测试套件来检查回归情况。此外,如果你添加了任何新的hugetlb功能,请在
+libhugetlbfs中添加适当的测试。
+
+--
+Mike Kravetz,2017年4月7日
diff --git a/Documentation/translations/zh_CN/mm/hwpoison.rst b/Documentation/translations/zh_CN/mm/hwpoison.rst
new file mode 100644
index 000000000000..310862edc937
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/hwpoison.rst
@@ -0,0 +1,166 @@
+
+:Original: Documentation/mm/hwpoison.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+========
+hwpoison
+========
+
+什么是hwpoison?
+===============
+
+
+即将推出的英特尔CPU支持从一些内存错误中恢复( ``MCA恢复`` )。这需要操作系统宣布
+一个页面"poisoned",杀死与之相关的进程,并避免在未来使用它。
+
+这个补丁包在虚拟机中实现了必要的(编程)框架。
+
+引用概述中的评论::
+
+ 高级机器的检查与处理。处理方法是损坏的页面被硬件报告,通常是由于2位ECC内
+ 存或高速缓存故障。
+
+ 这主要是针对在后台检测到的损坏的页面。当当前的CPU试图访问它时,当前运行的进程
+ 可以直接被杀死。因为还没有访问损坏的页面, 如果错误由于某种原因不能被处理,就可
+ 以安全地忽略它. 而不是用另外一个机器检查去处理它。
+
+ 处理不同状态的页面缓存页。这里棘手的部分是,相对于其他虚拟内存用户, 我们可以异
+ 步访问任何页面。因为内存故障可能随时随地发生,可能违反了他们的一些假设。这就是
+ 为什么这段代码必须非常小心。一般来说,它试图使用正常的锁规则,如获得标准锁,即使
+ 这意味着错误处理可能需要很长的时间。
+
+ 这里的一些操作有点低效,并且具有非线性的算法复杂性,因为数据结构没有针对这种情
+ 况进行优化。特别是从vma到进程的映射就是这种情况。由于这种情况大概率是罕见的,所
+ 以我们希望我们可以摆脱这种情况。
+
+该代码由mm/memory-failure.c中的高级处理程序、一个新的页面poison位和虚拟机中的
+各种检查组成,用来处理poison的页面。
+
+现在主要目标是KVM客户机,但它适用于所有类型的应用程序。支持KVM需要最近的qemu-kvm
+版本。
+
+对于KVM的使用,需要一个新的信号类型,这样KVM就可以用适当的地址将机器检查注入到客户
+机中。这在理论上也允许其他应用程序处理内存故障。我们的期望是,所有的应用程序都不要这
+样做,但一些非常专业的应用程序可能会这样做。
+
+故障恢复模式
+============
+
+有两种(实际上是三种)模式的内存故障恢复可以在。
+
+vm.memory_failure_recovery sysctl 置零:
+ 所有的内存故障都会导致panic。请不要尝试恢复。
+
+早期处理
+ (可以在全局和每个进程中控制) 一旦检测到错误,立即向应用程序发送SIGBUS这允许
+ 应用程序以温和的方式处理内存错误(例如,放弃受影响的对象) 这是KVM qemu使用的
+ 模式。
+
+推迟处理
+ 当应用程序运行到损坏的页面时,发送SIGBUS。这对不知道内存错误的应用程序来说是
+ 最好的,默认情况下注意一些页面总是被当作late kill处理。
+
+用户控制
+========
+
+vm.memory_failure_recovery
+ 参阅 sysctl.txt
+
+vm.memory_failure_early_kill
+ 全局启用early kill
+
+PR_MCE_KILL
+ 设置early/late kill mode/revert 到系统默认值。
+
+ arg1: PR_MCE_KILL_CLEAR:
+ 恢复到系统默认值
+ arg1: PR_MCE_KILL_SET:
+ arg2定义了线程特定模式
+
+ PR_MCE_KILL_EARLY:
+ Early kill
+ PR_MCE_KILL_LATE:
+ Late kill
+ PR_MCE_KILL_DEFAULT
+ 使用系统全局默认值
+
+ 注意,如果你想有一个专门的线程代表进程处理SIGBUS(BUS_MCEERR_AO),你应该在
+ 指定线程上调用prctl(PR_MCE_KILL_EARLY)。否则,SIGBUS将被发送到主线程。
+
+PR_MCE_KILL_GET
+ 返回当前模式
+
+测试
+====
+
+* madvise(MADV_HWPOISON, ....) (as root) - 在测试过程中Poison一个页面
+
+* 通过debugfs ``/sys/kernel/debug/hwpoison/`` hwpoison-inject模块
+
+ corrupt-pfn
+ 在PFN处注入hwpoison故障,并echoed到这个文件。这做了一些早期过滤,以避
+ 免在测试套件中损坏非预期页面。
+ unpoison-pfn
+ 在PFN的Software-unpoison页面对应到这个文件。这样,一个页面可以再次被
+ 复用。这只对Linux注入的故障起作用,对真正的内存故障不起作用。
+
+ 注意这些注入接口并不稳定,可能会在不同的内核版本中发生变化
+
+ corrupt-filter-dev-major, corrupt-filter-dev-minor
+ 只处理与块设备major/minor定义的文件系统相关的页面的内存故障。-1U是通
+ 配符值。这应该只用于人工注入的测试。
+
+ corrupt-filter-memcg
+ 限制注入到memgroup拥有的页面。由memcg的inode号指定。
+
+ Example::
+
+ mkdir /sys/fs/cgroup/mem/hwpoison
+
+ usemem -m 100 -s 1000 &
+ echo `jobs -p` > /sys/fs/cgroup/mem/hwpoison/tasks
+
+ memcg_ino=$(ls -id /sys/fs/cgroup/mem/hwpoison | cut -f1 -d' ')
+ echo $memcg_ino > /debug/hwpoison/corrupt-filter-memcg
+
+ page-types -p `pidof init` --hwpoison # shall do nothing
+ page-types -p `pidof usemem` --hwpoison # poison its pages
+
+ corrupt-filter-flags-mask, corrupt-filter-flags-value
+ 当指定时,只有在((page_flags & mask) == value)的情况下才会poison页面。
+ 这允许对许多种类的页面进行压力测试。page_flags与/proc/kpageflags中的相
+ 同。这些标志位在include/linux/kernel-page-flags.h中定义,并在
+ Documentation/admin-guide/mm/pagemap.rst中记录。
+
+* 架构特定的MCE注入器
+
+ x86 有 mce-inject, mce-test
+
+ 在mce-test中的一些便携式hwpoison测试程序,见下文。
+
+引用
+====
+
+http://halobates.de/mce-lc09-2.pdf
+ 09年LinuxCon的概述演讲
+
+git://git.kernel.org/pub/scm/utils/cpu/mce/mce-test.git
+ 测试套件(在tsrc中的hwpoison特定可移植测试)。
+
+git://git.kernel.org/pub/scm/utils/cpu/mce/mce-inject.git
+ x86特定的注入器
+
+
+限制
+====
+- 不是所有的页面类型都被支持,而且永远不会。大多数内核内部对象不能被恢
+ 复,目前只有LRU页。
+
+---
+Andi Kleen, 2009年10月
diff --git a/Documentation/translations/zh_CN/mm/index.rst b/Documentation/translations/zh_CN/mm/index.rst
new file mode 100644
index 000000000000..b950dd118be7
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/index.rst
@@ -0,0 +1,68 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/mm/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+=================
+Linux内存管理文档
+=================
+
+这是一份关于了解Linux的内存管理子系统的指南。如果你正在寻找关于简单分配内存的
+建议,请参阅内存分配指南
+(Documentation/translations/zh_CN/core-api/memory-allocation.rst)。
+关于控制和调整的指南,请看管理指南
+(Documentation/translations/zh_CN/admin-guide/mm/index.rst)。
+
+
+.. toctree::
+ :maxdepth: 1
+
+ highmem
+
+该处剩余文档待原始文档有内容后翻译。
+
+
+遗留文档
+========
+
+这是一个关于Linux内存管理(MM)子系统内部的旧文档的集合,其中有不同层次的细节,
+包括注释和邮件列表的回复,用于阐述数据结构和算法的描述。它应该被很好地整合到上述
+结构化的文档中,如果它已经完成了它的使命,可以删除。
+
+.. toctree::
+ :maxdepth: 1
+
+ active_mm
+ balance
+ damon/index
+ free_page_reporting
+ ksm
+ hmm
+ hwpoison
+ hugetlbfs_reserv
+ memory-model
+ mmu_notifier
+ numa
+ overcommit-accounting
+ page_frags
+ page_migration
+ page_owner
+ page_table_check
+ remap_file_pages
+ split_page_table_lock
+ vmalloced-kernel-stacks
+ z3fold
+ zsmalloc
+
+TODOLIST:
+* arch_pgtable_helpers
+* free_page_reporting
+* hugetlbfs_reserv
+* slub
+* transhuge
+* unevictable-lru
diff --git a/Documentation/translations/zh_CN/mm/ksm.rst b/Documentation/translations/zh_CN/mm/ksm.rst
new file mode 100644
index 000000000000..f0f458753d0c
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/ksm.rst
@@ -0,0 +1,70 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/mm/ksm.rst
+
+:翻译:
+
+ 徐鑫 xu xin <xu.xin16@zte.com.cn>
+
+============
+内核同页合并
+============
+
+KSM 是一种节省内存的数据去重功能,由CONFIG_KSM=y启用,并在2.6.32版本时被添加
+到Linux内核。详见 ``mm/ksm.c`` 的实现,以及http://lwn.net/Articles/306704和
+https://lwn.net/Articles/330589
+
+KSM的用户空间的接口在Documentation/translations/zh_CN/admin-guide/mm/ksm.rst
+文档中有描述。
+
+设计
+====
+
+概述
+----
+
+概述内容请见mm/ksm.c文档中的“DOC: Overview”
+
+逆映射
+------
+KSM维护着稳定树中的KSM页的逆映射信息。
+
+当KSM页面的共享数小于 ``max_page_sharing`` 的虚拟内存区域(VMAs)时,则代表了
+KSM页的稳定树其中的节点指向了一个ksm_rmap_item结构体类型的列表。同时,这个KSM页
+的 ``page->mapping`` 指向了该稳定树节点。
+
+如果共享数超过了阈值,KSM将给稳定树添加第二个维度。稳定树就变成链接一个或多
+个稳定树"副本"的"链"。每个副本都保留KSM页的逆映射信息,其中 ``page->mapping``
+指向该"副本"。
+
+每个链以及链接到该链中的所有"副本"强制不变的是,它们代表了相同的写保护内存
+内容,尽管任中一个"副本"是由同一片内存区的不同的KSM复制页所指向的。
+
+这样一来,相比与无限的逆映射链表,稳定树的查找计算复杂性不受影响。但在稳定树
+本身中不能有重复的KSM页面内容仍然是强制要求。
+
+由 ``max_page_sharing`` 强制决定的数据去重限制是必要的,以此来避免虚拟内存
+rmap链表变得过大。rmap的遍历具有O(N)的复杂度,其中N是共享页面的rmap_项(即
+虚拟映射)的数量,而这个共享页面的节点数量又被 ``max_page_sharing`` 所限制。
+因此,这有效地将线性O(N)计算复杂度从rmap遍历中分散到不同的KSM页面上。ksmd进
+程在稳定节点"链"上的遍历也是O(N),但这个N是稳定树"副本"的数量,而不是rmap项
+的数量,因此它对ksmd性能没有显著影响。实际上,最佳稳定树"副本"的候选节点将
+保留在"副本"列表的开头。
+
+``max_page_sharing`` 的值设置得高了会促使更快的内存合并(因为将有更少的稳定
+树副本排队进入稳定节点chain->hlist)和更高的数据去重系数,但代价是在交换、压
+缩、NUMA平衡和页面迁移过程中可能导致KSM页的最大rmap遍历速度较慢。
+
+``stable_node_dups/stable_node_chains`` 的比值还受 ``max_page_sharing`` 调控
+的影响,高比值可能意味着稳定节点dup中存在碎片,这可以通过在ksmd中引入碎片算
+法来解决,该算法将rmap项从一个稳定节点dup重定位到另一个稳定节点dup,以便释放
+那些仅包含极少rmap项的稳定节点"dup",但这可能会增加ksmd进程的CPU使用率,并可
+能会减慢应用程序在KSM页面上的只读计算。
+
+KSM会定期扫描稳定节点"链"中链接的所有稳定树"副本",以便删减过时了的稳定节点。
+这种扫描的频率由 ``stable_node_chains_prune_millisecs`` 这个sysfs 接口定义。
+
+参考
+====
+内核代码请见mm/ksm.c。
+涉及的函数(mm_slot ksm_scan stable_node rmap_item)。
diff --git a/Documentation/translations/zh_CN/mm/memory-model.rst b/Documentation/translations/zh_CN/mm/memory-model.rst
new file mode 100644
index 000000000000..77ec149a970c
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/memory-model.rst
@@ -0,0 +1,135 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+:Original: Documentation/mm/memory-model.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+============
+物理内存模型
+============
+
+系统中的物理内存可以用不同的方式进行寻址。最简单的情况是,物理内存从地址0开
+始,跨越一个连续的范围,直到最大的地址。然而,这个范围可能包含CPU无法访问的
+小孔隙。那么,在完全不同的地址可能有几个连续的范围。而且,别忘了NUMA,即不
+同的内存库连接到不同的CPU。
+
+Linux使用两种内存模型中的一种对这种多样性进行抽象。FLATMEM和SPARSEM。每
+个架构都定义了它所支持的内存模型,默认的内存模型是什么,以及是否有可能手动
+覆盖该默认值。
+
+所有的内存模型都使用排列在一个或多个数组中的 `struct page` 来跟踪物理页
+帧的状态。
+
+无论选择哪种内存模型,物理页框号(PFN)和相应的 `struct page` 之间都存
+在一对一的映射关系。
+
+每个内存模型都定义了 :c:func:`pfn_to_page` 和 :c:func:`page_to_pfn`
+帮助函数,允许从PFN到 `struct page` 的转换,反之亦然。
+
+FLATMEM
+=======
+
+最简单的内存模型是FLATMEM。这个模型适用于非NUMA系统的连续或大部分连续的
+物理内存。
+
+在FLATMEM内存模型中,有一个全局的 `mem_map` 数组来映射整个物理内存。对
+于大多数架构,孔隙在 `mem_map` 数组中都有条目。与孔洞相对应的 `struct page`
+对象从未被完全初始化。
+
+为了分配 `mem_map` 数组,架构特定的设置代码应该调用free_area_init()函数。
+然而,在调用memblock_free_all()函数之前,映射数组是不能使用的,该函数
+将所有的内存交给页分配器。
+
+一个架构可能会释放 `mem_map` 数组中不包括实际物理页的部分。在这种情况下,特
+定架构的 :c:func:`pfn_valid` 实现应该考虑到 `mem_map` 中的孔隙。
+
+使用FLATMEM,PFN和 `struct page` 之间的转换是直接的。 `PFN - ARCH_PFN_OFFSET`
+是 `mem_map` 数组的一个索引。
+
+`ARCH_PFN_OFFSET` 定义了物理内存起始地址不同于0的系统的第一个页框号。
+
+SPARSEMEM
+=========
+
+SPARSEMEM是Linux中最通用的内存模型,它是唯一支持若干高级功能的内存模型,
+如物理内存的热插拔、非易失性内存设备的替代内存图和较大系统的内存图的延迟
+初始化。
+
+SPARSEMEM模型将物理内存显示为一个部分的集合。一个区段用mem_section结构
+体表示,它包含 `section_mem_map` ,从逻辑上讲,它是一个指向 `struct page`
+阵列的指针。然而,它被存储在一些其他的magic中,以帮助分区管理。区段的大小
+和最大区段数是使用 `SECTION_SIZE_BITS` 和 `MAX_PHYSMEM_BITS` 常量
+来指定的,这两个常量是由每个支持SPARSEMEM的架构定义的。 `MAX_PHYSMEM_BITS`
+是一个架构所支持的物理地址的实际宽度,而 `SECTION_SIZE_BITS` 是一个任
+意的值。
+
+最大的段数表示为 `NR_MEM_SECTIONS` ,定义为
+
+.. math::
+
+ NR\_MEM\_SECTIONS = 2 ^ {(MAX\_PHYSMEM\_BITS - SECTION\_SIZE\_BITS)}
+
+`mem_section` 对象被安排在一个叫做 `mem_sections` 的二维数组中。这个数组的
+大小和位置取决于 `CONFIG_SPARSEM_EXTREME` 和可能的最大段数:
+
+* 当 `CONFIG_SPARSEMEM_EXTREME` 被禁用时, `mem_sections` 数组是静态的,有
+ `NR_MEM_SECTIONS` 行。每一行持有一个 `mem_section` 对象。
+* 当 `CONFIG_SPARSEMEM_EXTREME` 被启用时, `mem_sections` 数组被动态分配。
+ 每一行包含价值 `PAGE_SIZE` 的 `mem_section` 对象,行数的计算是为了适应所有的
+ 内存区。
+
+架构设置代码应该调用sparse_init()来初始化内存区和内存映射。
+
+通过SPARSEMEM,有两种可能的方式将PFN转换为相应的 `struct page` --"classic sparse"和
+ "sparse vmemmap"。选择是在构建时进行的,它由 `CONFIG_SPARSEMEM_VMEMMAP` 的
+ 值决定。
+
+Classic sparse在page->flags中编码了一个页面的段号,并使用PFN的高位来访问映射该页
+框的段。在一个区段内,PFN是指向页数组的索引。
+
+Sparse vmemmapvmemmap使用虚拟映射的内存映射来优化pfn_to_page和page_to_pfn操
+作。有一个全局的 `struct page *vmemmap` 指针,指向一个虚拟连续的 `struct page`
+对象阵列。PFN是该数组的一个索引,`struct page` 从 `vmemmap` 的偏移量是该页的PFN。
+
+为了使用vmemmap,一个架构必须保留一个虚拟地址的范围,以映射包含内存映射的物理页,并
+确保 `vmemmap`指向该范围。此外,架构应该实现 :c:func:`vmemmap_populate` 方法,
+它将分配物理内存并为虚拟内存映射创建页表。如果一个架构对vmemmap映射没有任何特殊要求,
+它可以使用通用内存管理提供的默认 :c:func:`vmemmap_populate_basepages`。
+
+虚拟映射的内存映射允许将持久性内存设备的 `struct page` 对象存储在这些设备上预先分
+配的存储中。这种存储用vmem_altmap结构表示,最终通过一长串的函数调用传递给
+vmemmap_populate()。vmemmap_populate()实现可以使用 `vmem_altmap` 和
+:c:func:`vmemmap_alloc_block_buf` 助手来分配持久性内存设备上的内存映射。
+
+ZONE_DEVICE
+===========
+`ZONE_DEVICE` 设施建立在 `SPARSEM_VMEMMAP` 之上,为设备驱动识别的物理地址范
+围提供 `struct page` `mem_map` 服务。 `ZONE_DEVICE` 的 "设备" 方面与以下
+事实有关:这些地址范围的页面对象从未被在线标记过,而且必须对设备进行引用,而不仅仅
+是页面,以保持内存被“锁定”以便使用。 `ZONE_DEVICE` ,通过 :c:func:`devm_memremap_pages` ,
+为给定的pfns范围执行足够的内存热插拔来开启 :c:func:`pfn_to_page`,
+:c:func:`page_to_pfn`, ,和 :c:func:`get_user_pages` 服务。由于页面引
+用计数永远不会低于1,所以页面永远不会被追踪为空闲内存,页面的 `struct list_head lru`
+空间被重新利用,用于向映射该内存的主机设备/驱动程序进行反向引用。
+
+虽然 `SPARSEMEM` 将内存作为一个区段的集合,可以选择收集并合成内存块,但
+`ZONE_DEVICE` 用户需要更小的颗粒度来填充 `mem_map` 。鉴于 `ZONE_DEVICE`
+内存从未被在线标记,因此它的内存范围从未通过sysfs内存热插拔api暴露在内存块边界
+上。这个实现依赖于这种缺乏用户接口的约束,允许子段大小的内存范围被指定给
+:c:func:`arch_add_memory` ,即内存热插拔的上半部分。子段支持允许2MB作为
+:c:func:`devm_memremap_pages` 的跨架构通用对齐颗粒度。
+
+`ZONE_DEVICE` 的用户是:
+
+* pmem: 通过DAX映射将平台持久性内存作为直接I/O目标使用。
+
+* hmm: 用 `->page_fault()` 和 `->page_free()` 事件回调扩展 `ZONE_DEVICE` ,
+ 以允许设备驱动程序协调与设备内存相关的内存管理事件,通常是GPU内存。参见Documentation/mm/hmm.rst。
+
+* p2pdma: 创建 `struct page` 对象,允许PCI/E拓扑结构中的peer设备协调它们之间的
+ 直接DMA操作,即绕过主机内存。
diff --git a/Documentation/translations/zh_CN/mm/mmu_notifier.rst b/Documentation/translations/zh_CN/mm/mmu_notifier.rst
new file mode 100644
index 000000000000..ce3664d1a410
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/mmu_notifier.rst
@@ -0,0 +1,97 @@
+:Original: Documentation/mm/mmu_notifier.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+
+什么时候需要页表锁内通知?
+==========================
+
+当清除一个pte/pmd时,我们可以选择通过在页表锁下(通知版的\*_clear_flush调用
+mmu_notifier_invalidate_range)通知事件。但这种通知并不是在所有情况下都需要的。
+
+对于二级TLB(非CPU TLB),如IOMMU TLB或设备TLB(当设备使用类似ATS/PASID的东西让
+IOMMU走CPU页表来访问进程的虚拟地址空间)。只有两种情况需要在清除pte/pmd时在持有页
+表锁的同时通知这些二级TLB:
+
+ A) 在mmu_notifier_invalidate_range_end()之前,支持页的地址被释放。
+ B) 一个页表项被更新以指向一个新的页面(COW,零页上的写异常,__replace_page(),...)。
+
+情况A很明显,你不想冒风险让设备写到一个现在可能被一些完全不同的任务使用的页面。
+
+情况B更加微妙。为了正确起见,它需要按照以下序列发生:
+
+ - 上页表锁
+ - 清除页表项并通知 ([pmd/pte]p_huge_clear_flush_notify())
+ - 设置页表项以指向新页
+
+如果在设置新的pte/pmd值之前,清除页表项之后没有进行通知,那么你就会破坏设备的C11或
+C++11等内存模型。
+
+考虑以下情况(设备使用类似于ATS/PASID的功能)。
+
+两个地址addrA和addrB,这样|addrA - addrB| >= PAGE_SIZE,我们假设它们是COW的
+写保护(B的其他情况也适用)。
+
+::
+
+ [Time N] --------------------------------------------------------------------
+ CPU-thread-0 {尝试写到addrA}
+ CPU-thread-1 {尝试写到addrB}
+ CPU-thread-2 {}
+ CPU-thread-3 {}
+ DEV-thread-0 {读取addrA并填充设备TLB}
+ DEV-thread-2 {读取addrB并填充设备TLB}
+ [Time N+1] ------------------------------------------------------------------
+ CPU-thread-0 {COW_step0: {mmu_notifier_invalidate_range_start(addrA)}}
+ CPU-thread-1 {COW_step0: {mmu_notifier_invalidate_range_start(addrB)}}
+ CPU-thread-2 {}
+ CPU-thread-3 {}
+ DEV-thread-0 {}
+ DEV-thread-2 {}
+ [Time N+2] ------------------------------------------------------------------
+ CPU-thread-0 {COW_step1: {更新页表以指向addrA的新页}}
+ CPU-thread-1 {COW_step1: {更新页表以指向addrB的新页}}
+ CPU-thread-2 {}
+ CPU-thread-3 {}
+ DEV-thread-0 {}
+ DEV-thread-2 {}
+ [Time N+3] ------------------------------------------------------------------
+ CPU-thread-0 {preempted}
+ CPU-thread-1 {preempted}
+ CPU-thread-2 {写入addrA,这是对新页面的写入}
+ CPU-thread-3 {}
+ DEV-thread-0 {}
+ DEV-thread-2 {}
+ [Time N+3] ------------------------------------------------------------------
+ CPU-thread-0 {preempted}
+ CPU-thread-1 {preempted}
+ CPU-thread-2 {}
+ CPU-thread-3 {写入addrB,这是一个写入新页的过程}
+ DEV-thread-0 {}
+ DEV-thread-2 {}
+ [Time N+4] ------------------------------------------------------------------
+ CPU-thread-0 {preempted}
+ CPU-thread-1 {COW_step3: {mmu_notifier_invalidate_range_end(addrB)}}
+ CPU-thread-2 {}
+ CPU-thread-3 {}
+ DEV-thread-0 {}
+ DEV-thread-2 {}
+ [Time N+5] ------------------------------------------------------------------
+ CPU-thread-0 {preempted}
+ CPU-thread-1 {}
+ CPU-thread-2 {}
+ CPU-thread-3 {}
+ DEV-thread-0 {从旧页中读取addrA}
+ DEV-thread-2 {从新页面读取addrB}
+
+所以在这里,因为在N+2的时候,清空页表项没有和通知一起作废二级TLB,设备在看到addrA的新值之前
+就看到了addrB的新值。这就破坏了设备的总内存序。
+
+当改变一个pte的写保护或指向一个新的具有相同内容的写保护页(KSM)时,将mmu_notifier_invalidate_range
+调用延迟到页表锁外的mmu_notifier_invalidate_range_end()是可以的。即使做页表更新的线程
+在释放页表锁后但在调用mmu_notifier_invalidate_range_end()前被抢占,也是如此。
diff --git a/Documentation/translations/zh_CN/mm/numa.rst b/Documentation/translations/zh_CN/mm/numa.rst
new file mode 100644
index 000000000000..61fad89272fa
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/numa.rst
@@ -0,0 +1,101 @@
+:Original: Documentation/mm/numa.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+始于1999年11月,作者: <kanoj@sgi.com>
+
+==========================
+何为非统一内存访问(NUMA)?
+==========================
+
+这个问题可以从几个视角来回答:硬件观点和Linux软件视角。
+
+从硬件角度看,NUMA系统是一个由多个组件或装配组成的计算机平台,每个组件可能包含0个或更多的CPU、
+本地内存和/或IO总线。为了简洁起见,并将这些物理组件/装配的硬件视角与软件抽象区分开来,我们在
+本文中称这些组件/装配为“单元”。
+
+每个“单元”都可以看作是系统的一个SMP[对称多处理器]子集——尽管独立的SMP系统所需的一些组件可能
+不会在任何给定的单元上填充。NUMA系统的单元通过某种系统互连连接在一起——例如,交叉开关或点对点
+链接是NUMA系统互连的常见类型。这两种类型的互连都可以聚合起来,以创建NUMA平台,其中的单元与其
+他单元有多个距离。
+
+对于Linux,感兴趣的NUMA平台主要是所谓的缓存相干NUMA--简称ccNUMA系统系统。在ccNUMA系统中,
+所有的内存都是可见的,并且可以从连接到任何单元的任何CPU中访问,缓存一致性是由处理器缓存和/或
+系统互连在硬件中处理。
+
+内存访问时间和有效的内存带宽取决于包含CPU的单元或进行内存访问的IO总线距离包含目标内存的单元
+有多远。例如,连接到同一单元的CPU对内存的访问将比访问其他远程单元的内存经历更快的访问时间和
+更高的带宽。 NUMA平台可以在任何给定单元上访问多种远程距离的(其他)单元。
+
+平台供应商建立NUMA系统并不只是为了让软件开发人员的生活变得有趣。相反,这种架构是提供可扩展
+内存带宽的一种手段。然而,为了实现可扩展的内存带宽,系统和应用软件必须安排大部分的内存引用
+[cache misses]到“本地”内存——同一单元的内存,如果有的话——或者到最近的有内存的单元。
+
+这就自然而然有了Linux软件对NUMA系统的视角:
+
+Linux将系统的硬件资源划分为多个软件抽象,称为“节点”。Linux将节点映射到硬件平台的物理单元
+上,对一些架构的细节进行了抽象。与物理单元一样,软件节点可能包含0或更多的CPU、内存和/或IO
+总线。同样,对“较近”节点的内存访问——映射到较近单元的节点——通常会比对较远单元的访问经历更快
+的访问时间和更高的有效带宽。
+
+对于一些架构,如x86,Linux将“隐藏”任何代表没有内存连接的物理单元的节点,并将连接到该单元
+的任何CPU重新分配到代表有内存的单元的节点上。因此,在这些架构上,我们不能假设Linux将所有
+的CPU与一个给定的节点相关联,会看到相同的本地内存访问时间和带宽。
+
+此外,对于某些架构,同样以x86为例,Linux支持对额外节点的仿真。对于NUMA仿真,Linux会将现
+有的节点或者非NUMA平台的系统内存分割成多个节点。每个模拟的节点将管理底层单元物理内存的一部
+分。NUMA仿真对于在非NUMA平台上测试NUMA内核和应用功能是非常有用的,当与cpusets一起使用时,
+可以作为一种内存资源管理机制。[见 Documentation/admin-guide/cgroup-v1/cpusets.rst]
+
+对于每个有内存的节点,Linux构建了一个独立的内存管理子系统,有自己的空闲页列表、使用中页列表、
+使用统计和锁来调解访问。此外,Linux为每个内存区[DMA、DMA32、NORMAL、HIGH_MEMORY、MOVABLE
+中的一个或多个]构建了一个有序的“区列表”。zonelist指定了当一个选定的区/节点不能满足分配请求
+时要访问的区/节点。当一个区没有可用的内存来满足请求时,这种情况被称为“overflow 溢出”或
+“fallback 回退”。
+
+由于一些节点包含多个包含不同类型内存的区,Linux必须决定是否对区列表进行排序,使分配回退到不同
+节点上的相同区类型,或同一节点上的不同区类型。这是一个重要的考虑因素,因为有些区,如DMA或DMA32,
+代表了相对稀缺的资源。Linux选择了一个默认的Node ordered zonelist。这意味着在使用按NUMA距
+离排序的远程节点之前,它会尝试回退到同一节点的其他分区。
+
+默认情况下,Linux会尝试从执行请求的CPU被分配到的节点中满足内存分配请求。具体来说,Linux将试
+图从请求来源的节点的适当分区列表中的第一个节点进行分配。这被称为“本地分配”。如果“本地”节点不能
+满足请求,内核将检查所选分区列表中其他节点的区域,寻找列表中第一个能满足请求的区域。
+
+本地分配将倾向于保持对分配的内存的后续访问 “本地”的底层物理资源和系统互连——只要内核代表其分配
+一些内存的任务后来不从该内存迁移。Linux调度器知道平台的NUMA拓扑结构——体现在“调度域”数据结构
+中[见 Documentation/scheduler/sched-domains.rst]——并且调度器试图尽量减少任务迁移到遥
+远的调度域中。然而,调度器并没有直接考虑到任务的NUMA足迹。因此,在充分不平衡的情况下,任务可
+以在节点之间迁移,远离其初始节点和内核数据结构。
+
+系统管理员和应用程序设计者可以使用各种CPU亲和命令行接口,如taskset(1)和numactl(1),以及程
+序接口,如sched_setaffinity(2),来限制任务的迁移,以改善NUMA定位。此外,人们可以使用
+Linux NUMA内存策略修改内核的默认本地分配行为。 [见
+Documentation/admin-guide/mm/numa_memory_policy.rst].
+
+系统管理员可以使用控制组和CPUsets限制非特权用户在调度或NUMA命令和功能中可以指定的CPU和节点
+的内存。 [见 Documentation/admin-guide/cgroup-v1/cpusets.rst]
+
+在不隐藏无内存节点的架构上,Linux会在分区列表中只包括有内存的区域[节点]。这意味着对于一个无
+内存的节点,“本地内存节点”——CPU节点的分区列表中的第一个区域的节点——将不是节点本身。相反,它
+将是内核在建立分区列表时选择的离它最近的有内存的节点。所以,默认情况下,本地分配将由内核提供
+最近的可用内存来完成。这是同一机制的结果,该机制允许这种分配在一个包含内存的节点溢出时回退到
+其他附近的节点。
+
+一些内核分配不希望或不能容忍这种分配回退行为。相反,他们想确保他们从指定的节点获得内存,或者
+得到通知说该节点没有空闲内存。例如,当一个子系统分配每个CPU的内存资源时,通常是这种情况。
+
+一个典型的分配模式是使用内核的numa_node_id()或CPU_to_node()函数获得“当前CPU”所在节点的
+节点ID,然后只从返回的节点ID请求内存。当这样的分配失败时,请求的子系统可以恢复到它自己的回退
+路径。板块内核内存分配器就是这样的一个例子。或者,子系统可以选择在分配失败时禁用或不启用自己。
+内核分析子系统就是这样的一个例子。
+
+如果架构支持——不隐藏无内存节点,那么连接到无内存节点的CPU将总是产生回退路径的开销,或者一些
+子系统如果试图完全从无内存的节点分配内存,将无法初始化。为了透明地支持这种架构,内核子系统可
+以使用numa_mem_id()或cpu_to_mem()函数来定位调用或指定CPU的“本地内存节点”。同样,这是同
+一个节点,默认的本地页分配将从这个节点开始尝试。
diff --git a/Documentation/translations/zh_CN/mm/overcommit-accounting.rst b/Documentation/translations/zh_CN/mm/overcommit-accounting.rst
new file mode 100644
index 000000000000..d8452d8b7fbb
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/overcommit-accounting.rst
@@ -0,0 +1,86 @@
+:Original: Documentation/mm/overcommit-accounting.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+
+==============
+超量使用审计
+==============
+
+Linux内核支持下列超量使用处理模式
+
+0
+ 启发式超量使用处理。拒绝明显的地址空间超量使用。用于一个典型的系统。
+ 它确保严重的疯狂分配失败,同时允许超量使用以减少swap的使用。在这种模式下,
+ 允许root分配稍多的内存。这是默认的。
+1
+ 总是超量使用。适用于一些科学应用。经典的例子是使用稀疏数组的代码,只是依赖
+ 几乎完全由零页组成的虚拟内存
+
+2
+ 不超量使用。系统提交的总地址空间不允许超过swap+一个可配置的物理RAM的数量
+ (默认为50%)。根据你使用的数量,在大多数情况下,这意味着一个进程在访问页面时
+ 不会被杀死,但会在内存分配上收到相应的错误。
+
+ 对于那些想保证他们的内存分配在未来可用而又不需要初始化每一个页面的应用程序来说
+ 是很有用的。
+
+超量使用策略是通过sysctl `vm.overcommit_memory` 设置的。
+
+可以通过 `vm.overcommit_ratio` (百分比)或 `vm.overcommit_kbytes` (绝对值)
+来设置超限数量。这些只有在 `vm.overcommit_memory` 被设置为2时才有效果。
+
+在 ``/proc/meminfo`` 中可以分别以CommitLimit和Committed_AS的形式查看当前
+的超量使用和提交量。
+
+陷阱
+====
+
+C语言的堆栈增长是一个隐含的mremap。如果你想得到绝对的保证,并在接近边缘的地方运行,
+你 **必须** 为你认为你需要的最大尺寸的堆栈进行mmap。对于典型的堆栈使用来说,这并
+不重要,但如果你真的非常关心的话,这就是一个值得关注的案例。
+
+
+在模式2中,MAP_NORESERVE标志被忽略。
+
+
+它是如何工作的
+==============
+
+超量使用是基于以下规则
+
+对于文件映射
+ | SHARED or READ-only - 0 cost (该文件是映射而不是交换)
+ | PRIVATE WRITABLE - 每个实例的映射大小
+
+对于匿名或者 ``/dev/zero`` 映射
+ | SHARED - 映射的大小
+ | PRIVATE READ-only - 0 cost (但作用不大)
+ | PRIVATE WRITABLE - 每个实例的映射大小
+
+额外的计数
+ | 通过mmap制作可写副本的页面
+ | 从同一池中提取的shmfs内存
+
+状态
+====
+
+* 我们核算mmap内存映射
+* 我们核算mprotect在提交中的变化
+* 我们核算mremap的大小变化
+* 我们的审计 brk
+* 审计munmap
+* 我们在/proc中报告commit 状态
+* 核对并检查分叉的情况
+* 审查堆栈处理/执行中的构建
+* 叙述SHMfs的情况
+* 实现实际限制的执行
+
+待续
+====
+* ptrace 页计数(这很难)。
diff --git a/Documentation/translations/zh_CN/mm/page_frags.rst b/Documentation/translations/zh_CN/mm/page_frags.rst
new file mode 100644
index 000000000000..20bd3fafdc8c
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/page_frags.rst
@@ -0,0 +1,38 @@
+:Original: Documentation/mm/page_frags.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+========
+页面片段
+========
+
+一个页面片段是一个任意长度的任意偏移的内存区域,它位于一个0或更高阶的复合页面中。
+该页中的多个碎片在该页的引用计数器中被单独计算。
+
+page_frag函数,page_frag_alloc和page_frag_free,为页面片段提供了一个简单
+的分配框架。这被网络堆栈和网络设备驱动使用,以提供一个内存的支持区域,作为
+sk_buff->head使用,或者用于skb_shared_info的 “frags” 部分。
+
+为了使用页面片段API,需要一个支持页面片段的缓冲区。这为碎片分配提供了一个中心点,
+并允许多个调用使用一个缓存的页面。这样做的好处是可以避免对get_page的多次调用,
+这在分配时开销可能会很大。然而,由于这种缓存的性质,要求任何对缓存的调用都要受到每
+个CPU的限制,或者每个CPU的限制,并在执行碎片分配时强制禁止中断。
+
+网络堆栈在每个CPU使用两个独立的缓存来处理碎片分配。netdev_alloc_cache被使用
+netdev_alloc_frag和__netdev_alloc_skb调用的调用者使用。napi_alloc_cache
+被调用__napi_alloc_frag和__napi_alloc_skb的调用者使用。这两个调用的主要区别是
+它们可能被调用的环境。“netdev” 前缀的函数可以在任何上下文中使用,因为这些函数
+将禁用中断,而 ”napi“ 前缀的函数只可以在softirq上下文中使用。
+
+许多网络设备驱动程序使用类似的方法来分配页面片段,但页面片段是在环或描述符级别上
+缓存的。为了实现这些情况,有必要提供一种拆解页面缓存的通用方法。出于这个原因,
+__page_frag_cache_drain被实现了。它允许通过一次调用从一个页面释放多个引用。
+这样做的好处是,它允许清理被添加到一个页面的多个引用,以避免每次分配都调用
+get_page。
+
+Alexander Duyck,2016年11月29日。
diff --git a/Documentation/translations/zh_CN/mm/page_migration.rst b/Documentation/translations/zh_CN/mm/page_migration.rst
new file mode 100644
index 000000000000..f95063826a15
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/page_migration.rst
@@ -0,0 +1,228 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/mm/page_migration.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+========
+页面迁移
+========
+
+页面迁移允许在进程运行时在NUMA系统的节点之间移动页面的物理位置。这意味着进程所看到的虚拟地
+址并没有改变。然而,系统会重新安排这些页面的物理位置。
+
+也可以参见 :ref: `<异构内存管理 (HMM)>` 以了解将页面迁移到设备私有内存或从设备私有内存中迁移。
+
+页面迁移的主要目的是通过将页面移到访问该内存的进程所运行的处理器附近来减少内存访问的延迟。
+
+页面迁移允许进程通过MF_MOVE和MF_MOVE_ALL选项手动重新定位其页面所在的节点,同时通过
+mbind()设置一个新的内存策略。一个进程的页面也可以通过sys_migrate_pages()函数调用从另
+一个进程重新定位。migrate_pages()函数调用接收两组节点,并将一个进程位于旧节点上的页面移
+动到目标节点上。页面迁移功能由Andi Kleen的numactl包提供(需要0.9.3以上的版本,其仓库
+地址https://github.com/numactl/numactl.git)。numactl提供了libnuma,它为页面迁移
+提供了与其他NUMA功能类似的接口。执行 cat ``/proc/<pid>/numa_maps`` 允许轻松查看进
+程的页面位置。参见proc(5)手册中的numa_maps文档。
+
+如果调度程序将一个进程重新安置到一个遥远的节点上的处理器,手动迁移是很有用的。批量调度程序
+或管理员可以检测到这种情况,并将进程的页面移到新处理器附近。内核本身只提供手动的页迁移支持。
+自动的页面迁移可以通过用户空间的进程移动页面来实现。一个特殊的函数调用 "move_pages" 允许
+在一个进程中移动单个页面。例如,NUMA分析器可以获得一个显示频繁的节点外访问的日志,并可以使
+用这个结果将页面移动到更有利的位置。
+
+较大型的设备通常使用cpusets将系统分割成若干个节点。Paul Jackson为cpusets配备了当任务被
+转移到另一个cpuset时移动页面的能力(见:ref:`CPUSETS <cpusets>`)。Cpusets允许进程定
+位的自动化。如果一个任务被移到一个新的cpuset上,那么它的所有页面也会随之移动,这样进程的
+性能就不会急剧下降。如果cpuset允许的内存节点发生变化,cpuset中的进程页也会被移动。
+
+页面迁移允许为所有迁移技术保留一组节点中页面的相对位置,这将保留生成的特定内存分配模式即使
+进程已被迁移。为了保留内存延迟,这一点是必要的。迁移后的进程将以类似的性能运行。
+
+页面迁移分几个步骤进行。首先为那些试图从内核中使用migrate_pages()的进程做一个高层次的
+描述(对于用户空间的使用,可以参考上面提到的Andi Kleen的numactl包),然后对低水平的细
+节工作做一个低水平描述。
+
+在内核中使用 migrate_pages()
+============================
+
+1. 从LRU中移除页面。
+
+ 要迁移的页面列表是通过扫描页面并把它们移到列表中来生成的。这是通过调用 isolate_lru_page()
+ 来完成的。调用isolate_lru_page()增加了对该页的引用,这样在页面迁移发生时它就不会
+ 消失。它还可以防止交换器或其他扫描器遇到该页。
+
+
+2. 我们需要有一个new_folio_t类型的函数,可以传递给migrate_pages()。这个函数应该计算
+ 出如何在给定的旧页面中分配正确的新页面。
+
+3. migrate_pages()函数被调用,它试图进行迁移。它将调用该函数为每个被考虑迁移的页面分
+ 配新的页面。
+
+migrate_pages()如何工作
+=======================
+
+migrate_pages()对它的页面列表进行了多次处理。如果当时对一个页面的所有引用都可以被移除,
+那么这个页面就会被移动。该页已经通过isolate_lru_page()从LRU中移除,并且refcount被
+增加,以便在页面迁移发生时不释放该页。
+
+步骤:
+
+1. 锁定要迁移的页面。
+
+2. 确保回写已经完成。
+
+3. 锁定我们要迁移到的新页面。锁定它是为了在迁移过程中立即阻止对这个(尚未更新的)页面的
+ 访问。
+
+4. 所有对该页的页表引用都被转换为迁移条目。这就减少了一个页面的mapcount。如果产生的
+ mapcount不是零,那么我们就不迁移该页。所有试图访问该页的用户空间进程现在将等待页
+ 面锁或者等待迁移页表项被移除。
+
+5. i_pages的锁被持有。这将导致所有试图通过映射访问该页的进程在自旋锁上阻塞。
+
+6. 检查该页的Refcount,如果还有引用,我们就退出。否则,我们知道我们是唯一引用这个页
+ 面的人。
+
+7. 检查基数树,如果它不包含指向这个页面的指针,那么我们就退出,因为其他人修改了基数树。
+
+8. 新的页面要用旧的页面的一些设置进行预处理,这样访问新的页面就会发现一个具有正确设置
+ 的页面。
+
+9. 基数树被改变以指向新的页面。
+
+10. 旧页的引用计数被删除,因为地址空间的引用已经消失。对新页的引用被建立,因为新页被
+ 地址空间引用。
+
+11. i_pages锁被放弃。这样一来,在映射中的查找又变得可能了。进程将从在锁上自旋到在
+ 被锁的新页上睡眠。
+
+12. 页面内容被复制到新的页面上。
+
+13. 剩余的页面标志被复制到新的页面上。
+
+14. 旧的页面标志被清除,以表明该页面不再提供任何信息。
+
+15. 新页面上的回写队列被触发了。
+
+16. 如果迁移条目被插入到页表中,那么就用真正的ptes替换它们。这样做将使那些尚未等待页
+ 锁的用户空间进程能够访问。
+
+17. 页面锁从新旧页面上被撤销。等待页锁的进程将重做他们的缺页异常,并将到达新的页面。
+
+18. 新的页面被移到LRU中,可以被交换器等再次扫描。
+
+非LRU页面迁移
+=============
+
+尽管迁移最初的目的是为了减少NUMA的内存访问延迟,但压缩也使用迁移来创建高阶页面。
+
+目前实现的问题是,它被设计为只迁移*LRU*页。然而,有一些潜在的非LRU页面可以在驱动中
+被迁移,例如,zsmalloc,virtio-balloon页面。
+
+对于virtio-balloon页面,迁移代码路径的某些部分已经被钩住,并添加了virtio-balloon
+的特定函数来拦截迁移逻辑。这对一个驱动来说太特殊了,所以其他想让自己的页面可移动的驱
+动就必须在迁移路径中添加自己的特定钩子。
+
+为了克服这个问题,VM支持非LRU页面迁移,它为非LRU可移动页面提供了通用函数,而在迁移
+路径中没有特定的驱动程序钩子。
+
+如果一个驱动程序想让它的页面可移动,它应该定义三个函数,这些函数是
+struct address_space_operations的函数指针。
+
+1. ``bool (*isolate_page) (struct page *page, isolate_mode_t mode);``
+
+ VM对驱动的isolate_page()函数的期望是,如果驱动成功隔离了该页,则返回*true*。
+ 返回true后,VM会将该页标记为PG_isolated,这样多个CPU的并发隔离就会跳过该
+ 页进行隔离。如果驱动程序不能隔离该页,它应该返回*false*。
+
+ 一旦页面被成功隔离,VM就会使用page.lru字段,因此驱动程序不应期望保留这些字段的值。
+
+2. ``int (*migratepage) (struct address_space *mapping,``
+| ``struct page *newpage, struct page *oldpage, enum migrate_mode);``
+
+ 隔离后,虚拟机用隔离的页面调用驱动的migratepage()。migratepage()的功能是将旧页
+ 的内容移动到新页,并设置struct page newpage的字段。请记住,如果你成功迁移了旧页
+ 并返回MIGRATEPAGE_SUCCESS,你应该通过page_lock下的__ClearPageMovable()向虚
+ 拟机表明旧页不再可移动。如果驱动暂时不能迁移该页,驱动可以返回-EAGAIN。在-EAGAIN
+ 时,VM会在短时间内重试页面迁移,因为VM将-EAGAIN理解为 "临时迁移失败"。在返回除
+ -EAGAIN以外的任何错误时,VM将放弃页面迁移而不重试。
+
+ 在migratepage()函数中,驱动程序不应该接触page.lru字段。
+
+3. ``void (*putback_page)(struct page *);``
+
+ 如果在隔离页上迁移失败,VM应该将隔离页返回给驱动,因此VM用隔离页调用驱动的
+ putback_page()。在这个函数中,驱动应该把隔离页放回自己的数据结构中。
+
+非LRU可移动页标志
+
+ 有两个页面标志用于支持非LRU可移动页面。
+
+ * PG_movable
+
+ 驱动应该使用下面的函数来使页面在page_lock下可移动。::
+
+ void __SetPageMovable(struct page *page, struct address_space *mapping)
+
+ 它需要address_space的参数来注册将被VM调用的migration family函数。确切地说,
+ PG_movable不是struct page的一个真正的标志。相反,VM复用了page->mapping的低
+ 位来表示它::
+
+ #define PAGE_MAPPING_MOVABLE 0x2
+ page->mapping = page->mapping | PAGE_MAPPING_MOVABLE;
+
+ 所以驱动不应该直接访问page->mapping。相反,驱动应该使用page_mapping(),它可
+ 以在页面锁下屏蔽掉page->mapping的低2位,从而获得正确的struct address_space。
+
+ 对于非LRU可移动页面的测试,VM支持__PageMovable()函数。然而,它并不能保证识别
+ 非LRU可移动页面,因为page->mapping字段与struct page中的其他变量是统一的。如
+ 果驱动程序在被虚拟机隔离后释放了页面,尽管page->mapping设置了PAGE_MAPPING_MOVABLE,
+ 但它并没有一个稳定的值(看看__ClearPageMovable)。但是__PageMovable()在页
+ 面被隔离后,无论页面是LRU还是非LRU可移动的,调用它开销都很低,因为LRU页面在
+ page->mapping中不可能有PAGE_MAPPING_MOVABLE设置。在用pfn扫描中的lock_page()
+ 进行更大开销的检查来选择受害者之前,它也很适合只是瞥一眼来测试非LRU可移动的页面。
+
+ 为了保证非LRU的可移动页面,VM提供了PageMovable()函数。与__PageMovable()不
+ 同,PageMovable()在lock_page()下验证page->mapping和
+ mapping->a_ops->isolate_page。lock_page()可以防止突然破坏page->mapping。
+
+ 使用__SetPageMovable()的驱动应该在释放页面之前通过page_lock()下的
+ __ClearMovablePage()清除该标志。
+
+ * PG_isolated
+
+ 为了防止几个CPU同时进行隔离,VM在lock_page()下将隔离的页面标记为PG_isolated。
+ 因此,如果一个CPU遇到PG_isolated非LRU可移动页面,它可以跳过它。驱动程序不需要
+ 操作这个标志,因为VM会自动设置/清除它。请记住,如果驱动程序看到PG_isolated页,
+ 这意味着该页已经被VM隔离,所以它不应该碰page.lru字段。PG_isolated标志与
+ PG_reclaim标志是同义的,所以驱动程序不应该为自己的目的使用PG_isolated。
+
+监测迁移
+========
+
+以下事件(计数器)可用于监控页面迁移。
+
+1. PGMIGRATE_SUCCESS: 正常的页面迁移成功。每个计数器意味着一个页面被迁移了。如果该
+ 页是一个非THP和非hugetlb页,那么这个计数器会增加1。如果该页面是一个THP或hugetlb
+ 页面,那么这个计数器会随着THP或hugetlb子页面的数量而增加。例如,迁移一个有4KB大小
+ 的基础页(子页)的2MB THP,将导致这个计数器增加512。
+
+2. PGMIGRATE_FAIL: 正常的页面迁移失败。与上面PGMIGRATE_SUCCESS的计数规则相同:如
+ 果是THP或hugetlb,这个计数将被子页的数量增加。
+
+3. THP_MIGRATION_SUCCESS: 一个THP被迁移而没有被分割。
+
+4. THP_MIGRATION_FAIL: 一个THP不能被迁移,也不能被分割。
+
+5. THP_MIGRATION_SPLIT: 一个THP被迁移了,但不是这样的:首先,这个THP必须被分割。
+ 在拆分之后,对它的子页面进行了迁移重试。
+
+THP_MIGRATION_* 事件也会更新相应的PGMIGRATE_SUCCESS或PGMIGRATE_FAIL事件。
+例如,一个THP迁移失败将导致THP_MIGRATION_FAIL和PGMIGRATE_FAIL增加。
+
+Christoph Lameter,2006年5月8日。
+
+Minchan Kim,2016年3月28日。
diff --git a/Documentation/translations/zh_CN/mm/page_owner.rst b/Documentation/translations/zh_CN/mm/page_owner.rst
new file mode 100644
index 000000000000..b72a972271d9
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/page_owner.rst
@@ -0,0 +1,170 @@
+:Original: Documentation/mm/page_owner.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+================================
+page owner: 跟踪谁分配的每个页面
+================================
+
+概述
+====
+
+page owner是用来追踪谁分配的每一个页面。它可以用来调试内存泄漏或找到内存占用者。
+当分配发生时,有关分配的信息,如调用堆栈和页面的顺序被存储到每个页面的特定存储中。
+当我们需要了解所有页面的状态时,我们可以获得并分析这些信息。
+
+尽管我们已经有了追踪页面分配/释放的tracepoint,但用它来分析谁分配的每个页面是
+相当复杂的。我们需要扩大跟踪缓冲区,以防止在用户空间程序启动前出现重叠。而且,启
+动的程序会不断地将跟踪缓冲区转出,供以后分析,这将会改变系统的行为,会产生更多的
+可能性,而不是仅仅保留在内存中,所以不利于调试。
+
+页面所有者也可以用于各种目的。例如,可以通过每个页面的gfp标志信息获得精确的碎片
+统计。如果启用了page owner,它就已经实现并激活了。我们非常欢迎其他用途。
+
+page owner在默认情况下是禁用的。所以,如果你想使用它,你需要在你的启动cmdline
+中加入"page_owner=on"。如果内核是用page owner构建的,并且由于没有启用启动
+选项而在运行时禁用page owner,那么运行时的开销是很小的。如果在运行时禁用,它不
+需要内存来存储所有者信息,所以没有运行时内存开销。而且,页面所有者在页面分配器的
+热路径中只插入了两个不可能的分支,如果不启用,那么分配就会像没有页面所有者的内核
+一样进行。这两个不可能的分支应该不会影响到分配的性能,特别是在静态键跳转标签修补
+功能可用的情况下。以下是由于这个功能而导致的内核代码大小的变化。
+
+尽管启用page owner会使内核的大小增加几千字节,但这些代码大部分都在页面分配器和
+热路径之外。构建带有page owner的内核,并在需要时打开它,将是调试内核内存问题的
+最佳选择。
+
+有一个问题是由实现细节引起的。页所有者将信息存储到struct page扩展的内存中。这
+个内存的初始化时间比稀疏内存系统中的页面分配器启动的时间要晚一些,所以,在初始化
+之前,许多页面可以被分配,但它们没有所有者信息。为了解决这个问题,这些早期分配的
+页面在初始化阶段被调查并标记为分配。虽然这并不意味着它们有正确的所有者信息,但至
+少,我们可以更准确地判断该页是否被分配。在2GB内存的x86-64虚拟机上,有13343
+个早期分配的页面被捕捉和标记,尽管它们大部分是由结构页扩展功能分配的。总之,在这
+之后,没有任何页面处于未追踪状态。
+
+使用方法
+========
+
+1) 构建用户空间的帮助::
+
+ cd tools/mm
+ make page_owner_sort
+
+2) 启用page owner: 添加 "page_owner=on" 到 boot cmdline.
+
+3) 做你想调试的工作。
+
+4) 分析来自页面所有者的信息::
+
+ cat /sys/kernel/debug/page_owner > page_owner_full.txt
+ ./page_owner_sort page_owner_full.txt sorted_page_owner.txt
+
+ ``page_owner_full.txt`` 的一般输出情况如下::
+
+ Page allocated via order XXX, ...
+ PFN XXX ...
+ // 栈详情
+
+ Page allocated via order XXX, ...
+ PFN XXX ...
+ // 栈详情
+ 默认情况下,它将以一个给定的pfn开始,做完整的pfn转储,且page_owner支持fseek。
+
+ FILE *fp = fopen("/sys/kernel/debug/page_owner", "r");
+ fseek(fp, pfn_start, SEEK_SET);
+
+ ``page_owner_sort`` 工具忽略了 ``PFN`` 行,将剩余的行放在buf中,使用regexp提
+ 取页序值,计算buf的次数和页数,最后根据参数进行排序。
+
+ 在 ``sorted_page_owner.txt`` 中可以看到关于谁分配了每个页面的结果。一般输出::
+
+ XXX times, XXX pages:
+ Page allocated via order XXX, ...
+ // Detailed stack
+
+ 默认情况下, ``page_owner_sort`` 是根据buf的时间来排序的。如果你想
+ 按buf的页数排序,请使用-m参数。详细的参数是:
+
+ 基本函数::
+
+ 排序:
+ -a 按内存分配时间排序
+ -m 按总内存排序
+ -p 按pid排序。
+ -P 按tgid排序。
+ -n 按任务命令名称排序。
+ -r 按内存释放时间排序。
+ -s 按堆栈跟踪排序。
+ -t 按时间排序(默认)。
+ --sort <order> 指定排序顺序。排序的语法是[+|-]key[,[+|-]key[,...]]。从
+ **标准格式指定器**那一节选择一个键。"+"是可选的,因为默认的方向是数字或
+ 词法的增加。允许混合使用缩写和完整格式的键。
+
+ 例子:
+ ./page_owner_sort <input> <output> --sort=n,+pid,-tgid
+ ./page_owner_sort <input> <output> --sort=at
+
+ 其它函数::
+
+ 剔除:
+ --cull <rules>
+ 指定剔除规则。剔除的语法是key[,key[,...]]。从**标准格式指定器**
+ 部分选择一个多字母键。
+ <rules>是一个以逗号分隔的列表形式的单一参数,它提供了一种指定单个剔除规则的
+ 方法。 识别的关键字在下面的**标准格式指定器**部分有描述。<规则>可以通过键的
+ 序列k1,k2,...来指定,在下面的标准排序键部分有描述。允许混合使用简写和完整形
+ 式的键。
+
+ Examples:
+ ./page_owner_sort <input> <output> --cull=stacktrace
+ ./page_owner_sort <input> <output> --cull=st,pid,name
+ ./page_owner_sort <input> <output> --cull=n,f
+
+ 过滤:
+ -f 过滤掉内存已被释放的块的信息。
+
+ 选择:
+ --pid <pidlist> 按pid选择。这将选择进程ID号出现在<pidlist>中的块。
+ --tgid <tgidlist> 按tgid选择。这将选择其线程组ID号出现在<tgidlist>
+ 中的块。
+ --name <cmdlist> 按任务命令名称选择。这将选择其任务命令名称出现在
+ <cmdlist>中的区块。
+
+ <pidlist>, <tgidlist>, <cmdlist>是以逗号分隔的列表形式的单个参数,
+ 它提供了一种指定单个选择规则的方法。
+
+
+ 例子:
+ ./page_owner_sort <input> <output> --pid=1
+ ./page_owner_sort <input> <output> --tgid=1,2,3
+ ./page_owner_sort <input> <output> --name name1,name2
+
+标准格式指定器
+==============
+::
+
+ --sort的选项:
+
+ 短键 长键 描述
+ p pid 进程ID
+ tg tgid 线程组ID
+ n name 任务命令名称
+ st stacktrace 页面分配的堆栈跟踪
+ T txt 块的全文
+ ft free_ts 页面释放时的时间戳
+ at alloc_ts 页面被分配时的时间戳
+ ator allocator 页面的内存分配器
+
+ --curl的选项:
+
+ 短键 长键 描述
+ p pid 进程ID
+ tg tgid 线程组ID
+ n name 任务命令名称
+ f free 该页是否已经释放
+ st stacktrace 页面分配的堆栈跟踪
+ ator allocator 页面的内存分配器
diff --git a/Documentation/translations/zh_CN/mm/page_table_check.rst b/Documentation/translations/zh_CN/mm/page_table_check.rst
new file mode 100644
index 000000000000..e8077310a76c
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/page_table_check.rst
@@ -0,0 +1,56 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+:Original: Documentation/mm/page_table_check.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+========
+页表检查
+========
+
+概述
+====
+
+页表检查允许通过确保防止某些类型的内存损坏来强化内核。
+
+当新的页面可以从用户空间访问时,页表检查通过将它们的页表项(PTEs PMD等)添加到页表中来执行额外
+的验证。
+
+在检测到损坏的情况下,内核会被崩溃。页表检查有一个小的性能和内存开销。因此,它在默认情况下是禁用
+的,但是在额外的加固超过性能成本的系统上,可以选择启用。另外,由于页表检查是同步的,它可以帮助调
+试双映射内存损坏问题,在错误的映射发生时崩溃内核,而不是在内存损坏错误发生后内核崩溃。
+
+双重映射检测逻辑
+================
+
++-------------------+-------------------+-------------------+------------------+
+| Current Mapping | New mapping | Permissions | Rule |
++===================+===================+===================+==================+
+| Anonymous | Anonymous | Read | Allow |
++-------------------+-------------------+-------------------+------------------+
+| Anonymous | Anonymous | Read / Write | Prohibit |
++-------------------+-------------------+-------------------+------------------+
+| Anonymous | Named | Any | Prohibit |
++-------------------+-------------------+-------------------+------------------+
+| Named | Anonymous | Any | Prohibit |
++-------------------+-------------------+-------------------+------------------+
+| Named | Named | Any | Allow |
++-------------------+-------------------+-------------------+------------------+
+
+启用页表检查
+============
+
+用以下方法构建内核:
+
+- PAGE_TABLE_CHECK=y
+ 注意,它只能在ARCH_SUPPORTS_PAGE_TABLE_CHECK可用的平台上启用。
+
+- 使用 "page_table_check=on" 内核参数启动。
+
+可以选择用PAGE_TABLE_CHECK_ENFORCED来构建内核,以便在没有额外的内核参数的情况下获得页表
+支持。
diff --git a/Documentation/translations/zh_CN/mm/remap_file_pages.rst b/Documentation/translations/zh_CN/mm/remap_file_pages.rst
new file mode 100644
index 000000000000..31e0c54dc36f
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/remap_file_pages.rst
@@ -0,0 +1,32 @@
+:Original: Documentation/mm/remap_file_pages.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+==============================
+remap_file_pages()系统调用
+==============================
+
+remap_file_pages()系统调用被用来创建一个非线性映射,也就是说,在这个映射中,
+文件的页面被无序映射到内存中。使用remap_file_pages()比重复调用mmap(2)的好
+处是,前者不需要内核创建额外的VMA(虚拟内存区)数据结构。
+
+支持非线性映射需要在内核虚拟内存子系统中编写大量的non-trivial的代码,包括热
+路径。另外,为了使非线性映射工作,内核需要一种方法来区分正常的页表项和带有文件
+偏移的项(pte_file)。内核为达到这个目的在PTE中保留了标志。PTE标志是稀缺资
+源,特别是在某些CPU架构上。如果能腾出这个标志用于其他用途就更好了。
+
+幸运的是,在生活中并没有很多remap_file_pages()的用户。只知道有一个企业的RDBMS
+实现在32位系统上使用这个系统调用来映射比32位虚拟地址空间线性尺寸更大的文件。
+由于64位系统的广泛使用,这种使用情况已经不重要了。
+
+syscall被废弃了,现在用一个模拟来代替它。仿真会创建新的VMA,而不是非线性映射。
+对于remap_file_pages()的少数用户来说,它的工作速度会变慢,但ABI被保留了。
+
+仿真的一个副作用(除了性能之外)是,由于额外的VMA,用户可以更容易达到
+vm.max_map_count的限制。关于限制的更多细节,请参见DEFAULT_MAX_MAP_COUNT
+的注释。
diff --git a/Documentation/translations/zh_CN/mm/split_page_table_lock.rst b/Documentation/translations/zh_CN/mm/split_page_table_lock.rst
new file mode 100644
index 000000000000..a2c288670a24
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/split_page_table_lock.rst
@@ -0,0 +1,96 @@
+:Original: Documentation/mm/split_page_table_lock.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+=================================
+分页表锁(split page table lock)
+=================================
+
+最初,mm->page_table_lock spinlock保护了mm_struct的所有页表。但是这种方
+法导致了多线程应用程序的缺页异常可扩展性差,因为对锁的争夺很激烈。为了提高可扩
+展性,我们引入了分页表锁。
+
+有了分页表锁,我们就有了单独的每张表锁来顺序化对表的访问。目前,我们对PTE和
+PMD表使用分页锁。对高层表的访问由mm->page_table_lock保护。
+
+有一些辅助工具来锁定/解锁一个表和其他访问器函数:
+
+ - pte_offset_map_lock()
+ 映射pte并获取PTE表锁,返回所取锁的指针;
+ - pte_unmap_unlock()
+ 解锁和解映射PTE表;
+ - pte_alloc_map_lock()
+ 如果需要的话,分配PTE表并获取锁,如果分配失败,返回已获取的锁的指针
+ 或NULL;
+ - pte_lockptr()
+ 返回指向PTE表锁的指针;
+ - pmd_lock()
+ 取得PMD表锁,返回所取锁的指针。
+ - pmd_lockptr()
+ 返回指向PMD表锁的指针;
+
+如果CONFIG_SPLIT_PTLOCK_CPUS(通常为4)小于或等于NR_CPUS,则在编译
+时启用PTE表的分页表锁。如果分页锁被禁用,所有的表都由mm->page_table_lock
+来保护。
+
+如果PMD表启用了分页锁,并且架构支持它,那么PMD表的分页锁就会被启用(见
+下文)。
+
+Hugetlb 和分页表锁
+==================
+
+Hugetlb可以支持多种页面大小。我们只对PMD级别使用分页锁,但不对PUD使用。
+
+Hugetlb特定的辅助函数:
+
+ - huge_pte_lock()
+ 对PMD_SIZE页面采取pmd分割锁,否则mm->page_table_lock;
+ - huge_pte_lockptr()
+ 返回指向表锁的指针。
+
+架构对分页表锁的支持
+====================
+
+没有必要特别启用PTE分页表锁:所有需要的东西都由pagetable_pte_ctor()
+和pagetable_pte_dtor()完成,它们必须在PTE表分配/释放时被调用。
+
+确保架构不使用slab分配器来分配页表:slab使用page->slab_cache来分配其页
+面。这个区域与page->ptl共享存储。
+
+PMD分页锁只有在你有两个以上的页表级别时才有意义。
+
+启用PMD分页锁需要在PMD表分配时调用pagetable_pmd_ctor(),在释放时调
+用pagetable_pmd_dtor()。
+
+分配通常发生在pmd_alloc_one()中,释放发生在pmd_free()和pmd_free_tlb()
+中,但要确保覆盖所有的PMD表分配/释放路径:即X86_PAE在pgd_alloc()中预先
+分配一些PMD。
+
+一切就绪后,你可以设置CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK。
+
+注意:pagetable_pte_ctor()和pagetable_pmd_ctor()可能失败--必
+须正确处理。
+
+page->ptl
+=========
+
+page->ptl用于访问分割页表锁,其中'page'是包含该表的页面struct page。它
+与page->private(以及union中的其他几个字段)共享存储。
+
+为了避免增加struct page的大小并获得最佳性能,我们使用了一个技巧:
+
+ - 如果spinlock_t适合于long,我们使用page->ptr作为spinlock,这样我们
+ 就可以避免间接访问并节省一个缓存行。
+ - 如果spinlock_t的大小大于long的大小,我们使用page->ptl作为spinlock_t
+ 的指针并动态分配它。这允许在启用DEBUG_SPINLOCK或DEBUG_LOCK_ALLOC的
+ 情况下使用分页锁,但由于间接访问而多花了一个缓存行。
+
+PTE表的spinlock_t分配在pagetable_pte_ctor()中,PMD表的spinlock_t
+分配在pagetable_pmd_ctor()中。
+
+请不要直接访问page->ptl - -使用适当的辅助函数。
diff --git a/Documentation/translations/zh_CN/mm/vmalloced-kernel-stacks.rst b/Documentation/translations/zh_CN/mm/vmalloced-kernel-stacks.rst
new file mode 100644
index 000000000000..d02a23f7f07e
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/vmalloced-kernel-stacks.rst
@@ -0,0 +1,133 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/mm/vmalloced-kernel-stacks.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+====================
+支持虚拟映射的内核栈
+====================
+
+:作者: Shuah Khan <skhan@linuxfoundation.org>
+
+.. contents:: :local:
+
+概览
+----
+
+这是介绍 `虚拟映射内核栈功能 <https://lwn.net/Articles/694348/>` 的代码
+和原始补丁系列的信息汇总。
+
+简介
+----
+
+内核堆栈溢出通常难以调试,并使内核容易被(恶意)利用。问题可能在稍后的时间出现,使其难以
+隔离和究其根本原因。
+
+带有保护页的虚拟映射内核堆栈如果溢出,会被立即捕获,而不会放任其导致难以诊断的损
+坏。
+
+HAVE_ARCH_VMAP_STACK和VMAP_STACK配置选项能够支持带有保护页的虚拟映射堆栈。
+当堆栈溢出时,这个特性会引发可靠的异常。溢出后堆栈跟踪的可用性以及对溢出本身的
+响应取决于架构。
+
+.. note::
+ 截至本文撰写时, arm64, powerpc, riscv, s390, um, 和 x86 支持VMAP_STACK。
+
+HAVE_ARCH_VMAP_STACK
+--------------------
+
+能够支持虚拟映射内核栈的架构应该启用这个bool配置选项。要求是:
+
+- vmalloc空间必须大到足以容纳许多内核堆栈。这可能排除了许多32位架构。
+- vmalloc空间的堆栈需要可靠地工作。例如,如果vmap页表是按需创建的,当堆栈指向
+ 具有未填充页表的虚拟地址时,这种机制需要工作,或者架构代码(switch_to()和
+ switch_mm(),很可能)需要确保堆栈的页表项在可能未填充的堆栈上运行之前已经填
+ 充。
+- 如果堆栈溢出到一个保护页,就应该发生一些合理的事情。“合理”的定义是灵活的,但
+ 在没有记录任何东西的情况下立即重启是不友好的。
+
+VMAP_STACK
+----------
+
+VMAP_STACK bool配置选项在启用时分配虚拟映射的任务栈。这个选项依赖于
+HAVE_ARCH_VMAP_STACK。
+
+- 如果你想使用带有保护页的虚拟映射的内核堆栈,请启用该选项。这将导致内核栈溢出
+ 被立即捕获,而不是难以诊断的损坏。
+
+.. note::
+
+ 使用KASAN的这个功能需要架构支持用真实的影子内存来支持虚拟映射,并且
+ 必须启用KASAN_VMALLOC。
+
+.. note::
+
+ 启用VMAP_STACK时,无法在堆栈分配的数据上运行DMA。
+
+内核配置选项和依赖性不断变化。请参考最新的代码库:
+
+`Kconfig <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/Kconfig>`
+
+分配方法
+--------
+
+当一个新的内核线程被创建时,线程堆栈是由页级分配器分配的虚拟连续的内存页组成。这
+些页面被映射到有PAGE_KERNEL保护的连续的内核虚拟空间。
+
+alloc_thread_stack_node()调用__vmalloc_node_range()来分配带有PAGE_KERNEL
+保护的栈。
+
+- 分配的堆栈被缓存起来,以后会被新的线程重用,所以在分配/释放堆栈给任务时,要手动
+ 进行memcg核算。因此,__vmalloc_node_range被调用时没有__GFP_ACCOUNT。
+- vm_struct被缓存起来,以便能够找到在中断上下文中启动的空闲线程。 free_thread_stack()
+ 可以在中断上下文中调用。
+- 在arm64上,所有VMAP的堆栈都需要有相同的对齐方式,以确保VMAP的堆栈溢出检测正常
+ 工作。架构特定的vmap堆栈分配器照顾到了这个细节。
+- 这并不涉及中断堆栈--参考原始补丁
+
+线程栈分配是由clone()、fork()、vfork()、kernel_thread()通过kernel_clone()
+启动的。留点提示在这,以便搜索代码库,了解线程栈何时以及如何分配。
+
+大量的代码是在:
+`kernel/fork.c <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/fork.c>`.
+
+task_struct中的stack_vm_area指针可以跟踪虚拟分配的堆栈,一个非空的stack_vm_area
+指针可以表明虚拟映射的内核堆栈已经启用。
+
+::
+
+ struct vm_struct *stack_vm_area;
+
+堆栈溢出处理
+------------
+
+前守护页和后守护页有助于检测堆栈溢出。当堆栈溢出到守护页时,处理程序必须小心不要再
+次溢出堆栈。当处理程序被调用时,很可能只留下很少的堆栈空间。
+
+在x86上,这是通过处理表明内核堆栈溢出的双异常堆栈的缺页异常来实现的。
+
+用守护页测试VMAP分配
+--------------------
+
+我们如何确保VMAP_STACK在分配时确实有前守护页和后守护页的保护?下面的 lkdtm 测试
+可以帮助检测任何回归。
+
+::
+
+ void lkdtm_STACK_GUARD_PAGE_LEADING()
+ void lkdtm_STACK_GUARD_PAGE_TRAILING()
+
+结论
+----
+
+- vmalloced堆栈的percpu缓存似乎比高阶堆栈分配要快一些,至少在缓存命中时是这样。
+- THREAD_INFO_IN_TASK完全摆脱了arch-specific thread_info,并简单地将
+ thread_info(仅包含标志)和'int cpu'嵌入task_struct中。
+- 一旦任务死亡,线程栈就可以被释放(无需等待RCU),然后,如果使用vmapped栈,就
+ 可以将整个栈缓存起来,以便在同一cpu上重复使用。
diff --git a/Documentation/translations/zh_CN/mm/z3fold.rst b/Documentation/translations/zh_CN/mm/z3fold.rst
new file mode 100644
index 000000000000..9569a6d88270
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/z3fold.rst
@@ -0,0 +1,31 @@
+:Original: Documentation/mm/z3fold.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+======
+z3fold
+======
+
+z3fold是一个专门用于存储压缩页的分配器。它被设计为每个物理页最多可以存储三个压缩页。
+它是zbud的衍生物,允许更高的压缩率,保持其前辈的简单性和确定性。
+
+z3fold和zbud的主要区别是:
+
+* 与zbud不同的是,z3fold允许最大的PAGE_SIZE分配。
+* z3fold在其页面中最多可以容纳3个压缩页面
+* z3fold本身没有输出任何API,因此打算通过zpool的API来使用
+
+为了保持确定性和简单性,z3fold,就像zbud一样,总是在每页存储一个整数的压缩页,但是
+它最多可以存储3页,不像zbud最多可以存储2页。因此压缩率达到2.7倍左右,而zbud的压缩
+率是1.7倍左右。
+
+不像zbud(但也像zsmalloc),z3fold_alloc()那样不返回一个可重复引用的指针。相反,它
+返回一个无符号长句柄,它编码了被分配对象的实际位置。
+
+保持有效的压缩率接近于zsmalloc,z3fold不依赖于MMU的启用,并提供更可预测的回收行
+为,这使得它更适合于小型和反应迅速的系统。
diff --git a/Documentation/translations/zh_CN/mm/zsmalloc.rst b/Documentation/translations/zh_CN/mm/zsmalloc.rst
new file mode 100644
index 000000000000..4c8c9b1006a9
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/zsmalloc.rst
@@ -0,0 +1,78 @@
+:Original: Documentation/mm/zsmalloc.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+========
+zsmalloc
+========
+
+这个分配器是为与zram一起使用而设计的。因此,该分配器应该在低内存条件下工作良好。特别是,
+它从未尝试过higher order页面的分配,这在内存压力下很可能会失败。另一方面,如果我们只
+是使用单(0-order)页,它将遭受非常高的碎片化 - 任何大小为PAGE_SIZE/2或更大的对象将
+占据整个页面。这是其前身(xvmalloc)的主要问题之一。
+
+为了克服这些问题,zsmalloc分配了一堆0-order页面,并使用各种"struct page"字段将它
+们链接起来。这些链接的页面作为一个单一的higher order页面,即一个对象可以跨越0-order
+页面的边界。代码将这些链接的页面作为一个实体,称为zspage。
+
+为了简单起见,zsmalloc只能分配大小不超过PAGE_SIZE的对象,因为这满足了所有当前用户的
+要求(在最坏的情况下,页面是不可压缩的,因此以"原样"即未压缩的形式存储)。对于大于这
+个大小的分配请求,会返回失败(见zs_malloc)。
+
+此外,zs_malloc()并不返回一个可重复引用的指针。相反,它返回一个不透明的句柄(无符号
+长),它编码了被分配对象的实际位置。这种间接性的原因是zsmalloc并不保持zspages的永久
+映射,因为这在32位系统上会导致问题,因为内核空间映射的VA区域非常小。因此,在使用分配
+的内存之前,对象必须使用zs_map_object()进行映射以获得一个可用的指针,随后使用
+zs_unmap_object()解除映射。
+
+stat
+====
+
+通过CONFIG_ZSMALLOC_STAT,我们可以通过 ``/sys/kernel/debug/zsmalloc/<user name>``
+看到zsmalloc内部信息。下面是一个统计输出的例子。::
+
+ # cat /sys/kernel/debug/zsmalloc/zram0/classes
+
+ class size almost_full almost_empty obj_allocated obj_used pages_used pages_per_zspage
+ ...
+ ...
+ 9 176 0 1 186 129 8 4
+ 10 192 1 0 2880 2872 135 3
+ 11 208 0 1 819 795 42 2
+ 12 224 0 1 219 159 12 4
+ ...
+ ...
+
+
+class
+ 索引
+size
+ zspage存储对象大小
+almost_empty
+ ZS_ALMOST_EMPTY zspage的数量(见下文)。
+almost_full
+ ZS_ALMOST_FULL zspage的数量(见下图)
+obj_allocated
+ 已分配对象的数量
+obj_used
+ 分配给用户的对象的数量
+pages_used
+ 为该类分配的页数
+pages_per_zspage
+ 组成一个zspage的0-order页面的数量
+
+当n <= N / f时,我们将一个zspage分配给ZS_ALMOST_EMPTYfullness组,其中
+
+* n = 已分配对象的数量
+* N = zspage可以存储的对象总数
+* f = fullness_threshold_frac(即,目前是4个)
+
+同样地,我们将zspage分配给:
+
+* ZS_ALMOST_FULL when n > N / f
+* ZS_EMPTY when n == 0
+* ZS_FULL when n == N
diff --git a/Documentation/translations/zh_CN/oops-tracing.txt b/Documentation/translations/zh_CN/oops-tracing.txt
deleted file mode 100644
index c5f3bda7abcb..000000000000
--- a/Documentation/translations/zh_CN/oops-tracing.txt
+++ /dev/null
@@ -1,212 +0,0 @@
-Chinese translated version of Documentation/admin-guide/bug-hunting.rst
-
-If you have any comment or update to the content, please contact the
-original document maintainer directly. However, if you have a problem
-communicating in English you can also ask the Chinese maintainer for
-help. Contact the Chinese maintainer if this translation is outdated
-or if there is a problem with the translation.
-
-Chinese maintainer: Dave Young <hidave.darkstar@gmail.com>
----------------------------------------------------------------------
-Documentation/admin-guide/bug-hunting.rst 的中文翻译
-
-如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
-交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
-译存在问题,请联系中文版维护者。
-
-中文版维护者: 杨瑞 Dave Young <hidave.darkstar@gmail.com>
-中文版翻译者: 杨瑞 Dave Young <hidave.darkstar@gmail.com>
-中文版校译者: 李阳 Li Yang <leoyang.li@nxp.com>
- 王聪 Wang Cong <xiyou.wangcong@gmail.com>
-
-以下为正文
----------------------------------------------------------------------
-
-注意: ksymoops 在2.6中是没有用的。 请以原有格式使用Oops(来自dmesg,等等)。
-忽略任何这样那样关于“解码Oops”或者“通过ksymoops运行”的文档。 如果你贴出运行过
-ksymoops的来自2.6的Oops,人们只会让你重贴一次。
-
-快速总结
--------------
-
-发现Oops并发送给看似相关的内核领域的维护者。别太担心对不上号。如果你不确定就发给
-和你所做的事情相关的代码的负责人。 如果可重现试着描述怎样重构。 那甚至比oops更有
-价值。
-
-如果你对于发送给谁一无所知, 发给linux-kernel@vger.kernel.org。感谢你帮助Linux
-尽可能地稳定。
-
-Oops在哪里?
-----------------------
-
-通常Oops文本由klogd从内核缓冲区里读取并传给syslogd,由syslogd写到syslog文件中,
-典型地是/var/log/messages(依赖于/etc/syslog.conf)。有时klogd崩溃了,这种情况下你
-能够运行dmesg > file来从内核缓冲区中读取数据并保存下来。 否则你可以
-cat /proc/kmsg > file, 然而你必须介入中止传输, kmsg是一个“永不结束的文件”。如
-果机器崩溃坏到你不能输入命令或者磁盘不可用那么你有三种选择:-
-
-(1) 手抄屏幕上的文本待机器重启后再输入计算机。 麻烦但如果没有针对崩溃的准备,
-这是仅有的选择。 另外,你可以用数码相机把屏幕拍下来-不太好,但比没有强。 如果信
-息滚动到了终端的上面,你会发现以高分辩率启动(比如,vga=791)会让你读到更多的文
-本。(注意:这需要vesafb,所以对‘早期’的oops没有帮助)
-
-(2)用串口终端启动(请参看Documentation/admin-guide/serial-console.rst),运行一个null
-modem到另一台机器并用你喜欢的通讯工具获取输出。Minicom工作地很好。
-
-(3)使用Kdump(请参看Documentation/admin-guide/kdump/kdump.rst),
-使用在Documentation/admin-guide/kdump/gdbmacros.txt中定义的dmesg gdb宏,从旧的内存中提取内核
-环形缓冲区。
-
-完整信息
-----------------
-
-注意:以下来自于Linus的邮件适用于2.4内核。 我因为历史原因保留了它,并且因为其中
-一些信息仍然适用。 特别注意的是,请忽略任何ksymoops的引用。
-
-From: Linus Torvalds <torvalds@osdl.org>
-
-怎样跟踪Oops.. [原发到linux-kernel的一封邮件]
-
-主要的窍门是有五年和这些烦人的oops消息打交道的经验;-)
-
-实际上,你有办法使它更简单。我有两个不同的方法:
-
- gdb /usr/src/linux/vmlinux
- gdb> disassemble <offending_function>
-
-那是发现问题的简单办法,至少如果bug报告做的好的情况下(象这个一样-运行ksymoops
-得到oops发生的函数及函数内的偏移)。
-
-哦,如果报告发生的内核以相同的编译器和相似的配置编译它会有帮助的。
-
-另一件要做的事是反汇编bug报告的“Code”部分:ksymoops也会用正确的工具来做这件事,
-但如果没有那些工具你可以写一个傻程序:
-
- char str[] = "\xXX\xXX\xXX...";
- main(){}
-
-并用gcc -g编译它然后执行“disassemble str”(XX部分是由Oops报告的值-你可以仅剪切
-粘贴并用“\x”替换空格-我就是这么做的,因为我懒得写程序自动做这一切)。
-
-另外,你可以用scripts/decodecode这个shell脚本。它的使用方法是:
-decodecode < oops.txt
-
-“Code”之后的十六进制字节可能(在某些架构上)有一些当前指令之前的指令字节以及
-当前和之后的指令字节
-
-Code: f9 0f 8d f9 00 00 00 8d 42 0c e8 dd 26 11 c7 a1 60 ea 2b f9 8b 50 08 a1
-64 ea 2b f9 8d 34 82 8b 1e 85 db 74 6d 8b 15 60 ea 2b f9 <8b> 43 04 39 42 54
-7e 04 40 89 42 54 8b 43 04 3b 05 00 f6 52 c0
-
-最后,如果你想知道代码来自哪里,你可以:
-
- cd /usr/src/linux
- make fs/buffer.s # 或任何产生BUG的文件
-
-然后你会比gdb反汇编更清楚的知道发生了什么。
-
-现在,问题是把你所拥有的所有数据结合起来:C源码(关于它应该怎样的一般知识),
-汇编代码及其反汇编得到的代码(另外还有从“oops”消息得到的寄存器状态-对了解毁坏的
-指针有用,而且当你有了汇编代码你也能拿其它的寄存器和任何它们对应的C表达式做匹配
-)。
-
-实际上,你仅需看看哪里不匹配(这个例子是“Code”反汇编和编译器生成的代码不匹配)。
-然后你须要找出为什么不匹配。通常很简单-你看到代码使用了空指针然后你看代码想知道
-空指针是怎么出现的,还有检查它是否合法..
-
-现在,如果明白这是一项耗时的工作而且需要一丁点儿的专心,没错。这就是我为什么大多
-只是忽略那些没有符号表信息的崩溃报告的原因:简单的说太难查找了(我有一些
-程序用于在内核代码段中搜索特定的模式,而且有时我也已经能找出那些崩溃的地方,但是
-仅仅是找出正确的序列也确实需要相当扎实的内核知识)
-
-_有时_会发生这种情况,我仅看到崩溃中的反汇编代码序列, 然后我马上就明白问题出在
-哪里。这时我才意识到自己干这个工作已经太长时间了;-)
-
- Linus
-
-
----------------------------------------------------------------------------
-关于Oops跟踪的注解:
-
-为了帮助Linus和其它内核开发者,klogd纳入了大量的支持来处理保护错误。为了拥有对
-地址解析的完整支持至少应该使用1.3-pl3的sysklogd包。
-
-当保护错误发生时,klogd守护进程自动把内核日志信息中的重要地址翻译成它们相应的符
-号。
-
-klogd执行两种类型的地址解析。首先是静态翻译其次是动态翻译。静态翻译和ksymoops
-一样使用System.map文件。为了做静态翻译klogd守护进程必须在初始化时能找到system
-map文件。关于klogd怎样搜索map文件请参看klogd手册页。
-
-动态地址翻译在使用内核可装载模块时很重要。 因为内核模块的内存是从内核动态内存池
-里分配的,所以不管是模块开始位置还是模块中函数和符号的位置都不是固定的。
-
-内核支持允许程序决定装载哪些模块和它们在内存中位置的系统调用。使用这些系统调用
-klogd守护进程生成一张符号表用于调试发生在可装载模块中的保护错误。
-
-至少klogd会提供产生保护错误的模块名。还可有额外的符号信息供可装载模块开发者选择
-以从模块中输出符号信息。
-
-因为内核模块环境可能是动态的,所以必须有一种机制当模块环境发生改变时来通知klogd
-守护进程。 有一些可用的命令行选项允许klogd向当前执行中的守护进程发送信号,告知符
-号信息应该被刷新了。 更多信息请参看klogd手册页。
-
-sysklogd发布时包含一个补丁修改了modules-2.0.0包,无论何时一个模块装载或者卸载都
-会自动向klogd发送信号。打上这个补丁提供了必要的对调试发生于内核可装载模块的保护
-错误的无缝支持。
-
-以下是被klogd处理过的发生在可装载模块中的一个保护错误例子:
----------------------------------------------------------------------------
-Aug 29 09:51:01 blizard kernel: Unable to handle kernel paging request at virtual address f15e97cc
-Aug 29 09:51:01 blizard kernel: current->tss.cr3 = 0062d000, %cr3 = 0062d000
-Aug 29 09:51:01 blizard kernel: *pde = 00000000
-Aug 29 09:51:01 blizard kernel: Oops: 0002
-Aug 29 09:51:01 blizard kernel: CPU: 0
-Aug 29 09:51:01 blizard kernel: EIP: 0010:[oops:_oops+16/3868]
-Aug 29 09:51:01 blizard kernel: EFLAGS: 00010212
-Aug 29 09:51:01 blizard kernel: eax: 315e97cc ebx: 003a6f80 ecx: 001be77b edx: 00237c0c
-Aug 29 09:51:01 blizard kernel: esi: 00000000 edi: bffffdb3 ebp: 00589f90 esp: 00589f8c
-Aug 29 09:51:01 blizard kernel: ds: 0018 es: 0018 fs: 002b gs: 002b ss: 0018
-Aug 29 09:51:01 blizard kernel: Process oops_test (pid: 3374, process nr: 21, stackpage=00589000)
-Aug 29 09:51:01 blizard kernel: Stack: 315e97cc 00589f98 0100b0b4 bffffed4 0012e38e 00240c64 003a6f80 00000001
-Aug 29 09:51:01 blizard kernel: 00000000 00237810 bfffff00 0010a7fa 00000003 00000001 00000000 bfffff00
-Aug 29 09:51:01 blizard kernel: bffffdb3 bffffed4 ffffffda 0000002b 0007002b 0000002b 0000002b 00000036
-Aug 29 09:51:01 blizard kernel: Call Trace: [oops:_oops_ioctl+48/80] [_sys_ioctl+254/272] [_system_call+82/128]
-Aug 29 09:51:01 blizard kernel: Code: c7 00 05 00 00 00 eb 08 90 90 90 90 90 90 90 90 89 ec 5d c3
----------------------------------------------------------------------------
-
-Dr. G.W. Wettstein Oncology Research Div. Computing Facility
-Roger Maris Cancer Center INTERNET: greg@wind.rmcc.com
-820 4th St. N.
-Fargo, ND 58122
-Phone: 701-234-7556
-
-
----------------------------------------------------------------------------
-受污染的内核
-
-一些oops报告在程序记数器之后包含字符串'Tainted: '。这表明内核已经被一些东西给污
-染了。 该字符串之后紧跟着一系列的位置敏感的字符,每个代表一个特定的污染值。
-
- 1:'G'如果所有装载的模块都有GPL或相容的许可证,'P'如果装载了任何的专有模块。
-没有模块MODULE_LICENSE或者带有insmod认为是与GPL不相容的的MODULE_LICENSE的模块被
-认定是专有的。
-
- 2:'F'如果有任何通过“insmod -f”被强制装载的模块,' '如果所有模块都被正常装载。
-
- 3:'S'如果oops发生在SMP内核中,运行于没有证明安全运行多处理器的硬件。 当前这种
-情况仅限于几种不支持SMP的速龙处理器。
-
- 4:'R'如果模块通过“insmod -f”被强制装载,' '如果所有模块都被正常装载。
-
- 5:'M'如果任何处理器报告了机器检查异常,' '如果没有发生机器检查异常。
-
- 6:'B'如果页释放函数发现了一个错误的页引用或者一些非预期的页标志。
-
- 7:'U'如果用户或者用户应用程序特别请求设置污染标志,否则' '。
-
- 8:'D'如果内核刚刚死掉,比如有OOPS或者BUG。
-
-使用'Tainted: '字符串的主要原因是要告诉内核调试者,这是否是一个干净的内核亦或发
-生了任何的不正常的事。污染是永久的:即使出错的模块已经被卸载了,污染值仍然存在,
-以表明内核不再值得信任。
diff --git a/Documentation/translations/zh_CN/peci/index.rst b/Documentation/translations/zh_CN/peci/index.rst
new file mode 100644
index 000000000000..4f6694c828fa
--- /dev/null
+++ b/Documentation/translations/zh_CN/peci/index.rst
@@ -0,0 +1,26 @@
+.. SPDX-License-Identifier: GPL-2.0-only
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/peci/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+=================
+Linux PECI 子系统
+=================
+
+.. toctree::
+
+
+ peci
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
diff --git a/Documentation/translations/zh_CN/peci/peci.rst b/Documentation/translations/zh_CN/peci/peci.rst
new file mode 100644
index 000000000000..a3b4f99b994c
--- /dev/null
+++ b/Documentation/translations/zh_CN/peci/peci.rst
@@ -0,0 +1,54 @@
+.. SPDX-License-Identifier: GPL-2.0-only
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/peci/peci.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+====
+概述
+====
+
+平台环境控制接口(PECI)是英特尔处理器和管理控制器(如底板管理控制器,BMC)
+之间的一个通信接口。PECI提供的服务允许管理控制器通过访问各种寄存器来配置、监
+控和调试平台。它定义了一个专门的命令协议,管理控制器作为PECI的发起者,处理器
+作为PECI的响应者。PECI可以用于基于单处理器和多处理器的系统中。
+
+注意:英特尔PECI规范没有作为专门的文件发布,而是作为英特尔CPU的外部设计规范
+(EDS)的一部分。外部设计规范通常是不公开的。
+
+PECI 线
+---------
+
+PECI线接口使用单线进行自锁和数据传输。它不需要任何额外的控制线--物理层是一个
+自锁的单线总线信号,每一个比特都从接近零伏的空闲状态开始驱动、上升边缘。驱动高
+电平信号的持续时间可以确定位值是逻辑 “0” 还是逻辑 “1”。PECI线还包括与每个信
+息建立的可变数据速率。
+
+对于PECI线,每个处理器包将在一个定义的范围内利用唯一的、固定的地址,该地址应
+该与处理器插座ID有固定的关系--如果其中一个处理器被移除,它不会影响其余处理器
+的地址。
+
+PECI子系统代码内嵌文档
+------------------------
+
+该API在以下内核代码中:
+
+include/linux/peci.h
+
+drivers/peci/internal.h
+
+drivers/peci/core.c
+
+drivers/peci/request.c
+
+PECI CPU 驱动 API
+-------------------
+
+该API在以下内核代码中:
+
+drivers/peci/cpu.c
diff --git a/Documentation/translations/zh_CN/power/energy-model.rst b/Documentation/translations/zh_CN/power/energy-model.rst
new file mode 100644
index 000000000000..48849919d8aa
--- /dev/null
+++ b/Documentation/translations/zh_CN/power/energy-model.rst
@@ -0,0 +1,210 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/power/energy-model.rst
+
+:翻译:
+
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+============
+设备能量模型
+============
+
+1. 概述
+-------
+
+能量模型(EM)框架是一种驱动程序与内核子系统之间的接口。其中驱动程序了解不同
+性能层级的设备所消耗的功率,而内核子系统愿意使用该信息做出能量感知决策。
+
+设备所消耗的功率的信息来源在不同的平台上可能有很大的不同。这些功率成本在某些
+情况下可以使用设备树数据来估算。在其它情况下,固件会更清楚。或者,用户空间可能
+是最清楚的。以此类推。为了避免每一个客户端子系统对每一种可能的信息源自己重新
+实现支持,EM框架作为一个抽象层介入,它在内核中对功率成本表的格式进行标准化,
+因此能够避免多余的工作。
+
+功率值可以用微瓦或“抽象刻度”表示。多个子系统可能使用EM,由系统集成商来检查
+功率值刻度类型的要求是否满足。可以在能量感知调度器的文档中找到一个例子
+Documentation/scheduler/sched-energy.rst。对于一些子系统,比如热能或
+powercap,用“抽象刻度”描述功率值可能会导致问题。这些子系统对过去使用的功率的
+估算值更感兴趣,因此可能需要真实的微瓦。这些要求的一个例子可以在智能功率分配
+Documentation/driver-api/thermal/power_allocator.rst文档中找到。
+
+内核子系统可能(基于EM内部标志位)实现了对EM注册设备是否具有不一致刻度的自动
+检查。要记住的重要事情是,当功率值以“抽象刻度”表示时,从中推导以微焦耳为单位
+的真实能量消耗是不可能的。
+
+下图描述了一个驱动的例子(这里是针对Arm的,但该方法适用于任何体系结构),它
+向EM框架提供了功率成本,感兴趣的客户端可从中读取数据::
+
+ +---------------+ +-----------------+ +---------------+
+ | Thermal (IPA) | | Scheduler (EAS) | | Other |
+ +---------------+ +-----------------+ +---------------+
+ | | em_cpu_energy() |
+ | | em_cpu_get() |
+ +---------+ | +---------+
+ | | |
+ v v v
+ +---------------------+
+ | Energy Model |
+ | Framework |
+ +---------------------+
+ ^ ^ ^
+ | | | em_dev_register_perf_domain()
+ +----------+ | +---------+
+ | | |
+ +---------------+ +---------------+ +--------------+
+ | cpufreq-dt | | arm_scmi | | Other |
+ +---------------+ +---------------+ +--------------+
+ ^ ^ ^
+ | | |
+ +--------------+ +---------------+ +--------------+
+ | Device Tree | | Firmware | | ? |
+ +--------------+ +---------------+ +--------------+
+
+对于CPU设备,EM框架管理着系统中每个“性能域”的功率成本表。一个性能域是一组
+性能一起伸缩的CPU。性能域通常与CPUFreq策略具有1对1映射。一个性能域中的
+所有CPU要求具有相同的微架构。不同性能域中的CPU可以有不同的微架构。
+
+
+2. 核心API
+----------
+
+2.1 配置选项
+^^^^^^^^^^^^
+
+必须使能CONFIG_ENERGY_MODEL才能使用EM框架。
+
+
+2.2 性能域的注册
+^^^^^^^^^^^^^^^^
+
+“高级”EM的注册
+~~~~~~~~~~~~~~~~
+
+“高级”EM因它允许驱动提供更精确的功率模型而得名。它并不受限于框架中的一些已
+实现的数学公式(就像“简单”EM那样)。它可以更好地反映每个性能状态的实际功率
+测量。因此,在EM静态功率(漏电流功率)是重要的情况下,应该首选这种注册方式。
+
+驱动程序应通过以下API将性能域注册到EM框架中::
+
+ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
+ struct em_data_callback *cb, cpumask_t *cpus, bool microwatts);
+
+驱动程序必须提供一个回调函数,为每个性能状态返回<频率,功率>元组。驱动程序
+提供的回调函数可以自由地从任何相关位置(DT、固件......)以及以任何被认为是
+必要的方式获取数据。只有对于CPU设备,驱动程序必须使用cpumask指定性能域的CPU。
+对于CPU以外的其他设备,最后一个参数必须被设置为NULL。
+
+最后一个参数“microwatts”(微瓦)设置成正确的值是很重要的,使用EM的内核
+子系统可能会依赖这个标志来检查所有的EM设备是否使用相同的刻度。如果有不同的
+刻度,这些子系统可能决定返回警告/错误,停止工作或崩溃(panic)。
+
+关于实现这个回调函数的驱动程序的例子,参见第3节。或者在第2.4节阅读这个API
+的更多文档。
+
+使用DT的EM注册
+==============
+
+EM也可以使用OPP框架和DT "操作点-v2 "中的信息注册。DT中的每个OPP条目都可
+以用一个包含微瓦特功率值的属性 "op-microwatt "来扩展。这个OPP DT属性允
+许平台注册反映总功率(静态+动态)的EM功率值。这些功率值可能直接来自实验和
+测量。
+
+“人工”EM的注册
+==============
+
+有一个选项可以为缺少关于每个性能状态的功率值的详细知识的驱动程序提供一个自
+定义回调。回调.get_cost()是可选的,它提供EAS使用的“成本”值。这对那些只提
+供CPU类型之间相对效率信息的平台很有用,人们可以利用这些信息来创建一个抽象的
+功率模型。但是,考虑到输入功率值的大小限制,即使是抽象的功率模型有时也很难装
+进去。.get_cost()允许提供反映CPU效率的“成本”值。这将允许提供EAS信息,它
+与EM内部计算'成本'值的公式有不同的关系。要为这样的平台注册EM,驱动程序必须
+将标志“microwatts”设置为0,提供.get_power()回调和.get_cost()回调。EM
+框架会在注册过程中正确处理这样的平台。这种平台会被设置EM_PERF_DOMAIN_ARTIFICIAL
+标志。其他使用EM的框架应该特别注意测试和正确对待这个标志。
+
+“简单”EM的注册
+~~~~~~~~~~~~~~~~
+
+“简单”EM是用框架的辅助函数cpufreq_register_em_with_opp()注册的。它实现了
+一个和以下数学公式紧密相关的功率模型::
+
+ Power = C * V^2 * f
+
+使用这种方法注册的EM可能无法正确反映真实设备的物理特性,例如当静态功率
+(漏电流功率)很重要时。
+
+
+2.3 访问性能域
+^^^^^^^^^^^^^^
+
+有两个API函数提供对能量模型的访问。em_cpu_get()以CPU id为参数,em_pd_get()
+以设备指针为参数。使用哪个接口取决于子系统,但对于CPU设备来说,这两个函数都返
+回相同的性能域。
+
+对CPU的能量模型感兴趣的子系统可以通过em_cpu_get() API检索它。在创建性能域时
+分配一次能量模型表,它保存在内存中不被修改。
+
+一个性能域所消耗的能量可以使用em_cpu_energy() API来估算。该估算假定CPU设备
+使用的CPUfreq监管器是schedutil。当前该计算不能提供给其它类型的设备。
+
+关于上述API的更多细节可以在 ``<linux/energy_model.h>`` 或第2.4节中找到。
+
+
+2.4 API的细节描述
+^^^^^^^^^^^^^^^^^
+参见 include/linux/energy_model.h 和 kernel/power/energy_model.c 的kernel doc。
+
+3. 驱动示例
+-----------
+
+CPUFreq框架支持专用的回调函数,用于为指定的CPU(们)注册EM:
+cpufreq_driver::register_em()。这个回调必须为每个特定的驱动程序正确实现,
+因为框架会在设置过程中适时地调用它。本节提供了一个简单的例子,展示CPUFreq驱动
+在能量模型框架中使用(假的)“foo”协议注册性能域。该驱动实现了一个est_power()
+函数提供给EM框架::
+
+ -> drivers/cpufreq/foo_cpufreq.c
+
+ 01 static int est_power(struct device *dev, unsigned long *mW,
+ 02 unsigned long *KHz)
+ 03 {
+ 04 long freq, power;
+ 05
+ 06 /* 使用“foo”协议设置频率上限 */
+ 07 freq = foo_get_freq_ceil(dev, *KHz);
+ 08 if (freq < 0);
+ 09 return freq;
+ 10
+ 11 /* 估算相关频率下设备的功率成本 */
+ 12 power = foo_estimate_power(dev, freq);
+ 13 if (power < 0);
+ 14 return power;
+ 15
+ 16 /* 将这些值返回给EM框架 */
+ 17 *mW = power;
+ 18 *KHz = freq;
+ 19
+ 20 return 0;
+ 21 }
+ 22
+ 23 static void foo_cpufreq_register_em(struct cpufreq_policy *policy)
+ 24 {
+ 25 struct em_data_callback em_cb = EM_DATA_CB(est_power);
+ 26 struct device *cpu_dev;
+ 27 int nr_opp;
+ 28
+ 29 cpu_dev = get_cpu_device(cpumask_first(policy->cpus));
+ 30
+ 31 /* 查找该策略支持的OPP数量 */
+ 32 nr_opp = foo_get_nr_opp(policy);
+ 33
+ 34 /* 并注册新的性能域 */
+ 35 em_dev_register_perf_domain(cpu_dev, nr_opp, &em_cb, policy->cpus,
+ 36 true);
+ 37 }
+ 38
+ 39 static struct cpufreq_driver foo_cpufreq_driver = {
+ 40 .register_em = foo_cpufreq_register_em,
+ 41 };
diff --git a/Documentation/translations/zh_CN/power/index.rst b/Documentation/translations/zh_CN/power/index.rst
new file mode 100644
index 000000000000..bc54983ba515
--- /dev/null
+++ b/Documentation/translations/zh_CN/power/index.rst
@@ -0,0 +1,56 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/power/index.rst
+
+:翻译:
+
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+========
+电源管理
+========
+
+.. toctree::
+ :maxdepth: 1
+
+ energy-model
+ opp
+
+TODOList:
+
+ * apm-acpi
+ * basic-pm-debugging
+ * charger-manager
+ * drivers-testing
+ * freezing-of-tasks
+ * pci
+ * pm_qos_interface
+ * power_supply_class
+ * runtime_pm
+ * s2ram
+ * suspend-and-cpuhotplug
+ * suspend-and-interrupts
+ * swsusp-and-swap-files
+ * swsusp-dmcrypt
+ * swsusp
+ * video
+ * tricks
+
+ * userland-swsusp
+
+ * powercap/powercap
+ * powercap/dtpm
+
+ * regulator/consumer
+ * regulator/design
+ * regulator/machine
+ * regulator/overview
+ * regulator/regulator
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
diff --git a/Documentation/translations/zh_CN/power/opp.rst b/Documentation/translations/zh_CN/power/opp.rst
new file mode 100644
index 000000000000..8d6e3f6f6202
--- /dev/null
+++ b/Documentation/translations/zh_CN/power/opp.rst
@@ -0,0 +1,341 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/power/opp.rst
+
+:翻译:
+
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+======================
+操作性能值(OPP)库
+======================
+
+(C) 2009-2010 Nishanth Menon <nm@ti.com>, 德州仪器公司
+
+.. 目录
+
+ 1. 简介
+ 2. OPP链表初始注册
+ 3. OPP搜索函数
+ 4. OPP可用性控制函数
+ 5. OPP数据检索函数
+ 6. 数据结构
+
+1. 简介
+=======
+
+1.1 何为操作性能值(OPP)?
+------------------------------
+
+当今复杂的单片系统(SoC)由多个子模块组成,这些子模块会联合工作。在一个执行不同用例
+的操作系统中,并不是SoC中的所有模块都需要一直以最高频率工作。为了促成这一点,SoC中
+的子模块被分组为不同域,允许一些域以较低的电压和频率运行,而其它域则以较高的“电压/
+频率对”运行。
+
+设备按域支持的由频率电压对组成的离散的元组的集合,被称为操作性能值(组),或OPPs。
+
+举例来说:
+
+让我们考虑一个支持下述频率、电压值的内存保护单元(MPU)设备:
+{300MHz,最低电压为1V}, {800MHz,最低电压为1.2V}, {1GHz,最低电压为1.3V}
+
+我们能将它们表示为3个OPP,如下述{Hz, uV}元组(译注:频率的单位是赫兹,电压的单位是
+微伏)。
+
+- {300000000, 1000000}
+- {800000000, 1200000}
+- {1000000000, 1300000}
+
+1.2 操作性能值库
+----------------
+
+OPP库提供了一组辅助函数来组织和查询OPP信息。该库位于drivers/opp/目录下,其头文件
+位于include/linux/pm_opp.h中。OPP库可以通过开启CONFIG_PM_OPP来启用。某些SoC,
+如德州仪器的OMAP框架允许在不需要cpufreq的情况下可选地在某一OPP下启动。
+
+OPP库的典型用法如下::
+
+ (用户) -> 注册一个默认的OPP集合 -> (库)
+ (SoC框架) -> 在必要的情况下,对某些OPP进行修改 -> OPP layer
+ -> 搜索/检索信息的查询 ->
+
+OPP层期望每个域由一个唯一的设备指针来表示。SoC框架在OPP层为每个设备注册了一组初始
+OPP。这个链表的长度被期望是一个最优化的小数字,通常每个设备大约5个。初始链表包含了
+一个OPP集合,这个集合被期望能在系统中安全使能。
+
+关于OPP可用性的说明
+^^^^^^^^^^^^^^^^^^^
+
+随着系统的运行,SoC框架可能会基于各种外部因素选择让某些OPP在每个设备上可用或不可用,
+示例:温度管理或其它异常场景中,SoC框架可能会选择禁用一个较高频率的OPP以安全地继续
+运行,直到该OPP被重新启用(如果可能)。
+
+OPP库在它的实现中达成了这个概念。以下操作函数只能对可用的OPP使用:
+dev_pm_opp_find_freq_{ceil, floor}, dev_pm_opp_get_voltage,
+dev_pm_opp_get_freq, dev_pm_opp_get_opp_count。
+
+dev_pm_opp_find_freq_exact是用来查找OPP指针的,该指针可被用在dev_pm_opp_enable/
+disable函数,使一个OPP在被需要时变为可用。
+
+警告:如果对一个设备调用dev_pm_opp_enable/disable函数,OPP库的用户应该使用
+dev_pm_opp_get_opp_count来刷新OPP的可用性计数。触发这些的具体机制,或者对有依赖的
+子系统(比如cpufreq)的通知机制,都是由使用OPP库的SoC特定框架酌情处理的。在这些操作
+中,同样需要注意刷新cpufreq表。
+
+2. OPP链表初始注册
+==================
+SoC的实现会迭代调用dev_pm_opp_add函数来增加每个设备的OPP。预期SoC框架将以最优的
+方式注册OPP条目 - 典型的数字范围小于5。通过注册OPP生成的OPP链表,在整个设备运行过程
+中由OPP库维护。SoC框架随后可以使用dev_pm_opp_enable / disable函数动态地
+控制OPP的可用性。
+
+dev_pm_opp_add
+ 为设备指针所指向的特定域添加一个新的OPP。OPP是用频率和电压定义的。一旦完成
+ 添加,OPP被认为是可用的,可以用dev_pm_opp_enable/disable函数来控制其可用性。
+ OPP库内部用dev_pm_opp结构体存储并管理这些信息。这个函数可以被SoC框架根据SoC
+ 的使用环境的需求来定义一个最优链表。
+
+ 警告:
+ 不要在中断上下文使用这个函数。
+
+ 示例::
+
+ soc_pm_init()
+ {
+ /* 做一些事情 */
+ r = dev_pm_opp_add(mpu_dev, 1000000, 900000);
+ if (!r) {
+ pr_err("%s: unable to register mpu opp(%d)\n", r);
+ goto no_cpufreq;
+ }
+ /* 做一些和cpufreq相关的事情 */
+ no_cpufreq:
+ /* 做剩余的事情 */
+ }
+
+3. OPP搜索函数
+==============
+cpufreq等高层框架对频率进行操作,为了将频率映射到相应的OPP,OPP库提供了便利的函数
+来搜索OPP库内部管理的OPP链表。这些搜索函数如果找到匹配的OPP,将返回指向该OPP的指针,
+否则返回错误。这些错误预计由标准的错误检查,如IS_ERR()来处理,并由调用者采取适当的
+行动。
+
+这些函数的调用者应在使用完OPP后调用dev_pm_opp_put()。否则,OPP的内存将永远不会
+被释放,并导致内存泄露。
+
+dev_pm_opp_find_freq_exact
+ 根据 *精确的* 频率和可用性来搜索OPP。这个函数对默认不可用的OPP特别有用。
+ 例子:在SoC框架检测到更高频率可用的情况下,它可以使用这个函数在调用
+ dev_pm_opp_enable之前找到OPP::
+
+ opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false);
+ dev_pm_opp_put(opp);
+ /* 不要操作指针.. 只是做有效性检查.. */
+ if (IS_ERR(opp)) {
+ pr_err("frequency not disabled!\n");
+ /* 触发合适的操作.. */
+ } else {
+ dev_pm_opp_enable(dev,1000000000);
+ }
+
+ 注意:
+ 这是唯一一个可以搜索不可用OPP的函数。
+
+dev_pm_opp_find_freq_floor
+ 搜索一个 *最多* 提供指定频率的可用OPP。这个函数在搜索较小的匹配或按频率
+ 递减的顺序操作OPP信息时很有用。
+ 例子:要找的一个设备的最高OPP::
+
+ freq = ULONG_MAX;
+ opp = dev_pm_opp_find_freq_floor(dev, &freq);
+ dev_pm_opp_put(opp);
+
+dev_pm_opp_find_freq_ceil
+ 搜索一个 *最少* 提供指定频率的可用OPP。这个函数在搜索较大的匹配或按频率
+ 递增的顺序操作OPP信息时很有用。
+ 例1:找到一个设备最小的OPP::
+
+ freq = 0;
+ opp = dev_pm_opp_find_freq_ceil(dev, &freq);
+ dev_pm_opp_put(opp);
+
+ 例: 一个SoC的cpufreq_driver->target的简易实现::
+
+ soc_cpufreq_target(..)
+ {
+ /* 做策略检查等操作 */
+ /* 找到和请求最接近的频率 */
+ opp = dev_pm_opp_find_freq_ceil(dev, &freq);
+ dev_pm_opp_put(opp);
+ if (!IS_ERR(opp))
+ soc_switch_to_freq_voltage(freq);
+ else
+ /* 当不能满足请求时,要做的事 */
+ /* 做其它事 */
+ }
+
+4. OPP可用性控制函数
+====================
+在OPP库中注册的默认OPP链表也许无法满足所有可能的场景。OPP库提供了一套函数来修改
+OPP链表中的某个OPP的可用性。这使得SoC框架能够精细地动态控制哪一组OPP是可用于操作
+的。设计这些函数的目的是在诸如考虑温度时 *暂时地* 删除某个OPP(例如,在温度下降
+之前不要使用某OPP)。
+
+警告:
+ 不要在中断上下文使用这些函数。
+
+dev_pm_opp_enable
+ 使一个OPP可用于操作。
+ 例子:假设1GHz的OPP只有在SoC温度低于某个阈值时才可用。SoC框架的实现可能
+ 会选择做以下事情::
+
+ if (cur_temp < temp_low_thresh) {
+ /* 若1GHz未使能,则使能 */
+ opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false);
+ dev_pm_opp_put(opp);
+ /* 仅仅是错误检查 */
+ if (!IS_ERR(opp))
+ ret = dev_pm_opp_enable(dev, 1000000000);
+ else
+ goto try_something_else;
+ }
+
+dev_pm_opp_disable
+ 使一个OPP不可用于操作。
+ 例子:假设1GHz的OPP只有在SoC温度高于某个阈值时才可用。SoC框架的实现可能
+ 会选择做以下事情::
+
+ if (cur_temp > temp_high_thresh) {
+ /* 若1GHz已使能,则关闭 */
+ opp = dev_pm_opp_find_freq_exact(dev, 1000000000, true);
+ dev_pm_opp_put(opp);
+ /* 仅仅是错误检查 */
+ if (!IS_ERR(opp))
+ ret = dev_pm_opp_disable(dev, 1000000000);
+ else
+ goto try_something_else;
+ }
+
+5. OPP数据检索函数
+==================
+由于OPP库对OPP信息进行了抽象化处理,因此需要一组函数来从dev_pm_opp结构体中提取
+信息。一旦使用搜索函数检索到一个OPP指针,以下函数就可以被SoC框架用来检索OPP层
+内部描述的信息。
+
+dev_pm_opp_get_voltage
+ 检索OPP指针描述的电压。
+ 例子: 当cpufreq切换到到不同频率时,SoC框架需要用稳压器框架将OPP描述
+ 的电压设置到提供电压的电源管理芯片中::
+
+ soc_switch_to_freq_voltage(freq)
+ {
+ /* 做一些事情 */
+ opp = dev_pm_opp_find_freq_ceil(dev, &freq);
+ v = dev_pm_opp_get_voltage(opp);
+ dev_pm_opp_put(opp);
+ if (v)
+ regulator_set_voltage(.., v);
+ /* 做其它事 */
+ }
+
+dev_pm_opp_get_freq
+ 检索OPP指针描述的频率。
+ 例子:比方说,SoC框架使用了几个辅助函数,通过这些函数,我们可以将OPP
+ 指针传入,而不是传入额外的参数,用来处理一系列数据参数::
+
+ soc_cpufreq_target(..)
+ {
+ /* 做一些事情.. */
+ max_freq = ULONG_MAX;
+ max_opp = dev_pm_opp_find_freq_floor(dev,&max_freq);
+ requested_opp = dev_pm_opp_find_freq_ceil(dev,&freq);
+ if (!IS_ERR(max_opp) && !IS_ERR(requested_opp))
+ r = soc_test_validity(max_opp, requested_opp);
+ dev_pm_opp_put(max_opp);
+ dev_pm_opp_put(requested_opp);
+ /* 做其它事 */
+ }
+ soc_test_validity(..)
+ {
+ if(dev_pm_opp_get_voltage(max_opp) < dev_pm_opp_get_voltage(requested_opp))
+ return -EINVAL;
+ if(dev_pm_opp_get_freq(max_opp) < dev_pm_opp_get_freq(requested_opp))
+ return -EINVAL;
+ /* 做一些事情.. */
+ }
+
+dev_pm_opp_get_opp_count
+ 检索某个设备可用的OPP数量。
+ 例子:假设SoC中的一个协处理器需要知道某个表中的可用频率,主处理器可以
+ 按如下方式发出通知::
+
+ soc_notify_coproc_available_frequencies()
+ {
+ /* 做一些事情 */
+ num_available = dev_pm_opp_get_opp_count(dev);
+ speeds = kzalloc(sizeof(u32) * num_available, GFP_KERNEL);
+ /* 按升序填充表 */
+ freq = 0;
+ while (!IS_ERR(opp = dev_pm_opp_find_freq_ceil(dev, &freq))) {
+ speeds[i] = freq;
+ freq++;
+ i++;
+ dev_pm_opp_put(opp);
+ }
+
+ soc_notify_coproc(AVAILABLE_FREQs, speeds, num_available);
+ /* 做其它事 */
+ }
+
+6. 数据结构
+===========
+通常,一个SoC包含多个可变电压域。每个域由一个设备指针描述。和OPP之间的关系可以
+按以下方式描述::
+
+ SoC
+ |- device 1
+ | |- opp 1 (availability, freq, voltage)
+ | |- opp 2 ..
+ ... ...
+ | `- opp n ..
+ |- device 2
+ ...
+ `- device m
+
+OPP库维护着一个内部链表,SoC框架使用上文描述的各个函数来填充和访问。然而,描述
+真实OPP和域的结构体是OPP库自身的内部组成,以允许合适的抽象在不同系统中得到复用。
+
+struct dev_pm_opp
+ OPP库的内部数据结构,用于表示一个OPP。除了频率、电压、可用性信息外,
+ 它还包含OPP库运行所需的内部统计信息。指向这个结构体的指针被提供给
+ 用户(比如SoC框架)使用,在与OPP层的交互中作为OPP的标识符。
+
+ 警告:
+ 结构体dev_pm_opp的指针不应该由用户解析或修改。一个实例的默认值由
+ dev_pm_opp_add填充,但OPP的可用性由dev_pm_opp_enable/disable函数
+ 修改。
+
+struct device
+ 这用于向OPP层标识一个域。设备的性质和它的实现是由OPP库的用户决定的,
+ 如SoC框架。
+
+总体来说,以一个简化的视角看,对数据结构的操作可以描述为下面各图::
+
+ 初始化 / 修改:
+ +-----+ /- dev_pm_opp_enable
+ dev_pm_opp_add --> | opp | <-------
+ | +-----+ \- dev_pm_opp_disable
+ \-------> domain_info(device)
+
+ 搜索函数:
+ /-- dev_pm_opp_find_freq_ceil ---\ +-----+
+ domain_info<---- dev_pm_opp_find_freq_exact -----> | opp |
+ \-- dev_pm_opp_find_freq_floor ---/ +-----+
+
+ 检索函数:
+ +-----+ /- dev_pm_opp_get_voltage
+ | opp | <---
+ +-----+ \- dev_pm_opp_get_freq
+
+ domain_info <- dev_pm_opp_get_opp_count
diff --git a/Documentation/translations/zh_CN/process/1.Intro.rst b/Documentation/translations/zh_CN/process/1.Intro.rst
index 10a15f3dc282..4f9284cbe33b 100644
--- a/Documentation/translations/zh_CN/process/1.Intro.rst
+++ b/Documentation/translations/zh_CN/process/1.Intro.rst
@@ -1,162 +1,170 @@
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/1.Intro.rst <development_process_intro>`
-:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+
+:Translator:
+
+ 时奎亮 Alex Shi <alex.shi@linux.alibaba.com>
+
+:校译:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
.. _cn_development_process_intro:
-介绍
+引言
====
-执行摘要
+内容提要
--------
-本节的其余部分涵盖了内核开发过程的范围,以及开发人员及其雇主在这方面可能遇
-到的各种挫折。内核代码应该合并到正式的(“主线”)内核中有很多原因,包括对用
-户的自动可用性、多种形式的社区支持以及影响内核开发方向的能力。提供给Linux
-内核的代码必须在与GPL兼容的许可证下可用。
+本节的其余部分涵盖了内核开发的过程,以及开发人员及其雇主在这方面可能遇到的
+各种问题。有很多原因使内核代码应被合并到正式的(“主线”)内核中,包括对用户
+的自动可用性、多种形式的社区支持以及影响内核开发方向的能力。提供给Linux内核
+的代码必须在与GPL兼容的许可证下可用。
:ref:`cn_development_process` 介绍了开发过程、内核发布周期和合并窗口的机制。
-涵盖了补丁开发、审查和合并周期中的各个阶段。有一些关于工具和邮件列表的讨论。
-鼓励希望开始内核开发的开发人员作为初始练习跟踪并修复bug。
+涵盖了补丁开发、审查和合并周期中的各个阶段。还有一些关于工具和邮件列表的讨论?
+鼓励希望开始内核开发的开发人员跟踪并修复缺陷以作为初步练习。
-:ref:`cn_development_early_stage` 包括早期项目规划,重点是尽快让开发社区参与
+:ref:`cn_development_early_stage` 包括项目的早期规划,重点是尽快让开发社区
+参与进来。
-:ref:`cn_development_coding` 是关于编码过程的;讨论了其他开发人员遇到的几个
-陷阱。对补丁的一些要求已经涵盖,并且介绍了一些工具,这些工具有助于确保内核
+:ref:`cn_development_coding` 是关于编程过程的;介绍了其他开发人员遇到的几个
+陷阱。也涵盖了对补丁的一些要求,并且介绍了一些工具,这些工具有助于确保内核
补丁是正确的。
-:ref:`cn_development_posting` 讨论发布补丁以供评审的过程。为了让开发社区
-认真对待,补丁必须正确格式化和描述,并且必须发送到正确的地方。遵循本节中的
-建议有助于确保为您的工作提供最好的接纳。
+:ref:`cn_development_posting` 描述发布补丁以供评审的过程。为了让开发社区能
+认真对待,补丁必须被正确格式化和描述,并且必须发送到正确的地方。遵循本节中的
+建议有助于确保您的工作能被较好地接纳。
-:ref:`cn_development_followthrough` 介绍了发布补丁之后发生的事情;该工作
-在这一点上还远远没有完成。与审阅者一起工作是开发过程中的一个重要部分;本节
-提供了一些关于如何在这个重要阶段避免问题的提示。当补丁被合并到主线中时,
-开发人员要注意不要假定任务已经完成。
+:ref:`cn_development_followthrough` 介绍了发布补丁之后发生的事情;工作在这时
+还远远没有完成。与审阅者一起工作是开发过程中的一个重要部分;本节提供了一些
+关于如何在这个重要阶段避免问题的提示。当补丁被合并到主线中时,开发人员要注意
+不要假定任务已经完成。
-:ref:`cn_development_advancedtopics` 介绍了两个“高级”主题:
-使用Git管理补丁和查看其他人发布的补丁。
+:ref:`cn_development_advancedtopics` 介绍了两个“高级”主题:使用Git管理补丁
+和查看其他人发布的补丁。
-:ref:`cn_development_conclusion` 总结了有关内核开发的更多信息,附带有带有
-指向资源的链接.
+:ref:`cn_development_conclusion` 总结了有关内核开发的更多信息,附带有相关资源
+链接。
-这个文件是关于什么的
+这个文档是关于什么的
--------------------
-Linux内核有超过800万行代码,每个版本的贡献者超过1000人,是现存最大、最活跃
-的免费软件项目之一。从1991年开始,这个内核已经发展成为一个最好的操作系统
-组件,运行在袖珍数字音乐播放器、台式PC、现存最大的超级计算机以及所有类型的
-系统上。它是一种适用于几乎任何情况的健壮、高效和可扩展的解决方案。
+Linux内核有超过800万行代码,每个版本的贡献者超过1000人,是现存最大、最活跃的
+免费软件项目之一。从1991年开始,这个内核已经发展成为一个最好的操作系统组件,
+运行在袖珍数字音乐播放器、台式电脑、现存最大的超级计算机以及所有类型的系统上。
+它是一种适用于几乎任何情况的健壮、高效和可扩展的解决方案。
随着Linux的发展,希望参与其开发的开发人员(和公司)的数量也在增加。硬件供应商
希望确保Linux能够很好地支持他们的产品,使这些产品对Linux用户具有吸引力。嵌入
式系统供应商使用Linux作为集成产品的组件,希望Linux能够尽可能地胜任手头的任务。
-分销商和其他基于Linux的软件供应商对Linux内核的功能、性能和可靠性有着明确的
-兴趣。最终用户也常常希望修改Linux,使之更好地满足他们的需求。
+分销商和其他基于Linux的软件供应商切实关心Linux内核的功能、性能和可靠性。最终
+用户也常常希望修改Linux,使之能更好地满足他们的需求。
Linux最引人注目的特性之一是这些开发人员可以访问它;任何具备必要技能的人都可以
改进Linux并影响其开发方向。专有产品不能提供这种开放性,这是自由软件的一个特点。
-但是,如果有什么不同的话,内核比大多数其他自由软件项目更开放。一个典型的三个月
-内核开发周期可以涉及1000多个开发人员,他们为100多个不同的公司
-(或者根本没有公司)工作。
+如果有什么不同的话,那就是内核比大多数其他自由软件项目更开放。一个典型的三个
+月内核开发周期可以涉及1000多个开发人员,他们为100多个不同的公司(或者根本不
+隶属公司)工作。
-与内核开发社区合作并不是特别困难。但是,尽管如此,许多潜在的贡献者在尝试做
-内核工作时遇到了困难。内核社区已经发展了自己独特的操作方式,使其能够在每天
+与内核开发社区合作并不是特别困难。但尽管如此,仍有许多潜在的贡献者在尝试做
+内核工作时遇到了困难。内核社区已经发展出自己独特的操作方式,使其能够在每天
都要更改数千行代码的环境中顺利运行(并生成高质量的产品)。因此,Linux内核开发
-过程与专有的开发方法有很大的不同也就不足为奇了。
+过程与专有的开发模式有很大的不同也就不足为奇了。
-对于新开发人员来说,内核的开发过程可能会让人感到奇怪和恐惧,但这个背后有充分的
-理由和坚实的经验。一个不了解内核社区的方式的开发人员(或者更糟的是,他们试图
-抛弃或规避内核社区的方式)会有一个令人沮丧的体验。开发社区, 在帮助那些试图学习
-的人的同时,没有时间帮助那些不愿意倾听或不关心开发过程的人。
+对于新开发人员来说,内核的开发过程可能会让人感到奇怪和恐惧,但这背后有充分的
+理由和坚实的经验。一个不了解内核社区工作方式的开发人员(或者更糟的是,他们
+试图抛弃或规避之)会得到令人沮丧的体验。开发社区在帮助那些试图学习的人的同时,
+没有时间帮助那些不愿意倾听或不关心开发过程的人。
-希望阅读本文的人能够避免这种令人沮丧的经历。这里有很多材料,但阅读时所做的
+希望阅读本文的人能够避免这种令人沮丧的经历。这些材料很长,但阅读它们时所做的
努力会在短时间内得到回报。开发社区总是需要能让内核变更好的开发人员;下面的
-文本应该帮助您或为您工作的人员加入我们的社区。
+文字应该帮助您或为您工作的人员加入我们的社区。
致谢
----
-本文件由Jonathan Corbet撰写,corbet@lwn.net。以下人员的建议使之更为完善:
+本文档由Jonathan Corbet <corbet@lwn.net> 撰写。以下人员的建议使之更为完善:
Johannes Berg, James Berry, Alex Chiang, Roland Dreier, Randy Dunlap,
Jake Edge, Jiri Kosina, Matt Mackall, Arthur Marsh, Amanda McPherson,
-Andrew Morton, Andrew Price, Tsugikazu Shibata, 和 Jochen Voß.
+Andrew Morton, Andrew Price, Tsugikazu Shibata 和 Jochen Voß 。
这项工作得到了Linux基金会的支持,特别感谢Amanda McPherson,他看到了这项工作
-的价值并把它变成现实。
+的价值并将其变成现实。
代码进入主线的重要性
--------------------
有些公司和开发人员偶尔会想,为什么他们要费心学习如何与内核社区合作,并将代码
放入主线内核(“主线”是由Linus Torvalds维护的内核,Linux发行商将其用作基础)。
-在短期内,贡献代码看起来像是一种可以避免的开销;仅仅将代码分开并直接支持用户
+在短期内,贡献代码看起来像是一种可以避免的开销;维护独立代码并直接支持用户
似乎更容易。事实上,保持代码独立(“树外”)是在经济上是错误的。
-作为说明树外代码成本的一种方法,下面是内核开发过程的一些相关方面;本文稍后将
-更详细地讨论其中的大部分内容。考虑:
+为了说明树外代码成本,下面给出内核开发过程的一些相关方面;本文稍后将更详细地
+讨论其中的大部分内容。请考虑:
- 所有Linux用户都可以使用合并到主线内核中的代码。它将自动出现在所有启用它的
- 发行版上。不需要驱动程序磁盘、下载,也不需要为多个发行版的多个版本提供支持;
- 对于开发人员和用户来说,这一切都是可行的。并入主线解决了大量的分布和支持问题
+ 发行版上。无需驱动程序磁盘、额外下载,也不需要为多个发行版的多个版本提供
+ 支持;这一切将方便所有开发人员和用户。并入主线解决了大量的分发和支持问题。
-- 当内核开发人员努力维护一个稳定的用户空间接口时,内部内核API处于不断变化之中.
- 缺乏一个稳定的内部接口是一个深思熟虑的设计决策;它允许在任何时候进行基本的改
- 进,并产生更高质量的代码。但该策略的一个结果是,如果要使用新的内核,任何树外
- 代码都需要持续的维护。维护树外代码需要大量的工作才能使代码保持工作状态。
+- 当内核开发人员努力维护一个稳定的用户空间接口时,内核内部API处于不断变化之中。
+ 不维持稳定的内部接口是一个慎重的设计决策;它允许在任何时候进行基本的改进,
+ 并产出更高质量的代码。但该策略导致结果是,若要使用新的内核,任何树外代码都
+ 需要持续的维护。维护树外代码会需要大量的工作才能使代码保持正常运行。
- 相反,位于主线中的代码不需要这样做,因为一个简单的规则要求进行API更改的任何
- 开发人员也必须修复由于该更改而破坏的任何代码。因此,合并到主线中的代码大大
- 降低了维护成本。
+ 相反,位于主线中的代码不需要这样做,因为基本规则要求进行API更改的任何开发
+ 人员也必须修复由于该更改而破坏的任何代码。因此,合并到主线中的代码大大降低
+ 了维护成本。
-- 除此之外,内核中的代码通常会被其他开发人员改进。令人惊讶的结果可能来自授权
- 您的用户社区和客户改进您的产品。
+- 除此之外,内核中的代码通常会被其他开发人员改进。您授权的用户社区和客户对您
+ 产品的改进可能会令人惊喜。
-- 内核代码在合并到主线之前和之后都要经过审查。不管原始开发人员的技能有多强,
+- 内核代码在合并到主线之前和之后都要经过审查。无论原始开发人员的技能有多强,
这个审查过程总是能找到改进代码的方法。审查经常发现严重的错误和安全问题。
- 这对于在封闭环境中开发的代码尤其如此;这种代码从外部开发人员的审查中获益
- 匪浅。树外代码是低质量代码。
+ 对于在封闭环境中开发的代码尤其如此;这种代码从外部开发人员的审查中获益匪浅。
+ 树外代码是低质量代码。
- 参与开发过程是您影响内核开发方向的方式。旁观者的抱怨会被听到,但是活跃的
开发人员有更强的声音——并且能够实现使内核更好地满足其需求的更改。
- 当单独维护代码时,总是存在第三方为类似功能提供不同实现的可能性。如果发生
- 这种情况,合并代码将变得更加困难——甚至到了不可能的地步。然后,您将面临以下
- 令人不快的选择:(1)无限期地维护树外的非标准特性,或(2)放弃代码并将用户
- 迁移到树内版本。
+ 这种情况,合并代码将变得更加困难——甚至成为不可能。之后,您将面临以下令人
+ 不快的选择:(1)无限期地维护树外的非标准特性,或(2)放弃代码并将用户迁移
+ 到树内版本。
-- 代码的贡献是使整个过程工作的根本。通过贡献代码,您可以向内核添加新功能,并
- 提供其他内核开发人员使用的功能和示例。如果您已经为Linux开发了代码(或者
- 正在考虑这样做),那么您显然对这个平台的持续成功感兴趣;贡献代码是确保成功
- 的最好方法之一。
+- 代码的贡献是使整个流程工作的根本。通过贡献代码,您可以向内核添加新功能,并
+ 提供其他内核开发人员使用的功能和示例。如果您已经为Linux开发了代码(或者正在
+ 考虑这样做),那么您显然对这个平台的持续成功感兴趣;贡献代码是确保成功的
+ 最好方法之一。
上述所有理由都适用于任何树外内核代码,包括以专有的、仅二进制形式分发的代码。
-然而,在考虑任何类型的纯二进制内核代码分布之前,还需要考虑其他因素。这些包括:
+然而,在考虑任何类型的纯二进制内核代码分布之前,还需要考虑其他因素。包括:
-- 围绕专有内核模块分发的法律问题充其量是模糊的;相当多的内核版权所有者认为,
- 大多数仅限二进制的模块是内核的派生产品,因此,它们的分发违反了GNU通用公共
- 许可证(下面将详细介绍)。您的作者不是律师,本文档中的任何内容都不可能被
+- 围绕专有内核模块分发的法律问题其实较为模糊;相当多的内核版权所有者认为,
+ 大多数仅二进制的模块是内核的派生产品,因此,它们的分发违反了GNU通用公共
+ 许可证(下面将详细介绍)。本文作者不是律师,本文档中的任何内容都不可能被
视为法律建议。封闭源代码模块的真实法律地位只能由法院决定。但不管怎样,困扰
这些模块的不确定性仍然存在。
- 二进制模块大大增加了调试内核问题的难度,以至于大多数内核开发人员甚至都不会
尝试。因此,只分发二进制模块将使您的用户更难从社区获得支持。
-- 对于只支持二进制的模块的发行者来说,支持也更加困难,他们必须为他们希望支持
- 的每个发行版和每个内核版本提供一个版本的模块。为了提供相当全面的覆盖范围,
+- 对于仅二进制的模块的发行者来说,支持也更加困难,他们必须为他们希望支持的
+ 每个发行版和每个内核版本提供不同版本的模块。为了提供较为全面的覆盖范围,
可能需要一个模块的几十个构建,并且每次升级内核时,您的用户都必须单独升级
- 您的模块。
+ 这些模块。
-- 上面提到的关于代码评审的所有问题都更加存在于封闭源代码。由于该代码根本不可
- 用,因此社区无法对其进行审查,毫无疑问,它将存在严重问题。
+- 上面提到的关于代码评审的所有问题都更加存在于封闭源代码中。由于该代码根本
+ 不可得,因此社区无法对其进行审查,毫无疑问,它将存在严重问题。
-尤其是嵌入式系统的制造商,可能会倾向于忽视本节中所说的大部分内容,因为他们
+尤其是嵌入式系统的制造商,可能会倾向于忽视本节中所说的大部分内容;因为他们
相信自己正在商用一种使用冻结内核版本的独立产品,在发布后不需要再进行开发。
这个论点忽略了广泛的代码审查的价值以及允许用户向产品添加功能的价值。但这些
-产品也有有限的商业寿命,之后必须发布新版本的产品。在这一点上,代码在主线上
-并得到良好维护的供应商将能够更好地占位,以使新产品快速上市。
+产品的商业寿命有限,之后必须发布新版本的产品。在这一点上,代码在主线上并得到
+良好维护的供应商将能够更好地占位,以使新产品快速上市。
许可
----
@@ -164,23 +172,24 @@ Andrew Morton, Andrew Price, Tsugikazu Shibata, 和 Jochen Voß.
代码是根据一些许可证提供给Linux内核的,但是所有代码都必须与GNU通用公共许可
证(GPLV2)的版本2兼容,该版本是覆盖整个内核分发的许可证。在实践中,这意味
着所有代码贡献都由GPLv2(可选地,语言允许在更高版本的GPL下分发)或3子句BSD
-许可(New BSD License, 译者注)覆盖。任何不包含在兼容许可证中的贡献都不会
+许可(New BSD License,译者注)覆盖。任何不包含在兼容许可证中的贡献都不会
被接受到内核中。
贡献给内核的代码不需要(或请求)版权分配。合并到主线内核中的所有代码都保留
其原始所有权;因此,内核现在拥有数千个所有者。
-这种所有权结构的一个暗示是,任何改变内核许可的尝试都注定会失败。很少有实际
-的场景可以获得所有版权所有者的同意(或者从内核中删除他们的代码)。因此,特
-别是,在可预见的将来,不可能迁移到GPL的版本3。
+这种所有权结构也暗示着,任何改变内核许可的尝试都注定会失败。很少有实际情况
+可以获得所有版权所有者的同意(或者从内核中删除他们的代码)。因此,尤其是在
+可预见的将来,许可证不大可能迁移到GPL的版本3。
-所有贡献给内核的代码都必须是合法的免费软件。因此,不接受匿名(或匿名)贡献
-者的代码。所有贡献者都需要在他们的代码上“sign off”,声明代码可以在GPL下与内
-核一起分发。无法提供未被其所有者许可为免费软件的代码,或可能为内核造成版权
-相关问题的代码(例如,由缺乏适当保护的反向工程工作派生的代码)不能被接受。
+所有贡献给内核的代码都必须是合法的免费软件。因此,不接受匿名(或化名)贡献
+者的代码。所有贡献者都需要在他们的代码上“sign off(签发)”,声明代码可以
+在GPL下与内核一起分发。无法提供未被其所有者许可为免费软件的代码,或可能为
+内核造成版权相关问题的代码(例如,由缺乏适当保护的反向工程工作派生的代码)
+不能被接受。
-有关版权相关问题的问题在Linux开发邮件列表中很常见。这样的问题通常会得到不少
-答案,但要记住,回答这些问题的人不是律师,不能提供法律咨询。如果您有关于
-Linux源代码的法律问题,那么与了解该领域的律师交流是无法替代的。依靠从技术
-邮件列表中获得的答案是一件冒险的事情。
+有关版权问题的提问在Linux开发邮件列表中很常见。这样的问题通常会得到不少答案,
+但请记住,回答这些问题的人不是律师,不能提供法律咨询。如果您有关于Linux源代码
+的法律问题,没有什么可以代替咨询了解这一领域的律师。依赖从技术邮件列表中获得
+的答案是一件冒险的事情。
diff --git a/Documentation/translations/zh_CN/process/2.Process.rst b/Documentation/translations/zh_CN/process/2.Process.rst
index ceb733bb0294..e68c9de0f7f8 100644
--- a/Documentation/translations/zh_CN/process/2.Process.rst
+++ b/Documentation/translations/zh_CN/process/2.Process.rst
@@ -1,17 +1,24 @@
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/2.Process.rst <development_process>`
-:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+
+:Translator:
+
+ 时奎亮 Alex Shi <alex.shi@linux.alibaba.com>
+
+:校译:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
.. _cn_development_process:
-开发流程如何工作
+开发流程如何进行
================
-90年代早期的Linux内核开发是一件相当松散的事情,涉及的用户和开发人员相对较
-少。由于拥有数以百万计的用户群,并且在一年的时间里有大约2000名开发人员参与
-进来,内核因此必须发展许多流程来保持开发的顺利进行。要成为流程的有效组成
-部分,需要对流程的工作方式有一个扎实的理解。
+90年代早期的Linux内核开发是一件相当松散的事情,涉及的用户和开发人员相对较少。
+由于拥有数以百万计的用户群,且每年有大约2000名开发人员参与进来,内核因此必须
+发展出许多既定流程来保证开发的顺利进行。要参与到流程中来,需要对此流程的进行
+方式有一个扎实的理解。
总览
----
@@ -20,112 +27,113 @@
内核版本。最近的发布历史记录如下:
====== =================
- 4.11 四月 30, 2017
- 4.12 七月 2, 2017
- 4.13 九月 3, 2017
- 4.14 十一月 12, 2017
- 4.15 一月 28, 2018
- 4.16 四月 1, 2018
+ 5.0 2019年3月3日
+ 5.1 2019年5月5日
+ 5.2 2019年7月7日
+ 5.3 2019年9月15日
+ 5.4 2019年11月24日
+ 5.5 2020年1月6日
====== =================
-每4.x版本都是一个主要的内核版本,具有新特性、内部API更改等等。一个典型的4.x
-版本包含大约13000个变更集,变更了几十万行代码。因此,4.x是Linux内核开发的前
+每个5.x版本都是一个主要的内核版本,具有新特性、内部API更改等等。一个典型的5.x
+版本包含大约13000个变更集,变更了几十万行代码。因此,5.x是Linux内核开发的前
沿;内核使用滚动开发模型,不断集成重大变化。
-对于每个版本的补丁合并,遵循一个相对简单的规则。在每个开发周期的开始,“合并
-窗口”被打开。当时,被认为足够稳定(并且被开发社区接受)的代码被合并到主线内
+对于每个版本的补丁合并,遵循一个相对简单的规则。在每个开发周期的开头,“合并
+窗口”被打开。这时,被认为足够稳定(并且被开发社区接受)的代码被合并到主线内
核中。在这段时间内,新开发周期的大部分变更(以及所有主要变更)将以接近每天
1000次变更(“补丁”或“变更集”)的速度合并。
-(顺便说一句,值得注意的是,合并窗口期间集成的更改并不是凭空产生的;它们是
-提前收集、测试和分级的。稍后将详细描述该过程的工作方式)。
+(顺便说一句,值得注意的是,合并窗口期间集成的更改并不是凭空产生的;它们是经
+提前收集、测试和分级的。稍后将详细描述该过程的工作方式。)
-合并窗口持续大约两周。在这段时间结束时,LinusTorvalds将声明窗口已关闭,并
-释放第一个“rc”内核。例如,对于目标为4.14的内核,在合并窗口结束时发生的释放
-将被称为4.14-rc1。RC1版本是一个信号,表示合并新特性的时间已经过去,稳定下一
-个内核的时间已经开始。
+合并窗口持续大约两周。在这段时间结束时,Linus Torvalds将声明窗口已关闭,并
+释放第一个“rc”内核。例如,对于目标为5.6的内核,在合并窗口结束时发生的释放
+将被称为5.6-rc1。-rc1 版本是一个信号,表示合并新特性的时间已经过去,稳定下一
+个内核的时间已经到来。
在接下来的6到10周内,只有修复问题的补丁才应该提交给主线。有时会允许更大的
-更改,但这种情况很少发生;试图在合并窗口外合并新功能的开发人员往往会受到不
+更改,但这种情况很少发生;试图在合并窗口外合并新功能的开发人员往往受不到
友好的接待。一般来说,如果您错过了给定特性的合并窗口,最好的做法是等待下一
-个开发周期。(对于以前不支持的硬件,偶尔会对驱动程序进行例外;如果它们不
-改变已有代码,则不会导致回归,并且应该可以随时安全地添加)。
+个开发周期。(偶尔会对未支持硬件的驱动程序进行例外;如果它们不改变已有代码,
+则不会导致回归,应该可以随时被安全地加入)。
随着修复程序进入主线,补丁速度将随着时间的推移而变慢。Linus大约每周发布一次
-新的-rc内核;一个正常的系列将在-rc6和-rc9之间,内核被认为足够稳定并最终发布。
+新的-rc内核;在内核被认为足够稳定并最终发布前,一般会达到-rc6到-rc9之间。
然后,整个过程又重新开始了。
-例如,这里是4.16的开发周期进行情况(2018年的所有日期):
+例如,这里是5.4的开发周期进行情况(2019年):
============== ==============================
- 一月 28 4.15 稳定版发布
- 二月 11 4.16-rc1, 合并窗口关闭
- 二月 18 4.16-rc2
- 二月 25 4.16-rc3
- 三月 4 4.16-rc4
- 三月 11 4.16-rc5
- 三月 18 4.16-rc6
- 三月 25 4.16-rc7
- 四月 1 4.16 稳定版发布
+ 九月 15 5.3 稳定版发布
+ 九月 30 5.4-rc1 合并窗口关闭
+ 十月 6 5.4-rc2
+ 十月 13 5.4-rc3
+ 十月 20 5.4-rc4
+ 十月 27 5.4-rc5
+ 十一月 3 5.4-rc6
+ 十一月 10 5.4-rc7
+ 十一月 17 5.4-rc8
+ 十一月 24 5.4 稳定版发布
============== ==============================
-开发人员如何决定何时结束开发周期并创建稳定的版本?使用的最重要的指标是以前
-版本的回归列表。不欢迎出现任何错误,但是那些破坏了以前能工作的系统的错误被
-认为是特别严重的。因此,导致回归的补丁是不受欢迎的,很可能在稳定期内删除。
+开发人员如何决定何时结束开发周期并创建稳定版本?最重要的指标是以前版本的
+回归列表。不欢迎出现任何错误,但是那些破坏了以前能工作的系统的错误被认为是
+特别严重的。因此,导致回归的补丁是不受欢迎的,很可能在稳定期内删除。
开发人员的目标是在稳定发布之前修复所有已知的回归。在现实世界中,这种完美是
-很难实现的;在这种规模的项目中,变量太多了。有一点,延迟最终版本只会使问题
-变得更糟;等待下一个合并窗口的一堆更改将变大,从而在下次创建更多的回归错误。
-因此,大多数4.x内核都有一些已知的回归错误,不过,希望没有一个是严重的。
+很难实现的;在这种规模的项目中,变数太多了。需要说明的是,延迟最终版本只会
+使问题变得更糟;等待下一个合并窗口的更改将变多,导致下次出现更多的回归错误。
+因此,大多数5.x内核都有一些已知的回归错误,不过,希望没有一个是严重的。
-一旦一个稳定的版本发布,它正在进行的维护工作就被移交给“稳定团队”,目前由
-Greg Kroah-Hartman组成。稳定团队将使用4.x.y编号方案不定期的发布稳定版本的更
-新。要加入更新版本,补丁程序必须(1)修复一个重要的bug,(2)已经合并到
-下一个开发主线中。内核通常会在超过其初始版本的一个以上的开发周期内接收稳定
-的更新。例如,4.13内核的历史如下
+一旦一个稳定的版本发布,它的持续维护工作就被移交给“稳定团队”,目前由
+Greg Kroah-Hartman领导。稳定团队将使用5.x.y编号方案不定期地发布稳定版本的
+更新。要合入更新版本,补丁必须(1)修复一个重要的缺陷,且(2)已经合并到
+下一个开发版本主线中。内核通常会在其初始版本后的一个以上的开发周期内收到
+稳定版更新。例如,5.2内核的历史如下(2019年):
============== ===============================
- 九月 3 4.13 稳定版发布
- 九月 13 4.13.1
- 九月 20 4.13.2
- 九月 27 4.13.3
- 十月 5 4.13.4
- 十月 12 4.13.5
+ 七月 7 5.2 稳定版发布
+ 七月 13 5.2.1
+ 七月 21 5.2.2
+ 七月 26 5.2.3
+ 七月 28 5.2.4
+ 七月 31 5.2.5
... ...
- 十一月 24 4.13.16
+ 十月 11 5.2.21
============== ===============================
-4.13.16是4.13版本的最终稳定更新。
+5.2.21是5.2版本的最终稳定更新。
有些内核被指定为“长期”内核;它们将得到更长时间的支持。在本文中,当前的长期
内核及其维护者是:
- ====== ====================== ==============================
- 3.16 Ben Hutchings (长期稳定内核)
- 4.1 Sasha Levin
- 4.4 Greg Kroah-Hartman (长期稳定内核)
- 4.9 Greg Kroah-Hartman
- 4.14 Greg Kroah-Hartman
- ====== ====================== ==============================
+ ====== ================================ ================
+ 3.16 Ben Hutchings (长期稳定内核)
+ 4.4 Greg Kroah-Hartman & Sasha Levin (长期稳定内核)
+ 4.9 Greg Kroah-Hartman & Sasha Levin
+ 4.14 Greg Kroah-Hartman & Sasha Levin
+ 4.19 Greg Kroah-Hartman & Sasha Levin
+ 5.4 Greg Kroah-Hartman & Sasha Levin
+ ====== ================================ ================
-为长期支持选择内核纯粹是维护人员有必要和时间来维护该版本的问题。目前还没有
-为即将发布的任何特定版本提供长期支持的已知计划。
+长期支持内核的选择纯粹是维护人员是否有需求和时间来维护该版本的问题。
+目前还没有为即将发布的任何特定版本提供长期支持的已知计划。
补丁的生命周期
--------------
补丁不会直接从开发人员的键盘进入主线内核。相反,有一个稍微复杂(如果有些非
正式)的过程,旨在确保对每个补丁进行质量审查,并确保每个补丁实现了一个在主线
-中需要的更改。对于小的修复,这个过程可能会很快发生,或者,在大的和有争议的
-变更的情况下,会持续数年。许多开发人员的挫折来自于对这个过程缺乏理解或者
-试图绕过它。
+中需要的更改。对于小的修复,这个过程可能会很快完成,,而对于较大或有争议的
+变更,可能会持续数年。许多开发人员的沮丧来自于对这个过程缺乏理解或者试图绕过它。
-为了减少这种挫折感,本文将描述补丁如何进入内核。下面是一个介绍,它以某种
-理想化的方式描述了这个过程。更详细的过程将在后面的章节中介绍。
+为了减少这种挫败,本文将描述补丁如何进入内核。下面的介绍以一种较为理想化的
+方式描述了这个过程。更详细的过程将在后面的章节中介绍。
-补丁程序经历的阶段通常是:
+补丁通常要经历以下阶段:
-- 设计。这就是补丁的真正需求——以及满足这些需求的方式——的所在。设计工作通常
+- 设计。这就是补丁的真正需求——以及满足这些需求的方式——所在。设计工作通常
是在不涉及社区的情况下完成的,但是如果可能的话,最好是在公开的情况下完成
这项工作;这样可以节省很多稍后再重新设计的时间。
@@ -134,53 +142,51 @@ Greg Kroah-Hartman组成。稳定团队将使用4.x.y编号方案不定期的发
- 更广泛的评审。当补丁接近准备好纳入主线时,它应该被相关的子系统维护人员
接受——尽管这种接受并不能保证补丁会一直延伸到主线。补丁将出现在维护人员的
- 子系统树中,并进入 -next 树(如下所述)。当流程工作时,此步骤将导致对补丁
- 进行更广泛的审查,并发现由于将此补丁与其他人所做的工作集成而导致的任何
+ 子系统树中,并进入 -next 树(如下所述)。当流程进行时,此步骤将会对补丁
+ 进行更广泛的审查,并发现由于将此补丁与其他人所做的工作合并而导致的任何
问题。
-- 请注意,大多数维护人员也有日常工作,因此合并补丁可能不是他们的最高优先级。
- 如果您的补丁程序得到了关于所需更改的反馈,那么您应该进行这些更改,或者为
- 不应该进行这些更改的原因辩护。如果您的补丁没有评审意见,但没有被其相应的
- 子系统或驱动程序维护者接受,那么您应该坚持不懈地将补丁更新到当前内核,使
- 其干净地应用,并不断地将其发送以供审查和合并。
+- 请注意,大多数维护人员也有日常工作,因此合并补丁可能不是他们的最优先工作。
+ 如果您的补丁得到了需要更改的反馈,那么您应该进行这些更改,或者解释为何
+ 不应该进行这些更改。如果您的补丁没有评审意见,也没有被其相应的子系统或
+ 驱动程序维护者接受,那么您应该坚持不懈地将补丁更新到当前内核使其可被正常
+ 应用,并不断地发送它以供审查和合并。
- 合并到主线。最终,一个成功的补丁将被合并到由LinusTorvalds管理的主线存储库
- 中。此时可能会出现更多的评论和/或问题;开发人员应对这些问题并解决出现的
- 任何问题很重要。
+ 中。此时可能会出现更多的评论和/或问题;对开发人员来说应对这些问题并解决
+ 出现的任何问题仍很重要。
-- 稳定版发布。可能受补丁影响的用户数量现在很大,因此可能再次出现新的问题。
+- 稳定版发布。大量用户可能受此补丁影响,因此可能再次出现新的问题。
- 长期维护。虽然开发人员在合并代码后可能会忘记代码,但这种行为往往会给开发
- 社区留下不良印象。合并代码消除了一些维护负担,因为其他代码将修复由API
- 更改引起的问题。但是,如果代码要长期保持有用,原始开发人员应该继续为
- 代码负责。
+ 社区留下不良印象。合并代码消除了一些维护负担,因为其他人将修复由API更改
+ 引起的问题。但是,如果代码要长期保持可用,原始开发人员应该继续为代码负责。
-内核开发人员(或他们的雇主)犯的最大错误之一是试图将流程简化为一个
-“合并到主线”步骤。这种方法总是会让所有相关人员感到沮丧。
+内核开发人员(或他们的雇主)犯的最大错误之一是试图将流程简化为一个“合并到
+主线”步骤。这种方法总是会让所有相关人员感到沮丧。
补丁如何进入内核
----------------
-只有一个人可以将补丁合并到主线内核存储库中:LinusTorvalds。但是,在进入
+只有一个人可以将补丁合并到主线内核存储库中:Linus Torvalds。但是,在进入
2.6.38内核的9500多个补丁中,只有112个(大约1.3%)是由Linus自己直接选择的。
-内核项目已经发展到一个规模,没有一个开发人员可以在没有支持的情况下检查和
-选择每个补丁。内核开发人员处理这种增长的方式是通过使用围绕信任链构建的
-助理系统。
+内核项目已经发展到一个没有一个开发人员可以在没有支持的情况下检查和选择每个
+补丁的规模。内核开发人员处理这种增长的方式是使用围绕信任链构建的助理系统。
-内核代码库在逻辑上被分解为一组子系统:网络、特定的体系结构支持、内存管理、
-视频设备等。大多数子系统都有一个指定的维护人员,开发人员对该子系统中的代码
-负有全部责任。这些子系统维护者(松散地)是他们所管理的内核部分的守护者;
-他们(通常)会接受一个补丁以包含到主线内核中。
+内核代码库在逻辑上被分解为一组子系统:网络、特定体系结构支持、内存管理、视
+频设备等。大多数子系统都有一个指定的维护人员,其总体负责该子系统中的代码。
+这些子系统维护者(松散地)是他们所管理的内核部分的“守门员”;他们(通常)
+会接受一个补丁以包含到主线内核中。
-子系统维护人员每个人都使用git源代码管理工具管理自己版本的内核源代码树。Git
-等工具(以及Quilt或Mercurial等相关工具)允许维护人员跟踪补丁列表,包括作者
+子系统维护人员每个人都管理着自己版本的内核源代码树,通常(并非总是)使用Git。
+Git等工具(以及Quilt或Mercurial等相关工具)允许维护人员跟踪补丁列表,包括作者
信息和其他元数据。在任何给定的时间,维护人员都可以确定他或她的存储库中的哪
些补丁在主线中找不到。
-当合并窗口打开时,顶级维护人员将要求Linus从其存储库中“拉出”他们为合并选择
+当合并窗口打开时,顶级维护人员将要求Linus从存储库中“拉出”他们为合并选择
的补丁。如果Linus同意,补丁流将流向他的存储库,成为主线内核的一部分。
-Linus对拉操作中接收到的特定补丁的关注程度各不相同。很明显,有时他看起来很
-关注。但是,作为一般规则,Linus相信子系统维护人员不会向上游发送坏补丁。
+Linus对拉取中接收到的特定补丁的关注程度各不相同。很明显,有时他看起来很
+关注。但是一般来说,Linus相信子系统维护人员不会向上游发送坏补丁。
子系统维护人员反过来也可以从其他维护人员那里获取补丁。例如,网络树是由首先
在专用于网络设备驱动程序、无线网络等的树中积累的补丁构建的。此存储链可以
@@ -195,32 +201,32 @@ Next 树
子系统树链引导补丁流到内核,但它也提出了一个有趣的问题:如果有人想查看为
下一个合并窗口准备的所有补丁怎么办?开发人员将感兴趣的是,还有什么其他的
-更改有待解决,以查看是否存在需要担心的冲突;例如,更改核心内核函数原型的
+更改有待解决,以了解是否存在需要担心的冲突;例如,更改核心内核函数原型的
修补程序将与使用该函数旧形式的任何其他修补程序冲突。审查人员和测试人员希望
-在所有这些变更到达主线内核之前,能够访问它们的集成形式中的变更。您可以从所有
-有趣的子系统树中提取更改,但这将是一项大型且容易出错的工作。
+在所有这些变更到达主线内核之前,能够访问它们的集成形式的变更。您可以从所有
+相关的子系统树中提取更改,但这将是一项复杂且容易出错的工作。
-答案以-next树的形式出现,在这里子系统树被收集以供测试和审查。Andrew Morton
-维护的这些旧树被称为“-mm”(用于内存管理,这就是它的启动名字)。-mm 树集成了
-一长串子系统树中的补丁;它还包含一些旨在帮助调试的补丁。
+解决方案以-next树的形式出现,在这里子系统树被收集以供测试和审查。这些树中
+由Andrew Morton维护的较老的一个,被称为“-mm”(用于内存管理,创建时为此)。
+-mm 树集成了一长串子系统树中的补丁;它还包含一些旨在帮助调试的补丁。
除此之外,-mm 还包含大量由Andrew直接选择的补丁。这些补丁可能已经发布在邮件
-列表上,或者它们可能应用于内核中没有指定子系统树的部分。结果,-mm 作为一种
-最后手段的子系统树运行;如果没有其他明显的路径可以让补丁进入主线,那么它很
-可能以-mm 结束。累积在-mm 中的各种补丁最终将被转发到适当的子系统树,或者直接
+列表上,或者它们可能应用于内核中未指定子系统树的部分。同时,-mm 作为最后
+手段的子系统树;如果没有其他明显的路径可以让补丁进入主线,那么它很可能最
+终选择-mm 树。累积在-mm 中的各种补丁最终将被转发到适当的子系统树,或者直接
发送到Linus。在典型的开发周期中,大约5-10%的补丁通过-mm 进入主线。
-当前-mm 补丁可在“mmotm”(-mm of the moment)目录中找到,地址:
+当前-mm 补丁可在“mmotm”(-mm of the moment)目录中找到:
- http://www.ozlabs.org/~akpm/mmotm/
+ https://www.ozlabs.org/~akpm/mmotm/
-然而,使用mmotm树可能是一种令人沮丧的体验;它甚至可能无法编译。
+然而,使用MMOTM树可能会十分令人头疼;它甚至可能无法编译。
下一个周期补丁合并的主要树是linux-next,由Stephen Rothwell 维护。根据设计
linux-next 是下一个合并窗口关闭后主线的快照。linux-next树在Linux-kernel 和
Linux-next 邮件列表中发布,可从以下位置下载:
- http://www.kernel.org/pub/linux/kernel/next/
+ https://www.kernel.org/pub/linux/kernel/next/
Linux-next 已经成为内核开发过程中不可或缺的一部分;在一个给定的合并窗口中合并
的所有补丁都应该在合并窗口打开之前的一段时间内找到进入Linux-next 的方法。
@@ -228,51 +234,50 @@ Linux-next 已经成为内核开发过程中不可或缺的一部分;在一个
Staging 树
----------
-内核源代码树包含drivers/staging/directory,其中有许多驱动程序或文件系统的
-子目录正在被添加到内核树中。它们然需要更多的工作的时候可以保留在
-driver/staging目录中;一旦完成,就可以将它们移到内核中。这是一种跟踪不符合
-Linux内核编码或质量标准的驱动程序的方法,但人们可能希望使用它们并跟踪开发。
+内核源代码树包含drivers/staging/目录,其中有许多驱动程序或文件系统的子目录
+正在被添加到内核树中。它们在仍然需要更多的修正的时候可以保留在driver/staging/
+目录中;一旦完成,就可以将它们移到内核中。这是一种跟踪不符合Linux内核编码或
+质量标准的驱动程序的方法,人们可能希望使用它们并跟踪开发。
-Greg Kroah Hartman 目前负责维护staging 树。仍需要工作的驱动程序将发送给他,
+Greg Kroah Hartman 目前负责维护staging 树。仍需要修正的驱动程序将发送给他,
每个驱动程序在drivers/staging/中都有自己的子目录。除了驱动程序源文件之外,
-目录中还应该有一个TODO文件。todo文件列出了驱动程序需要接受的挂起的工作,
+目录中还应该有一个TODO文件。TODO文件列出了驱动程序需要接受的暂停的工作,
以及驱动程序的任何补丁都应该抄送的人员列表。当前的规则要求,staging的驱动
程序必须至少正确编译。
-Staging 是一种相对容易的方法,可以让新的驱动程序进入主线,幸运的是,他们会
-引起其他开发人员的注意,并迅速改进。然而,进入staging并不是故事的结尾;
-staging中没有看到常规进展的代码最终将被删除。经销商也倾向于相对不愿意使用
-staging驱动程序。因此,在成为一名合适的主线驱动的路上,staging 充其量只是
-一个停留。
+Staging 是一种让新的驱动程序进入主线的相对容易的方法,它们会幸运地引起其他
+开发人员的注意,并迅速改进。然而,进入staging并不是故事的结尾;staging中
+没有看到常规进展的代码最终将被删除。经销商也倾向于相对不愿意使用staging驱动
+程序。因此,在成为一个合适的主线驱动的路上,staging 仅是一个中转站。
工具
----
从上面的文本可以看出,内核开发过程在很大程度上依赖于在不同方向上聚集补丁的
能力。如果没有适当强大的工具,整个系统将无法在任何地方正常工作。关于如何使用
-这些工具的教程远远超出了本文档的范围,但是还是有一些指南的空间。
+这些工具的教程远远超出了本文档的范围,但还是用一点篇幅介绍一些关键点。
到目前为止,内核社区使用的主要源代码管理系统是git。Git是在自由软件社区中开发
的许多分布式版本控制系统之一。它非常适合内核开发,因为它在处理大型存储库和
-大量补丁时性能非常好。它还有一个难以学习和使用的名声,尽管随着时间的推移它
-变得更好了。对于内核开发人员来说,对Git的某种熟悉几乎是一种要求;即使他们不
-将它用于自己的工作,他们也需要Git来跟上其他开发人员(以及主线)正在做的事情。
+大量补丁时性能非常好。它也以难以学习和使用而著称,尽管随着时间的推移它变得
+更好了。对于内核开发人员来说,对Git的某种熟悉几乎是一种要求;即使他们不将它
+用于自己的工作,他们也需要Git来跟上其他开发人员(以及主线)正在做的事情。
-现在几乎所有的Linux发行版都打包了Git。主页位于:
+现在几乎所有的Linux发行版都打包了Git。Git主页位于:
- http://git-scm.com/
+ https://git-scm.com/
-那个页面有指向文档和教程的指针。
+此页面包含了文档和教程的链接。
-在不使用git的内核开发人员中,最流行的选择几乎肯定是mercurial:
+在不使用git的内核开发人员中,最流行的选择几乎肯定是Mercurial:
http://www.seleric.com/mercurial/
Mercurial与Git共享许多特性,但它提供了一个界面,许多人觉得它更易于使用。
-另一个值得了解的工具是quilt:
+另一个值得了解的工具是Quilt:
- http://savannah.nongnu.org/projects/quilt
+ https://savannah.nongnu.org/projects/quilt
Quilt 是一个补丁管理系统,而不是源代码管理系统。它不会随着时间的推移跟踪历史;
相反,它面向根据不断发展的代码库跟踪一组特定的更改。一些主要的子系统维护人员
@@ -282,79 +287,79 @@ Quilt 是一个补丁管理系统,而不是源代码管理系统。它不会
邮件列表
--------
-大量的Linux内核开发工作是通过邮件列表完成的。如果不在某个地方加入至少一个列表,
-就很难成为社区中一个功能完备的成员。但是,Linux邮件列表对开发人员来说也是一个
-潜在的危险,他们可能会被一堆电子邮件淹没,违反Linux列表上使用的约定,或者
-两者兼而有之。
+大量的Linux内核开发工作是通过邮件列表完成的。如果不加入至少一个某个列表,
+就很难成为社区中的一个“全功能”成员。但是,Linux邮件列表对开发人员来说也是
+一个潜在的危险,他们可能会被一堆电子邮件淹没、违反Linux列表上使用的约定,
+或者两者兼而有之。
大多数内核邮件列表都在vger.kernel.org上运行;主列表位于:
http://vger.kernel.org/vger-lists.html
-不过,也有一些列表托管在别处;其中一些列表位于lists.redhat.com。
+不过,也有一些列表托管在别处;其中一些列表位于
+redhat.com/mailman/listinfo。
-当然,内核开发的核心邮件列表是linux-kernel。这个名单是一个令人生畏的地方;
-每天的信息量可以达到500条,噪音很高,谈话技术性很强,参与者并不总是表现出
+当然,内核开发的核心邮件列表是linux-kernel。这个列表是一个令人生畏的地方:
+每天的信息量可以达到500条,噪音很高,谈话技术性很强,且参与者并不总是表现出
高度的礼貌。但是,没有其他地方可以让内核开发社区作为一个整体聚集在一起;
-避免使用此列表的开发人员将错过重要信息。
+不使用此列表的开发人员将错过重要信息。
-有一些提示可以帮助在linux-kernel生存:
+以下一些提示可以帮助在linux-kernel生存:
-- 将邮件转移到单独的文件夹,而不是主邮箱。我们必须能够持续地忽略洪流。
+- 将邮件转移到单独的文件夹,而不是主邮箱文件夹。我们必须能够持续地忽略洪流。
-- 不要试图跟踪每一次谈话-其他人都不会。重要的是要对感兴趣的主题(尽管请
- 注意,长时间的对话可以在不更改电子邮件主题行的情况下偏离原始主题)和参与
- 的人进行筛选。
+- 不要试图跟上每一次谈话——没人会这样。重要的是要筛选感兴趣的主题(但请注意
+ 长时间的对话可能会偏离原来的主题,尽管未改变电子邮件的主题)和参与的人。
-- 不要挑事。如果有人试图激起愤怒的反应,忽略他们。
+- 不要回复挑事的人。如果有人试图激起愤怒,请忽略他们。
-- 当响应Linux内核电子邮件(或其他列表上的电子邮件)时,请为所有相关人员保留
- cc:header。如果没有强有力的理由(如明确的请求),则不应删除收件人。一定要
- 确保你要回复的人在cc:list中。这个惯例也使你不必在回复邮件时明确要求被抄送。
+- 当回复Linux内核电子邮件(或其他列表上的电子邮件)时,请为所有相关人员保留
+ Cc: 抄送头。如果没有确实的理由(如明确的请求),则不应删除收件人。一定要
+ 确保你要回复的人在抄送列表中。这个惯例也使你不必在回复邮件时明确要求被抄送。
-- 在提出问题之前,搜索列表档案(和整个网络)。有些开发人员可能会对那些显然
+- 在提出问题之前,搜索列表存档(和整个网络)。有些开发人员可能会对那些显然
没有完成家庭作业的人感到不耐烦。
-- 避免贴顶帖(把你的答案放在你要回复的引文上面的做法)。这会让你的回答更难
+- 避免顶部回复(把你的答案放在你要回复的引文上面的做法)。这会让你的回答更难
理解,印象也很差。
-- 询问正确的邮件列表。linux-kernel 可能是通用的讨论点,但它不是从所有子系统
- 中寻找开发人员的最佳场所。
+- 在正确的邮件列表发问。linux-kernel 可能是通用的讨论场所,但它不是寻找所有
+ 子系统开发人员的最佳场所。
-最后一点——找到正确的邮件列表——是开发人员出错的常见地方。在Linux内核上提出与
-网络相关的问题的人几乎肯定会收到一个礼貌的建议,转而在netdev列表上提出,
-因为这是大多数网络开发人员经常出现的列表。还有其他列表可用于scsi、
-video4linux、ide、filesystem等子系统。查找邮件列表的最佳位置是与内核源代码
-一起打包的MAINTAINERS文件。
+最后一点——找到正确的邮件列表——是开发人员常出错的地方。在linux-kernel上
+提出与网络相关的问题的人几乎肯定会收到一个礼貌的建议,转到netdev列表上提出,
+因为这是大多数网络开发人员经常出现的列表。还有其他列表可用于scsi、video4linux、
+ide、filesystem等子系统。查找邮件列表的最佳位置是与内核源代码一起打包的
+MAINTAINERS文件。
开始内核开发
------------
-关于如何开始内核开发过程的问题很常见——来自个人和公司。同样常见的是错误,这
-使得关系的开始比必须的更困难。
+关于如何开始内核开发过程的问题很常见——个人和公司皆然。同样常见的是失误,这
+使得关系的开始比本应的更困难。
公司通常希望聘请知名的开发人员来启动开发团队。实际上,这是一种有效的技术。
-但它也往往是昂贵的,而且没有增长经验丰富的内核开发人员储备。考虑到时间的
-投入,可以让内部开发人员加快Linux内核的开发速度。花这个时间可以让雇主拥有
-一批了解内核和公司的开发人员,他们也可以帮助培训其他人。从中期来看,这往往
-是更有利可图的方法。
+但它也往往是昂贵的,而且对增加有经验的内核开发人员的数量没有多大帮助。考
+虑到时间投入,可以让内部开发人员加快Linux内核的开发速度。利用这段时间可以
+让雇主拥有一批既了解内核又了解公司的开发人员,还可以帮助培训其他人。从中期
+来看,这通常是更有利可图的方法。
可以理解的是,单个开发人员往往对起步感到茫然。从一个大型项目开始可能会很
-吓人;人们往往想先用一些较小的东西来测试水域。这是一些开发人员开始创建修补
-拼写错误或轻微编码风格问题的补丁的地方。不幸的是,这样的补丁会产生一定程度
-的噪音,这会分散整个开发社区的注意力,因此,越来越多的人看不起它们。希望向
-社区介绍自己的新开发人员将无法通过这些方式获得他们想要的那种接待。
+吓人;人们往往想先用一些较小的东西来试试水。由此,一些开发人员开始创建修补
+拼写错误或轻微编码风格问题的补丁。不幸的是,这样的补丁会产生一定程度的噪音,
+这会分散整个开发社区的注意力,因此,它们越来越被人不看重。希望向社区介绍
+自己的新开发人员将无法通过这些方式获得他们期待的反响。
-Andrew Morton 为有抱负的内核开发人员提供了这个建议
+Andrew Morton 为有抱负的内核开发人员提供了如下建议
::
- 所有内核初学者的No.1项目肯定是“确保内核在所有的机器上,你可以触摸
- 到的,始终运行良好" 通常这样做的方法是与其他人一起解决问题(这
- 可能需要坚持!)但这很好——这是内核开发的一部分
+ 所有内核开发者的第一个项目肯定应该是“确保内核在您可以操作的所有
+ 机器上始终完美运行”。通常的方法是和其他人一起解决问题(这可能需
+ 要坚持!),但就是如此——这是内核开发的一部分。
-(http://lwn.net/articles/283982/)
+(http://lwn.net/Articles/283982/)
-在没有明显问题需要解决的情况下,建议开发人员查看当前的回归和开放式错误列表.
-解决需要修复的问题没有任何缺点;通过解决这些问题,开发人员将获得处理过程的
-经验,同时与开发社区的其他人建立尊重。
+在没有明显问题需要解决的情况下,通常建议开发人员查看当前的回归和开放缺陷
+列表。从来都不缺少需要解决的问题;通过解决这些问题,开发人员将从该过程获得
+经验,同时与开发社区的其他成员建立相互尊重。
diff --git a/Documentation/translations/zh_CN/process/3.Early-stage.rst b/Documentation/translations/zh_CN/process/3.Early-stage.rst
index b8676aec6005..2caba4753b75 100644
--- a/Documentation/translations/zh_CN/process/3.Early-stage.rst
+++ b/Documentation/translations/zh_CN/process/3.Early-stage.rst
@@ -1,7 +1,14 @@
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/3.Early-stage.rst <development_early_stage>`
-:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+
+:Translator:
+
+ 时奎亮 Alex Shi <alex.shi@linux.alibaba.com>
+
+:校译:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
.. _cn_development_early_stage:
@@ -9,45 +16,45 @@
========
当考虑一个Linux内核开发项目时,很可能会直接跳进去开始编码。然而,与任何重要
-的项目一样,成功的许多基础最好是在第一行代码编写之前就做好了。在早期计划和
-沟通中花费一些时间可以节省更多的时间。
+的项目一样,许多成功的基础最好是在第一行代码编写之前就打下。在早期计划和
+沟通中花费一些时间可以在之后节省更多的时间。
-详述问题
+搞清问题
--------
-与任何工程项目一样,成功的内核增强从要解决的问题的清晰描述开始。在某些情况
-下,这个步骤很容易:例如,当某个特定硬件需要驱动程序时。不过,在其他方面,
-将实际问题与建议的解决方案混淆是很有诱惑力的,这可能会导致困难。
+与任何工程项目一样,成功的内核改善从清晰描述要解决的问题开始。在某些情况
+下,这个步骤很容易:例如当某个特定硬件需要驱动程序时。不过,在其他情况下,
+很容易将实际问题与建议的解决方案混在一起,这可能会导致麻烦。
-举个例子:几年前,使用Linux音频的开发人员寻求一种方法来运行应用程序,而不因
-系统延迟过大而导致退出或其他工件。他们得到的解决方案是一个内核模块,旨在连
-接到Linux安全模块(LSM)框架中;这个模块可以配置为允许特定的应用程序访问
-实时调度程序。这个模块被实现并发送到Linux内核邮件列表,在那里它立即遇到问题。
+举个例子:几年前,Linux音频的开发人员寻求一种方法来运行应用程序,而不会因
+系统延迟过大而导致退出或其他问题。他们得到的解决方案是一个连接到Linux安全
+模块(LSM)框架中的内核模块;这个模块可以配置为允许特定的应用程序访问实时
+调度程序。这个模块被实现并发到linux-kernel邮件列表,在那里它立即遇到了麻烦。
对于音频开发人员来说,这个安全模块足以解决他们当前的问题。但是,对于更广泛的
内核社区来说,这被视为对LSM框架的滥用(LSM框架并不打算授予他们原本不具备的
进程特权),并对系统稳定性造成风险。他们首选的解决方案包括短期的通过rlimit
机制进行实时调度访问,以及长期的减少延迟的工作。
-然而,音频社区看不到他们实施的特定解决方案的过去;他们不愿意接受替代方案。
+然而,音频社区无法超越他们实施的特定解决方案来看问题;他们不愿意接受替代方案。
由此产生的分歧使这些开发人员对整个内核开发过程感到失望;其中一个开发人员返回
-到音频列表并发布了以下内容:
+到audio列表并发布了以下内容:
- 有很多非常好的Linux内核开发人员,但他们往往会被一群傲慢的傻瓜所压倒。
- 试图向这些人传达用户需求是浪费时间。他们太“聪明”了,根本听不到少数人
- 的话。
+ 有很多非常好的Linux内核开发人员,但他们往往会被一群傲慢的傻瓜所压倒。
+ 试图向这些人传达用户需求是浪费时间。他们太“聪明”了,根本听不到少数
+ 人的话。
-(http://lwn.net/articles/131776/)
+(http://lwn.net/Articles/131776/)
-实际情况不同;与特定模块相比,内核开发人员更关心系统稳定性、长期维护以及找到
-正确的问题解决方案。这个故事的寓意是把重点放在问题上——而不是具体的解决方案
-上——并在投入创建代码之前与开发社区讨论这个问题。
+实际情况却是不同的;与特定模块相比,内核开发人员更关心系统稳定性、长期维护
+以及找到问题的正确解决方案。这个故事的寓意是把重点放在问题上——而不是具体的
+解决方案上——并在开始编写代码之前与开发社区讨论这个问题。
因此,在考虑一个内核开发项目时,我们应该得到一组简短问题的答案:
- - 究竟需要解决的问题是什么?
+ - 需要解决的问题究竟是什么?
- - 受此问题影响的用户是谁?解决方案应该解决哪些用例?
+ - 受此问题影响的用户有哪些?解决方案应该解决哪些使用案例?
- 内核现在为何没能解决这个问题?
@@ -62,100 +69,100 @@
- 很可能问题是由内核以您不理解的方式解决的。Linux内核很大,具有许多不明显
的特性和功能。并不是所有的内核功能都像人们所希望的那样有文档记录,而且很
- 容易遗漏一些东西。你的作者发出了一个完整的驱动程序,复制了一个新作者不
- 知道的现有驱动程序。重新设计现有轮子的代码不仅浪费,而且不会被接受到主线
+ 容易遗漏一些东西。某作者发布了一个完整的驱动程序,重复了一个其不
+ 知道的现有驱动程序。重新发明现有轮子的代码不仅浪费,而且不会被接受到主线
内核中。
- - 建议的解决方案中可能有一些元素不适用于主线合并。在编写代码之前,最好先
- 了解这样的问题。
+ - 建议的解决方案中可能有一些要素不适合并入主线。在编写代码之前,最好先了解
+ 这样的问题。
- 其他开发人员完全有可能考虑过这个问题;他们可能有更好的解决方案的想法,并且
可能愿意帮助创建这个解决方案。
在内核开发社区的多年经验给了我们一个明确的教训:闭门设计和开发的内核代码总是
有一些问题,这些问题只有在代码发布到社区中时才会被发现。有时这些问题很严重,
-需要数月或数年的努力才能使代码达到内核社区的标准。一些例子包括:
+需要数月或数年的努力才能使代码达到内核社区的标准。例如:
- 设计并实现了单处理器系统的DeviceScape网络栈。只有使其适合于多处理器系统,
- 才能将其合并到主线中。在代码中改装锁等等是一项困难的任务;因此,这段代码
+ 才能将其合并到主线中。在代码中修改锁等等是一项困难的任务;因此,这段代码
(现在称为mac80211)的合并被推迟了一年多。
- Reiser4文件系统包含许多功能,核心内核开发人员认为这些功能应该在虚拟文件
系统层中实现。它还包括一些特性,这些特性在不将系统暴露于用户引起的死锁的
- 情况下是不容易实现的。这些问题的最新发现——以及对其中一些问题的拒绝——已经
- 导致Reiser4远离了主线内核。
+ 情况下是不容易实现的。这些问题过迟发现——以及拒绝处理其中一些问题——已经
+ 导致Reiser4置身主线内核之外。
- Apparmor安全模块以被认为不安全和不可靠的方式使用内部虚拟文件系统数据结构。
- 这种担心(包括其他)使Apparmor多年不在主线上。
+ 这种担心(包括其他)使Apparmor多年来无法进入主线。
-在每一种情况下,通过与内核开发人员的早期讨论,可以避免大量的痛苦和额外的工作。
+在这些情况下,与内核开发人员的早期讨论,可以避免大量的痛苦和额外的工作。
-找谁交流
---------
+找谁交流?
+----------
当开发人员决定公开他们的计划时,下一个问题是:我们从哪里开始?答案是找到正确
的邮件列表和正确的维护者。对于邮件列表,最好的方法是在维护者(MAINTAINERS)文件
-中查找要发布的相关位置。如果有一个合适的子系统列表,那么发布它通常比在Linux
-内核上发布更可取;您更有可能接触到在相关子系统中具有专业知识的开发人员,并且
-环境可能具支持性。
+中查找要发布的相关位置。如果有一个合适的子系统列表,那么其上发布通常比在
+linux-kernel上发布更可取;您更有可能接触到在相关子系统中具有专业知识的开发
+人员,并且环境可能具支持性。
-找到维护人员可能会有点困难。同样,维护者文件是开始的地方。但是,该文件往往不总
-是最新的,并且并非所有子系统都在那里表示。实际上,维护者文件中列出的人员可能
+找到维护人员可能会有点困难。同样,维护者文件是开始的地方。但是,该文件往往不
+是最新的,并且并非所有子系统都在那里显示。实际上,维护者文件中列出的人员可能
不是当前实际担任该角色的人员。因此,当对联系谁有疑问时,一个有用的技巧是使用
-git(尤其是“git-log”)查看感兴趣的子系统中当前活动的用户。看看谁在写补丁,
-如果有人的话,谁会在这些补丁上加上用线签名的。这些人将是帮助新开发项目的最佳
-人选。
+git(尤其是“git-log”)查看感兴趣的子系统中当前活动的用户。看看谁在写补丁、
+谁会在这些补丁上加上Signed-off-by行签名(如有)。这些人将是帮助新开发项目的
+最佳人选。
-找到合适的维护者的任务有时是非常具有挑战性的,以至于内核开发人员添加了一个
-脚本来简化过程:
+找到合适的维护者有时是非常具有挑战性的,以至于内核开发人员添加了一个脚本来
+简化这个过程:
::
.../scripts/get_maintainer.pl
-当给定“-f”选项时,此脚本将返回给定文件或目录的当前维护者。如果在命令行上传递
-了一个补丁,它将列出可能接收补丁副本的维护人员。有许多选项可以调节
-get_maintainer.pl搜索维护者的难易程度;请小心使用更具攻击性的选项,因为最终
+当给定“-f”选项时,此脚本将返回指定文件或目录的当前维护者。如果在命令行上
+给出了一个补丁,它将列出可能接收补丁副本的维护人员。有许多选项可以调节
+get_maintainer.pl搜索维护者的严格程度;请小心使用更激进的选项,因为最终结果
可能会包括对您正在修改的代码没有真正兴趣的开发人员。
-如果所有其他方法都失败了,那么与Andrew Morton交谈可以成为一种有效的方法来跟踪
-特定代码段的维护人员。
+如果所有其他方法都失败了,那么与Andrew Morton交流是跟踪特定代码段维护人员
+的一种有效方法。
何时邮寄?
----------
-如果可能的话,在早期阶段发布你的计划只会有帮助。描述正在解决的问题以及已经
+如果可能的话,在早期阶段发布你的计划只会更有帮助。描述正在解决的问题以及已经
制定的关于如何实施的任何计划。您可以提供的任何信息都可以帮助开发社区为项目
提供有用的输入。
-在这个阶段可能发生的一件令人沮丧的事情不是敌对的反应,而是很少或根本没有
-反应。可悲的事实是:(1)内核开发人员往往很忙;(2)不缺少有宏伟计划和很少
-代码(甚至代码前景)支持他们的人;(3)没有人有义务审查或评论别人发表的
-想法。除此之外,高级设计常常隐藏一些问题,这些问题只有在有人真正尝试实现
-这些设计时才会被发现;因此,内核开发人员宁愿看到代码。
+在这个阶段可能发生的一件令人沮丧的事情不是得到反对意见,而是很少或根本没有
+反馈。令人伤心的事实是:(1)内核开发人员往往很忙;(2)不缺少有宏伟计划但
+代码(甚至代码设想)很少的人去支持他们;(3)没有人有义务审查或评论别人发表
+的想法。除此之外,高层级的设计常常隐藏着一些问题,这些问题只有在有人真正尝试
+实现这些设计时才会被发现;因此,内核开发人员宁愿看到代码。
-如果发表评论的请求在评论的方式上没有什么效果,不要假设这意味着对项目没有
-兴趣。不幸的是,你也不能假设你的想法没有问题。在这种情况下,最好的做法是
-继续进行,把你的进展随时通知社区。
+如果发布请求评论(RFC)并没得到什么有用的评论,不要以为这意味着无人对此项目
+有兴趣,同时你也不能假设你的想法没有问题。在这种情况下,最好的做法是继续进
+行,把你的进展随时通知社区。
获得官方认可
-----------------------
-如果您的工作是在公司环境中完成的,就像大多数Linux内核工作一样,显然,在您将
-公司的计划或代码发布到公共邮件列表之前,必须获得适当授权的经理的许可。发布
-不确定是否兼容GPL的代码可能是有特别问题的;公司的管理层和法律人员越早能够就
-发布内核开发项目达成一致,对参与的每个人都越好。
+如果您的工作是在公司环境中完成的,就像大多数Linux内核工作一样;显然,在您将
+公司的计划或代码发布到公共邮件列表之前,必须获得有适当权利经理的许可。发布
+不确定是否兼容GPL的代码尤其会带来问题;公司的管理层和法律人员越早能够就发布
+内核开发项目达成一致,对参与的每个人都越好。
一些读者可能会认为他们的核心工作是为了支持还没有正式承认存在的产品。将雇主
的计划公布在公共邮件列表上可能不是一个可行的选择。在这种情况下,有必要考虑
保密是否真的是必要的;通常不需要把开发计划关在门内。
-也就是说,有些情况下,一家公司在开发过程的早期就不能合法地披露其计划。拥有
-经验丰富的内核开发人员的公司可以选择以开环的方式进行,前提是他们以后能够避免
+的确,有些情况下一家公司在开发过程的早期无法合法地披露其计划。拥有经验丰富
+的内核开发人员的公司可能选择以开环的方式进行开发,前提是他们以后能够避免
严重的集成问题。对于没有这种内部专业知识的公司,最好的选择往往是聘请外部
-开发商根据保密协议审查计划。Linux基金会运行了一个NDA程序,旨在帮助解决这种
-情况;
+开发者根据保密协议审查计划。Linux基金会运行了一个NDA程序,旨在帮助解决这种
+情况;更多信息参见:
- http://www.linuxfoundation.org/en/NDA_program
+ http://www.linuxfoundation.org/nda/
这种审查通常足以避免以后出现严重问题,而无需公开披露项目。
diff --git a/Documentation/translations/zh_CN/process/4.Coding.rst b/Documentation/translations/zh_CN/process/4.Coding.rst
index b82b1dde3122..7cac9424f5d5 100644
--- a/Documentation/translations/zh_CN/process/4.Coding.rst
+++ b/Documentation/translations/zh_CN/process/4.Coding.rst
@@ -1,155 +1,160 @@
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/4.Coding.rst <development_coding>`
-:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+
+:Translator:
+
+ 时奎亮 Alex Shi <alex.shi@linux.alibaba.com>
+
+:校译:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
.. _cn_development_coding:
使代码正确
======================
-虽然对于一个坚实的、面向社区的设计过程有很多话要说,但是任何内核开发项目的
-证明都在生成的代码中。它是将由其他开发人员检查并合并(或不合并)到主线树中
+虽然一个坚实的、面向社区的设计过程有很多值得说道的,但是任何内核开发项目工作
+的证明都反映在代码中。它是将由其他开发人员检查并合并(或不合并)到主线树中
的代码。所以这段代码的质量决定了项目的最终成功。
-本节将检查编码过程。我们将从内核开发人员出错的几种方式开始。然后重点将转移
-到正确的事情和可以帮助这个任务的工具上。
+本节将检查编码过程。我们将从内核开发人员常犯的几种错误开始。然后重点将转移
+到正确的做法和相关有用的工具上。
陷阱
----
-编码风格
+代码风格
********
-内核长期以来都有一种标准的编码风格,如
+内核长期以来都有其标准的代码风格,如
:ref:`Documentation/translations/zh_CN/process/coding-style.rst <cn_codingstyle>`
-中所述。在大部分时间里,该文件中描述的政策被认为至多是建议性的。因此,内核
-中存在大量不符合编码风格准则的代码。代码的存在会给内核开发人员带来两个独立
-的危害。
-
-首先,要相信内核编码标准并不重要,也不强制执行。事实上,如果没有按照标准对代
-码进行编码,那么向内核添加新代码是非常困难的;许多开发人员甚至会在审查代码之
-前要求对代码进行重新格式化。一个与内核一样大的代码库需要一些统一的代码,以使
-开发人员能够快速理解其中的任何部分。所以已经没有空间来存放奇怪的格式化代码了。
-
-偶尔,内核的编码风格会与雇主的强制风格发生冲突。在这种情况下,内核的风格必须
-在代码合并之前获胜。将代码放入内核意味着以多种方式放弃一定程度的控制权——包括
-控制代码的格式化方式。
-
-另一个陷阱是假定已经在内核中的代码迫切需要编码样式的修复。开发人员可能会开始
-生成重新格式化补丁,作为熟悉过程的一种方式,或者作为将其名称写入内核变更日志
-的一种方式,或者两者兼而有之。但是纯编码风格的修复被开发社区视为噪音;它们往
-往受到冷遇。因此,最好避免使用这种类型的补丁。由于其他原因,在处理一段代码的
-同时修复它的样式是很自然的,但是编码样式的更改不应该仅为了更改而进行。
-
-编码风格的文档也不应该被视为绝对的法律,这是永远不会被违反的。如果有一个很好
-的理由反对这种样式(例如,如果拆分为适合80列限制的行,那么它的可读性就会大大
-降低),那么就这样做。
-
-请注意,您还可以使用 ``clang-format`` 工具来帮助您处理这些规则,自动重新格式
-化部分代码,并查看完整的文件,以发现编码样式错误、拼写错误和可能的改进。它还
-可以方便地进行排序,包括对齐变量/宏、回流文本和其他类似任务。有关详细信息,请
-参阅文件 :ref:`Documentation/process/clang-format.rst <clangformat>`
+中所述。在多数时候,该文档中描述的准则至多被认为是建议性的。因此,内核中存在
+大量不符合代码风格准则的代码。这种代码的存在会给内核开发人员带来两方面的危害。
+
+首先,相信内核代码标准并不重要,也不强制执行。但事实上,如果没有按照标准
+编写代码,那么新代码将很难加入到内核中;许多开发人员甚至会在审查代码之前要求
+对代码进行重新格式化。一个像内核这么大的代码库需要一些统一格式的代码,以使
+开发人员能够快速理解其中的任何部分。所以再也经不起奇怪格式的代码的折腾了。
+
+内核的代码风格偶尔会与雇主的强制风格发生冲突。在这种情况下,必须在代码合并
+之前遵从内核代码风格。将代码放入内核意味着以多种方式放弃一定程度的控制权——
+包括控制代码样式。
+
+另一个危害是认为已经在内核中的代码迫切需要修复代码样式。开发者可能会开始编写
+重新格式化补丁,作为熟悉开发过程的一种方式,或者作为将其名字写入内核变更日志
+的一种方式,或者两者兼而有之。但是纯代码风格的修复被开发社区视为噪音,它们往
+往受到冷遇。因此,最好避免编写这种类型的补丁。在由于其他原因处理一段代码的
+同时顺带修复其样式是很自然的,但是不应该仅为了更改代码样式而更改之。
+
+代码风格文档也不应该被视为绝对不可违反的规则。如果有一个足够的理由反对这种
+样式(例如为了80列限制拆分行会导致可读性大大降低),那么就这样做吧。
+
+注意您还可以使用 ``clang-format`` 工具来帮助您处理这些规则,快速自动重新格式
+化部分代码,和审阅完整的文件以发现代码样式错误、拼写错误和可能的改进。它还
+可以方便地排序 ``#includes`` 、对齐变量/宏、重排文本和其他类似任务。有关详细
+信息,请参阅文档 :ref:`Documentation/process/clang-format.rst <clangformat>`
抽象层
******
计算机科学教授教学生以灵活性和信息隐藏的名义广泛使用抽象层。当然,内核广泛
-地使用了抽象;任何涉及数百万行代码的项目都不能做到这一点并存活下来。但经验
-表明,过度或过早的抽象可能和过早的优化一样有害。抽象应用于所需的级别,
+地使用了抽象;任何涉及数百万行代码的项目都必须做到这一点以存续下来。但经验
+表明,过度或过早的抽象可能和过早的优化一样有害。抽象应用在适当层级,
不要过度。
-在一个简单的级别上,考虑一个函数的参数,该参数总是由所有调用方作为零传递。
-我们可以保留这个论点: 以防有人最终需要使用它提供的额外灵活性。不过,到那时,
-实现这个额外参数的代码很有可能以某种从未被注意到的微妙方式被破坏——因为它从
-未被使用过。或者,当需要额外的灵活性时,它不会以符合程序员早期期望的方式来
-这样做。内核开发人员通常会提交补丁来删除未使用的参数;一般来说,首先不应该
-添加这些参数。
+简单点,先考虑一个调用时始终只有一个参数且总为零的函数。我们可以保留这个参数,
+以在需要使用它时提供的额外灵活性。不过,在那时实现了这个额外参数的代码很有
+可能以某种从未被注意到的微妙方式被破坏——因为它从未被使用过。或者当需要额外
+的灵活性时,它并未以符合程序员当初期望的方式来实现。内核开发人员通常会提交
+补丁来删除未使用的参数;一般来说,一开始就不应该添加这些参数。
-隐藏硬件访问的抽象层——通常允许大量的驱动程序在多个操作系统中使用——尤其不受
+隐藏硬件访问的抽象层——通常为了允许大量的驱动程序兼容多个操作系统——尤其不受
欢迎。这样的层使代码变得模糊,可能会造成性能损失;它们不属于Linux内核。
-另一方面,如果您发现自己从另一个内核子系统复制了大量的代码,那么现在是时候
-问一下,事实上,将这些代码中的一些提取到单独的库中,或者在更高的层次上实现
-这些功能是否有意义。在整个内核中复制相同的代码没有价值。
+另一方面,如果您发现自己从另一个内核子系统复制了大量的代码,那么是时候
+了解一下:是否需要将这些代码中的部分提取到单独的库中,或者在更高的层次上
+实现这些功能。在整个内核中复制相同的代码没有价值。
#ifdef 和预处理
***************
-C预处理器似乎给一些C程序员带来了强大的诱惑,他们认为它是一种有效地将大量灵
-活性编码到源文件中的方法。但是预处理器不是C,大量使用它会导致代码对其他人来
-说更难读取,对编译器来说更难检查正确性。大量的预处理器几乎总是代码需要一些
+C预处理器似乎给一些C程序员带来了强大的诱惑,他们认为它是一种将大量灵活性加入
+源代码中的方法。但是预处理器不是C,大量使用它会导致代码对其他人来说更难阅读,
+对编译器来说更难检查正确性。使用了大量预处理器几乎总是代码需要一些
清理工作的标志。
-使用ifdef的条件编译实际上是一个强大的功能,它在内核中使用。但是很少有人希望
-看到代码被大量地撒上ifdef块。作为一般规则,ifdef的使用应尽可能限制在头文件
-中。有条件编译的代码可以限制函数,如果代码不存在,这些函数就会变成空的。然后
-编译器将悄悄地优化对空函数的调用。结果是代码更加清晰,更容易理解。
+使用#ifdef的条件编译实际上是一个强大的功能,它在内核中使用。但是很少有人希望
+看到代码被铺满#ifdef块。一般规定,ifdef的使用应尽可能限制在头文件中。条件
+编译代码可以限制函数,如果代码不存在,这些函数就直接变成空的。然后编译器将
+悄悄地优化对空函数的调用。使得代码更加清晰,更容易理解。
-C预处理器宏存在许多危险,包括可能对具有副作用且没有类型安全性的表达式进行多
-重评估。如果您试图定义宏,请考虑创建一个内联函数。结果相同的代码,但是内联
-函数更容易读取,不会多次计算其参数,并且允许编译器对参数和返回值执行类型检查。
+C预处理器宏存在许多危险性,包括可能对具有副作用且没有类型安全的表达式进行多
+重评估。如果您试图定义宏,请考虑创建一个内联函数替代。结果相同的代码,内联
+函数更容易阅读,不会多次计算其参数,并且允许编译器对参数和返回值执行类型检查。
内联函数
********
不过,内联函数本身也存在风险。程序员可以倾心于避免函数调用和用内联函数填充源
文件所固有的效率。然而,这些功能实际上会降低性能。因为它们的代码在每个调用站
-点都被复制,所以它们最终会增加编译内核的大小。反过来,这会对处理器的内存缓存
-造成压力,从而大大降低执行速度。通常,内联函数应该非常小,而且相对较少。毕竟,
-函数调用的成本并不高;大量内联函数的创建是过早优化的典型例子。
+点都被复制一遍,所以最终会增加编译内核的大小。此外,这也对处理器的内存缓存
+造成压力,从而大大降低执行速度。通常内联函数应该非常小,而且相对较少。毕竟
+函数调用的成本并不高;大量创建内联函数是过早优化的典型例子。
-一般来说,内核程序员会忽略缓存效果,这会带来危险。在开始的数据结构课程中,经
-典的时间/空间权衡通常不适用于当代硬件。空间就是时间,因为一个大的程序比一个
+一般来说,内核程序员会自冒风险忽略缓存效果。在数据结构课程开头中的经典
+时间/空间权衡通常不适用于当代硬件。空间 *就是* 时间,因为一个大的程序比一个
更紧凑的程序运行得慢。
-最近的编译器在决定一个给定函数是否应该被内联方面扮演着越来越积极的角色。
-因此,“inline”关键字的自由放置可能不仅仅是过度的,它也可能是无关的。
+较新的编译器越来越激进地决定一个给定函数是否应该内联。因此,随意放置使用
+“inline”关键字可能不仅仅是过度的,也可能是无用的。
**
-2006年5月,“deviceescape”网络堆栈在GPL下发布,并被纳入主线内核。这是一个受
-欢迎的消息;对Linux中无线网络的支持充其量被认为是不合格的,而deviceescape
-堆栈提供了修复这种情况的承诺。然而,直到2007年6月(2.6.22),这段代码才真
+2006年5月,“deviceescape”网络堆栈在前呼后拥下以GPL发布,并被纳入主线内核。
+这是一个受欢迎的消息;Linux中对无线网络的支持充其量被认为是不合格的,而
+Deviceescape堆栈承诺修复这种情况。然而直到2007年6月(2.6.22),这段代码才真
正进入主线。发生了什么?
-这段代码显示了许多闭门造车的迹象。但一个特别大的问题是,它并不是设计用于多
-处理器系统。在合并这个网络堆栈(现在称为mac80211)之前,需要对其进行一个锁
-方案的改造。
+这段代码出现了许多闭门造车的迹象。但一个大麻烦是,它并不是为多处理器系统而
+设计。在合并这个网络堆栈(现在称为mac80211)之前,需要对其进行一个锁方案的
+改造。
曾经,Linux内核代码可以在不考虑多处理器系统所带来的并发性问题的情况下进行
-开发。然而,现在,这个文件是写在双核笔记本电脑上的。即使在单处理器系统上,
+开发。然而现在,这个文档就是在双核笔记本电脑上写的。即使在单处理器系统上,
为提高响应能力所做的工作也会提高内核内的并发性水平。编写内核代码而不考虑锁
-的日子已经过去很长了。
+的日子早已远去。
可以由多个线程并发访问的任何资源(数据结构、硬件寄存器等)必须由锁保护。新
-的代码应该记住这一要求;事后改装锁是一项相当困难的任务。内核开发人员应该花
-时间充分了解可用的锁原语,以便为作业选择正确的工具。显示对并发性缺乏关注的
-代码进入主线将很困难。
+的代码应该谨记这一要求;事后修改锁是一项相当困难的任务。内核开发人员应该花
+时间充分了解可用的锁原语,以便为工作选择正确的工具。对并发性缺乏关注的代码
+很难进入主线。
回归
****
-最后一个值得一提的危险是:它可能会引起改变(这可能会带来很大的改进),从而
-导致现有用户的某些东西中断。这种变化被称为“回归”,回归已经成为主线内核最不
-受欢迎的。除少数例外情况外,如果回归不能及时修正,会导致回归的变化将被取消。
-最好首先避免回归。
+最后一个值得一提的危险是回归:它可能会引起导致现有用户的某些东西中断的改变
+(这也可能会带来很大的改进)。这种变化被称为“回归”,回归已经成为主线内核
+最不受欢迎的问题。除了少数例外情况,如果回归不能及时修正,会导致回归的修改
+将被取消。最好首先避免回归发生。
-人们常常争论,如果回归让更多人可以工作,远超过产生问题,那么回归是合理的。
-如果它破坏的一个系统却为十个系统带来新的功能,为什么不进行更改呢?2007年7月,
+人们常常争论,如果回归带来的功能远超过产生的问题,那么回归是否为可接受的。
+如果它破坏了一个系统却为十个系统带来新的功能,为何不改改态度呢?2007年7月,
Linus对这个问题给出了最佳答案:
::
- 所以我们不会通过引入新问题来修复错误。那样的谎言很疯狂,没有人知道
- 你是否真的有进展。是前进两步,后退一步,还是向前一步,向后两步?
-(http://lwn.net/articles/243460/)
+ 所以我们不会通过引入新问题来修复错误。这种方式是靠不住的,没人知道
+ 是否真的有进展。是前进两步、后退一步,还是前进一步、后退两步?
+
+(http://lwn.net/Articles/243460/)
-一种特别不受欢迎的回归类型是用户空间ABI的任何变化。一旦接口被导出到用户空间,
+特别不受欢迎的一种回归类型是用户空间ABI的任何变化。一旦接口被导出到用户空间,
就必须无限期地支持它。这一事实使得用户空间接口的创建特别具有挑战性:因为它们
-不能以不兼容的方式进行更改,所以必须第一次正确地进行更改。因此,用户空间界面
-总是需要大量的思考、清晰的文档和广泛的审查。
+不能以不兼容的方式进行更改,所以必须一次就对。因此,用户空间接口总是需要大量
+的思考、清晰的文档和广泛的审查。
代码检查工具
@@ -157,60 +162,58 @@ Linus对这个问题给出了最佳答案:
至少目前,编写无错误代码仍然是我们中很少人能达到的理想状态。不过,我们希望做
的是,在代码进入主线内核之前,尽可能多地捕获并修复这些错误。为此,内核开发人
-员已经组装了一系列令人印象深刻的工具,可以自动捕获各种各样的模糊问题。计算机
+员已经提供了一系列令人印象深刻的工具,可以自动捕获各种各样的隐藏问题。计算机
发现的任何问题都是一个以后不会困扰用户的问题,因此,只要有可能,就应该使用
自动化工具。
-第一步只是注意编译器产生的警告。当代版本的GCC可以检测(并警告)大量潜在错误。
-通常,这些警告都指向真正的问题。提交以供审阅的代码通常不会产生任何编译器警告。
-在消除警告时,注意了解真正的原因,并尽量避免“修复”,使警告消失而不解决其原因。
+第一步是注意编译器产生的警告。当前版本的GCC可以检测(并警告)大量潜在错误。
+通常,这些警告都指向真正的问题。提交以供审阅的代码一般不会产生任何编译器警告。
+在消除警告时,注意了解真正的原因,并尽量避免仅“修复”使警告消失而不解决其原因。
-请注意,并非所有编译器警告都默认启用。使用“make EXTRA_CFLAGS=-W”构建内核以
+请注意,并非所有编译器警告都默认启用。使用“make KCFLAGS=-W”构建内核以
获得完整集合。
内核提供了几个配置选项,可以打开调试功能;大多数配置选项位于“kernel hacking”
子菜单中。对于任何用于开发或测试目的的内核,都应该启用其中几个选项。特别是,
您应该打开:
- - 启用 ENABLE_MUST_CHECK and FRAME_WARN 以获得一组额外的警告,以解决使用不
- 推荐使用的接口或忽略函数的重要返回值等问题。这些警告生成的输出可能是冗长
- 的,但您不必担心来自内核其他部分的警告。
+ - FRAME_WARN 获取大于给定数量的堆栈帧的警告。
+ 这些警告生成的输出可能比较冗长,但您不必担心来自内核其他部分的警告。
- - DEBUG_OBJECTS 将添加代码,以跟踪内核创建的各种对象的生存期,并在出现问题时
- 发出警告。如果要添加创建(和导出)自己的复杂对象的子系统,请考虑添加对对象
- 调试基础结构的支持。
+ - DEBUG_OBJECTS 将添加代码以跟踪内核创建的各种对象的生命周期,并在出现问题
+ 时发出警告。如果你要添加创建(和导出)关于其自己的复杂对象的子系统,请
+ 考虑打开对象调试基础结构的支持。
- DEBUG_SLAB 可以发现各种内存分配和使用错误;它应该用于大多数开发内核。
- - DEBUG_SPINLOCK, DEBUG_ATOMIC_SLEEP and DEBUG_MUTEXES 会发现许多常见的
- 锁定错误.
+ - DEBUG_SPINLOCK, DEBUG_ATOMIC_SLEEP 和 DEBUG_MUTEXES 会发现许多常见的
+ 锁错误。
-还有很多其他调试选项,其中一些将在下面讨论。其中一些具有显著的性能影响,不应
-一直使用。但是,在学习可用选项上花费的一些时间可能会在短期内得到多次回报。
+还有很多其他调试选项,其中一些将在下面讨论。其中一些有显著的性能影响,不应
+一直使用。在学习可用选项上花费一些时间,可能会在短期内得到许多回报。
-其中一个较重的调试工具是锁定检查器或“lockdep”。该工具将跟踪系统中每个锁
+其中一个较重的调试工具是锁检查器或“lockdep”。该工具将跟踪系统中每个锁
(spinlock或mutex)的获取和释放、获取锁的相对顺序、当前中断环境等等。然后,
-它可以确保总是以相同的顺序获取锁,相同的中断假设适用于所有情况,等等。换句话
-说,lockdep可以找到许多场景,在这些场景中,系统很少会死锁。在部署的系统中,
-这种问题可能会很痛苦(对于开发人员和用户而言);LockDep允许提前以自动方式
-发现问题。具有任何类型的非普通锁定的代码在提交包含前应在启用lockdep的情况
-下运行。
+它可以确保总是以相同的顺序获取锁,相同的中断假设适用于所有情况等等。换句话
+说,lockdep可以找到许多导致系统死锁的场景。在部署的系统中,这种问题可能会
+很痛苦(对于开发人员和用户而言);LockDep允许提前以自动方式发现问题。具有
+任何类型的非普通锁的代码在提交合并前应在启用lockdep的情况下运行测试。
作为一个勤奋的内核程序员,毫无疑问,您将检查任何可能失败的操作(如内存分配)
-的返回状态。然而,事实上,最终的故障恢复路径可能完全没有经过测试。未测试的
-代码往往会被破坏;如果所有这些错误处理路径都被执行了几次,那么您可能对代码
+的返回状态。然而,事实上,最终的故障复现路径可能完全没有经过测试。未测试的
+代码往往会出问题;如果所有这些错误处理路径都被执行了几次,那么您可能对代码
更有信心。
内核提供了一个可以做到这一点的错误注入框架,特别是在涉及内存分配的情况下。
-启用故障注入后,内存分配的可配置百分比将失败;这些失败可以限制在特定的代码
+启用故障注入后,内存分配的可配置失败的百分比;这些失败可以限定在特定的代码
范围内。在启用了故障注入的情况下运行,程序员可以看到当情况恶化时代码如何响
应。有关如何使用此工具的详细信息,请参阅
Documentation/fault-injection/fault-injection.rst。
-使用“sparse”静态分析工具可以发现其他类型的错误。对于sparse,可以警告程序员
-用户空间和内核空间地址之间的混淆、big endian和small endian数量的混合、在需
-要一组位标志的地方传递整数值等等。sparse必须单独安装(如果您的分发服务器没
-有将其打包,可以在 https://sparse.wiki.kernel.org/index.php/Main_page)找到,
+“sparse”静态分析工具可以发现其他类型的错误。sparse可以警告程序员用户空间
+和内核空间地址之间的混淆、大端序与小端序的混淆、在需要一组位标志的地方传递
+整数值等等。sparse必须单独安装(如果您的分发服务器没有将其打包,
+可以在 https://sparse.wiki.kernel.org/index.php/Main_page 找到),
然后可以通过在make命令中添加“C=1”在代码上运行它。
“Coccinelle”工具 :ref:`http://coccinelle.lip6.fr/ <devtools_coccinelle>`
@@ -221,10 +224,10 @@ scripts/coccinelle目录下已经打包了相当多的内核“语义补丁”
其他类型的可移植性错误最好通过为其他体系结构编译代码来发现。如果没有S/390系统
-或Blackfin开发板,您仍然可以执行编译步骤。可以在以下位置找到一组用于x86系统的
-大型交叉编译器:
+或Blackfin开发板,您仍然可以执行编译步骤。可以在以下位置找到一大堆用于x86系统的
+交叉编译器:
- http://www.kernel.org/pub/tools/crosstool/
+ https://www.kernel.org/pub/tools/crosstool/
花一些时间安装和使用这些编译器将有助于避免以后的尴尬。
@@ -233,22 +236,22 @@ scripts/coccinelle目录下已经打包了相当多的内核“语义补丁”
文档通常比内核开发规则更为例外。即便如此,足够的文档将有助于简化将新代码合并
到内核中的过程,使其他开发人员的生活更轻松,并对您的用户有所帮助。在许多情况
-下,文件的添加已基本上成为强制性的。
+下,添加文档已基本上是强制性的。
任何补丁的第一个文档是其关联的变更日志。日志条目应该描述正在解决的问题、解决
方案的形式、处理补丁的人员、对性能的任何相关影响,以及理解补丁可能需要的任何
-其他内容。确保changelog说明了为什么补丁值得应用;大量开发人员未能提供这些信息。
+其他内容。确保变更日志说明了*为什么*补丁值得应用;大量开发者未能提供这些信息。
-任何添加新用户空间界面的代码(包括新的sysfs或/proc文件)都应该包含该界面的
-文档,该文档使用户空间开发人员能够知道他们在使用什么。请参阅
-Documentation/ABI/README,了解如何格式化此文档以及需要提供哪些信息。
+任何添加新用户空间接口的代码——包括新的sysfs或/proc文件——都应该包含该接口
+的文档,该文档使用户空间开发人员能够知道他们在使用什么。请参阅
+Documentation/ABI/README,了解如何此文档格式以及需要提供哪些信息。
-文件 :ref:`Documentation/admin-guide/kernel-parameters.rst <kernelparameters>`
-描述了内核的所有引导时间参数。任何添加新参数的补丁都应该向该文件添加适当的
+文档 :ref:`Documentation/admin-guide/kernel-parameters.rst <kernelparameters>`
+描述了内核的所有引导时间参数。任何添加新参数的补丁都应该向该文档添加适当的
条目。
-任何新的配置选项都必须附有帮助文本,帮助文本清楚地解释了这些选项以及用户可能
-希望何时选择它们。
+任何新的配置选项都必须附有帮助文本,帮助文本需清楚地解释这些选项以及用户可能
+希望何时使用它们。
许多子系统的内部API信息通过专门格式化的注释进行记录;这些注释可以通过
“kernel-doc”脚本以多种方式提取和格式化。如果您在具有kerneldoc注释的子系统中
@@ -257,31 +260,31 @@ Documentation/ABI/README,了解如何格式化此文档以及需要提供哪
来说是一个有用的活动。这些注释的格式以及如何创建kerneldoc模板的一些信息可以在
:ref:`Documentation/doc-guide/ <doc_guide>` 上找到。
-任何阅读大量现有内核代码的人都会注意到,注释的缺失往往是最值得注意的。再一次,
-对新代码的期望比过去更高;合并未注释的代码将更加困难。这就是说,人们几乎不希望
-用语言注释代码。代码本身应该是可读的,注释解释了更微妙的方面。
+任何阅读大量现有内核代码的人都会注意到,注释的缺失往往是最值得注意的。同时,
+对新代码的要求比过去更高;合并未注释的代码将更加困难。这就是说,人们并不期望
+详细注释的代码。代码本身应该是自解释的,注释阐释了更微妙的方面。
某些事情应该总是被注释。使用内存屏障时,应附上一行文字,解释为什么需要设置内存
-屏障。数据结构的锁定规则通常需要在某个地方解释。一般来说,主要数据结构需要全面
-的文档。应该指出单独代码位之间不明显的依赖性。任何可能诱使代码看门人进行错误的
-“清理”的事情都需要一个注释来说明为什么要这样做。等等。
+屏障。数据结构的锁规则通常需要在某个地方解释。一般来说,主要数据结构需要全面
+的文档。应该指出代码中分立的位之间不明显的依赖性。任何可能诱使代码管理人进行
+错误的“清理”的事情都需要一个注释来说明为什么要这样做。等等。
内部API更改
-----------
-内核提供给用户空间的二进制接口不能被破坏,除非在最严重的情况下。相反,内核的
-内部编程接口是高度流动的,当需要时可以更改。如果你发现自己不得不处理一个内核
-API,或者仅仅因为它不满足你的需求而不使用特定的功能,这可能是API需要改变的一
-个标志。作为内核开发人员,您有权进行此类更改。
+内核提供给用户空间的二进制接口不能被破坏,除非逼不得已。而内核的内部编程接口
+是高度流动的,当需要时可以更改。如果你发现自己不得不处理一个内核API,或者仅
+仅因为它不满足你的需求导致无法使用特定的功能,这可能是API需要改变的一个标志。
+作为内核开发人员,您有权进行此类更改。
-当然, 可以进行API更改,但它们必须是合理的。因此,任何进行内部API更改的补丁都
-应该附带一个关于更改内容和必要原因的描述。这种变化也应该分解成一个单独的补丁,
-而不是埋在一个更大的补丁中。
+的确可以进行API更改,但更改必须是合理的。因此任何进行内部API更改的补丁都应该
+附带关于更改内容和必要原因的描述。这种变化也应该拆分成一个单独的补丁,而不是
+埋在一个更大的补丁中。
另一个要点是,更改内部API的开发人员通常要负责修复内核树中被更改破坏的任何代码。
-对于一个广泛使用的函数,这个职责可以导致成百上千的变化,其中许多变化可能与其他
-开发人员正在做的工作相冲突。不用说,这可能是一项大工作,所以最好确保理由是
+对于一个广泛使用的函数,这个责任可以导致成百上千的变化,其中许多变化可能与其他
+开发人员正在做的工作相冲突。不用说,这可能是一项大工程,所以最好确保理由是
可靠的。请注意,coccinelle工具可以帮助进行广泛的API更改。
在进行不兼容的API更改时,应尽可能确保编译器捕获未更新的代码。这将帮助您确保找
diff --git a/Documentation/translations/zh_CN/process/5.Posting.rst b/Documentation/translations/zh_CN/process/5.Posting.rst
index 41aba21ff050..6a469e1c7deb 100644
--- a/Documentation/translations/zh_CN/process/5.Posting.rst
+++ b/Documentation/translations/zh_CN/process/5.Posting.rst
@@ -1,150 +1,156 @@
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/5.Posting.rst <development_posting>`
-:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+
+:Translator:
+
+ 时奎亮 Alex Shi <alex.shi@linux.alibaba.com>
+
+:校译:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
.. _cn_development_posting:
-发送补丁
+发布补丁
========
-迟早,当您的工作准备好提交给社区进行审查,并最终包含到主线内核中时。不出所料,
+您的工作迟早会准备好提交给社区进行审查,并最终包含到主线内核中。毫不稀奇,
内核开发社区已经发展出一套用于发布补丁的约定和过程;遵循这些约定和过程将使
-参与其中的每个人的生活更加轻松。本文件将试图合理详细地涵盖这些期望;更多信息
-也可在以下文件中找到
-:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`,
-:ref:`Documentation/process/submitting-drivers.rst <submittingdrivers>`
-和 :ref:`Documentation/translations/zh_CN/process/submit-checklist.rst <cn_submitchecklist>`.
+参与其中的每个人的生活更加轻松。本文档试图描述这些约定的部分细节;更多信息
+也可在以下文档中找到
+:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
+和 :ref:`Documentation/translations/zh_CN/process/submit-checklist.rst <cn_submitchecklist>`。
-何时邮寄
+何时寄送
--------
-在补丁完全“准备好”之前,有一个不断的诱惑来避免发布补丁。对于简单的补丁,
-这不是问题。但是,如果正在完成的工作很复杂,那么在工作完成之前从社区获得
-反馈就可以获得很多好处。因此,您应该考虑发布正在进行的工作,甚至使Git树
-可用,以便感兴趣的开发人员可以随时赶上您的工作。
+在补丁完全“准备好”之前,避免发布补丁是一种持续的诱惑。对于简单的补丁,这
+不是问题。但是如果正在完成的工作很复杂,那么在工作完成之前从社区获得反馈就
+可以获得很多好处。因此,您应该考虑发布正在进行的工作,甚至维护一个可用的Git
+树,以便感兴趣的开发人员可以随时赶上您的工作。
-当发布还没有准备好包含的代码时,最好在发布本身中这样说。还应提及任何有待完成
-的主要工作和任何已知问题。很少有人会看到那些被认为是半生不熟的补丁,但是那些
-人会想到他们可以帮助你把工作推向正确的方向。
+当发布中有尚未准备好被包含的代码,最好在发布中说明。还应提及任何有待完成的
+主要工作和任何已知问题。很少有人会愿意看那些被认为是半生不熟的补丁,但是
+那些愿意的人会带着他们的点子来一起帮助你把工作推向正确的方向。
创建补丁之前
------------
-在考虑将补丁发送到开发社区之前,有许多事情应该做。这些包括:
+在考虑将补丁发送到开发社区之前,有许多事情应该做。包括:
- - 尽可能地测试代码。利用内核的调试工具,确保内核使用所有合理的配置选项组合
- 进行构建,使用跨编译器为不同的体系结构进行构建等。
+ - 尽可能地测试代码。利用内核的调试工具,确保内核使用了所有可能的配置选项组合
+ 进行构建,使用交叉编译器为不同的体系结构进行构建等。
- - 确保您的代码符合内核编码风格指南。
+ - 确保您的代码符合内核代码风格指南。
- 您的更改是否具有性能影响?如果是这样,您应该运行基准测试来显示您的变更的
影响(或好处);结果的摘要应该包含在补丁中。
- 确保您有权发布代码。如果这项工作是为雇主完成的,雇主对这项工作具有所有权,
- 并且必须同意根据GPL对其进行放行。
+ 并且必须同意根据GPL对其进行发布。
一般来说,在发布代码之前进行一些额外的思考,几乎总是能在短时间内得到回报。
补丁准备
--------
-准备发布补丁可能是一个惊人的工作量,但再次尝试节省时间在这里通常是不明智的,
-即使在短期内。
+准备补丁发布的工作量可能很惊人,但在此尝试节省时间通常是不明智的,即使在短期
+内亦然。
-必须针对内核的特定版本准备补丁。作为一般规则,补丁程序应该基于Linus的Git树中
-的当前主线。当以主线为基础时,从一个众所周知的发布点开始——一个稳定的或RC的
-发布——而不是在一个主线分支任意点。
+必须针对内核的特定版本准备补丁。一般来说,补丁应该基于Linus的Git树中的当前
+主线。当以主线为基础时,请从一个众所周知的发布点开始——如稳定版本或 -rc
+版本发布点——而不是在一个任意的主线分支点。
-但是,可能需要针对-mm、linux-next或子系统树生成版本,以便于更广泛的测试和审查。
-根据补丁的区域以及其他地方的情况,针对这些其他树建立补丁可能需要大量的工作来
+也可能需要针对-mm、linux-next或子系统树生成版本,以便于更广泛的测试和审查。
+根据补丁的区域以及其他地方的情况,针对其他树建立的补丁可能需要大量的工作来
解决冲突和处理API更改。
只有最简单的更改才应格式化为单个补丁;其他所有更改都应作为一系列逻辑更改进行。
分割补丁是一门艺术;一些开发人员花了很长时间来弄清楚如何按照社区期望的方式来
-做。然而,有一些经验法则可以大大帮助:
+分割。不过,这些经验法则也许有帮助:
- - 您发布的补丁程序系列几乎肯定不会是工作系统中的一系列更改。相反,您所做的
- 更改需要在最终形式中加以考虑,然后以有意义的方式进行拆分。开发人员对离散的、
- 自包含的更改感兴趣,而不是您获取这些更改的路径。
+ - 您发布的补丁系列几乎肯定不会是开发过程中版本控制系统中的一系列更改。相反,
+ 需要对您所做更改的最终形式加以考虑,然后以有意义的方式进行拆分。开发人员对
+ 离散的、自包含的更改感兴趣,而不是您创造这些更改的原始路径。
- - 每个逻辑上独立的变更都应该格式化为单独的补丁。这些更改可以是小的(“向此
- 结构添加字段”)或大的(例如,添加一个重要的新驱动程序),但它们在概念上
- 应该是小的,并且可以接受一行描述。每个补丁都应该做一个特定的更改,可以单独
- 检查并验证它所做的事情。
+ - 每个逻辑上独立的变更都应该格式化为单独的补丁。这些更改可以是小的(如“向
+ 此结构体添加字段”)或大的(如添加一个重要的新驱动程序),但它们在概念上
+ 应该是小的,并且可以在一行内简述。每个补丁都应该做一个特定的、可以单独
+ 检查并验证它所做的事情的更改。
- - 作为重申上述准则的一种方法:不要在同一补丁中混合不同类型的更改。如果一个
- 补丁修复了一个关键的安全漏洞,重新排列了一些结构,并重新格式化了代码,那么
- 很有可能它会被忽略,而重要的修复将丢失。
+ - 换种方式重申上述准则,也就是说:不要在同一补丁中混合不同类型的更改。如果
+ 一个补丁修复了一个关键的安全漏洞,又重新排列了一些结构,还重新格式化了代
+ 码,那么它很有可能会被忽略,从而导致重要的修复丢失。
- - 每个补丁都应该产生一个内核,它可以正确地构建和运行;如果补丁系列在中间被
- 中断,那么结果应该仍然是一个工作的内核。补丁系列的部分应用是使用
- “git bisct”工具查找回归的一个常见场景;如果结果是一个损坏的内核,那么对于
- 那些从事追踪问题的高尚工作的开发人员和用户来说,将使他们的生活更加艰难。
+ - 每个补丁都应该能创建一个可以正确地构建和运行的内核;如果补丁系列在中间被
+ 断开,那么结果仍应是一个正常工作的内核。部分应用一系列补丁是使用
+ “git bisct”工具查找回归的一个常见场景;如果结果是一个损坏的内核,那么将使
+ 那些从事追踪问题的高尚工作的开发人员和用户的生活更加艰难。
- - 不过,不要过分。一位开发人员曾经将一组编辑内容作为500个单独的补丁发布到一个
- 文件中,这并没有使他成为内核邮件列表中最受欢迎的人。一个补丁可以相当大,
- 只要它仍然包含一个单一的逻辑变更。
+ - 不要过分分割。一位开发人员曾经将一组针对单个文件的编辑分成500个单独的补丁
+ 发布,这并没有使他成为内核邮件列表中最受欢迎的人。一个补丁可以相当大,
+ 只要它仍然包含一个单一的 *逻辑* 变更。
- - 用一系列补丁添加一个全新的基础设施是很有诱惑力的,但是在系列中的最后一个
- 补丁启用整个补丁之前,该基础设施是不使用的。如果可能的话,应该避免这种
- 诱惑;如果这个系列增加了回归,那么二分法将指出最后一个补丁是导致问题的
- 补丁,即使真正的bug在其他地方。只要有可能,添加新代码的补丁程序应该立即
- 激活该代码。
+ - 用一系列补丁添加一个全新的基础设施,但是该设施在系列中的最后一个补丁启用
+ 整个变更之前不能使用,这看起来很诱人。如果可能的话,应该避免这种诱惑;
+ 如果这个系列增加了回归,那么二分法将指出最后一个补丁是导致问题的补丁,
+ 即使真正的bug在其他地方。只要有可能,添加新代码的补丁程序应该立即激活该
+ 代码。
-创建完美补丁系列的工作可能是一个令人沮丧的过程,在完成“真正的工作”之后需要花费
-大量的时间和思考。但是,如果做得好,这是一段很好的时间。
+创建完美补丁系列的工作可能是一个令人沮丧的过程,在完成“真正的工作”之后需要
+花费大量的时间和思考。但是如果做得好,花费的时间就是值得的。
补丁格式和更改日志
------------------
所以现在你有了一系列完美的补丁可以发布,但是这项工作还没有完成。每个补丁都
-需要被格式化成一条消息,它可以快速而清晰地将其目的传达给世界其他地方。为此,
+需要被格式化成一条消息,以快速而清晰地将其目的传达到世界其他地方。为此,
每个补丁将由以下部分组成:
- - 命名补丁作者的可选“from”行。只有当你通过电子邮件传递别人的补丁时,这一行
- 才是必要的,但是如果有疑问,添加它不会有任何伤害。
+ - 可选的“From”行,表明补丁作者。只有当你通过电子邮件发送别人的补丁时,这一行
+ 才是必须的,但是为防止疑问加上它也不会有什么坏处。
- - 一行描述补丁的作用。对于没有其他上下文的读者来说,此消息应该足够了解补丁
- 的范围;这是将在“短格式”变更日志中显示的行。此消息通常首先用相关的子系统
- 名称格式化,然后是补丁的目的。例如:
+ - 一行描述,说明补丁的作用。对于在没有其他上下文的情况下看到该消息的读者来说,
+ 该消息应足以确定修补程序的范围;此行将显示在“short form(简短格式)”变更
+ 日志中。此消息通常需要先加上子系统名称前缀,然后是补丁的目的。例如:
- ::
+ ::
- gpio: fix build on CONFIG_GPIO_SYSFS=n
+ gpio: fix build on CONFIG_GPIO_SYSFS=n
- - 一个空白行,后面是补丁内容的详细描述。这个描述可以是必需的;它应该说明补丁
+ - 一行空白,后接补丁内容的详细描述。此描述可以是任意需要的长度;它应该说明补丁
的作用以及为什么它应该应用于内核。
- - 一个或多个标记行,至少有一个由补丁作者的:signed-off-by 签名。签名将在下面
- 更详细地描述。
+ - 一个或多个标记行,至少有一个由补丁作者的 Signed-off-by 签名。标记将在下面
+ 详细描述。
-上面的项目一起构成补丁的变更日志。写一篇好的变更日志是一门至关重要但常常被
-忽视的艺术;值得花一点时间来讨论这个问题。当你写一个变更日志时,你应该记住
-有很多不同的人会读你的话。其中包括子系统维护人员和审查人员,他们需要决定是否
-应该包括补丁,分销商和其他维护人员试图决定是否应该将补丁反向移植到其他内核,
-bug搜寻人员想知道补丁是否负责他们正在追查的问题,想知道内核如何变化的用户。
-等等。一个好的变更日志以最直接和最简洁的方式向所有这些人传达所需的信息。
+上面的项目一起构成补丁的变更日志。写一则好的变更日志是一门至关重要但常常被
+忽视的艺术;值得花一点时间来讨论这个问题。当你编写变更日志时,你应该记住有
+很多不同的人会读你的话。其中包括子系统维护人员和审查人员,他们需要决定是否
+应该合并补丁,分销商和其他维护人员试图决定是否应该将补丁反向移植到其他内核,
+缺陷搜寻人员想知道补丁是否导致他们正在追查的问题,以及想知道内核如何变化的
+用户等等。一个好的变更日志以最直接和最简洁的方式向所有这些人传达所需的信息。
-为此,总结行应该描述变更的影响和动机,以及在一行约束条件下可能发生的变化。
+在结尾,总结行应该描述变更的影响和动机,以及在一行约束条件下可能发生的变化。
然后,详细的描述可以详述这些主题,并提供任何需要的附加信息。如果补丁修复了
-一个bug,请引用引入该bug的commit(如果可能,请在引用commits时同时提供commit id
-和标题)。如果某个问题与特定的日志或编译器输出相关联,请包含该输出以帮助其他
-人搜索同一问题的解决方案。如果更改是为了支持以后补丁中的其他更改,那么就这么
-说。如果更改了内部API,请详细说明这些更改以及其他开发人员应该如何响应。一般
-来说,你越能把自己放在每个阅读你的changelog的人的位置上,changelog(和内核
+一个缺陷,请引用引入该缺陷的提交(如果可能,请在引用提交时同时提供其 id 和
+标题)。如果某个问题与特定的日志或编译器输出相关联,请包含该输出以帮助其他
+人搜索同一问题的解决方案。如果更改是为了支持以后补丁中的其他更改,那么应当
+说明。如果更改了内部API,请详细说明这些更改以及其他开发人员应该如何响应。
+一般来说,你越把自己放在每个阅读你变更日志的人的位置上,变更日志(和内核
作为一个整体)就越好。
-不用说,变更日志应该是将变更提交到修订控制系统时使用的文本。接下来是:
+不需要说,变更日志是将变更提交到版本控制系统时使用的文本。接下来将是:
- - 补丁本身,采用统一的(“-u”)补丁格式。将“-p”选项用于diff将使函数名与更改
- 相关联,从而使结果补丁更容易被其他人读取。
+ - 补丁本身,采用统一的(“-u”)补丁格式。使用“-p”选项来diff将使函数名与
+ 更改相关联,从而使结果补丁更容易被其他人读取。
-您应该避免在补丁中包括对不相关文件(例如,由构建过程生成的文件或编辑器
-备份文件)的更改。文档目录中的文件“dontdiff”在这方面有帮助;使用“-X”选项将
+您应该避免在补丁中包括与更改不相关文件(例如,构建过程生成的文件或编辑器
+备份文件)。文档目录中的“dontdiff”文件在这方面有帮助;使用“-X”选项将
其传递给diff。
-上面提到的标签用于描述各种开发人员如何与这个补丁的开发相关联。
+上面提到的标签(tag)用于描述各种开发人员如何与这个补丁的开发相关联。
:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
文档中对它们进行了详细描述;下面是一个简短的总结。每一行的格式如下:
@@ -154,87 +160,87 @@ bug搜寻人员想知道补丁是否负责他们正在追查的问题,想知
常用的标签有:
- - Signed-off-by: 这是一个开发人员的证明,他或她有权提交补丁以包含到内核中。
- 这是开发来源认证协议,其全文可在
+ - Signed-off-by: 这是一个开发人员的证明,证明他或她有权提交补丁以包含到内核
+ 中。这表明同意开发者来源认证协议,其全文见
:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
- 中找到,如果没有适当的签字,则不能合并到主线中。
+ 如果没有合适的签字,则不能合并到主线中。
- Co-developed-by: 声明补丁是由多个开发人员共同创建的;当几个人在一个补丁上
- 工作时,它用于将属性赋予共同作者(除了 From: 所赋予的作者之外)。因为
- Co-developed-by: 表示作者身份,所以每个共同开发人, 必须紧跟在相关合作作者
- 的签名之后。具体内容和示例可以在以下文件中找到
+ 工作时,它用于给出共同作者(除了 From: 所给出的作者之外)。由于
+ Co-developed-by: 表示作者身份,所以每个共同开发人,必须紧跟在相关合作作者
+ 的Signed-off-by之后。具体内容和示例见以下文件
:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
- Acked-by: 表示另一个开发人员(通常是相关代码的维护人员)同意补丁适合包含
在内核中。
- - Tested-by: 声明指定的人已经测试了补丁并发现它可以工作。
+ - Tested-by: 声明某人已经测试了补丁并确认它可以工作。
- - Reviewed-by: 指定的开发人员已经审查了补丁的正确性;有关详细信息,请参阅
+ - Reviewed-by: 表示某开发人员已经审查了补丁的正确性;有关详细信息,请参阅
:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
- - Reported-by: 指定报告此补丁修复的问题的用户;此标记用于提供感谢。
+ - Reported-by: 指定报告此补丁修复的问题的用户;此标记用于表示感谢。
- - Cc:指定的人收到了补丁的副本,并有机会对此发表评论。
+ - Cc:指定某人收到了补丁的副本,并有机会对此发表评论。
-在补丁中添加标签时要小心:只有cc:才适合在没有指定人员明确许可的情况下添加。
+在补丁中添加标签时要小心:只有Cc:才适合在没有指定人员明确许可的情况下添加。
-发送补丁
+寄送补丁
--------
-在邮寄补丁之前,您还需要注意以下几点:
+在寄送补丁之前,您还需要注意以下几点:
- - 您确定您的邮件发送程序不会损坏补丁吗?有免费的空白更改或由邮件客户端
- 执行的行包装的补丁不会在另一端复原,并且通常不会进行任何详细检查。如果有
- 任何疑问,把补丁寄给你自己,让你自己相信它是完好无损的。
+ - 您确定您的邮件发送程序不会损坏补丁吗?被邮件客户端更改空白或修饰了行的补丁
+ 无法被另一端接受,并且通常不会进行任何详细检查。如果有任何疑问,先把补丁寄
+ 给你自己,让你自己确定它是完好无损的。
:ref:`Documentation/translations/zh_CN/process/email-clients.rst <cn_email_clients>`
- 提供了一些有用的提示,可以让特定的邮件客户机工作以发送补丁。
+ 提供了一些有用的提示,可以让特定的邮件客户端正常发送补丁。
- - 你确定你的补丁没有愚蠢的错误吗?您应该始终通过scripts/checkpatch.pl运行
- 补丁程序,并解决它提出的投诉。请记住,checkpatch.pl虽然是大量思考内核
- 补丁应该是什么样子的体现,但它并不比您聪明。如果修复checkpatch.pl投诉会
+ - 你确定你的补丁没有荒唐的错误吗?您应该始终通过scripts/checkpatch.pl检查
+ 补丁程序,并解决它提出的问题。请记住,checkpatch.pl,虽然体现了对内核补丁
+ 应该是什么样的大量思考,但它并不比您聪明。如果修复checkpatch.pl给的问题会
使代码变得更糟,请不要这样做。
补丁应始终以纯文本形式发送。请不要将它们作为附件发送;这使得审阅者在答复中更难
引用补丁的部分。相反,只需将补丁直接放到您的消息中。
-邮寄补丁时,重要的是将副本发送给任何可能感兴趣的人。与其他一些项目不同,内核
-鼓励人们错误地发送过多的副本;不要假定相关人员会看到您在邮件列表中的发布。
+寄出补丁时,重要的是将副本发送给任何可能感兴趣的人。与其他一些项目不同,内核
+鼓励人们甚至错误地发送过多的副本;不要假定相关人员会看到您在邮件列表中的发布。
尤其是,副本应发送至:
- - 受影响子系统的维护人员。如前所述,维护人员文件是查找这些人员的第一个地方。
+ - 受影响子系统的维护人员。如前所述,维护人员文件是查找这些人员的首选地方。
- 其他在同一领域工作的开发人员,尤其是那些现在可能在那里工作的开发人员。使用
git查看还有谁修改了您正在处理的文件,这很有帮助。
- - 如果您对错误报告或功能请求做出响应,也可以抄送原始发送人。
+ - 如果您对某错误报告或功能请求做出响应,也可以抄送原始发送人。
- - 将副本发送到相关邮件列表,或者,如果没有其他应用,则发送到Linux内核列表。
+ - 将副本发送到相关邮件列表,或者若无相关列表,则发送到linux-kernel列表。
- - 如果您正在修复一个bug,请考虑该修复是否应进入下一个稳定更新。如果是这样,
- stable@vger.kernel.org 应该得到补丁的副本。另外,在补丁本身的标签中添加
- 一个“cc:stable@vger.kernel.org”;这将使稳定团队在修复进入主线时收到通知。
+ - 如果您正在修复一个缺陷,请考虑该修复是否应进入下一个稳定更新。如果是这样,
+ 补丁副本也应发到stable@vger.kernel.org 。另外,在补丁本身的标签中添加一个
+ “Cc: stable@vger.kernel.org”;这将使稳定版团队在修复进入主线时收到通知。
-当为一个补丁选择接收者时,最好知道你认为谁最终会接受这个补丁并将其合并。虽然
-可以将补丁直接发送给LinusTorvalds并让他合并,但通常情况下不会这样做。Linus
-很忙,并且有子系统维护人员负责监视内核的特定部分。通常您会希望维护人员合并您
-的补丁。如果没有明显的维护人员,Andrew Morton通常是最后的补丁目标。
+当为一个补丁选择接收者时,最好清楚你认为谁最终会接受这个补丁并将其合并。虽然
+可以将补丁直接发给Linus Torvalds并让他合并,但通常情况下不会这样做。Linus很
+忙,并且有子系统维护人员负责监视内核的特定部分。通常您会希望维护人员合并您的
+补丁。如果没有明显的维护人员,Andrew Morton通常是最后的补丁接收者。
-补丁需要好的主题行。补丁程序行的规范格式如下:
+补丁需要好的主题行。补丁主题行的规范格式如下:
::
[PATCH nn/mm] subsys: one-line description of the patch
-其中“nn”是补丁的序号,“mm”是系列中补丁的总数,“subsys”是受影响子系统的名称。
-显然,一个单独的补丁可以省略nn/mm。
+其中“nn”是补丁的序号,“mm”是系列中补丁的总数,“subsys”是受影响子系统的
+名称。当然,一个单独的补丁可以省略nn/mm。
-如果您有一系列重要的补丁,那么通常将介绍性描述作为零部分发送。不过,这种约定
-并没有得到普遍遵循;如果您使用它,请记住简介中的信息不会使它进入内核变更日志。
+如果您有一系列重要的补丁,那么通常发送一个简介作为第〇部分。不过,这个约定
+并没有得到普遍遵循;如果您使用它,请记住简介中的信息不会进入内核变更日志。
因此,请确保补丁本身具有完整的变更日志信息。
一般来说,多部分补丁的第二部分和后续部分应作为对第一部分的回复发送,以便它们
在接收端都连接在一起。像git和coilt这样的工具有命令,可以通过适当的线程发送
-一组补丁。但是,如果您有一个长系列,并且正在使用git,请远离–chain reply-to
-选项,以避免创建异常深的嵌套。
+一组补丁。但是,如果您有一长串补丁,并正使用git,请不要使用–-chain-reply-to
+选项,以避免创建过深的嵌套。
diff --git a/Documentation/translations/zh_CN/process/6.Followthrough.rst b/Documentation/translations/zh_CN/process/6.Followthrough.rst
index f509e077e1cb..2a127e737b6a 100644
--- a/Documentation/translations/zh_CN/process/6.Followthrough.rst
+++ b/Documentation/translations/zh_CN/process/6.Followthrough.rst
@@ -1,145 +1,152 @@
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/6.Followthrough.rst <development_followthrough>`
-:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+
+:Translator:
+
+ 时奎亮 Alex Shi <alex.shi@linux.alibaba.com>
+
+:校译:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
.. _cn_development_followthrough:
跟进
====
-在这一点上,您已经遵循了到目前为止给出的指导方针,并且,随着您自己的工程技能
-的增加,已经发布了一系列完美的补丁。即使是经验丰富的内核开发人员也能犯的最大
-错误之一是,认为他们的工作现在已经完成了。事实上,发布补丁意味着进入流程的下
-一个阶段,可能还需要做很多工作。
+此时,您已经遵循了到目前为止给出的指导方针,并且,随着您自己的工程技能的增加,
+已经发布了一系列完美的补丁。即使是经验丰富的内核开发人员也能犯的最大错误之一
+是,认为他们的工作现在已经完成了。事实上,发布补丁意味着进入流程的下一个阶段,
+可能还需要做很多工作。
-一个补丁在第一次发布时就非常出色,没有改进的余地,这是很罕见的。内核开发流程
-认识到这一事实,因此,它非常注重对已发布代码的改进。作为代码的作者,您应该与
+一个补丁在首次发布时就非常出色、没有改进的余地,这是很罕见的。内核开发流程已
+认识到这一事实,因此它非常注重对已发布代码的改进。作为代码的作者,您应该与
内核社区合作,以确保您的代码符合内核的质量标准。如果不参与这个过程,很可能会
-阻止将补丁包含到主线中。
+无法将补丁合并到主线中。
与审阅者合作
------------
任何意义上的补丁都会导致其他开发人员在审查代码时发表大量评论。对于许多开发
-人员来说,与审查人员合作可能是内核开发过程中最令人生畏的部分。但是,如果你
+人员来说,与审阅人员合作可能是内核开发过程中最令人生畏的部分。但是如果你
记住一些事情,生活会变得容易得多:
- - 如果你已经很好地解释了你的补丁,评论人员会理解它的价值,以及为什么你会
- 费尽心思去写它。但是这个并不能阻止他们提出一个基本的问题:五年或十年后
- 用这个代码维护一个内核会是什么感觉?你可能被要求做出的许多改变——从编码风格
- 的调整到大量的重写——都来自于对Linux的理解,即从现在起十年后,Linux仍将在
- 开发中。
+ - 如果你已经很好地解释了你的补丁,审阅人员会理解它的价值,以及为什么你会
+ 费尽心思去写它。但是这个并不能阻止他们提出一个基本的问题:在五年或十年后
+ 维护含有此代码的内核会怎么样?你可能被要求做出的许多改变——从编码风格的
+ 调整到大量的重写——都来自于对Linux的理解,即从现在起十年后,Linux仍将
+ 在开发中。
- 代码审查是一项艰苦的工作,这是一项相对吃力不讨好的工作;人们记得谁编写了
- 内核代码,但对于那些审查它的人来说,几乎没有什么持久的名声。因此,评论
+ 内核代码,但对于那些审查它的人来说,几乎没有什么长久的名声。因此,审阅
人员可能会变得暴躁,尤其是当他们看到同样的错误被一遍又一遍地犯下时。如果
- 你得到了一个看起来愤怒、侮辱或完全冒犯你的评论,抵制以同样方式回应的冲动。
- 代码审查是关于代码的,而不是关于人的,代码审查人员不会亲自攻击您。
+ 你得到了一个看起来愤怒、侮辱或完全冒犯你的评论,请抑制以同样方式回应的冲动。
+ 代码审查是关于代码的,而不是关于人的,代码审阅人员不会亲自攻击您。
- - 同样,代码审查人员也不想以牺牲你雇主的利益为代价来宣传他们雇主的议程。
+ - 同样,代码审阅人员也不想以牺牲你雇主的利益为代价来宣传他们雇主的议程。
内核开发人员通常希望今后几年能在内核上工作,但他们明白他们的雇主可能会改
变。他们真的,几乎毫无例外地,致力于创造他们所能做到的最好的内核;他们并
没有试图给雇主的竞争对手造成不适。
-所有这些归根结底都是,当审阅者向您发送评论时,您需要注意他们正在进行的技术
-观察。不要让他们的表达方式或你自己的骄傲阻止这种事情的发生。当你在一个补丁
-上得到评论时,花点时间去理解评论人想说什么。如果可能的话,请修复审阅者要求
-您修复的内容。然后回复审稿人:谢谢他们,并描述你将如何回答他们的问题。
+所有这些归根结底就是,当审阅者向您发送评论时,您需要注意他们正在进行的技术
+评论。不要让他们的表达方式或你自己的骄傲阻止此事。当你在一个补丁上得到评论
+时,花点时间去理解评论人想说什么。如果可能的话,请修复审阅者要求您修复的内
+容。然后回复审阅者:谢谢他们,并描述你将如何回答他们的问题。
请注意,您不必同意审阅者建议的每个更改。如果您认为审阅者误解了您的代码,请
解释到底发生了什么。如果您对建议的更改有技术上的异议,请描述它并证明您对该
-问题的解决方案是正确的。如果你的解释有道理,审稿人会接受的。不过,如果你的
-解释不能证明是有说服力的,尤其是当其他人开始同意审稿人的观点时,请花些时间
-重新考虑一下。你很容易对自己解决问题的方法视而不见,以至于你没有意识到某个
-问题根本是错误的,或者你甚至没有解决正确的问题。
+问题的解决方案是正确的。如果你的解释有道理,审阅者会接受的。不过,如果你的
+解释证明缺乏说服力,尤其是当其他人开始同意审稿人的观点时,请花些时间重新考虑
+一下。你很容易对自己解决问题的方法视而不见,以至于你没有意识到某些东西完全
+是错误的,或者你甚至没有解决正确的问题。
-Andrew Morton建议,每一条不会导致代码更改的评论都应该导致额外的代码注释;
-这可以帮助未来的评论人员避免出现第一次出现的问题。
+Andrew Morton建议,每一个不会导致代码更改的审阅评论都应该产生一个额外的代码
+注释;这可以帮助未来的审阅人员避免第一次出现的问题。
-一个致命的错误是忽视评论,希望它们会消失。他们不会走的。如果您在没有对之前
-收到的注释做出响应的情况下重新发布代码,那么很可能会发现补丁毫无用处。
+一个致命的错误是忽视评论,希望它们会消失。它们不会走的。如果您在没有对之前
+收到的评论做出响应的情况下重新发布代码,那么很可能会发现补丁毫无用处。
说到重新发布代码:请记住,审阅者不会记住您上次发布的代码的所有细节。因此,
-提醒审查人员以前提出的问题以及您如何处理这些问题总是一个好主意;补丁变更
+提醒审阅人员以前提出的问题以及您如何处理这些问题总是一个好主意;补丁变更
日志是提供此类信息的好地方。审阅者不必搜索列表档案来熟悉上次所说的内容;
-如果您帮助他们开始运行,当他们重新访问您的代码时,他们的心情会更好。
+如果您帮助他们直接开始,当他们重新查看您的代码时,心情会更好。
如果你已经试着做正确的事情,但事情仍然没有进展呢?大多数技术上的分歧都可以
-通过讨论来解决,但有时人们只需要做出决定。如果你真的认为这个决定对你不利,
-你可以试着向更高的权力上诉。在这篇文章中,更高的权力倾向于Andrew Morton。
-Andrew在内核开发社区中受i很大的尊重;他经常为似乎被绝望地阻塞事情清障。
-尽管如此,对Andrew的呼吁不应轻而易举,也不应在所有其他替代方案都被探索之前
-使用。当然,记住,他也可能不同意你的意见。
+通过讨论来解决,但有时人们仍需要做出决定。如果你真的认为这个决定对你不利,
+你可以试着向有更高权力的人上诉。对于本文,更高权力的人是 Andrew Morton 。
+Andrew 在内核开发社区中非常受尊敬;他经常为似乎被绝望阻塞的事情清障。尽管
+如此,不应轻易就直接找 Andrew ,也不应在所有其他替代方案都被尝试之前找他。
+当然,记住,他也可能不同意你的意见。
接下来会发生什么
----------------
-如果一个补丁被认为是添加到内核中的一件好事,并且一旦大多数审查问题得到解决,
-下一步通常是进入子系统维护人员的树中。工作方式因子系统而异;每个维护人员都
-有自己的工作方式。特别是,可能有不止一棵树——一棵树,也许,专门用于计划下一
-个合并窗口的补丁,另一棵树用于长期工作。
+如果一个补丁被认为适合添加到内核中,并且大多数审查问题得到解决,下一步通常
+是进入子系统维护人员的树中。工作方式因子系统而异;每个维护人员都有自己的
+工作方式。特别是可能有不止一棵树——也许一棵树专门用于计划下一个合并窗口的
+补丁,另一棵树用于长期工作。
-对于应用于没有明显子系统树(例如内存管理修补程序)的区域的修补程序,默认树
-通常以-mm结尾。影响多个子系统的补丁也可以最终通过-mm树。
+对于应用到不属于明显子系统树(例如内存管理修补程序)的区域的修补程序,默认树
+通常上溯到-mm。影响多个子系统的补丁也可以最终进入-mm树。
包含在子系统树中可以提高补丁的可见性。现在,使用该树的其他开发人员将默认获
得补丁。子系统树通常也为Linux提供支持,使其内容对整个开发社区可见。在这一点
上,您很可能会从一组新的审阅者那里得到更多的评论;这些评论需要像上一轮那样
-得到回答。
+得到回应。
-在这一点上也会发生什么,这取决于你的补丁的性质,是与其他人正在做的工作发生
+在这时也会发生点什么,这取决于你的补丁的性质,是否与其他人正在做的工作发生
冲突。在最坏的情况下,严重的补丁冲突可能会导致一些工作被搁置,以便剩余的补丁
可以成形并合并。另一些时候,冲突解决将涉及到与其他开发人员合作,可能还会
在树之间移动一些补丁,以确保所有的应用都是干净的。这项工作可能是一件痛苦的
-事情,但要计算您的福祉:在Linux下一棵树出现之前,这些冲突通常只在合并窗口
-中出现,必须迅速解决。现在可以在合并窗口打开之前,在空闲时解决这些问题。
+事情,但也需庆幸现在的幸福:在linux-next树出现之前,这些冲突通常只在合并窗口
+中出现,必须迅速解决。现在可以在合并窗口打开之前的空闲时间解决这些问题。
有朝一日,如果一切顺利,您将登录并看到您的补丁已经合并到主线内核中。祝贺你!
-然而,一旦庆祝活动完成(并且您已经将自己添加到维护人员文件中),就值得记住
-一个重要的小事实:工作仍然没有完成。并入主线带来了自身的挑战。
+然而,一旦庆祝完了(并且您已经将自己添加到维护人员文件中),就一定要记住
+一个重要的小事实:工作仍然没有完成。并入主线也带来了它的挑战。
-首先,补丁的可见性再次提高。可能会有新一轮的开发者评论,他们以前不知道这
-个补丁。忽略它们可能很有诱惑力,因为您的代码不再存在任何被合并的问题。但是,
-要抵制这种诱惑,您仍然需要对有问题或建议的开发人员作出响应。
+首先,补丁的可见性再次提高。可能会有以前不知道这个补丁的开发者的新一轮评论。
+忽略它们可能很有诱惑力,因为您的代码不再存在任何被合并的问题。但是,要抵制
+这种诱惑,您仍然需要对有问题或建议的开发人员作出响应。
-不过,更重要的是:将代码包含在主线中会将代码交给更大的一组测试人员。即使您
-为尚未提供的硬件提供了驱动程序,您也会惊讶于有多少人会将您的代码构建到内核
-中。当然,如果有测试人员,也会有错误报告。
+不过,更重要的是:将代码包含在主线中会将代码交给更多的一些测试人员。即使您
+为尚未可用的硬件提供了驱动程序,您也会惊讶于有多少人会将您的代码构建到内核
+中。当然,如果有测试人员,也可能会有错误报告。
-最糟糕的错误报告是回归。如果你的补丁导致回归,你会发现很多不舒服的眼睛盯着
-你;回归需要尽快修复。如果您不愿意或无法修复回归(其他人都不会为您修复),
+最糟糕的错误报告是回归。如果你的补丁导致回归,你会发现多到让你不舒服的眼睛盯
+着你;回归需要尽快修复。如果您不愿意或无法修复回归(其他人都不会为您修复),
那么在稳定期内,您的补丁几乎肯定会被移除。除了否定您为使补丁进入主线所做的
-所有工作之外,如果由于未能修复回归而取消补丁,很可能会使将来的工作更难合并。
+所有工作之外,如果由于未能修复回归而取消补丁,很可能会使将来的工作更难被合并。
-在处理完任何回归之后,可能还有其他普通的bug需要处理。稳定期是修复这些错误并
-确保代码在主线内核版本中的首次发布尽可能可靠的最好机会。所以,请回答错误
+在处理完任何回归之后,可能还有其他普通缺陷需要处理。稳定期是修复这些错误并
+确保代码在主线内核版本中的首次发布尽可能可靠的最好机会。所以,请回应错误
报告,并尽可能解决问题。这就是稳定期的目的;一旦解决了旧补丁的任何问题,就
-可以开始创建酷的新补丁。
+可以开始尽情创建新补丁。
-别忘了,还有其他里程碑也可能会创建bug报告:下一个主线稳定版本,当著名的发行
-商选择包含补丁的内核版本时,等等。继续响应这些报告是您工作的基本骄傲。但是,
-如果这不是足够的动机,那么也值得考虑的是,开发社区会记住那些在合并后对代码
-失去兴趣的开发人员。下一次你发布补丁时,他们会以你以后不会在身边维护它为假
-设来评估它。
+别忘了,还有其他节点也可能会创建缺陷报告:下一个主线稳定版本,当著名的发行
+商选择包含您补丁的内核版本时等等。继续响应这些报告是您工作的基本素养。但是
+如果这不能提供足够的动机,那么也需要考虑:开发社区会记住那些在合并后对代码
+失去兴趣的开发人员。下一次你发布补丁时,他们会以你以后不会持续维护它为前提
+来评估它。
其他可能发生的事情
------------------
-有一天,你可以打开你的邮件客户端,看到有人给你寄了一个代码补丁。毕竟,这是
+某天,当你打开你的邮件客户端时,看到有人给你寄了一个代码补丁。毕竟,这是
让您的代码公开存在的好处之一。如果您同意这个补丁,您可以将它转发给子系统
-维护人员(确保包含一个正确的From:行,这样属性是正确的,并添加一个您自己
-的签准),或者回复一个Acked-by,让原始发送者向上发送它。
+维护人员(确保包含一个正确的From:行,这样属性是正确的,并添加一个您自己的
+signoff ),或者回复一个 Acked-by: 让原始发送者向上发送它。
-如果您不同意补丁,请发送一个礼貌的回复,解释原因。如果可能的话,告诉作者需要
-做哪些更改才能让您接受补丁。对于代码的编写者和维护者所反对的合并补丁,存在着
-一定的阻力,但仅此而已。如果你被认为不必要的阻碍了好的工作,那么这些补丁最
-终会经过你身边并进入主线。在Linux内核中,没有人对任何代码拥有绝对的否决权。
-除了Linus。
+如果您不同意补丁,请礼貌地回复,解释原因。如果可能的话,告诉作者需要做哪些
+更改才能让您接受补丁。合并代码的编写者和维护者所反对的补丁的确存在着一定的
+阻力,但仅此而已。如果你被认为不必要的阻碍了好的工作,那么这些补丁最终会
+绕过你并进入主线。在Linux内核中,没有人对任何代码拥有绝对的否决权。可能除
+了Linus。
在非常罕见的情况下,您可能会看到完全不同的东西:另一个开发人员发布了针对您
-的问题的不同解决方案。在这一点上,两个补丁中的一个可能不会合并,“我的在这里
-是第一个”不被认为是一个令人信服的技术论据。如果有人的补丁取代了你的补丁而进
-入了主线,那么只有一种方法可以回应你:高兴你的问题得到解决,继续你的工作。
-以这种方式把一个人的工作推到一边可能会伤害和气馁,但是在他们忘记了谁的补丁
-真正被合并很久之后,社区会记住你的反应。
+的问题的不同解决方案。在这时,两个补丁之一可能不会被合并,“我的补丁首先
+发布”不被认为是一个令人信服的技术论据。如果有别人的补丁取代了你的补丁而进
+入了主线,那么只有一种方法可以回应你:很高兴你的问题解决了,请继续工作吧。
+以这种方式把某人的工作推到一边可能导致伤心和气馁,但是社区会记住你的反应,
+即使很久以后他们已经忘记了谁的补丁真正被合并。
diff --git a/Documentation/translations/zh_CN/process/7.AdvancedTopics.rst b/Documentation/translations/zh_CN/process/7.AdvancedTopics.rst
index 956815edbd18..57beca02181c 100644
--- a/Documentation/translations/zh_CN/process/7.AdvancedTopics.rst
+++ b/Documentation/translations/zh_CN/process/7.AdvancedTopics.rst
@@ -1,7 +1,14 @@
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/7.AdvancedTopics.rst <development_advancedtopics>`
-:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+
+:Translator:
+
+ 时奎亮 Alex Shi <alex.shi@linux.alibaba.com>
+
+:校译:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
.. _cn_development_advancedtopics:
@@ -15,110 +22,112 @@
---------------
内核使用分布式版本控制始于2002年初,当时Linus首次开始使用专有的Bitkeeper应用
-程序。虽然bitkeeper存在争议,但它所体现的软件版本管理方法却肯定不是。分布式
-版本控制可以立即加速内核开发项目。在当前的时代,有几种免费的比特保持器替代品。
-无论好坏,内核项目都将Git作为其选择的工具。
+程序。虽然BitKeeper存在争议,但它所体现的软件版本管理方法却肯定不是。分布式
+版本控制可以立即加速内核开发项目。现在有好几种免费的BitKeeper替代品。
+但无论好坏,内核项目都已经选择了Git作为其工具。
-使用Git管理补丁可以使开发人员的生活更加轻松,尤其是随着补丁数量的增加。Git
-也有其粗糙的边缘和一定的危险,它是一个年轻和强大的工具,仍然在其开发人员完善
+使用Git管理补丁可以使开发人员的生活更加轻松,尤其是随着补丁数量的增长。Git也
+有其粗糙的边角和一定的危险性,它是一个年轻和强大的工具,仍然在其开发人员完善
中。本文档不会试图教会读者如何使用git;这会是个巨长的文档。相反,这里的重点
-将是Git如何特别适合内核开发过程。想要加快Git的开发人员可以在以下网站上找到
-更多信息:
+将是Git如何特别适合内核开发过程。想要加快用Git速度的开发人员可以在以下网站上
+找到更多信息:
+
+ https://git-scm.com/
- http://git-scm.com/
+ https://www.kernel.org/pub/software/scm/git/docs/user-manual.html
- http://www.kernel.org/pub/software/scm/git/docs/user-manual.html
+同时网上也能找到各种各样的教程。
-在尝试使用它使补丁可供其他人使用之前,第一要务是阅读上述站点,对Git的工作
-方式有一个扎实的了解。使用Git的开发人员应该能够获得主线存储库的副本,探索
-修订历史,提交对树的更改,使用分支等。了解Git用于重写历史的工具(如Rebase)
-也很有用。Git有自己的术语和概念;Git的新用户应该了解refs、远程分支、索引、
-快进合并、推拉、分离头等。一开始可能有点吓人,但这些概念不难通过一点学习来
+在尝试使用它生成补丁供他人使用之前,第一要务是阅读上述网页,对Git的工作方式
+有一个扎实的了解。使用Git的开发人员应能进行拉取主线存储库的副本,查询修订
+历史,提交对树的更改,使用分支等操作。了解Git用于重写历史的工具(如rebase)
+也很有用。Git有自己的术语和概念;Git的新用户应该了解引用、远程分支、索引、
+快进合并、推拉、游离头等。一开始可能有点吓人,但这些概念不难通过一点学习来
理解。
使用git生成通过电子邮件提交的补丁是提高速度的一个很好的练习。
-当您准备好开始安装Git树供其他人查看时,您当然需要一个可以从中提取的服务器。
-如果您有一个可以访问Internet的系统,那么使用git守护进程设置这样的服务器相
-对简单。否则,免费的公共托管网站(例如github)开始出现在网络上。成熟的开发
-人员可以在kernel.org上获得一个帐户,但这些帐户并不容易找到;有关更多信息,
-请参阅 http://kernel.org/faq/
+当您准备好开始建立Git树供其他人查看时,无疑需要一个可以从中拉取的服务器。
+如果您有一个可以访问因特网的系统,那么使用git-daemon设置这样的服务器相对
+简单。同时,免费的公共托管网站(例如github)也开始出现在网络上。成熟的开发
+人员可以在kernel.org上获得一个帐户,但这些帐户并不容易得到;更多有关信息,
+请参阅 https://kernel.org/faq/ 。
正常的Git工作流程涉及到许多分支的使用。每一条开发线都可以分为单独的“主题
-分支”,并独立维护。Git的分支机构很便宜,没有理由不免费使用它们。而且,在
-任何情况下,您都不应该在任何您打算让其他人从中受益的分支中进行开发。应该
-小心地创建公开可用的分支;当它们处于完整的形式并准备好运行时(而不是之前),
-合并开发分支的补丁。
+分支”,并独立维护。Git的分支很容易使用,没有理由不使用它们。而且,在任何
+情况下,您都不应该在任何您打算让其他人从中拉取的分支中进行开发。应该小心地
+创建公开可用的分支;当开发分支处于完整状态并已准备好时(而不是之前)才合并
+开发分支的补丁。
Git提供了一些强大的工具,可以让您重写开发历史。一个不方便的补丁(比如说,
一个打破二分法的补丁,或者有其他一些明显的缺陷)可以在适当的位置修复,或者
-完全从历史中消失。一个补丁系列可以被重写,就好像它是在今天的主线之上写的
-一样,即使你已经花了几个月的时间在写它。可以透明地将更改从一个分支转移到另
-一个分支。等等。明智地使用git修改历史的能力可以帮助创建问题更少的干净补丁集。
+完全从历史中消失。一个补丁系列可以被重写,就好像它是在今天的主线上写的一样,
+即使你已经花了几个月的时间在写它。可以透明地将更改从一个分支转移到另一个
+分支。等等。明智地使用git修改历史的能力可以帮助创建问题更少的干净补丁集。
-然而,过度使用这种能力可能会导致其他问题,而不仅仅是对创建完美项目历史的
-简单痴迷。重写历史将重写该历史中包含的更改,将经过测试(希望)的内核树变
-为未经测试的内核树。但是,除此之外,如果开发人员没有对项目历史的共享视图,
-他们就无法轻松地协作;如果您重写了其他开发人员拉入他们存储库的历史,您将
-使这些开发人员的生活更加困难。因此,这里有一个简单的经验法则:被导出到其他
-人的历史在此后通常被认为是不可变的。
+然而,过度使用这种功能可能会导致其他问题,而不仅仅是对创建完美项目历史的
+简单痴迷。重写历史将重写该历史中包含的更改,将经过测试(希望如此)的内核树
+变为未经测试的内核树。除此之外,如果开发人员没有共享项目历史,他们就无法
+轻松地协作;如果您重写了其他开发人员拉入他们存储库的历史,您将使这些开发
+人员的生活更加困难。因此,这里有一个简单的经验法则:被导出到其他地方的历史
+在此后通常被认为是不可变的。
因此,一旦将一组更改推送到公开可用的服务器上,就不应该重写这些更改。如果您
-尝试强制进行不会导致快进合并(即不共享同一历史记录的更改)的更改,Git将尝
-试强制执行此规则。可以重写此检查,有时可能需要重写导出的树。在树之间移动变
-更集以避免Linux-next中的冲突就是一个例子。但这种行为应该是罕见的。这就是为
-什么开发应该在私有分支中进行(必要时可以重写)并且只有在公共分支处于合理的
-高级状态时才转移到公共分支中的原因之一。
+尝试强制进行无法快进合并的更改(即不共享同一历史记录的更改),Git将尝试强制
+执行此规则。这可能覆盖检查,有时甚至需要重写导出的树。在树之间移动变更集以
+避免linux-next中的冲突就是一个例子。但这种行为应该是罕见的。这就是为什么
+开发应该在私有分支中进行(必要时可以重写)并且只有在公共分支处于合理的较新
+状态时才转移到公共分支中的原因之一。
当主线(或其他一组变更所基于的树)前进时,很容易与该树合并以保持领先地位。
对于一个私有的分支,rebasing 可能是一个很容易跟上另一棵树的方法,但是一旦
-一棵树被导出到全世界,rebasing就不是一个选项。一旦发生这种情况,就必须进行
-完全合并(merge)。合并有时是很有意义的,但是过于频繁的合并会不必要地扰乱
-历史。在这种情况下,建议的技术是不经常合并,通常只在特定的发布点(如主线-rc
-发布)合并。如果您对特定的更改感到紧张,则可以始终在私有分支中执行测试合并。
-在这种情况下,git rerere 工具很有用;它记住合并冲突是如何解决的,这样您就
-不必重复相同的工作。
+一棵树被导出到外界,rebasing就不可取了。一旦发生这种情况,就必须进行完全
+合并(merge)。合并有时是很有意义的,但是过于频繁的合并会不必要地扰乱历史。
+在这种情况下建议的做法是不要频繁合并,通常只在特定的发布点(如主线-rc发布)
+合并。如果您对特定的更改感到紧张,则可以始终在私有分支中执行测试合并。在
+这种情况下,git“rerere”工具很有用;它能记住合并冲突是如何解决的,这样您
+就不必重复相同的工作。
关于Git这样的工具的一个最大的反复抱怨是:补丁从一个存储库到另一个存储库的
大量移动使得很容易陷入错误建议的变更中,这些变更避开审查雷达进入主线。当内
-核开发人员看到这种情况发生时,他们往往会感到不高兴;在Git树上放置未查看或
-主题外的补丁可能会影响您将来获取树的能力。引用Linus:
+核开发人员看到这种情况发生时,他们往往会感到不高兴;在Git树上放置未审阅或
+主题外的补丁可能会影响您将来让树被拉取的能力。引用Linus的话:
::
- 你可以给我发补丁,但要我从你哪里取一个Git补丁,我需要知道你知道
- 你在做什么,我需要能够相信事情而不去检查每个个人改变。
+ 你可以给我发补丁,但当我从你那里拉取一个Git补丁时,我需要知道你清楚
+ 自己在做什么,我需要能够相信事情而 *无需* 手动检查每个单独的更改。
-(http://lwn.net/articles/224135/)。
+(http://lwn.net/Articles/224135/)。
为了避免这种情况,请确保给定分支中的所有补丁都与相关主题紧密相关;“驱动程序
修复”分支不应更改核心内存管理代码。而且,最重要的是,不要使用Git树来绕过
-审查过程。不时的将树的摘要发布到相关的列表中,当时间合适时,请求
-Linux-next 中包含该树。
+审查过程。不时的将树的摘要发布到相关的列表中,在合适时候请求linux-next中
+包含该树。
-如果其他人开始发送补丁以包含到您的树中,不要忘记查看它们。还要确保您维护正确
-的作者信息; ``git am`` 工具在这方面做得最好,但是如果它通过第三方转发给您,
-您可能需要在补丁中添加“From:”行。
+如果其他人开始发送补丁以包含到您的树中,不要忘记审阅它们。还要确保您维护正确
+的作者信息; git “am”工具在这方面做得最好,但是如果补丁通过第三方转发给您,
+您可能需要在补丁中添加“From:”行。
-请求pull操作时,请务必提供所有相关信息:树的位置、要拉的分支以及拉操作将导致
-的更改。在这方面,git request pull 命令非常有用;它将按照其他开发人员的预期
-格式化请求,并检查以确保您记住了将这些更改推送到公共服务器。
+请求拉取时,请务必提供所有相关信息:树的位置、要拉取的分支以及拉取将导致的
+更改。在这方面 git request-pull 命令非常有用;它将按照其他开发人员所期望的
+格式化请求,并检查以确保您已记得将这些更改推送到公共服务器。
-审查补丁
+审阅补丁
--------
-一些读者当然会反对将本节与“高级主题”放在一起,因为即使是刚开始的内核开发人员
-也应该检查补丁。当然,学习如何在内核环境中编程没有比查看其他人发布的代码更好
-的方法了。此外,审阅者永远供不应求;通过查看代码,您可以对整个流程做出重大贡献。
+一些读者显然会反对将本节与“高级主题”放在一起,因为即使是刚开始的内核开发人员
+也应该审阅补丁。当然,没有比查看其他人发布的代码更好的方法来学习如何在内核环境
+中编程了。此外,审阅者永远供不应求;通过审阅代码,您可以对整个流程做出重大贡献。
-审查代码可能是一个令人生畏的前景,特别是对于一个新的内核开发人员来说,他们
+审查代码可能是一副令人生畏的图景,特别是对一个新的内核开发人员来说,他们
可能会对公开询问代码感到紧张,而这些代码是由那些有更多经验的人发布的。不过,
-即使是最有经验的开发人员编写的代码也可以得到改进。也许对评审员(所有评审员)
-最好的建议是:把评审评论当成问题而不是批评。询问“在这条路径中如何释放锁?”
+即使是最有经验的开发人员编写的代码也可以得到改进。也许对(所有)审阅者最好
+的建议是:把审阅评论当成问题而不是批评。询问“在这条路径中如何释放锁?”
总是比说“这里的锁是错误的”更好。
-不同的开发人员将从不同的角度审查代码。一些主要关注的是编码样式以及代码行是
-否有尾随空格。其他人将主要关注补丁作为一个整体实现的变更是否对内核有好处。
-然而,其他人会检查是否存在锁定问题、堆栈使用过度、可能的安全问题、在其他
-地方发现的代码重复、足够的文档、对性能的不利影响、用户空间ABI更改等。所有
-类型的检查,如果它们导致更好的代码进入内核,都是受欢迎和值得的。
+不同的开发人员将从不同的角度审查代码。部分人会主要关注代码风格以及代码行是
+否有尾随空格。其他人会主要关注补丁作为一个整体实现的变更是否对内核有好处。
+同时也有人会检查是否存在锁问题、堆栈使用过度、可能的安全问题、在其他地方
+发现的代码重复、足够的文档、对性能的不利影响、用户空间ABI更改等。所有类型
+的检查,只要它们能引导更好的代码进入内核,都是受欢迎和值得的。
diff --git a/Documentation/translations/zh_CN/process/8.Conclusion.rst b/Documentation/translations/zh_CN/process/8.Conclusion.rst
index 2bbd76161e10..643b88af97bb 100644
--- a/Documentation/translations/zh_CN/process/8.Conclusion.rst
+++ b/Documentation/translations/zh_CN/process/8.Conclusion.rst
@@ -1,7 +1,13 @@
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/8.Conclusion.rst <development_conclusion>`
-:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+:Translator:
+
+ 时奎亮 Alex Shi <alex.shi@linux.alibaba.com>
+
+:校译:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
.. _cn_development_conclusion:
@@ -9,56 +15,55 @@
========
关于Linux内核开发和相关主题的信息来源很多。首先是在内核源代码分发中找到的
-文档目录。顶级 :ref:`Documentation/translations/zh_CN/process/howto.rst <cn_process_howto>`
-文件是一个重要的起点
+文档目录。顶级
+:ref:`Documentation/translations/zh_CN/process/howto.rst <cn_process_howto>`
+文件是一个重要的起点;
:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
-和 :ref:`process/submitting-drivers.rst <submittingdrivers>`
也是所有内核开发人员都应该阅读的内容。许多内部内核API都是使用kerneldoc机制
-记录的;“make htmldocs”或“make pdfdocs”可用于以HTML或PDF格式生成这些文档(
-尽管某些发行版提供的tex版本会遇到内部限制,无法正确处理文档)。
+记录的;“make htmldocs”或“make pdfdocs”可用于以HTML或PDF格式生成这些文档
+(尽管某些发行版提供的tex版本会遇到内部限制,无法正确处理文档)。
-不同的网站在各个细节层次上讨论内核开发。您的作者想谦虚地建议用 http://lwn.net/
-作为来源;有关许多特定内核主题的信息可以通过以下网址的lwn内核索引找到:
+不同的网站在各个细节层次上讨论内核开发。本文作者想谦虚地建议用 https://lwn.net/
+作为来源;有关许多特定内核主题的信息可以通过以下网址的 LWN 内核索引找到:
- http://lwn.net/kernel/index/
+ http://lwn.net/kernel/index/
除此之外,内核开发人员的一个宝贵资源是:
- http://kernelnewbies.org/
+ https://kernelnewbies.org/
-当然,我们不应该忘记 http://kernel.org/ 这是内核发布信息的最终位置。
+当然,也不应该忘记 https://kernel.org/ ,这是内核发布信息的最终位置。
关于内核开发有很多书:
- Linux设备驱动程序,第三版(Jonathan Corbet、Alessandro Rubini和Greg Kroah Hartman)。
- 在线:http://lwn.net/kernel/ldd3/
+ 《Linux设备驱动程序》第三版(Jonathan Corbet、Alessandro Rubini和Greg Kroah Hartman)
+ 线上版本在 http://lwn.net/kernel/ldd3/
- Linux内核开发(Robert Love)。
+ 《Linux内核设计与实现》(Robert Love)
- 了解Linux内核(Daniel Bovet和Marco Cesati)。
+ 《深入理解Linux内核》(Daniel Bovet和Marco Cesati)
-然而,所有这些书都有一个共同的缺点:当它们上架时,它们往往有些过时,而且它们
-已经上架一段时间了。不过,在那里还可以找到相当多的好信息。
+然而,所有这些书都有一个共同的缺点:它们上架时就往往有些过时,而且已经上架
+一段时间了。不过,在那里还是可以找到相当多的好信息。
有关git的文档,请访问:
- http://www.kernel.org/pub/software/scm/git/docs/
+ https://www.kernel.org/pub/software/scm/git/docs/
- http://www.kernel.org/pub/software/scm/git/docs/user-manual.html
+ https://www.kernel.org/pub/software/scm/git/docs/user-manual.html
结论
====
-祝贺所有通过这篇冗长的文件的人。希望它能够帮助您理解Linux内核是如何开发的,
+祝贺所有通过这篇冗长的文档的人。希望它能够帮助您理解Linux内核是如何开发的,
以及您如何参与这个过程。
-最后,重要的是参与。任何开源软件项目都不超过其贡献者投入其中的总和。Linux内核
-的发展速度和以前一样快,因为它得到了大量开发人员的帮助,他们都在努力使它变得
-更好。内核是一个主要的例子,说明当成千上万的人为了一个共同的目标一起工作时,
-可以做些什么。
+最后,重要的是参与。任何开源软件项目都不会超过其贡献者投入其中的总和。Linux
+内核的发展速度和以前一样快,因为它得到了大量开发人员的帮助,他们都在努力使它
+变得更好。内核是一个最成功的例子,说明了当成千上万的人为了一个共同的目标一起
+工作时,可以做出什么。
-不过,内核总是可以从更大的开发人员基础中获益。总有更多的工作要做。但是,同样
+不过,内核总是可以从更大的开发人员基础中获益。总有更多的工作要做。但是同样
重要的是,Linux生态系统中的大多数其他参与者可以通过为内核做出贡献而受益。使
代码进入主线是提高代码质量、降低维护和分发成本、提高对内核开发方向的影响程度
-等的关键。这是一种人人都赢的局面。踢开你的编辑,来加入我们吧,你会非常受
-欢迎的。
+等的关键。这是一种共赢的局面。启动你的编辑器,来加入我们吧;你会非常受欢迎的。
diff --git a/Documentation/translations/zh_CN/process/coding-style.rst b/Documentation/translations/zh_CN/process/coding-style.rst
index 4f6237392e65..fa28ef0a7fee 100644
--- a/Documentation/translations/zh_CN/process/coding-style.rst
+++ b/Documentation/translations/zh_CN/process/coding-style.rst
@@ -1,21 +1,23 @@
.. include:: ../disclaimer-zh_CN.rst
-:Original: :ref:`Documentation/process/coding-style.rst <codingstyle>`
+:Original: Documentation/process/coding-style.rst
.. _cn_codingstyle:
-译者::
+:译者:
+ - 张乐 Zhang Le <r0bertz@gentoo.org>
+ - Andy Deng <theandy.deng@gmail.com>
+ - 吴想成 <bobwxc@email.cn>
- 中文版维护者: 张乐 Zhang Le <r0bertz@gentoo.org>
- 中文版翻译者: 张乐 Zhang Le <r0bertz@gentoo.org>
- 中文版校译者: 王聪 Wang Cong <xiyou.wangcong@gmail.com>
- wheelz <kernel.zeng@gmail.com>
- 管旭东 Xudong Guan <xudong.guan@gmail.com>
- Li Zefan <lizf@cn.fujitsu.com>
- Wang Chen <wangchen@cn.fujitsu.com>
+:校译:
+ - 王聪 Wang Cong <xiyou.wangcong@gmail.com>
+ - wheelz <kernel.zeng@gmail.com>
+ - 管旭东 Xudong Guan <xudong.guan@gmail.com>
+ - Li Zefan <lizf@cn.fujitsu.com>
+ - Wang Chen <wangchen@cn.fujitsu.com>
Linux 内核代码风格
-=========================
+==================
这是一个简短的文档,描述了 linux 内核的首选代码风格。代码风格是因人而异的,
而且我不愿意把自己的观点强加给任何人,但这就像我去做任何事情都必须遵循的原则
@@ -29,7 +31,7 @@ Linux 内核代码风格
1) 缩进
---------------
+-------
制表符是 8 个字符,所以缩进也是 8 个字符。有些异端运动试图将缩进变为 4 (甚至
2!) 字符深,这几乎相当于尝试将圆周率的值定义为 3。
@@ -61,7 +63,7 @@ Linux 内核代码风格
case 'K':
case 'k':
mem <<= 10;
- /* fall through */
+ fallthrough;
default:
break;
}
@@ -73,6 +75,22 @@ Linux 内核代码风格
if (condition) do_this;
do_something_everytime;
+不要使用逗号来避免使用大括号:
+
+.. code-block:: c
+
+ if (condition)
+ do_this(), do_that();
+
+使用大括号包裹多语句:
+
+.. code-block:: c
+
+ if (condition) {
+ do_this();
+ do_that();
+ }
+
也不要在一行里放多个赋值语句。内核代码风格超级简单。就是避免可能导致别人误读
的表达式。
@@ -83,20 +101,25 @@ Linux 内核代码风格
2) 把长的行和字符串打散
-------------------------------
+-----------------------
代码风格的意义就在于使用平常使用的工具来维持代码的可读性和可维护性。
每一行的长度的限制是 80 列,我们强烈建议您遵守这个惯例。
长于 80 列的语句要打散成有意义的片段。除非超过 80 列能显著增加可读性,并且不
-会隐藏信息。子片段要明显短于母片段,并明显靠右。这同样适用于有着很长参数列表
-的函数头。然而,绝对不要打散对用户可见的字符串,例如 printk 信息,因为这样就
+会隐藏信息。
+
+子片段要明显短于母片段,并明显靠右。一种非常常用的样式是将子体与函数左括号对齐。
+
+这同样适用于有着很长参数列表的函数头。
+
+然而,绝对不要打散对用户可见的字符串,例如 printk 信息,因为这样就
很难对它们 grep。
3) 大括号和空格的放置
-------------------------------
+---------------------
C 语言风格中另外一个常见问题是大括号的放置。和缩进大小不同,选择或弃用某种放
置策略并没有多少技术上的原因,不过首选的方式,就像 Kernighan 和 Ritchie 展示
@@ -132,12 +155,12 @@ C 语言风格中另外一个常见问题是大括号的放置。和缩进大小
body of function
}
-全世界的异端可能会抱怨这个不一致性是... 呃... 不一致的,不过所有思维健全的人
+全世界的异端可能会抱怨这个不一致性是……呃……不一致,不过所有思维健全的人
都知道 (a) K&R 是 **正确的** 并且 (b) K&R 是正确的。此外,不管怎样函数都是特
殊的 (C 函数是不能嵌套的)。
注意结束大括号独自占据一行,除非它后面跟着同一个语句的剩余部分,也就是 do 语
-句中的 "while" 或者 if 语句中的 "else",像这样:
+句中的 ``while`` 或者 if 语句中的 ``else`` ,像这样:
.. code-block:: c
@@ -191,7 +214,7 @@ C 语言风格中另外一个常见问题是大括号的放置。和缩进大小
}
3.1) 空格
-********************
+*********
Linux 内核的空格使用方式 (主要) 取决于它是用于函数还是关键字。(大多数) 关键字
后要加一个空格。值得注意的例外是 sizeof, typeof, alignof 和 __attribute__,这
@@ -254,7 +277,7 @@ Linux 内核的空格使用方式 (主要) 取决于它是用于函数还是关
4) 命名
-------------------------------
+-------
C 是一个简朴的语言,你的命名也应该这样。和 Modula-2 和 Pascal 程序员不同,
C 程序员不使用类似 ThisVariableIsATemporaryCounter 这样华丽的名字。C 程序员会
@@ -268,19 +291,38 @@ C 程序员不使用类似 ThisVariableIsATemporaryCounter 这样华丽的名字
``count_active_users()`` 或者类似的名字,你不应该叫它 ``cntuser()`` 。
在函数名中包含函数类型 (所谓的匈牙利命名法) 是脑子出了问题——编译器知道那些类
-型而且能够检查那些类型,这样做只能把程序员弄糊涂了。难怪微软总是制造出有问题
-的程序。
+型而且能够检查那些类型,这样做只能把程序员弄糊涂了。
本地变量名应该简短,而且能够表达相关的含义。如果你有一些随机的整数型的循环计
数器,它应该被称为 ``i`` 。叫它 ``loop_counter`` 并无益处,如果它没有被误解的
可能的话。类似的, ``tmp`` 可以用来称呼任意类型的临时变量。
如果你怕混淆了你的本地变量名,你就遇到另一个问题了,叫做函数增长荷尔蒙失衡综
-合症。请看第六章 (函数)。
+合征。请看第六章 (函数)。
+对于符号名称和文档,避免引入新的“master/slave”(或独立于“master”的“slave”)
+和“blacklist/whitelist”。
+
+“master/slave”推荐替换为:
+ '{primary,main} / {secondary,replica,subordinate}'
+ '{initiator,requester} / {target,responder}'
+ '{controller,host} / {device,worker,proxy}'
+ 'leader/follower'
+ 'director/performer'
+
+“blacklist/whitelist”推荐替换为:
+ 'denylist/allowlist'
+ 'blocklist/passlist'
+
+引入新用法的例外情况是:维护用户空间ABI/API,或更新现有(截至2020年)硬件或
+协议规范的代码时要求这些术语。对于新规范,尽可能将术语的规范用法转换为内核
+编码标准。
+
+.. warning::
+ 以上主从、黑白名单规则不适用于中文文档,请勿更改中文术语!
5) Typedef
------------
+----------
不要使用类似 ``vps_t`` 之类的东西。
@@ -309,7 +351,7 @@ C 程序员不使用类似 ThisVariableIsATemporaryCounter 这样华丽的名字
.. note::
- 不透明性和 "访问函数" 本身是不好的。我们使用 pte_t 等类型的原因在于真
+ 不透明性和“访问函数”本身是不好的。我们使用 pte_t 等类型的原因在于真
的是完全没有任何共用的可访问信息。
(b) 清楚的整数类型,如此,这层抽象就可以 **帮助** 消除到底是 ``int`` 还是
@@ -354,7 +396,7 @@ C 程序员不使用类似 ThisVariableIsATemporaryCounter 这样华丽的名字
6) 函数
-------------------------------
+-------
函数应该简短而漂亮,并且只完成一件事情。函数应该可以一屏或者两屏显示完 (我们
都知道 ISO/ANSI 屏幕大小是 80x24),只做一件事情,而且把它做好。
@@ -384,12 +426,46 @@ C 程序员不使用类似 ThisVariableIsATemporaryCounter 这样华丽的名字
}
EXPORT_SYMBOL(system_is_up);
-在函数原型中,包含函数名和它们的数据类型。虽然 C 语言里没有这样的要求,在
+6.1) 函数原型
+*************
+
+在函数原型中包含参数名和它们的数据类型。虽然 C 语言里没有这样的要求,但在
Linux 里这是提倡的做法,因为这样可以很简单的给读者提供更多的有价值的信息。
+不要在函数声明里使用 ``extern`` 关键字,因为这会导致代码行变长,并且不是严格
+必需的。
+
+写函数原型时,请保持 `元素顺序规则 <https://lore.kernel.org/mm-commits/CAHk-=wiOCLRny5aifWNhr621kYrJwhfURsa0vFPeUEm8mF0ufg@mail.gmail.com/>`_ 。
+例如下列函数声明::
+
+ __init void * __must_check action(enum magic value, size_t size, u8 count,
+ char *fmt, ...) __printf(4, 5) __malloc;
+
+推荐的函数原型元素顺序是:
+
+- 储存类型(下方的 ``static __always_inline`` ,注意 ``__always_inline``
+ 技术上来讲是个属性但被当做 ``inline`` )
+- 储存类型属性(上方的 ``__init`` ——即节声明,但也像 ``__cold`` )
+- 返回类型(上方的 ``void *`` )
+- 返回类型属性(上方的 ``__must_check`` )
+- 函数名(上方的 ``action`` )
+- 函数参数(上方的 ``(enum magic value, size_t size, u8 count, char *fmt, ...)`` ,
+ 注意必须写上参数名)
+- 函数参数属性(上方的 ``__printf(4, 5)`` )
+- 函数行为属性(上方的 ``__malloc`` )
+
+请注意,对于函数 **定义** (即实际函数体),编译器不允许在函数参数之后添加函
+数参数属性。在这种情况下,它们应该跟随存储类型属性(例如,与上面的 **声明**
+示例相比,请注意下面的 ``__printf(4, 5)`` 的位置发生了变化)::
+
+ static __always_inline __init __printf(4, 5) void * __must_check action(enum magic value,
+ size_t size, u8 count, char *fmt, ...) __malloc
+ {
+ ...
+ }
7) 集中的函数退出途径
-------------------------------
+---------------------
虽然被某些人声称已经过时,但是 goto 语句的等价物还是经常被编译器所使用,具体
形式是无条件跳转指令。
@@ -433,7 +509,7 @@ Linux 里这是提倡的做法,因为这样可以很简单的给读者提供
return result;
}
-一个需要注意的常见错误是 ``一个 err 错误`` ,就像这样:
+一个需要注意的常见错误是 ``单 err 错误`` ,就像这样:
.. code-block:: c
@@ -457,19 +533,19 @@ Linux 里这是提倡的做法,因为这样可以很简单的给读者提供
8) 注释
-------------------------------
+-------
注释是好的,不过有过度注释的危险。永远不要在注释里解释你的代码是如何运作的:
更好的做法是让别人一看你的代码就可以明白,解释写的很差的代码是浪费时间。
-一般的,你想要你的注释告诉别人你的代码做了什么,而不是怎么做的。也请你不要把
+一般来说你用注释告诉别人你的代码做了什么,而不是怎么做的。也请你不要把
注释放在一个函数体内部:如果函数复杂到你需要独立的注释其中的一部分,你很可能
需要回到第六章看一看。你可以做一些小注释来注明或警告某些很聪明 (或者槽糕) 的
做法,但不要加太多。你应该做的,是把注释放在函数的头部,告诉人们它做了什么,
也可以加上它做这些事情的原因。
-当注释内核 API 函数时,请使用 kernel-doc 格式。请看
-Documentation/doc-guide/ 和 scripts/kernel-doc 以获得详细信息。
+当注释内核 API 函数时,请使用 kernel-doc 格式。详见
+Documentation/translations/zh_CN/doc-guide/index.rst 和 scripts/kernel-doc 。
长 (多行) 注释的首选风格是:
@@ -501,17 +577,18 @@ Documentation/doc-guide/ 和 scripts/kernel-doc 以获得详细信息。
9) 你已经把事情弄糟了
-------------------------------
+---------------------
-这没什么,我们都是这样。可能你的使用了很长时间 Unix 的朋友已经告诉你
+这没什么,我们都是这样。可能你长期使用 Unix 的朋友已经告诉你
``GNU emacs`` 能自动帮你格式化 C 源代码,而且你也注意到了,确实是这样,不过它
所使用的默认值和我们想要的相去甚远 (实际上,甚至比随机打的还要差——无数个猴子
-在 GNU emacs 里打字永远不会创造出一个好程序) (译注:Infinite Monkey Theorem)
+在 GNU emacs 里打字永远不会创造出一个好程序)
+*(译注:Infinite Monkey Theorem)*
所以你要么放弃 GNU emacs,要么改变它让它使用更合理的设定。要采用后一个方案,
你可以把下面这段粘贴到你的 .emacs 文件里。
-.. code-block:: none
+.. code-block:: elisp
(defun c-lineup-arglist-tabs-only (ignored)
"Line up argument lists by tabs, not spaces"
@@ -530,7 +607,7 @@ Documentation/doc-guide/ 和 scripts/kernel-doc 以获得详细信息。
(c-offsets-alist . (
(arglist-close . c-lineup-arglist-tabs-only)
(arglist-cont-nonempty .
- (c-lineup-gcc-asm-reg c-lineup-arglist-tabs-only))
+ (c-lineup-gcc-asm-reg c-lineup-arglist-tabs-only))
(arglist-intro . +)
(brace-list-intro . +)
(c . c-lineup-C-comments)
@@ -574,9 +651,14 @@ Documentation/doc-guide/ 和 scripts/kernel-doc 以获得详细信息。
``indent`` 有很多选项,特别是重新格式化注释的时候,你可能需要看一下它的手册。
不过记住: ``indent`` 不能修正坏的编程习惯。
+请注意,您还可以使用 ``clang-format`` 工具帮助您处理这些规则,快速自动重新格
+式化部分代码,并审阅整个文件以发现代码风格错误、打字错误和可能的改进。它还可
+以方便地排序 ``#include`` ,对齐变量/宏,重排文本和其他类似任务。
+详见 Documentation/process/clang-format.rst 。
+
10) Kconfig 配置文件
-------------------------------
+--------------------
对于遍布源码树的所有 Kconfig* 配置文件来说,它们缩进方式有所不同。紧挨着
``config`` 定义的行,用一个制表符缩进,然而 help 信息的缩进则额外增加 2 个空
@@ -599,11 +681,11 @@ Documentation/doc-guide/ 和 scripts/kernel-doc 以获得详细信息。
depends on ADFS_FS
...
-要查看配置文件的完整文档,请看 Documentation/kbuild/kconfig-language.rst。
+要查看配置文件的完整文档,请看 Documentation/kbuild/kconfig-language.rst 。
11) 数据结构
-------------------------------
+------------
如果一个数据结构,在创建和销毁它的单线执行环境之外可见,那么它必须要有一个引
用计数器。内核里没有垃圾收集 (并且内核之外的垃圾收集慢且效率低下),这意味着你
@@ -627,7 +709,7 @@ mm_count),和文件系统 (``struct super_block``: s_count 和 s_active) 中
12) 宏,枚举和RTL
-------------------------------
+-----------------
用于定义常量的宏的名字及枚举里的标签需要大写。
@@ -639,7 +721,7 @@ mm_count),和文件系统 (``struct super_block``: s_count 和 s_active) 中
宏的名字请用大写字母,不过形如函数的宏的名字可以用小写字母。
-一般的,如果能写成内联函数就不要写成像函数的宏。
+通常如果能写成内联函数就不要写成像函数的宏。
含有多个语句的宏应该被包含在一个 do-while 代码块里:
@@ -697,18 +779,18 @@ mm_count),和文件系统 (``struct super_block``: s_count 和 s_active) 中
(ret); \
})
-ret 是本地变量的通用名字 - __foo_ret 更不容易与一个已存在的变量冲突。
+ret 是本地变量的通用名字—— __foo_ret 更不容易与一个已存在的变量冲突。
cpp 手册对宏的讲解很详细。gcc internals 手册也详细讲解了 RTL,内核里的汇编语
言经常用到它。
13) 打印内核消息
-------------------------------
+----------------
-内核开发者应该是受过良好教育的。请一定注意内核信息的拼写,以给人以好的印象。
+内核开发者应该看起来有文化。请一定注意内核信息的拼写,以给人良好的印象。
不要用不规范的单词比如 ``dont``,而要用 ``do not`` 或者 ``don't`` 。保证这些信
-息简单明了,无歧义。
+息简单明了、无歧义。
内核信息不必以英文句号结束。
@@ -725,17 +807,18 @@ dev_info() 等等。对于那些不和某个特定设备相关连的信息,<li
或设定了 CONFIG_DYNAMIC_DEBUG。实际这同样是为了 dev_dbg(),一个相关约定是在一
个已经开启了 DEBUG 时,使用 VERBOSE_DEBUG 来添加 dev_vdbg()。
-许多子系统拥有 Kconfig 调试选项来开启 -DDEBUG 在对应的 Makefile 里面;在其他
+许多子系统拥有 Kconfig 调试选项来开启对应 Makefile 里面的 -DDEBUG;在其他
情况下,特殊文件使用 #define DEBUG。当一条调试信息需要被无条件打印时,例如,
如果已经包含一个调试相关的 #ifdef 条件,printk(KERN_DEBUG ...) 就可被使用。
14) 分配内存
-------------------------------
+------------
内核提供了下面的一般用途的内存分配函数:
kmalloc(), kzalloc(), kmalloc_array(), kcalloc(), vmalloc() 和 vzalloc()。
-请参考 API 文档以获取有关它们的详细信息。
+请参考 API 文档以获取有关它们的详细信息:
+Documentation/translations/zh_CN/core-api/memory-allocation.rst 。
传递结构体大小的首选形式是这样的:
@@ -762,11 +845,13 @@ kmalloc(), kzalloc(), kmalloc_array(), kcalloc(), vmalloc() 和 vzalloc()。
p = kcalloc(n, sizeof(...), ...);
-两种形式检查分配大小 n * sizeof(...) 的溢出,如果溢出返回 NULL。
+两种形式都会检查分配 n * sizeof(...) 大小时内存的溢出,如果溢出返回 NULL。
+在没有 __GFP_NOWARN 的情况下使用时,这些通用分配函数都会在失败时发起堆栈转储,
+因此当返回NULL时,没有必要发出额外的失败消息。
15) 内联弊病
-------------------------------
+------------
有一个常见的误解是 ``内联`` 是 gcc 提供的可以让代码运行更快的一个选项。虽然使
用内联函数有时候是恰当的 (比如作为一种替代宏的方式,请看第十二章),不过很多情
@@ -787,7 +872,7 @@ inline gcc 也可以自动使其内联。而且其他用户可能会要求移除
16) 函数返回值及命名
-------------------------------
+--------------------
函数可以返回多种不同类型的值,最常见的一种是表明函数执行成功或者失败的值。这样
的一个值可以表示为一个错误代码整数 (-Exxx=失败,0=成功) 或者一个 ``成功``
@@ -798,7 +883,7 @@ inline gcc 也可以自动使其内联。而且其他用户可能会要求移除
产生这种 bug,请遵循下面的惯例::
如果函数的名字是一个动作或者强制性的命令,那么这个函数应该返回错误代
- 码整数。如果是一个判断,那么函数应该返回一个 "成功" 布尔值。
+ 码整数。如果是一个判断,那么函数应该返回一个“成功”布尔值。
比如, ``add work`` 是一个命令,所以 add_work() 在成功时返回 0,在失败时返回
-EBUSY。类似的,因为 ``PCI device present`` 是一个判断,所以 pci_dev_present()
@@ -807,13 +892,35 @@ inline gcc 也可以自动使其内联。而且其他用户可能会要求移除
所有 EXPORTed 函数都必须遵守这个惯例,所有的公共函数也都应该如此。私有
(static) 函数不需要如此,但是我们也推荐这样做。
-返回值是实际计算结果而不是计算是否成功的标志的函数不受此惯例的限制。一般的,
+返回值是实际计算结果而不是计算是否成功的标志的函数不受此惯例的限制。通常
他们通过返回一些正常值范围之外的结果来表示出错。典型的例子是返回指针的函数,
他们使用 NULL 或者 ERR_PTR 机制来报告错误。
+17) 使用布尔类型
+----------------
+
+Linux内核布尔(bool)类型是C99 _Bool类型的别名。布尔值只能为0或1,而对布尔的
+隐式或显式转换将自动将值转换为true或false。在使用布尔类型时 **不需要** 构造,
+它会消除一类错误。
+
+使用布尔值时,应使用true和false定义,而不是1和0。
-17) 不要重新发明内核宏
-------------------------------
+布尔函数返回类型和堆栈变量总是可以在适当的时候使用。鼓励使用布尔来提高可读性,
+并且布尔值在存储时通常比“int”更好。
+
+如果缓存行布局或值的大小很重要,请不要使用布尔,因为其大小和对齐方式根据编译
+的体系结构而不同。针对对齐和大小进行优化的结构体不应使用布尔。
+
+如果一个结构体有多个true/false值,请考虑将它们合并为具有1比特成员的位域,或使
+用适当的固定宽度类型,如u8。
+
+类似地,对于函数参数,多个true/false值可以合并为单个按位的“标志”参数,如果调
+用点具有裸true/false常量,“标志”参数通常是更具可读性的替代方法。
+
+总之,在结构体和参数中有限地使用布尔可以提高可读性。
+
+18) 不要重新发明内核宏
+----------------------
头文件 include/linux/kernel.h 包含了一些宏,你应该使用它们,而不要自己写一些
它们的变种。比如,如果你需要计算一个数组的长度,使用这个宏
@@ -826,18 +933,18 @@ inline gcc 也可以自动使其内联。而且其他用户可能会要求移除
.. code-block:: c
- #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
+ #define sizeof_field(t, f) (sizeof(((t*)0)->f))
还有可以做严格的类型检查的 min() 和 max() 宏,如果你需要可以使用它们。你可以
自己看看那个头文件里还定义了什么你可以拿来用的东西,如果有定义的话,你就不应
在你的代码里自己重新定义。
-18) 编辑器模式行和其他需要罗嗦的事情
---------------------------------------------------
+19) 编辑器模式行和其他需要罗嗦的事情
+------------------------------------
有一些编辑器可以解释嵌入在源文件里的由一些特殊标记标明的配置信息。比如,emacs
-能够解释被标记成这样的行:
+能够解析被标记成这样的行:
.. code-block:: c
@@ -853,7 +960,7 @@ inline gcc 也可以自动使其内联。而且其他用户可能会要求移除
End:
*/
-Vim 能够解释这样的标记:
+Vim 能够解析这样的标记:
.. code-block:: c
@@ -864,8 +971,8 @@ Vim 能够解释这样的标记:
的模式,或者使用其他可以产生正确的缩进的巧妙方法。
-19) 内联汇编
-------------------------------
+20) 内联汇编
+------------
在特定架构的代码中,你可能需要内联汇编与 CPU 和平台相关功能连接。需要这么做时
就不要犹豫。然而,当 C 可以完成工作时,不要平白无故地使用内联汇编。在可能的情
@@ -881,8 +988,8 @@ Vim 能够解释这样的标记:
移除了。你不必总是这样做,尽管,这不必要的举动会限制优化。
在写一个包含多条指令的单个内联汇编语句时,把每条指令用引号分割而且各占一行,
-除了最后一条指令外,在每个指令结尾加上 \n\t,让汇编输出时可以正确地缩进下一条
-指令:
+除了最后一条指令外,在每个指令结尾加上 ``\n\t`` ,让汇编输出时可以正确地缩进
+下一条指令:
.. code-block:: c
@@ -891,10 +998,10 @@ Vim 能够解释这样的标记:
: /* outputs */ : /* inputs */ : /* clobbers */);
-20) 条件编译
-------------------------------
+21) 条件编译
+------------
-只要可能,就不要在 .c 文件里面使用预处理条件 (#if, #ifdef);这样做让代码更难
+只要可能,就不要在 .c 文件里面使用预处理条件 (#if, #ifdef);这样做会让代码更难
阅读并且更难去跟踪逻辑。替代方案是,在头文件中用预处理条件提供给那些 .c 文件
使用,再给 #else 提供一个空桩 (no-op stub) 版本,然后在 .c 文件内无条件地调用
那些 (定义在头文件内的) 函数。这样做,编译器会避免为桩函数 (stub) 的调用生成
@@ -905,8 +1012,8 @@ Vim 能够解释这样的标记:
条件到这个辅助函数内。
如果你有一个在特定配置中,可能变成未使用的函数或变量,编译器会警告它定义了但
-未使用,把它标记为 __maybe_unused 而不是将它包含在一个预处理条件中。(然而,如
-果一个函数或变量总是未使用,就直接删除它。)
+未使用,请把它标记为 __maybe_unused 而不是将它包含在一个预处理条件中。(然而,
+如果一个函数或变量总是未使用,就直接删除它。)
在代码中,尽可能地使用 IS_ENABLED 宏来转化某个 Kconfig 标记为 C 的布尔
表达式,并在一般的 C 条件中使用它:
@@ -932,23 +1039,45 @@ Vim 能够解释这样的标记:
#endif /* CONFIG_SOMETHING */
-附录 I) 参考
--------------------
+附录 I) 参考资料
+----------------
-The C Programming Language, 第二版
+The C Programming Language, 2nd Edition
作者:Brian W. Kernighan 和 Denni M. Ritchie.
Prentice Hall, Inc., 1988.
-ISBN 0-13-110362-8 (软皮), 0-13-110370-9 (硬皮).
+ISBN 0-13-110362-8 (平装), 0-13-110370-9 (精装).
+
+.. note::
+
+ 《C程序设计语言(第2版)》
+ 作者:[美] Brian W. Kernighan / [美] Dennis M. Ritchie
+ 译者:徐宝文 / 李志 / 尤晋元(审校)
+ 出版社:机械工业出版社,2019
+ ISBN:9787111617945
The Practice of Programming
作者:Brian W. Kernighan 和 Rob Pike.
Addison-Wesley, Inc., 1999.
ISBN 0-201-61586-X.
+.. note::
+
+ 《程序设计实践》
+ 作者:[美] Brian W. Kernighan / [美] Rob Pike
+ 出版社:机械工业出版社,2005
+ ISBN:9787111091578
+
+ 《程序设计实践》
+ 作者:[美] Brian W. Kernighan / Rob Pike
+ 译者:裘宗燕
+ 出版社:机械工业出版社,2000
+ ISBN:9787111075738
+
GNU 手册 - 遵循 K&R 标准和此文本 - cpp, gcc, gcc internals and indent,
-都可以从 http://www.gnu.org/manual/ 找到
+都可以从 https://www.gnu.org/manual/ 找到
WG14 是 C 语言的国际标准化工作组,URL: http://www.open-std.org/JTC1/SC22/WG14/
-Kernel process/coding-style.rst,作者 greg@kroah.com 发表于 OLS 2002:
+内核文档 Documentation/process/coding-style.rst,
+作者 greg@kroah.com 发表于 OLS 2002:
http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
diff --git a/Documentation/translations/zh_CN/process/development-process.rst b/Documentation/translations/zh_CN/process/development-process.rst
index 30cffe66c075..c10d8e2e21eb 100644
--- a/Documentation/translations/zh_CN/process/development-process.rst
+++ b/Documentation/translations/zh_CN/process/development-process.rst
@@ -8,9 +8,10 @@
内核开发过程指南
================
-内容:
+本文档的目的是帮助开发人员(及其经理)以最小的挫折感与开发社区合作。它试图记录这个社区如何以一种不熟悉Linux内核开发(或者实际上是自由软件开发)的人可以访问的方式工作。虽然这里有一些技术资料,但这是一个面向过程的讨论,不需要深入了解内核编程就可以理解。
.. toctree::
+ :caption: 内容
:numbered:
:maxdepth: 2
@@ -22,5 +23,3 @@
6.Followthrough
7.AdvancedTopics
8.Conclusion
-
-本文档的目的是帮助开发人员(及其经理)以最小的挫折感与开发社区合作。它试图记录这个社区如何以一种不熟悉Linux内核开发(或者实际上是自由软件开发)的人可以访问的方式工作。虽然这里有一些技术资料,但这是一个面向过程的讨论,不需要深入了解内核编程就可以理解。
diff --git a/Documentation/translations/zh_CN/process/email-clients.rst b/Documentation/translations/zh_CN/process/email-clients.rst
index 102023651118..34d51cdadc7b 100644
--- a/Documentation/translations/zh_CN/process/email-clients.rst
+++ b/Documentation/translations/zh_CN/process/email-clients.rst
@@ -1,17 +1,20 @@
-.. _cn_email_clients:
+.. SPDX-License-Identifier: GPL-2.0-or-later
.. include:: ../disclaimer-zh_CN.rst
-:Original: :ref:`Documentation/process/email-clients.rst <email_clients>`
+.. _cn_email_clients:
-译者::
+:Original: Documentation/process/email-clients.rst
- 中文版维护者: 贾威威 Harry Wei <harryxiyou@gmail.com>
- 中文版翻译者: 贾威威 Harry Wei <harryxiyou@gmail.com>
- 时奎亮 Alex Shi <alex.shi@linux.alibaba.com>
- 中文版校译者: Yinglin Luan <synmyth@gmail.com>
- Xiaochen Wang <wangxiaochen0@gmail.com>
- yaxinsn <yaxinsn@163.com>
+:译者:
+ - 贾威威 Harry Wei <harryxiyou@gmail.com>
+ - 时奎亮 Alex Shi <alexs@kernel.org>
+ - 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+:校译:
+ - Yinglin Luan <synmyth@gmail.com>
+ - Xiaochen Wang <wangxiaochen0@gmail.com>
+ - yaxinsn <yaxinsn@163.com>
Linux邮件客户端配置信息
=======================
@@ -27,12 +30,17 @@ Git
改日志。如果工作正常,再将补丁发送到相应的邮件列表。
-普通配置
+通用配置
--------
+
Linux内核补丁是通过邮件被提交的,最好把补丁作为邮件体的内嵌文本。有些维护者
接收附件,但是附件的内容格式应该是"text/plain"。然而,附件一般是不赞成的,
因为这会使补丁的引用部分在评论过程中变的很困难。
+同时也强烈建议在补丁或其他邮件的正文中使用纯文本格式。https://useplaintext.email
+有助于了解如何配置你喜欢的邮件客户端,并在您还没有首选的情况下列出一些推荐的
+客户端。
+
用来发送Linux内核补丁的邮件客户端在发送补丁时应该处于文本的原始状态。例如,
他们不能改变或者删除制表符或者空格,甚至是在每一行的开头或者结尾。
@@ -40,17 +48,17 @@ Linux内核补丁是通过邮件被提交的,最好把补丁作为邮件体的
不要让你的邮件客户端进行自动换行。这样也会破坏你的补丁。
-邮件客户端不能改变文本的字符集编码方式。要发送的补丁只能是ASCII或者UTF-8编码方式,
-如果你使用UTF-8编码方式发送邮件,那么你将会避免一些可能发生的字符集问题。
+邮件客户端不能改变文本的字符集编码方式。要发送的补丁只能是ASCII或者UTF-8编码
+方式,如果你使用UTF-8编码方式发送邮件,那么你将会避免一些可能发生的字符集问题。
-邮件客户端应该形成并且保持 References: 或者 In-Reply-To: 标题,那么
-邮件话题就不会中断。
+邮件客户端应该生成并且保持“References:”或者“In-Reply-To:”邮件头,这样邮件会话
+就不会中断。
-复制粘帖(或者剪贴粘帖)通常不能用于补丁,因为制表符会转换为空格。使用xclipboard, xclip
-或者xcutsel也许可以,但是最好测试一下或者避免使用复制粘帖。
+复制粘帖(或者剪贴粘帖)通常不能用于补丁,因为制表符会转换为空格。使用xclipboard,
+xclip或者xcutsel也许可以,但是最好测试一下或者避免使用复制粘帖。
-不要在使用PGP/GPG署名的邮件中包含补丁。这样会使得很多脚本不能读取和适用于你的补丁。
-(这个问题应该是可以修复的)
+不要在使用PGP/GPG签名的邮件中包含补丁。这样会使得很多脚本不能读取和适用于你的
+补丁。(这个问题应该是可以修复的)
在给内核邮件列表发送补丁之前,给自己发送一个补丁是个不错的主意,保存接收到的
邮件,将补丁用'patch'命令打上,如果成功了,再给内核邮件列表发送。
@@ -58,98 +66,133 @@ Linux内核补丁是通过邮件被提交的,最好把补丁作为邮件体的
一些邮件客户端提示
------------------
+
这里给出一些详细的MUA配置提示,可以用于给Linux内核发送补丁。这些并不意味是
所有的软件包配置总结。
说明:
-TUI = 以文本为基础的用户接口
-GUI = 图形界面用户接口
+
+- TUI = 以文本为基础的用户接口
+- GUI = 图形界面用户接口
Alpine (TUI)
-~~~~~~~~~~~~
+************
配置选项:
-在"Sending Preferences"部分:
-- "Do Not Send Flowed Text"必须开启
-- "Strip Whitespace Before Sending"必须关闭
+在 :menuselection:`Sending Preferences` 菜单:
+
+- :menuselection:`Do Not Send Flowed Text` 必须开启
+- :menuselection:`Strip Whitespace Before Sending` 必须关闭
+
+当写邮件时,光标应该放在补丁会出现的地方,然后按下 :kbd:`CTRL-R` 组合键,使指
+定的补丁文件嵌入到邮件中。
+
+Claws Mail (GUI)
+****************
+
+可以用,有人用它成功地发过补丁。
-当写邮件时,光标应该放在补丁会出现的地方,然后按下CTRL-R组合键,使指定的
-补丁文件嵌入到邮件中。
+用 :menuselection:`Message-->Insert File` (:kbd:`CTRL-I`) 或外置编辑器插入补丁。
+
+若要在Claws编辑窗口重修改插入的补丁,需关闭
+:menuselection:`Configuration-->Preferences-->Compose-->Wrapping`
+的 `Auto wrapping` 。
Evolution (GUI)
-~~~~~~~~~~~~~~~
+***************
-一些开发者成功的使用它发送补丁
+一些开发者成功的使用它发送补丁。
-当选择邮件选项:Preformat
- 从Format->Heading->Preformatted (Ctrl-7)或者工具栏
+撰写邮件时:
+从 :menuselection:`格式-->段落样式-->预格式化` (:kbd:`CTRL-7`)
+或工具栏选择 :menuselection:`预格式化` ;
然后使用:
- Insert->Text File... (Alt-n x)插入补丁文件。
+:menuselection:`插入-->文本文件...` (:kbd:`ALT-N x`) 插入补丁文件。
-你还可以"diff -Nru old.c new.c | xclip",选择Preformat,然后使用中间键进行粘帖。
+你还可以 ``diff -Nru old.c new.c | xclip`` ,选择 :menuselection:`预格式化` ,
+然后使用鼠标中键进行粘帖。
Kmail (GUI)
-~~~~~~~~~~~
+***********
一些开发者成功的使用它发送补丁。
-默认设置不为HTML格式是合适的;不要启用它。
+默认撰写设置禁用HTML格式是合适的;不要启用它。
-当书写一封邮件的时候,在选项下面不要选择自动换行。唯一的缺点就是你在邮件中输入的任何文本
-都不会被自动换行,因此你必须在发送补丁之前手动换行。最简单的方法就是启用自动换行来书写邮件,
-然后把它保存为草稿。一旦你在草稿中再次打开它,它已经全部自动换行了,那么你的邮件虽然没有
-选择自动换行,但是还不会失去已有的自动换行。
+当书写一封邮件的时候,在选项下面不要选择自动换行。唯一的缺点就是你在邮件中输
+入的任何文本都不会被自动换行,因此你必须在发送补丁之前手动换行。最简单的方法
+就是启用自动换行来书写邮件,然后把它保存为草稿。一旦你在草稿中再次打开它,它
+已经全部自动换行了,那么你的邮件虽然没有选择自动换行,但是还不会失去已有的自
+动换行。
-在邮件的底部,插入补丁之前,放上常用的补丁定界符:三个连字号(---)。
+在邮件的底部,插入补丁之前,放上常用的补丁定界符:三个连字符(``---``)。
-然后在"Message"菜单条目,选择插入文件,接着选取你的补丁文件。还有一个额外的选项,你可以
-通过它配置你的邮件建立工具栏菜单,还可以带上"insert file"图标。
+然后在 :menuselection:`信件` 菜单,选择 :menuselection:`插入文本文件` ,接
+着选取你的补丁文件。还有一个额外的选项,你可以通过它配置你的创建新邮件工具栏,
+加上 :menuselection:`插入文本文件` 图标。
-你可以安全地通过GPG标记附件,但是内嵌补丁最好不要使用GPG标记它们。作为内嵌文本的签发补丁,
-当从GPG中提取7位编码时会使他们变的更加复杂。
+将编辑器窗口拉到足够宽避免折行。对于KMail 1.13.5 (KDE 4.5.4),它会在发送邮件
+时对编辑器窗口中显示折行的地方自动换行。在选项菜单中取消自动换行仍不能解决。
+因此,如果你的补丁中有非常长的行,必须在发送之前把编辑器窗口拉得非常宽。
+参见:https://bugs.kde.org/show_bug.cgi?id=174034
-如果你非要以附件的形式发送补丁,那么就右键点击附件,然后选中属性,突出"Suggest automatic
-display",这样内嵌附件更容易让读者看到。
+你可以安全地用GPG签名附件,但是内嵌补丁最好不要使用GPG签名它们。作为内嵌文本
+插入的签名补丁将使其难以从7-bit编码中提取。
-当你要保存将要发送的内嵌文本补丁,你可以从消息列表窗格选择包含补丁的邮件,然后右击选择
-"save as"。你可以使用一个没有更改的包含补丁的邮件,如果它是以正确的形式组成。当你正真在它
-自己的窗口之下察看,那时没有选项可以保存邮件--已经有一个这样的bug被汇报到了kmail的bugzilla
-并且希望这将会被处理。邮件是以只针对某个用户可读写的权限被保存的,所以如果你想把邮件复制到其他地方,
-你不得不把他们的权限改为组或者整体可读。
+如果你非要以附件的形式发送补丁,那么就右键点击附件,然后选择
+:menuselection:`属性` ,打开 :menuselection:`建议自动显示` ,使附件内联更容
+易让读者看到。
+
+当你要保存将要发送的内嵌文本补丁,你可以从消息列表窗格选择包含补丁的邮件,然
+后右键选择 :menuselection:`另存为` 。如果整个电子邮件的组成正确,您可直接将
+其作为补丁使用。电子邮件以当前用户可读写权限保存,因此您必须 ``chmod`` ,以
+使其在复制到别处时用户组和其他人可读。
Lotus Notes (GUI)
-~~~~~~~~~~~~~~~~~
+*****************
不要使用它。
+IBM Verse (Web GUI)
+*******************
+
+同上条。
+
Mutt (TUI)
-~~~~~~~~~~
+**********
+
+很多Linux开发人员使用mutt客户端,这证明它肯定工作得非常漂亮。
-很多Linux开发人员使用mutt客户端,所以证明它肯定工作的非常漂亮。
+Mutt不自带编辑器,所以不管你使用什么编辑器,不自动断行就行。大多数编辑器都有
+:menuselection:`插入文件` 选项,它可以在不改变文件内容的情况下插入文件。
-Mutt不自带编辑器,所以不管你使用什么编辑器都不应该带有自动断行。大多数编辑器都带有
-一个"insert file"选项,它可以通过不改变文件内容的方式插入文件。
+用 ``vim`` 作为mutt的编辑器::
-'vim'作为mutt的编辑器:
set editor="vi"
- 如果使用xclip,敲入以下命令
+如果使用xclip,敲入以下命令::
+
:set paste
- 按中键之前或者shift-insert或者使用
+
+然后再按中键或者shift-insert或者使用::
+
:r filename
-如果想要把补丁作为内嵌文本。
-(a)ttach工作的很好,不带有"set paste"。
+把补丁插入为内嵌文本。
+在未设置 ``set paste`` 时(a)ttach工作的很好。
你可以通过 ``git format-patch`` 生成补丁,然后用 Mutt发送它们::
- $ mutt -H 0001-some-bug-fix.patch
+ $ mutt -H 0001-some-bug-fix.patch
配置选项:
+
它应该以默认设置的形式工作。
-然而,把"send_charset"设置为"us-ascii::utf-8"也是一个不错的主意。
+然而,把 ``send_charset`` 设置一下也是一个不错的主意::
+
+ set send_charset="us-ascii:utf-8"
Mutt 是高度可配置的。 这里是个使用mutt通过 Gmail 发送的补丁的最小配置::
@@ -178,71 +221,107 @@ Mutt 是高度可配置的。 这里是个使用mutt通过 Gmail 发送的补丁
set from = "username@gmail.com"
set use_from = yes
-Mutt文档含有更多信息:
+Mutt文档含有更多信息:
- http://dev.mutt.org/trac/wiki/UseCases/Gmail
+ https://gitlab.com/muttmua/mutt/-/wikis/UseCases/Gmail
- http://dev.mutt.org/doc/manual.html
+ http://www.mutt.org/doc/manual/
Pine (TUI)
-~~~~~~~~~~
+**********
Pine过去有一些空格删减问题,但是这些现在应该都被修复了。
-如果可以,请使用alpine(pine的继承者)
+如果可以,请使用alpine(pine的继承者)。
配置选项:
-- 最近的版本需要消除流程文本
-- "no-strip-whitespace-before-send"选项也是需要的。
+
+- 最近的版本需要 ``quell-flowed-text``
+- ``no-strip-whitespace-before-send`` 选项也是需要的。
Sylpheed (GUI)
-~~~~~~~~~~~~~~
+**************
- 内嵌文本可以很好的工作(或者使用附件)。
- 允许使用外部的编辑器。
-- 对于目录较多时非常慢。
+- 收件箱较多时非常慢。
- 如果通过non-SSL连接,无法使用TLS SMTP授权。
-- 在组成窗口中有一个很有用的ruler bar。
-- 给地址本中添加地址就不会正确的了解显示名。
+- 撰写窗口的标尺很有用。
+- 将地址添加到通讯簿时无法正确理解显示的名称。
Thunderbird (GUI)
-~~~~~~~~~~~~~~~~~
+*****************
+
+Thunderbird是Outlook的克隆版本,它很容易损坏文本,但也有一些方法强制修正。
+
+在完成修改后(包括安装扩展),您需要重新启动Thunderbird。
+
+- 允许使用外部编辑器:
+
+ 使用Thunderbird发补丁最简单的方法是使用扩展来打开您最喜欢的外部编辑器。
+
+ 下面是一些能够做到这一点的扩展样例。
+
+ - “External Editor Revived”
+
+ https://github.com/Frederick888/external-editor-revived
+
+ https://addons.thunderbird.net/en-GB/thunderbird/addon/external-editor-revived/
+
+ 它需要安装“本地消息主机(native messaging host)”。
+ 参见以下文档:
+ https://github.com/Frederick888/external-editor-revived/wiki
+
+ - “External Editor”
+
+ https://github.com/exteditor/exteditor
+
+ 下载并安装此扩展,然后打开 :menuselection:`新建消息` 窗口, 用
+ :menuselection:`查看-->工具栏-->自定义...` 给它增加一个按钮,直接点击此
+ 按钮即可使用外置编辑器。
+
+ 请注意,“External Editor”要求你的编辑器不能fork,换句话说,编辑器必须在
+ 关闭前不返回。你可能需要传递额外的参数或修改编辑器设置。最值得注意的是,
+ 如果您使用的是gvim,那么您必须将 :menuselection:`external editor` 设置的
+ 编辑器字段设置为 ``/usr/bin/gvim --nofork"`` (假设可执行文件在
+ ``/usr/bin`` ),以传递 ``-f`` 参数。如果您正在使用其他编辑器,请阅读其
+ 手册了解如何处理。
-默认情况下,thunderbird很容易损坏文本,但是还有一些方法可以强制它变得更好。
+若要修正内部编辑器,请执行以下操作:
-- 在用户帐号设置里,组成和寻址,不要选择"Compose messages in HTML format"。
+- 修改你的Thunderbird设置,不要使用 ``format=flowed`` !
+ 回到主窗口,按照
+ :menuselection:`主菜单-->首选项-->常规-->配置编辑器...`
+ 打开Thunderbird的配置编辑器。
-- 编辑你的Thunderbird配置设置来使它不要拆行使用:user_pref("mailnews.wraplength", 0);
+ - 将 ``mailnews.send_plaintext_flowed`` 设为 ``false``
-- 编辑你的Thunderbird配置设置,使它不要使用"format=flowed"格式:user_pref("mailnews.
- send_plaintext_flowed", false);
+ - 将 ``mailnews.wraplength`` 从 ``72`` 改为 ``0``
-- 你需要使Thunderbird变为预先格式方式:
- 如果默认情况下你书写的是HTML格式,那不是很难。仅仅从标题栏的下拉框中选择"Preformat"格式。
- 如果默认情况下你书写的是文本格式,你不得把它改为HTML格式(仅仅作为一次性的)来书写新的消息,
- 然后强制使它回到文本格式,否则它就会拆行。要实现它,在写信的图标上使用shift键来使它变为HTML
- 格式,然后标题栏的下拉框中选择"Preformat"格式。
+- 不要写HTML邮件!
+ 回到主窗口,打开
+ :menuselection:`主菜单-->账户设置-->你的@邮件.地址-->通讯录/编写&地址簿` ,
+ 关掉 ``以HTML格式编写消息`` 。
-- 允许使用外部的编辑器:
- 针对Thunderbird打补丁最简单的方法就是使用一个"external editor"扩展,然后使用你最喜欢的
- $EDITOR来读取或者合并补丁到文本中。要实现它,可以下载并且安装这个扩展,然后添加一个使用它的
- 按键View->Toolbars->Customize...最后当你书写信息的时候仅仅点击它就可以了。
+- 只用纯文本格式查看邮件!
+ 回到主窗口, :menuselection:`主菜单-->查看-->消息体为-->纯文本` !
TkRat (GUI)
-~~~~~~~~~~~
+***********
可以使用它。使用"Insert file..."或者外部的编辑器。
Gmail (Web GUI)
-~~~~~~~~~~~~~~~
+***************
不要使用它发送补丁。
Gmail网页客户端自动地把制表符转换为空格。
-虽然制表符转换为空格问题可以被外部编辑器解决,同时它还会使用回车换行把每行拆分为78个字符。
+虽然制表符转换为空格问题可以被外部编辑器解决,但它同时还会使用回车换行把每行
+拆分为78个字符。
-另一个问题是Gmail还会把任何不是ASCII的字符的信息改为base64编码。它把东西变的像欧洲人的名字。
+另一个问题是Gmail还会把任何含有非ASCII的字符的消息改用base64编码,如欧洲人的
+名字。
- ###
diff --git a/Documentation/translations/zh_CN/process/embargoed-hardware-issues.rst b/Documentation/translations/zh_CN/process/embargoed-hardware-issues.rst
new file mode 100644
index 000000000000..cf5f1fca3d92
--- /dev/null
+++ b/Documentation/translations/zh_CN/process/embargoed-hardware-issues.rst
@@ -0,0 +1,228 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: :ref:`Documentation/process/embargoed-hardware-issues.rst <embargoed_hardware_issues>`
+:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+
+被限制的硬件问题
+================
+
+范围
+----
+
+导致安全问题的硬件问题与只影响Linux内核的纯软件错误是不同的安全错误类别。
+
+必须区别对待诸如熔毁(Meltdown)、Spectre、L1TF等硬件问题,因为它们通常会影响
+所有操作系统(“OS”),因此需要在不同的OS供应商、发行版、硬件供应商和其他各方
+之间进行协调。对于某些问题,软件缓解可能依赖于微码或固件更新,这需要进一步的
+协调。
+
+.. _zh_Contact:
+
+接触
+----
+
+Linux内核硬件安全小组独立于普通的Linux内核安全小组。
+
+该小组只负责协调被限制的硬件安全问题。Linux内核中纯软件安全漏洞的报告不由该
+小组处理,报告者将被引导至常规Linux内核安全小组(:ref:`Documentation/admin-guide/
+<securitybugs>`)联系。
+
+可以通过电子邮件 <hardware-security@kernel.org> 与小组联系。这是一份私密的安全
+官名单,他们将帮助您根据我们的文档化流程协调问题。
+
+邮件列表是加密的,发送到列表的电子邮件可以通过PGP或S/MIME加密,并且必须使用报告
+者的PGP密钥或S/MIME证书签名。该列表的PGP密钥和S/MIME证书可从
+https://www.kernel.org/.... 获得。
+
+虽然硬件安全问题通常由受影响的硬件供应商处理,但我们欢迎发现潜在硬件缺陷的研究
+人员或个人与我们联系。
+
+硬件安全官
+^^^^^^^^^^
+
+目前的硬件安全官小组:
+
+ - Linus Torvalds(Linux基金会院士)
+ - Greg Kroah Hartman(Linux基金会院士)
+ - Thomas Gleixner(Linux基金会院士)
+
+邮件列表的操作
+^^^^^^^^^^^^^^
+
+处理流程中使用的加密邮件列表托管在Linux Foundation的IT基础设施上。通过提供这项
+服务,Linux基金会的IT基础设施安全总监在技术上有能力访问被限制的信息,但根据他
+的雇佣合同,他必须保密。Linux基金会的IT基础设施安全总监还负责 kernel.org 基础
+设施。
+
+Linux基金会目前的IT基础设施安全总监是 Konstantin Ryabitsev。
+
+保密协议
+--------
+
+Linux内核硬件安全小组不是正式的机构,因此无法签订任何保密协议。核心社区意识到
+这些问题的敏感性,并提供了一份谅解备忘录。
+
+谅解备忘录
+----------
+
+Linux内核社区深刻理解在不同操作系统供应商、发行商、硬件供应商和其他各方之间
+进行协调时,保持硬件安全问题处于限制状态的要求。
+
+Linux内核社区在过去已经成功地处理了硬件安全问题,并且有必要的机制允许在限制
+限制下进行符合社区的开发。
+
+Linux内核社区有一个专门的硬件安全小组负责初始联系,并监督在限制规则下处理
+此类问题的过程。
+
+硬件安全小组确定开发人员(领域专家),他们将组成特定问题的初始响应小组。最初
+的响应小组可以引入更多的开发人员(领域专家)以最佳的技术方式解决这个问题。
+
+所有相关开发商承诺遵守限制规定,并对收到的信息保密。违反承诺将导致立即从当前
+问题中排除,并从所有相关邮件列表中删除。此外,硬件安全小组还将把违反者排除在
+未来的问题之外。这一后果的影响在我们社区是一种非常有效的威慑。如果发生违规
+情况,硬件安全小组将立即通知相关方。如果您或任何人发现潜在的违规行为,请立即
+向硬件安全人员报告。
+
+流程
+^^^^
+
+由于Linux内核开发的全球分布式特性,面对面的会议几乎不可能解决硬件安全问题。
+由于时区和其他因素,电话会议很难协调,只能在绝对必要时使用。加密电子邮件已被
+证明是解决此类问题的最有效和最安全的通信方法。
+
+开始披露
+""""""""
+
+披露内容首先通过电子邮件联系Linux内核硬件安全小组。此初始联系人应包含问题的
+描述和任何已知受影响硬件的列表。如果您的组织制造或分发受影响的硬件,我们建议
+您也考虑哪些其他硬件可能会受到影响。
+
+硬件安全小组将提供一个特定于事件的加密邮件列表,用于与报告者进行初步讨论、
+进一步披露和协调。
+
+硬件安全小组将向披露方提供一份开发人员(领域专家)名单,在与开发人员确认他们
+将遵守本谅解备忘录和文件化流程后,应首先告知开发人员有关该问题的信息。这些开发
+人员组成初始响应小组,并在初始接触后负责处理问题。硬件安全小组支持响应小组,
+但不一定参与缓解开发过程。
+
+虽然个别开发人员可能通过其雇主受到保密协议的保护,但他们不能以Linux内核开发
+人员的身份签订个别保密协议。但是,他们将同意遵守这一书面程序和谅解备忘录。
+
+披露方应提供已经或应该被告知该问题的所有其他实体的联系人名单。这有几个目的:
+
+ - 披露的实体列表允许跨行业通信,例如其他操作系统供应商、硬件供应商等。
+
+ - 可联系已披露的实体,指定应参与缓解措施开发的专家。
+
+ - 如果需要处理某一问题的专家受雇于某一上市实体或某一上市实体的成员,则响应
+ 小组可要求该实体披露该专家。这确保专家也是实体反应小组的一部分。
+
+披露
+""""
+
+披露方通过特定的加密邮件列表向初始响应小组提供详细信息。
+
+根据我们的经验,这些问题的技术文档通常是一个足够的起点,最好通过电子邮件进行
+进一步的技术澄清。
+
+缓解开发
+""""""""
+
+初始响应小组设置加密邮件列表,或在适当的情况下重新修改现有邮件列表。
+
+使用邮件列表接近于正常的Linux开发过程,并且在过去已经成功地用于为各种硬件安全
+问题开发缓解措施。
+
+邮件列表的操作方式与正常的Linux开发相同。发布、讨论和审查修补程序,如果同意,
+则应用于非公共git存储库,参与开发人员只能通过安全连接访问该存储库。存储库包含
+针对主线内核的主开发分支,并根据需要为稳定的内核版本提供向后移植分支。
+
+最初的响应小组将根据需要从Linux内核开发人员社区中确定更多的专家。引进专家可以
+在开发过程中的任何时候发生,需要及时处理。
+
+如果专家受雇于披露方提供的披露清单上的实体或其成员,则相关实体将要求其参与。
+
+否则,披露方将被告知专家参与的情况。谅解备忘录涵盖了专家,要求披露方确认参与。
+如果披露方有令人信服的理由提出异议,则必须在五个工作日内提出异议,并立即与事件
+小组解决。如果披露方在五个工作日内未作出回应,则视为默许。
+
+在确认或解决异议后,专家由事件小组披露,并进入开发过程。
+
+协调发布
+""""""""
+
+有关各方将协商限制结束的日期和时间。此时,准备好的缓解措施集成到相关的内核树中
+并发布。
+
+虽然我们理解硬件安全问题需要协调限制时间,但限制时间应限制在所有有关各方制定、
+测试和准备缓解措施所需的最短时间内。人为地延长限制时间以满足会议讨论日期或其他
+非技术原因,会给相关的开发人员和响应小组带来了更多的工作和负担,因为补丁需要
+保持最新,以便跟踪正在进行的上游内核开发,这可能会造成冲突的更改。
+
+CVE分配
+"""""""
+
+硬件安全小组和初始响应小组都不分配CVE,开发过程也不需要CVE。如果CVE是由披露方
+提供的,则可用于文档中。
+
+流程专使
+--------
+
+为了协助这一进程,我们在各组织设立了专使,他们可以回答有关报告流程和进一步处理
+的问题或提供指导。专使不参与特定问题的披露,除非响应小组或相关披露方提出要求。
+现任专使名单:
+
+ ============= ========================================================
+ ARM
+ AMD Tom Lendacky <thomas.lendacky@amd.com>
+ IBM
+ Intel Tony Luck <tony.luck@intel.com>
+ Qualcomm Trilok Soni <tsoni@codeaurora.org>
+
+ Microsoft Sasha Levin <sashal@kernel.org>
+ VMware
+ Xen Andrew Cooper <andrew.cooper3@citrix.com>
+
+ Canonical John Johansen <john.johansen@canonical.com>
+ Debian Ben Hutchings <ben@decadent.org.uk>
+ Oracle Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+ Red Hat Josh Poimboeuf <jpoimboe@redhat.com>
+ SUSE Jiri Kosina <jkosina@suse.cz>
+
+ Amazon
+ Google Kees Cook <keescook@chromium.org>
+ ============= ========================================================
+
+如果要将您的组织添加到专使名单中,请与硬件安全小组联系。被提名的专使必须完全
+理解和支持我们的过程,并且在Linux内核社区中很容易联系。
+
+加密邮件列表
+------------
+
+我们使用加密邮件列表进行通信。这些列表的工作原理是,发送到列表的电子邮件使用
+列表的PGP密钥或列表的/MIME证书进行加密。邮件列表软件对电子邮件进行解密,并
+使用订阅者的PGP密钥或S/MIME证书为每个订阅者分别对其进行重新加密。有关邮件列表
+软件和用于确保列表安全和数据保护的设置的详细信息,请访问:
+https://www.kernel.org/....
+
+关键点
+^^^^^^
+
+初次接触见 :ref:`zh_Contact`. 对于特定于事件的邮件列表,密钥和S/MIME证书通过
+特定列表发送的电子邮件传递给订阅者。
+
+订阅事件特定列表
+^^^^^^^^^^^^^^^^
+
+订阅由响应小组处理。希望参与通信的披露方将潜在订户的列表发送给响应组,以便
+响应组可以验证订阅请求。
+
+每个订户都需要通过电子邮件向响应小组发送订阅请求。电子邮件必须使用订阅服务器
+的PGP密钥或S/MIME证书签名。如果使用PGP密钥,则必须从公钥服务器获得该密钥,
+并且理想情况下该密钥连接到Linux内核的PGP信任网。另请参见:
+https://www.kernel.org/signature.html.
+
+响应小组验证订阅者,并将订阅者添加到列表中。订阅后,订阅者将收到来自邮件列表
+的电子邮件,该邮件列表使用列表的PGP密钥或列表的/MIME证书签名。订阅者的电子邮件
+客户端可以从签名中提取PGP密钥或S/MIME证书,以便订阅者可以向列表发送加密电子
+邮件。
diff --git a/Documentation/translations/zh_CN/process/howto.rst b/Documentation/translations/zh_CN/process/howto.rst
index a8e6ab818983..cc47be356dd3 100644
--- a/Documentation/translations/zh_CN/process/howto.rst
+++ b/Documentation/translations/zh_CN/process/howto.rst
@@ -45,7 +45,7 @@ Linux内核大部分是由C语言写成的,一些体系结构相关的代码
- "C: A Reference Manual" by Harbison and Steele [Prentice Hall]
《C语言参考手册(原书第5版)》(邱仲潘 等译)[机械工业出版社]
-Linux内核使用GNU C和GNU工具链开发。虽然它遵循ISO C89标准,但也用到了一些
+Linux内核使用GNU C和GNU工具链开发。虽然它遵循ISO C11标准,但也用到了一些
标准中没有定义的扩展。内核是自给自足的C环境,不依赖于标准C库的支持,所以
并不支持C标准中的部分定义。比如long long类型的大数除法和浮点运算就不允许
使用。有时候确实很难弄清楚内核对工具链的要求和它所使用的扩展,不幸的是目
@@ -69,7 +69,7 @@ Linux内核源代码都是在GPL(通用公共许可证)的保护下发布的
邮件组里的人并不是律师,不要期望他们的话有法律效力。
对于GPL的常见问题和解答,请访问以下链接:
- http://www.gnu.org/licenses/gpl-faq.html
+ https://www.gnu.org/licenses/gpl-faq.html
文档
@@ -96,7 +96,6 @@ Linux内核代码中包含有大量的文档。这些文档对于学习如何与
的代码。
:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
- :ref:`Documentation/process/submitting-drivers.rst <submittingdrivers>`
这两份文档明确描述如何创建和发送补丁,其中包括(但不仅限于):
- 邮件内容
@@ -109,7 +108,7 @@ Linux内核代码中包含有大量的文档。这些文档对于学习如何与
其他关于如何正确地生成补丁的优秀文档包括:
"The Perfect Patch"
- http://www.ozlabs.org/~akpm/stuff/tpp.txt
+ https://www.ozlabs.org/~akpm/stuff/tpp.txt
"Linux kernel patch submission format"
@@ -126,7 +125,7 @@ Linux内核代码中包含有大量的文档。这些文档对于学习如何与
这篇文档对于理解Linux的开发哲学至关重要。对于将开发平台从其他操作系
统转移到Linux的人来说也很重要。
- :ref:`Documentation/admin-guide/security-bugs.rst <securitybugs>`
+ :ref:`Documentation/process/security-bugs.rst <securitybugs>`
如果你认为自己发现了Linux内核的安全性问题,请根据这篇文档中的步骤来
提醒其他内核开发者并帮助解决这个问题。
@@ -163,7 +162,7 @@ ReST格式的文档会生成在 Documentation/output. 目录中。
------------------
如果你对Linux内核开发一无所知,你应该访问“Linux内核新手”计划:
- http://kernelnewbies.org
+ https://kernelnewbies.org
它拥有一个可以问各种最基本的内核开发问题的邮件列表(在提问之前一定要记得
查找已往的邮件,确认是否有人已经回答过相同的问题)。它还拥有一个可以获得
@@ -176,7 +175,7 @@ ReST格式的文档会生成在 Documentation/output. 目录中。
如果你想加入内核开发社区并协助完成一些任务,却找不到从哪里开始,可以访问
“Linux内核房管员”计划:
- http://kernelnewbies.org/KernelJanitors
+ https://kernelnewbies.org/KernelJanitors
这是极佳的起点。它提供一个相对简单的任务列表,列出内核代码中需要被重新
整理或者改正的地方。通过和负责这个计划的开发者们一同工作,你会学到将补丁
@@ -212,7 +211,7 @@ ReST格式的文档会生成在 Documentation/output. 目录中。
- 每当一个新版本的内核被发布,为期两周的集成窗口将被打开。在这段时间里
维护者可以向Linus提交大段的修改,通常这些修改已经被放到-mm内核中几个
星期了。提交大量修改的首选方式是使用git工具(内核的代码版本管理工具
- ,更多的信息可以在 http://git-scm.com/ 获取),不过使用普通补丁也是
+ ,更多的信息可以在 https://git-scm.com/ 获取),不过使用普通补丁也是
可以的。
- 两个星期以后-rc1版本内核发布。之后只有不包含可能影响整个内核稳定性的
新功能的补丁才可能被接受。请注意一个全新的驱动程序(或者文件系统)有
@@ -252,10 +251,10 @@ Linux-next 集成测试树
在将子系统树的更新合并到主线树之前,需要对它们进行集成测试。为此,存在一个
特殊的测试存储库,其中几乎每天都会提取所有子系统树:
- https://git.kernel.org/?p=linux/kernel/git/next/linux-next.git
+ https://git.kernel.org/?p=linux/kernel/git/next/linux-next.git
通过这种方式,Linux-next 对下一个合并阶段将进入主线内核的内容给出了一个概要
-展望。非常欢冒险的测试者运行测试Linux-next。
+展望。非常欢迎冒险的测试者运行测试Linux-next。
多个主要版本的稳定版内核树
-----------------------------------
@@ -307,7 +306,7 @@ bugzilla.kernel.org是Linux内核开发者们用来跟踪内核Bug的网站。
网上很多地方都有这个邮件列表的存档(archive)。可以使用搜索引擎来找到这些
存档。比如:
- http://dir.gmane.org/gmane.linux.kernel
+ https://lore.kernel.org/lkml/
在发信之前,我们强烈建议你先在存档中搜索你想要讨论的问题。很多已经被详细
讨论过的问题只在邮件列表的存档中可以找到。
@@ -381,7 +380,7 @@ MAINTAINERS文件中可以找到不同话题对应的邮件列表。
内核社区的工作模式同大多数传统公司开发队伍的工作模式并不相同。下面这些例
子,可以帮助你避免某些可能发生问题:
-用这些话介绍你的修改提案会有好处:
+用这些话介绍你的修改提案会有好处:(在任何时候你都不应该用中文写提案)
- 它同时解决了多个问题
- 它删除了2000行代码
@@ -448,8 +447,8 @@ Linux内核社区并不喜欢一下接收大段的代码。修改需要被恰当
保证修改分成很多小块,这样在整个项目都准备好被包含进内核之前,其中的一部
分可能会先被接收。
-必须了解这样做是不可接受的:试图将未完成的工作提交进内核,然后再找时间修
-复。
+你必须明白这么做是无法令人接受的:试图将不完整的代码提交进内核,然后再找
+时间修复。
证明修改的必要性
@@ -472,11 +471,11 @@ Linux内核社区并不喜欢一下接收大段的代码。修改需要被恰当
想了解它具体应该看起来像什么,请查阅以下文档中的“ChangeLog”章节:
“The Perfect Patch”
- http://www.ozlabs.org/~akpm/stuff/tpp.txt
+ https://www.ozlabs.org/~akpm/stuff/tpp.txt
-这些事情有时候做起来很难。要在任何方面都做到完美可能需要好几年时间。这是
-一个持续提高的过程,它需要大量的耐心和决心。只要不放弃,你一定可以做到。
+这些事情有时候做起来很难。想要在任何方面都做到完美可能需要好几年时间。这
+是一个持续提高的过程,它需要大量的耐心和决心。只要不放弃,你一定可以做到。
很多人已经做到了,而他们都曾经和现在的你站在同样的起点上。
diff --git a/Documentation/translations/zh_CN/process/index.rst b/Documentation/translations/zh_CN/process/index.rst
index be1e764a80d2..3ca02d281be0 100644
--- a/Documentation/translations/zh_CN/process/index.rst
+++ b/Documentation/translations/zh_CN/process/index.rst
@@ -5,32 +5,53 @@
.. include:: ../disclaimer-zh_CN.rst
-:Original: :ref:`Documentation/process/index.rst <process_index>`
-:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+:Original: Documentation/process/index.rst
-.. _cn_process_index:
+:翻译:
+ Alex Shi <alex.shi@linux.alibaba.com>
+
+========================
与Linux 内核社区一起工作
========================
-那么你想成为Linux内核开发人员? 欢迎! 不但从技术意义上讲有很多关于内核的知识
-需要学,而且了解我们社区的工作方式也很重要。 阅读这些文章可以让您以更轻松地,
-麻烦最少的方式将更改合并到内核。
+你想成为Linux内核开发人员吗?欢迎之至!在学习许多关于内核的技术知识的同时,
+了解我们社区的工作方式也很重要。阅读这些文档可以让您以更轻松的、麻烦更少的
+方式将更改合并到内核。
-以下是每位开发人员应阅读的基本指南。
+以下是每位开发人员都应阅读的基本指南:
.. toctree::
:maxdepth: 1
+ license-rules
howto
code-of-conduct
code-of-conduct-interpretation
+ development-process
submitting-patches
programming-language
coding-style
- development-process
+ maintainer-pgp-guide
email-clients
- license-rules
+ kernel-enforcement-statement
+ kernel-driver-statement
+
+TODOLIST:
+
+* handling-regressions
+* maintainer-handbooks
+
+安全方面, 请阅读:
+
+.. toctree::
+ :maxdepth: 1
+
+ embargoed-hardware-issues
+
+TODOLIST:
+
+* security-bugs
其它大多数开发人员感兴趣的社区指南:
@@ -38,19 +59,38 @@
.. toctree::
:maxdepth: 1
- submitting-drivers
- submit-checklist
stable-api-nonsense
- stable-kernel-rules
management-style
+ stable-kernel-rules
+ submit-checklist
+
+TODOLIST:
+
+* changes
+* kernel-docs
+* deprecated
+* maintainers
+* researcher-guidelines
+* contribution-maturity-model
-这些是一些总体技术指南,由于缺乏更好的地方,现在已经放在这里
+
+这些是一些总体性技术指南,由于不大好分类而放在这里:
.. toctree::
:maxdepth: 1
magic-number
volatile-considered-harmful
+ ../arch/riscv/patch-acceptance
+ ../core-api/unaligned-memory-access
+
+TODOLIST:
+
+* applying-patches
+* backporting
+* adding-syscalls
+* botching-up-ioctls
+* clang-format
.. only:: subproject and html
diff --git a/Documentation/translations/zh_CN/process/kernel-driver-statement.rst b/Documentation/translations/zh_CN/process/kernel-driver-statement.rst
new file mode 100644
index 000000000000..2b3375bcccfd
--- /dev/null
+++ b/Documentation/translations/zh_CN/process/kernel-driver-statement.rst
@@ -0,0 +1,199 @@
+.. _cn_process_statement_driver:
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: :ref:`Documentation/process/kernel-driver-statement.rst <process_statement_driver>`
+:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+
+内核驱动声明
+------------
+
+关于Linux内核模块的立场声明
+===========================
+
+我们,以下署名的Linux内核开发人员,认为任何封闭源Linux内核模块或驱动程序都是
+有害的和不可取的。我们已经一再发现它们对Linux用户,企业和更大的Linux生态系统
+有害。这样的模块否定了Linux开发模型的开放性,稳定性,灵活性和可维护性,并使
+他们的用户无法使用Linux社区的专业知识。提供闭源内核模块的供应商迫使其客户
+放弃Linux的主要优势或选择新的供应商。因此,为了充分利用开源所提供的成本节省和
+共享支持优势,我们敦促供应商采取措施,以开源内核代码在Linux上为其客户提供支持。
+
+我们只为自己说话,而不是我们今天可能会为之工作,过去或将来会为之工作的任何公司。
+
+ - Dave Airlie
+ - Nick Andrew
+ - Jens Axboe
+ - Ralf Baechle
+ - Felipe Balbi
+ - Ohad Ben-Cohen
+ - Muli Ben-Yehuda
+ - Jiri Benc
+ - Arnd Bergmann
+ - Thomas Bogendoerfer
+ - Vitaly Bordug
+ - James Bottomley
+ - Josh Boyer
+ - Neil Brown
+ - Mark Brown
+ - David Brownell
+ - Michael Buesch
+ - Franck Bui-Huu
+ - Adrian Bunk
+ - François Cami
+ - Ralph Campbell
+ - Luiz Fernando N. Capitulino
+ - Mauro Carvalho Chehab
+ - Denis Cheng
+ - Jonathan Corbet
+ - Glauber Costa
+ - Alan Cox
+ - Magnus Damm
+ - Ahmed S. Darwish
+ - Robert P. J. Day
+ - Hans de Goede
+ - Arnaldo Carvalho de Melo
+ - Helge Deller
+ - Jean Delvare
+ - Mathieu Desnoyers
+ - Sven-Thorsten Dietrich
+ - Alexey Dobriyan
+ - Daniel Drake
+ - Alex Dubov
+ - Randy Dunlap
+ - Michael Ellerman
+ - Pekka Enberg
+ - Jan Engelhardt
+ - Mark Fasheh
+ - J. Bruce Fields
+ - Larry Finger
+ - Jeremy Fitzhardinge
+ - Mike Frysinger
+ - Kumar Gala
+ - Robin Getz
+ - Liam Girdwood
+ - Jan-Benedict Glaw
+ - Thomas Gleixner
+ - Brice Goglin
+ - Cyrill Gorcunov
+ - Andy Gospodarek
+ - Thomas Graf
+ - Krzysztof Halasa
+ - Harvey Harrison
+ - Stephen Hemminger
+ - Michael Hennerich
+ - Tejun Heo
+ - Benjamin Herrenschmidt
+ - Kristian Høgsberg
+ - Henrique de Moraes Holschuh
+ - Marcel Holtmann
+ - Mike Isely
+ - Takashi Iwai
+ - Olof Johansson
+ - Dave Jones
+ - Jesper Juhl
+ - Matthias Kaehlcke
+ - Kenji Kaneshige
+ - Jan Kara
+ - Jeremy Kerr
+ - Russell King
+ - Olaf Kirch
+ - Roel Kluin
+ - Hans-Jürgen Koch
+ - Auke Kok
+ - Peter Korsgaard
+ - Jiri Kosina
+ - Aaro Koskinen
+ - Mariusz Kozlowski
+ - Greg Kroah-Hartman
+ - Michael Krufky
+ - Aneesh Kumar
+ - Clemens Ladisch
+ - Christoph Lameter
+ - Gunnar Larisch
+ - Anders Larsen
+ - Grant Likely
+ - John W. Linville
+ - Yinghai Lu
+ - Tony Luck
+ - Pavel Machek
+ - Matt Mackall
+ - Paul Mackerras
+ - Roland McGrath
+ - Patrick McHardy
+ - Kyle McMartin
+ - Paul Menage
+ - Thierry Merle
+ - Eric Miao
+ - Akinobu Mita
+ - Ingo Molnar
+ - James Morris
+ - Andrew Morton
+ - Paul Mundt
+ - Oleg Nesterov
+ - Luca Olivetti
+ - S.Çağlar Onur
+ - Pierre Ossman
+ - Keith Owens
+ - Venkatesh Pallipadi
+ - Nick Piggin
+ - Nicolas Pitre
+ - Evgeniy Polyakov
+ - Richard Purdie
+ - Mike Rapoport
+ - Sam Ravnborg
+ - Gerrit Renker
+ - Stefan Richter
+ - David Rientjes
+ - Luis R. Rodriguez
+ - Stefan Roese
+ - Francois Romieu
+ - Rami Rosen
+ - Stephen Rothwell
+ - Maciej W. Rozycki
+ - Mark Salyzyn
+ - Yoshinori Sato
+ - Deepak Saxena
+ - Holger Schurig
+ - Amit Shah
+ - Yoshihiro Shimoda
+ - Sergei Shtylyov
+ - Kay Sievers
+ - Sebastian Siewior
+ - Rik Snel
+ - Jes Sorensen
+ - Alexey Starikovskiy
+ - Alan Stern
+ - Timur Tabi
+ - Hirokazu Takata
+ - Eliezer Tamir
+ - Eugene Teo
+ - Doug Thompson
+ - FUJITA Tomonori
+ - Dmitry Torokhov
+ - Marcelo Tosatti
+ - Steven Toth
+ - Theodore Tso
+ - Matthias Urlichs
+ - Geert Uytterhoeven
+ - Arjan van de Ven
+ - Ivo van Doorn
+ - Rik van Riel
+ - Wim Van Sebroeck
+ - Hans Verkuil
+ - Horst H. von Brand
+ - Dmitri Vorobiev
+ - Anton Vorontsov
+ - Daniel Walker
+ - Johannes Weiner
+ - Harald Welte
+ - Matthew Wilcox
+ - Dan J. Williams
+ - Darrick J. Wong
+ - David Woodhouse
+ - Chris Wright
+ - Bryan Wu
+ - Rafael J. Wysocki
+ - Herbert Xu
+ - Vlad Yasevich
+ - Peter Zijlstra
+ - Bartlomiej Zolnierkiewicz
diff --git a/Documentation/translations/zh_CN/process/kernel-enforcement-statement.rst b/Documentation/translations/zh_CN/process/kernel-enforcement-statement.rst
new file mode 100644
index 000000000000..75f7b7b9137c
--- /dev/null
+++ b/Documentation/translations/zh_CN/process/kernel-enforcement-statement.rst
@@ -0,0 +1,151 @@
+.. _cn_process_statement_kernel:
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: :ref:`Documentation/process/kernel-enforcement-statement.rst <process_statement_kernel>`
+:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+
+Linux 内核执行声明
+------------------
+
+作为Linux内核的开发人员,我们对如何使用我们的软件以及如何实施软件许可证有着
+浓厚的兴趣。遵守GPL-2.0的互惠共享义务对我们软件和社区的长期可持续性至关重要。
+
+虽然有权强制执行对我们社区的贡献中的单独版权权益,但我们有共同的利益,即确保
+个人强制执行行动的方式有利于我们的社区,不会对我们软件生态系统的健康和增长
+产生意外的负面影响。为了阻止无益的执法行动,我们同意代表我们自己和我们版权
+利益的任何继承人对Linux内核用户作出以下符合我们开发社区最大利益的承诺:
+
+ 尽管有GPL-2.0的终止条款,我们同意,采用以下GPL-3.0条款作为我们许可证下的
+ 附加许可,作为任何对许可证下权利的非防御性主张,这符合我们开发社区的最佳
+ 利益。
+
+ 但是,如果您停止所有违反本许可证的行为,则您从特定版权持有人处获得的
+ 许可证将被恢复:(a)暂时恢复,除非版权持有人明确并最终终止您的许可证;
+ 以及(b)永久恢复, 如果版权持有人未能在你终止违反后60天内以合理方式
+ 通知您违反本许可证的行为,则永久恢复您的许可证。
+
+ 此外,如果版权所有者以某种合理的方式通知您违反了本许可,这是您第一次
+ 从该版权所有者处收到违反本许可的通知(对于任何作品),并且您在收到通知
+ 后的30天内纠正违规行为。则您从特定版权所有者处获得的许可将永久恢复.
+
+我们提供这些保证的目的是鼓励更多地使用该软件。我们希望公司和个人使用、修改和
+分发此软件。我们希望以公开和透明的方式与用户合作,以消除我们对法规遵从性或强制
+执行的任何不确定性,这些不确定性可能会限制我们软件的采用。我们将法律行动视为
+最后手段,只有在其他社区努力未能解决这一问题时才采取行动。
+
+最后,一旦一个不合规问题得到解决,我们希望用户会感到欢迎,加入我们为之努力的
+这个项目。共同努力,我们会更强大。
+
+除了下面提到的以外,我们只为自己说话,而不是为今天、过去或将来可能为之工作的
+任何公司说话。
+
+ - Laura Abbott
+ - Bjorn Andersson (Linaro)
+ - Andrea Arcangeli
+ - Neil Armstrong
+ - Jens Axboe
+ - Pablo Neira Ayuso
+ - Khalid Aziz
+ - Ralf Baechle
+ - Felipe Balbi
+ - Arnd Bergmann
+ - Ard Biesheuvel
+ - Tim Bird
+ - Paolo Bonzini
+ - Christian Borntraeger
+ - Mark Brown (Linaro)
+ - Paul Burton
+ - Javier Martinez Canillas
+ - Rob Clark
+ - Kees Cook (Google)
+ - Jonathan Corbet
+ - Dennis Dalessandro
+ - Vivien Didelot (Savoir-faire Linux)
+ - Hans de Goede
+ - Mel Gorman (SUSE)
+ - Sven Eckelmann
+ - Alex Elder (Linaro)
+ - Fabio Estevam
+ - Larry Finger
+ - Bhumika Goyal
+ - Andy Gross
+ - Juergen Gross
+ - Shawn Guo
+ - Ulf Hansson
+ - Stephen Hemminger (Microsoft)
+ - Tejun Heo
+ - Rob Herring
+ - Masami Hiramatsu
+ - Michal Hocko
+ - Simon Horman
+ - Johan Hovold (Hovold Consulting AB)
+ - Christophe JAILLET
+ - Olof Johansson
+ - Lee Jones (Linaro)
+ - Heiner Kallweit
+ - Srinivas Kandagatla
+ - Jan Kara
+ - Shuah Khan (Samsung)
+ - David Kershner
+ - Jaegeuk Kim
+ - Namhyung Kim
+ - Colin Ian King
+ - Jeff Kirsher
+ - Greg Kroah-Hartman (Linux Foundation)
+ - Christian König
+ - Vinod Koul
+ - Krzysztof Kozlowski
+ - Viresh Kumar
+ - Aneesh Kumar K.V
+ - Julia Lawall
+ - Doug Ledford
+ - Chuck Lever (Oracle)
+ - Daniel Lezcano
+ - Shaohua Li
+ - Xin Long
+ - Tony Luck
+ - Catalin Marinas (Arm Ltd)
+ - Mike Marshall
+ - Chris Mason
+ - Paul E. McKenney
+ - Arnaldo Carvalho de Melo
+ - David S. Miller
+ - Ingo Molnar
+ - Kuninori Morimoto
+ - Trond Myklebust
+ - Martin K. Petersen (Oracle)
+ - Borislav Petkov
+ - Jiri Pirko
+ - Josh Poimboeuf
+ - Sebastian Reichel (Collabora)
+ - Guenter Roeck
+ - Joerg Roedel
+ - Leon Romanovsky
+ - Steven Rostedt (VMware)
+ - Frank Rowand
+ - Ivan Safonov
+ - Anna Schumaker
+ - Jes Sorensen
+ - K.Y. Srinivasan
+ - David Sterba (SUSE)
+ - Heiko Stuebner
+ - Jiri Kosina (SUSE)
+ - Willy Tarreau
+ - Dmitry Torokhov
+ - Linus Torvalds
+ - Thierry Reding
+ - Rik van Riel
+ - Luis R. Rodriguez
+ - Geert Uytterhoeven (Glider bvba)
+ - Eduardo Valentin (Amazon.com)
+ - Daniel Vetter
+ - Linus Walleij
+ - Richard Weinberger
+ - Dan Williams
+ - Rafael J. Wysocki
+ - Arvind Yadav
+ - Masahiro Yamada
+ - Wei Yongjun
+ - Lv Zheng
+ - Marc Zyngier (Arm Ltd)
diff --git a/Documentation/translations/zh_CN/process/magic-number.rst b/Documentation/translations/zh_CN/process/magic-number.rst
index e4c225996af0..4e4aeaca796c 100644
--- a/Documentation/translations/zh_CN/process/magic-number.rst
+++ b/Documentation/translations/zh_CN/process/magic-number.rst
@@ -1,150 +1,82 @@
-.. _cn_magicnumbers:
-
.. include:: ../disclaimer-zh_CN.rst
-:Original: :ref:`Documentation/process/magic-number.rst <magicnumbers>`
+:Original: Documentation/process/magic-number.rst
+
+:翻译:
-如果想评论或更新本文的内容,请直接发信到LKML。如果你使用英文交流有困难的话,也可
-以向中文版维护者求助。如果本翻译更新不及时或者翻译存在问题,请联系中文版维护者::
+ 贾威威 Jia Wei Wei <harryxiyou@gmail.com>
- 中文版维护者: 贾威威 Jia Wei Wei <harryxiyou@gmail.com>
- 中文版翻译者: 贾威威 Jia Wei Wei <harryxiyou@gmail.com>
- 中文版校译者: 贾威威 Jia Wei Wei <harryxiyou@gmail.com>
+:校译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
Linux 魔术数
============
-这个文件是有关当前使用的魔术值注册表。当你给一个结构添加了一个魔术值,你也应该把这个魔术值添加到这个文件,因为我们最好把用于各种结构的魔术值统一起来。
+这个文件是有关当前使用的魔术值注册表。当你给一个结构体添加了一个魔术值,你也
+应该把这个魔术值添加到这个文件,因为我们最好把用于各种结构体的魔术值统一起来。
-使用魔术值来保护内核数据结构是一个非常好的主意。这就允许你在运行期检查(a)一个结构是否已经被攻击,或者(b)你已经给一个例行程序通过了一个错误的结构。后一种情况特别地有用---特别是当你通过一个空指针指向结构体的时候。tty源码,例如,经常通过特定驱动使用这种方法并且反复地排列特定方面的结构。
+使用魔术值来保护内核数据结构是一个 **非常好的主意** 。这就允许你在运行时检
+查一个结构体(a)是否已经被攻击,或者(b)你已经给一个例程传递了一个错误的结构
+体。最后一种情况特别地有用---特别是当你通过一个空指针指向结构体的时候。例如,
+tty源码经常通过特定驱动使用这种方法用来反复地排列特定方面的结构体。
-使用魔术值的方法是在结构的开始处声明的,如下::
+使用魔术值的方法是在结构体的开头声明它们,如下::
struct tty_ldisc {
int magic;
...
};
-当你以后给内核添加增强功能的时候,请遵守这条规则!这样就会节省数不清的调试时间,特别是一些古怪的情况,例如,数组超出范围并且重新写了超出部分。遵守这个规则,‪这些情况可以被快速地,安全地避免。
+当你以后给内核添加增强功能的时候,请遵守这条规则!这样就会节省数不清的调试
+时间,特别是一些古怪的情况,例如,数组超出范围并且覆盖写了超出部分。利用这
+个规则,这些情况可以被快速地,安全地检测到这些案例。
+
+变更日志::
- Theodore Ts'o
- 31 Mar 94
+ Theodore Ts'o
+ 31 Mar 94
-给当前的Linux 2.1.55添加魔术表。
+ 给当前的Linux 2.1.55添加魔术表。
- Michael Chastain
- <mailto:mec@shout.net>
- 22 Sep 1997
+ Michael Chastain
+ <mailto:mec@shout.net>
+ 22 Sep 1997
-现在应该最新的Linux 2.1.112.因为在特性冻结期间,不能在2.2.x前改变任何东西。这些条目被数域所排序。
+ 现在应该最新的Linux 2.1.112.因为在特性冻结期间,不能在2.2.x前改变任
+ 何东西。这些条目被数域所排序。
- Krzysztof G.Baranowski
- <mailto: kgb@knm.org.pl>
- 29 Jul 1998
+ Krzysztof G.Baranowski
+ <mailto: kgb@knm.org.pl>
+ 29 Jul 1998
-更新魔术表到Linux 2.5.45。刚好越过特性冻结,但是有可能还会有一些新的魔术值在2.6.x之前融入到内核中。
+ 更新魔术表到Linux 2.5.45。刚好越过特性冻结,但是有可能还会有一些新的魔
+ 术值在2.6.x之前融入到内核中。
- Petr Baudis
- <pasky@ucw.cz>
- 03 Nov 2002
+ Petr Baudis
+ <pasky@ucw.cz>
+ 03 Nov 2002
-更新魔术表到Linux 2.5.74。
+ 更新魔术表到Linux 2.5.74。
- Fabian Frederick
- <ffrederick@users.sourceforge.net>
- 09 Jul 2003
+ Fabian Frederick
+ <ffrederick@users.sourceforge.net>
+ 09 Jul 2003
===================== ================ ======================== ==========================================
魔术数名 数字 结构 文件
===================== ================ ======================== ==========================================
PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/pg.h``
-CMAGIC 0x0111 user ``include/linux/a.out.h``
-MKISS_DRIVER_MAGIC 0x04bf mkiss_channel ``drivers/net/mkiss.h``
-HDLC_MAGIC 0x239e n_hdlc ``drivers/char/n_hdlc.c``
APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
-CYCLADES_MAGIC 0x4359 cyclades_port ``include/linux/cyclades.h``
-DB_MAGIC 0x4442 fc_info ``drivers/net/iph5526_novram.c``
-DL_MAGIC 0x444d fc_info ``drivers/net/iph5526_novram.c``
FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
-FF_MAGIC 0x4646 fc_info ``drivers/net/iph5526_novram.c``
-ISICOM_MAGIC 0x4d54 isi_port ``include/linux/isicom.h``
-PTY_MAGIC 0x5001 ``drivers/char/pty.c``
-PPP_MAGIC 0x5002 ppp ``include/linux/if_pppvar.h``
-SSTATE_MAGIC 0x5302 serial_state ``include/linux/serial.h``
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
-STRIP_MAGIC 0x5303 strip ``drivers/net/strip.c``
-X25_ASY_MAGIC 0x5303 x25_asy ``drivers/net/x25_asy.h``
-SIXPACK_MAGIC 0x5304 sixpack ``drivers/net/hamradio/6pack.h``
-AX25_MAGIC 0x5316 ax_disp ``drivers/net/mkiss.h``
-TTY_MAGIC 0x5401 tty_struct ``include/linux/tty.h``
-MGSL_MAGIC 0x5401 mgsl_info ``drivers/char/synclink.c``
-TTY_DRIVER_MAGIC 0x5402 tty_driver ``include/linux/tty_driver.h``
-MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c``
-TTY_LDISC_MAGIC 0x5403 tty_ldisc ``include/linux/tty_ldisc.h``
-USB_SERIAL_MAGIC 0x6702 usb_serial ``drivers/usb/serial/usb-serial.h``
-FULL_DUPLEX_MAGIC 0x6969 ``drivers/net/ethernet/dec/tulip/de2104x.c``
-USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/class/bluetty.c``
-RFCOMM_TTY_MAGIC 0x6d02 ``net/bluetooth/rfcomm/tty.c``
-USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port ``drivers/usb/serial/usb-serial.h``
-CG_MAGIC 0x00090255 ufs_cylinder_group ``include/linux/ufs_fs.h``
-RPORT_MAGIC 0x00525001 r_port ``drivers/char/rocket_int.h``
-LSEMAGIC 0x05091998 lse ``drivers/fc4/fc.c``
-GDTIOCTL_MAGIC 0x06030f07 gdth_iowr_str ``drivers/scsi/gdth_ioctl.h``
-RIEBL_MAGIC 0x09051990 ``drivers/net/atarilance.c``
-NBD_REQUEST_MAGIC 0x12560953 nbd_request ``include/linux/nbd.h``
-RED_MAGIC2 0x170fc2a5 (any) ``mm/slab.c``
BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c``
-ISDN_X25IFACE_MAGIC 0x1e75a2b9 isdn_x25iface_proto_data ``drivers/isdn/isdn_x25iface.h``
-ECP_MAGIC 0x21504345 cdkecpsig ``include/linux/cdk.h``
-LSOMAGIC 0x27091997 lso ``drivers/fc4/fc.c``
-LSMAGIC 0x2a3b4d2a ls ``drivers/fc4/fc.c``
-WANPIPE_MAGIC 0x414C4453 sdla_{dump,exec} ``include/linux/wanpipe.h``
-CS_CARD_MAGIC 0x43525553 cs_card ``sound/oss/cs46xx.c``
-LABELCL_MAGIC 0x4857434c labelcl_info_s ``include/asm/ia64/sn/labelcl.h``
-ISDN_ASYNC_MAGIC 0x49344C01 modem_info ``include/linux/isdn.h``
-CTC_ASYNC_MAGIC 0x49344C01 ctc_tty_info ``drivers/s390/net/ctctty.c``
-ISDN_NET_MAGIC 0x49344C02 isdn_net_local_s ``drivers/isdn/i4l/isdn_net_lib.h``
-SAVEKMSG_MAGIC2 0x4B4D5347 savekmsg ``arch/*/amiga/config.c``
-CS_STATE_MAGIC 0x4c4f4749 cs_state ``sound/oss/cs46xx.c``
-SLAB_C_MAGIC 0x4f17a36d kmem_cache ``mm/slab.c``
-COW_MAGIC 0x4f4f4f4d cow_header_v1 ``arch/um/drivers/ubd_user.c``
-I810_CARD_MAGIC 0x5072696E i810_card ``sound/oss/i810_audio.c``
-TRIDENT_CARD_MAGIC 0x5072696E trident_card ``sound/oss/trident.c``
-ROUTER_MAGIC 0x524d4157 wan_device [in ``wanrouter.h`` pre 3.9]
-SAVEKMSG_MAGIC1 0x53415645 savekmsg ``arch/*/amiga/config.c``
-GDA_MAGIC 0x58464552 gda ``arch/mips/include/asm/sn/gda.h``
-RED_MAGIC1 0x5a2cf071 (any) ``mm/slab.c``
-EEPROM_MAGIC_VALUE 0x5ab478d2 lanai_dev ``drivers/atm/lanai.c``
HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
-PCXX_MAGIC 0x5c6df104 channel ``drivers/char/pcxx.h``
KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``
-I810_STATE_MAGIC 0x63657373 i810_state ``sound/oss/i810_audio.c``
-TRIDENT_STATE_MAGIC 0x63657373 trient_state ``sound/oss/trident.c``
-M3_CARD_MAGIC 0x646e6f50 m3_card ``sound/oss/maestro3.c``
-FW_HEADER_MAGIC 0x65726F66 fw_header ``drivers/atm/fore200e.h``
-SLOT_MAGIC 0x67267321 slot ``drivers/hotplug/cpqphp.h``
-SLOT_MAGIC 0x67267322 slot ``drivers/hotplug/acpiphp.h``
-LO_MAGIC 0x68797548 nbd_device ``include/linux/nbd.h``
-OPROFILE_MAGIC 0x6f70726f super_block ``drivers/oprofile/oprofilefs.h``
-M3_STATE_MAGIC 0x734d724d m3_state ``sound/oss/maestro3.c``
-VMALLOC_MAGIC 0x87654320 snd_alloc_track ``sound/core/memory.c``
-KMALLOC_MAGIC 0x87654321 snd_alloc_track ``sound/core/memory.c``
-PWC_MAGIC 0x89DC10AB pwc_device ``drivers/usb/media/pwc.h``
-NBD_REPLY_MAGIC 0x96744668 nbd_reply ``include/linux/nbd.h``
-ENI155_MAGIC 0xa54b872d midway_eprom ``drivers/atm/eni.h``
CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h``
-DPMEM_MAGIC 0xc0ffee11 gdt_pci_sram ``drivers/scsi/gdth.h``
YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c``
CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c``
QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c``
QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c``
-HTB_CMAGIC 0xFEFAFEF1 htb_class ``net/sched/sch_htb.c``
NMI_MAGIC 0x48414d4d455201 nmi_s ``arch/mips/include/asm/sn/nmi.h``
===================== ================ ======================== ==========================================
-
-
-请注意,在声音记忆管理中仍然有一些特殊的为每个驱动定义的魔术值。查看include/sound/sndmagic.h来获取他们完整的列表信息。很多OSS声音驱动拥有自己从声卡PCI ID构建的魔术值-他们也没有被列在这里。
-
-IrDA子系统也使用了大量的自己的魔术值,查看include/net/irda/irda.h来获取他们完整的信息。
-
-HFS是另外一个比较大的使用魔术值的文件系统-你可以在fs/hfs/hfs.h中找到他们。
diff --git a/Documentation/translations/zh_CN/process/maintainer-pgp-guide.rst b/Documentation/translations/zh_CN/process/maintainer-pgp-guide.rst
new file mode 100644
index 000000000000..eb12694a4c59
--- /dev/null
+++ b/Documentation/translations/zh_CN/process/maintainer-pgp-guide.rst
@@ -0,0 +1,789 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/process/maintainer-pgp-guide.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+===================
+内核维护者 PGP 指南
+===================
+
+:作者: Konstantin Ryabitsev <konstantin@linuxfoundation.org>
+
+本文档面向 Linux 内核开发者,特别是子系统维护人员。文档中含有Linux 基金
+会发布的更通用的 `保护代码完整性`_ 指南中讨论的内容子集。阅读该文档,以更
+深入地讨论本指南中提到的一些主题。
+
+.. _`保护代码完整性`: https://github.com/lfit/itpol/blob/master/protecting-code-integrity.md
+
+PGP 在 Linux 内核开发中的作用
+=============================
+
+PGP 有助于确保 Linux 内核开发社区产出代码的完整性,并在较小程度上,通过
+PGP 签名的电子邮件交换,在开发者之间建立可信的交流渠道。
+
+Linux 内核源代码主要有两种(维护)方式:
+
+- 分布式源仓库 (git)
+- 定期发布快照 (tarballs)
+
+git 仓库和 tarball 都带有创建官方内核版本的内核开发者的 PGP 签名。这
+些签名提供了加密保证,即保证 kernel.org 或任何其他镜像提供的可下载版本
+与这些开发者在其工作站上的版本相同。为此:
+
+- git 仓库在所有标签上提供 PGP 签名
+- tarball 为所有下载提供独立的 PGP 签名
+
+信任开发者,不要信基础设施
+--------------------------
+
+自从 2011 年 kernel.org 核心系统遭到入侵以来,内核存档项目的主要运行原
+则就是假定基础设施的任何部分都可能随时受到入侵。因此,管理员特意采取措施,
+强调必须始终信任开发者,不能信任代码托管基础设施,无论后者的安全实践有多好。
+
+上述指导原则正是需要本指南的原因。希望确保通过对开发者的信任,我们不会简
+单地将未来潜在安全事件的责任归咎于其他人。目的是提供一套指导开发者可以用
+来创建安全的工作环境并保护用于建立 Linux 内核本身完整性的 PGP 密钥。
+
+PGP 工具
+========
+
+使用 GnuPG 2.2 或更高版本
+-------------------------
+
+默认情况下,你的发行版应该已经安装了 GnuPG,你只需要验证你使用的是相当新的
+版本即可。要检查,请运行::
+
+ $ gpg --version | head -n1
+
+如果你有 2.2 或更高版本,那么你就可以开始了。如果你的版本早于 2.2,则本指
+南中的某些命令可能不起作用。
+
+配置 gpg-agent 选项
+~~~~~~~~~~~~~~~~~~~
+
+GnuPG agent是一个辅助工具,每当你使用该命令时,它都会自动启动gpg,并在
+后台运行,目的是缓存私钥密码。你应该知道两个选项,以便调整密码何时从缓存
+过期:
+
+- ``default-cache-ttl`` (秒): 如果在生命周期结束之前再次使用相同的
+ 密钥,倒计时将重置为另一段时间。默认值为 600(10 分钟)。
+- ``max-cache-ttl`` (秒): 无论你自输入初始密码以来多久使用过密钥,
+ 如果最大生存时间倒计时结束,你都必须再次输入密码。默认值为 30 分钟。
+
+如果你发现这些默认值太短(或太长),你可以编辑 ``~/.gnupg/gpg-agent.conf``
+文件以设置你自己的值::
+
+ # 常规ttl设置为30分钟,最大ttl设置为2小时
+ default-cache-ttl 1800
+ max-cache-ttl 7200
+
+.. note::
+
+ 不需要在 shell 会话开始时手动启动 gpg-agent。你可能需要检查
+ rc 文件来删除旧版本 GnuPG 中的所有内容,因为它可能不再做正确
+ 的事情。
+
+保护你的 PGP 密钥
+=================
+
+本指南假定你已经拥有用于 Linux 内核开发目的的 PGP 密钥。如果你还没
+有,请参阅前面提到的 "`保护代码完整性`_" 文档,以获取有关如何创建新
+密钥的指导。
+
+如果你当前的密钥低于 2048 位 (RSA),你还应该创建一个新密钥。
+
+了解 PGP 子密钥
+---------------
+
+PGP 密钥很少由单个密钥对组成 - 通常它是独立子密钥的集合,这些子密钥
+可根据其功能用于不同的目的,并在创建时分配。PGP 定义了密钥可以具有的
+四种功能:
+
+- **[S]** 密钥可用于签名
+- **[E]** 密钥可用于加密
+- **[A]** 密钥可用于身份验证
+- **[C]** 密钥可用于验证其他密钥
+
+具有 **[C]** 功能的密钥通常称为“主”密钥,但该术语具有误导性,因为
+它意味着可以使用Certify密钥来代替同一链上的任何其他子密钥(如物理
+“主密钥”可用于打开为其他钥匙制作的锁)。由于情况并非如此,本指南将
+其称为“认证密钥”以避免任何歧义。
+
+充分理解以下内容至关重要:
+
+1. 所有子项彼此完全独立。如果你丢失了私有子密钥,则无法从链上的任何
+ 其他私钥恢复或重新创建它。
+2. 除 Certify 密钥外,可以有多个具有相同功能的子密钥(例如,你可
+ 以有 2 个有效的加密子密钥、3 个有效的签名子密钥,但只有 1 个有
+ 效的认证子密钥)。所有子密钥都是完全独立的——加密到一个 **[E]**
+ 子密钥的信息(messages)无法使用你可能拥有的任何其他 **[E]**
+ 子密钥解密。
+3. 单个子密钥可能具有多种功能(例如,你的 **[C]** 密钥也可以是你
+ 的 **[S]** 密钥)。
+
+携带 **[C]** (证明)能力的密钥是唯一可以用来指示与其他密钥的关系
+的密钥。仅 **[C]** 密钥可用于:
+
+- 添加或撤销具有 S/E/A 功能的其他密钥(子密钥)
+- 添加、更改或撤销与密钥关联的身份 (uid)
+- 添加或更改其本身或任何子密钥的到期日期
+- 出于信任网络的目的签署其他人的密钥
+
+默认情况下,GnuPG 在生成新密钥时创建以下内容:
+
+- 一个子密钥同时具有认证和签名功能 (**[SC]**)
+- 具有加密功能的单独子密钥 (**[E]**)
+
+如果你在生成密钥时使用了默认参数,那么这就是你将得到的。你可以通过
+运行命令来验证,例如: ``gpg --list-secret-keys``
+
+::
+
+ sec ed25519 2022-12-20 [SC] [expires: 2024-12-19]
+ 000000000000000000000000AAAABBBBCCCCDDDD
+ uid [ultimate] Alice Dev <adev@kernel.org>
+ ssb cv25519 2022-12-20 [E] [expires: 2024-12-19]
+
+在 ``sec`` 这行下面长长的一行就是你的密钥指纹-无论在下文任何地方
+看到 ``[fpr]`` 都指的是这40个字符。
+
+确保你的密码强度高
+------------------
+
+GnuPG 在将私钥存储到磁盘之前使用密码对其进行加密。这样,即使你的
+``.gnupg`` 目录全部泄露或被盗,攻击者在没有事先获取密码来解密的
+情况下也无法使用你的私钥。
+
+你的私钥受到强密码保护是绝对必要的。要设置或更改它,请使用::
+
+ $ gpg --change-passphrase [fpr]
+
+创建一个单独的签名子密钥
+------------------------
+
+我们的目的是通过将你的证书密钥移动到离线媒介来保护它,因此如果你只
+有组合的 **[SC]** 密钥,那么你应该创建一个单独的签名子密钥::
+
+ $ gpg --quick-addkey [fpr] ed25519 sign
+
+.. note:: GnuPG 中的 ECC 支持
+
+ 请注意,如果你打算使用不支持 ED25519 ECC 密钥的硬件密钥,则
+ 应选择“nistp256”或“ed25519”。请参阅下面有关推荐硬件设备的
+ 部分。
+
+
+备份你的证书密钥以进行灾难恢复
+------------------------------
+
+你的 PGP 密钥上来自其他开发者的签名越多,出于灾难恢复的原因,你就越
+有理由创建一个位于数字媒体之外的备份版本。
+
+创建私钥的可打印硬拷贝的最佳方法是使用 ``paperkey`` 为此目的编写
+的软件。有关输出格式及其相对于其他解决方案的优势的更多详细信息,请参
+阅 ``paperkey`` 参考资料。大多数发行版都应该已经打包了 Paperkey。
+
+运行以下命令来创建私钥的硬拷贝备份::
+
+ $ gpg --export-secret-key [fpr] | paperkey -o /tmp/key-backup.txt
+
+打印出该文件(或将输出直接传输到 lpr),然后用笔在纸的边缘写下你的密
+码。 **强烈建议这样做**,因为密钥打印输出仍然使用该密码进行加密,并且
+如果你更改了它,你将不记得创建备份时它曾经是什么 - *保证*。
+
+将生成的打印输出和手写密码放入信封中,并存放在安全且受到良好保护的地
+方,最好远离你的家,例如银行保险柜。
+
+.. note::
+
+ 你的打印机可能不再是连接到并行端口的简单哑设备,但由于输出仍然使
+ 用你的密码进行加密,因此即使“云端打印”的现代打印机也应该保持相
+ 对安全的操作
+
+备份整个 GnuPG 目录
+-------------------
+
+.. warning::
+
+ **!!!不要跳过这个步骤!!!**
+
+如果你需要恢复 PGP 密钥,拥有一个随时可用的备份非常重要。这与我们
+所做的灾难级准备不同 ``paperkey`` 。每当你需要使用你的证书密钥时,
+例如在会议和峰会后更改你自己的密钥或签署其他人的密钥时,你还将依赖
+这些外部副本。
+
+首先获取一个小型 USB “拇指” 驱动器(最好是两个!),用于备份目的。
+你需要使用 LUKS 对其进行加密——请参阅你的发行版文档以了解如何完成
+此操作。
+
+对于加密密码,你可以使用与 PGP 密钥相同的密码。
+
+加密过程完成后,重新插入 USB 驱动器并确保其正确安装。将整个 ``.gnupg``
+目录复制到加密存储::
+
+ $ cp -a ~/.gnupg /media/disk/foo/gnupg-backup
+
+你现在应该测试一下,确保一切依然能正常工作::
+
+ $ gpg --homedir=/media/disk/foo/gnupg-backup --list-key [fpr]
+
+如果没有出现任何错误,那么就可以开始了。卸下 USB 驱动器,给它贴上
+明显的标签,这样下次需要使用随机 USB 驱动器时就不会把它吹走,然后
+放在安全的地方 - 但不要太远,因为你每次都需要使用它时不时地用于诸
+如编辑身份、添加或撤销子密钥或签署其他人的密钥之类的事情。
+
+从你的 homedir 中删除 Certify 密钥
+----------------------------------
+
+我们的主目录中的文件并没有我们想象的那么受到保护。它们可以通过多种
+不同的方式泄露或被盗:
+
+- 在制作快速主目录备份以设置新工作站时意外发生
+- 系统管理员的疏忽或恶意
+- 通过不安全的备份
+- 通过桌面应用程序(浏览器、pdf 查看器等)中的恶意软件
+- 跨越国界时通过胁迫
+
+使用良好的密码短语保护你的密钥极大地有助于降低上述任何风险,但密码
+短语可以通过键盘记录器、肩窥或任何其他方式发现。因此,建议的设置是
+从主目录中删除你的证书密钥并将其存储在离线存储中。
+
+.. warning::
+
+ 请参阅上一节并确保你已完整备份 GnuPG 目录。如果你没有可用的
+ 备份,我们要做的事情将使你的密钥毫无用处!
+
+首先,确定你的证书密钥的keygrip::
+
+ $ gpg --with-keygrip --list-key [fpr]
+
+输出将是这样的::
+
+ pub ed25519 2022-12-20 [SC] [expires: 2022-12-19]
+ 000000000000000000000000AAAABBBBCCCCDDDD
+ Keygrip = 1111000000000000000000000000000000000000
+ uid [ultimate] Alice Dev <adev@kernel.org>
+ sub cv25519 2022-12-20 [E] [expires: 2022-12-19]
+ Keygrip = 2222000000000000000000000000000000000000
+ sub ed25519 2022-12-20 [S]
+ Keygrip = 3333000000000000000000000000000000000000
+
+找到该线 ``pub`` 下方的keygrip项 (位于“认证密钥指纹”的正下方)。
+这将直接对应于你``~/.gnupg`` 目录中的一个文件::
+
+ $ cd ~/.gnupg/private-keys-v1.d
+ $ ls
+ 1111000000000000000000000000000000000000.key
+ 2222000000000000000000000000000000000000.key
+ 3333000000000000000000000000000000000000.key
+
+你所要做的只是删除与证书密钥 keygrip 对应的 .key 文件::
+
+ $ cd ~/.gnupg/private-keys-v1.d
+ $ rm 1111000000000000000000000000000000000000.key
+
+现在,如果你发出命令 ``--list-secret-keys`` ,它将显示证书密钥丢
+失( 表示 ``#`` 它不可用)::
+
+ $ gpg --list-secret-keys
+ sec# ed25519 2022-12-20 [SC] [expires: 2024-12-19]
+ 000000000000000000000000AAAABBBBCCCCDDDD
+ uid [ultimate] Alice Dev <adev@kernel.org>
+ ssb cv25519 2022-12-20 [E] [expires: 2024-12-19]
+ ssb ed25519 2022-12-20 [S]
+
+你还应该删除 ``~/.gnupg``目录中的所有 ``secring.gpg`` 文件 ,这些
+文件可能是以前版本的 GnuPG 留下的。
+
+如果你没有“private-keys-v1.d”目录
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+如果你没有 ``~/.gnupg/private-keys-v1.d`` 目录,那么你的密钥仍存
+储在 GnuPG v1 使用的旧文件 ``secring.gpg`` 中。对密钥进行任何更改
+(例如更改密码或添加子密钥)应该会自动转换旧 ``secring.gpg`` 格式以
+供使用 ``private-keys-v1.d`` 。
+
+完成此操作后,请确保删除过时的 ``secring.gpg`` 文件,其中仍然包含你
+的私钥。
+
+
+将子密钥移至专用加密设备
+========================
+
+尽管 Certify 密钥现在不会被泄露或被盗,但子密钥仍然位于你的主目录中。
+任何设法获得这些内容的人都将能够解密你的通信或伪造你的签名(如果他们知
+道密码)。此外,每次执行 GnuPG 操作时,密钥都会加载到系统内存中,并
+可能被足够高级的恶意软件(例如 Meltdown 和 Spectre)从那里窃取。
+
+完全保护密钥的最佳方法是将它们转移到能够进行智能卡操作的专用硬件设备上。
+
+智能卡的好处
+------------
+
+智能卡包含一个加密芯片,能够存储私钥并直接在卡本身上执行加密操作。由于
+密钥内容永远不会离开智能卡,因此插入硬件设备的计算机的操作系统无法自行
+检索私钥。这与我们之前用于备份目的的加密 USB 存储设备有很大不同——当
+USB 设备插入并安装时,操作系统能够访问私钥内容。
+
+使用外部加密 USB 介质并不能替代具有智能卡功能的设备。
+
+可用的智能卡设备
+----------------
+
+除非你的所有笔记本电脑和工作站都有智能卡读卡器,否则最简单的方法是获
+取实现智能卡功能的专用 USB 设备。有多种选择::
+
+- `Nitrokey Start`_: 开放硬件和免费软件,日本基于FSI的 `Gnuk` 。
+ 少数支持 ED25519 ECC 密钥的商用设备之一,但提供的安全功能最少
+ (例如防篡改或某些旁路攻击)。
+- `Nitrokey Pro 2`_: 与 Nitrokey Start 类似,但更防篡改并提供
+ 更多安全功能。Pro 2 支持 ECC 加密 (NISTP)。
+- `Yubikey 5`_: 专有硬件和软件,但比 Nitrokey Pro 便宜,并且以
+ USB-C 形式提供,对于较新的笔记本电脑更有用。提供额外的安全功能,
+ 例如 FIDO U2F 等,现在终于支持 NISTP 和 ED25519 ECC 密钥。
+
+你的选择将取决于成本、你所在地理区域的货运便利性以及开放/专有硬件考虑
+因素。
+
+.. note::
+
+ 如果你位列于 MAINTAINERS 中或在 kernel.org 上拥有帐户,则你有
+ 资格获得Linux 基金会提供的_`qualify for a free Nitrokey Start` 。
+
+.. _`Nitrokey Start`: https://shop.nitrokey.com/shop/product/nitrokey-start-6
+.. _`Nitrokey Pro 2`: https://shop.nitrokey.com/shop/product/nkpr2-nitrokey-pro-2-3
+.. _`Yubikey 5`: https://www.yubico.com/products/yubikey-5-overview/
+.. _Gnuk: https://www.fsij.org/doc-gnuk/
+.. _`qualify for a free Nitrokey Start`: https://www.kernel.org/nitrokey-digital-tokens-for-kernel-developers.html
+
+配置你的智能卡设备
+------------------
+
+当你将智能卡设备插入任何现代 Linux 工作站时,它就应该可以正常工作
+(TM)。你可以通过运行来验证它::
+
+ $ gpg --card-status
+
+如果你看到完整的智能卡详细信息,那么你就可以开始了。不幸的是,对所有
+可能无法正常工作的原因进行故障排除超出了本指南的范围。如果你在使该卡
+与 GnuPG 配合使用时遇到问题,请通过常规支持渠道寻求帮助。
+
+要配置你的智能卡,你需要使用 GnuPG 菜单系统,因为没有方便的命令行开
+关::
+
+ $ gpg --card-edit
+ [...omitted...]
+ gpg/card> admin
+ Admin commands are allowed
+ gpg/card> passwd
+
+你应该设置用户 PIN (1)、管理员 PIN (3) 和重置代码 (4)。请确保将
+这些信息记录并存储在安全的地方,尤其是管理员 PIN 码和重置代码(它允
+许你完全擦除智能卡)。你很少需要使用管理员 PIN 码,如果你不记录它,
+你将不可避免地忘记它是什么。
+
+回到主卡菜单,你还可以设置其他值(例如姓名、性别、登录数据等),但这
+不是必需的,并且如果你丢失智能卡,还会泄露有关智能卡的信息。
+
+.. note::
+
+ 尽管名称为“PIN”,但卡上的用户 PIN 和管理员 PIN 都不需要是数字。
+
+.. warning::
+
+ 某些设备可能要求你将子密钥移至设备上,然后才能更改密码。请检查设
+ 备制造商提供的文档。
+
+将子密钥移至你的智能卡
+----------------------
+
+退出卡菜单(使用“q”)并保存所有更改。接下来,让我们将子密钥移至智能卡
+上。对于大多数操作,你将需要 PGP 密钥密码和卡的管理员 PIN::
+
+ $ gpg --edit-key [fpr]
+
+ Secret subkeys are available.
+
+ pub ed25519/AAAABBBBCCCCDDDD
+ created: 2022-12-20 expires: 2024-12-19 usage: SC
+ trust: ultimate validity: ultimate
+ ssb cv25519/1111222233334444
+ created: 2022-12-20 expires: never usage: E
+ ssb ed25519/5555666677778888
+ created: 2017-12-07 expires: never usage: S
+ [ultimate] (1). Alice Dev <adev@kernel.org>
+
+ gpg>
+
+使用 ``--edit-key`` 使我们再次进入菜单模式,你会注意到按键列表有点
+不同。从现在开始,所有命令都在此菜单模式内完成,如 所示 ``gpg>``。
+
+首先,让我们选择要放入卡上的密钥 - 你可以通过键入 ``key 1`` (它是
+列表中的第一个, **[E]** 子密钥)来完成此操作:
+
+ gpg> key 1
+
+在输出中,你现在在 **[E]** 子密钥应该看到 ``ssb*`` 。意味着这个子
+密钥当前被选中。它用作切换键,这意味着如果你再次输入 ``key 1`` ,
+``*`` 将会消失并且该键将不再被选择。
+
+现在,让我们将该密钥移至智能卡上::
+
+ gpg> keytocard
+ Please select where to store the key:
+ (2) Encryption key
+ Your selection? 2
+
+由于它是我们的 **[E]** 密钥,因此将其放入加密槽中是有意义的。当你提
+交选择时,系统将首先提示你输入 PGP 密钥密码,然后输入管理员 PIN 码。
+如果命令返回且没有错误,则你的密钥已被移动。
+
+**重要提示**:现在再次键入 ``key 1`` 以取消选择第一个键,并 ``key 2``
+选择 **[S]** 密钥::
+
+ gpg> key 1
+ gpg> key 2
+ gpg> keytocard
+ Please select where to store the key:
+ (1) Signature key
+ (3) Authentication key
+ Your selection? 1
+
+你可以使用 **[S]** 密钥进行签名和身份验证,但我们希望确保它位于签名槽中,
+因此选择 (1)。跟之前一样,如果你的命令返回且没有错误,则操作成功::
+
+ gpg> q
+ Save changes? (y/N) y
+
+保存更改将删除你从主目录移动到卡上的密钥(但这没关系,因为我们还有备份,
+让我们需要替换智能卡时再次执行此操作)。
+
+验证密钥是否已移动
+~~~~~~~~~~~~~~~~~~
+
+如果你现在执行 ``--list-secret-keys`` ,你将看到输出中存在细微的差异::
+
+ $ gpg --list-secret-keys
+ sec# ed25519 2022-12-20 [SC] [expires: 2024-12-19]
+ 000000000000000000000000AAAABBBBCCCCDDDD
+ uid [ultimate] Alice Dev <adev@kernel.org>
+ ssb> cv25519 2022-12-20 [E] [expires: 2024-12-19]
+ ssb> ed25519 2022-12-20 [S]
+
+在 ``ssb>``中的 ``>`` 输出意味着子密钥只能在智能卡上可用,如果你返回
+密钥目录并查看那里的内容,你会注意到 ``.key`` 那里的文件已被存根替换::
+
+ $ cd ~/.gnupg/private-keys-v1.d
+ $ strings *.key | grep 'private-key'
+
+输出应包含 ``shadowed-private-key`` 指示这些文件只是存根,实际内容
+位于智能卡上。
+
+验证智能卡是否正常工作
+~~~~~~~~~~~~~~~~~~~~~~
+
+要验证智能卡是否按预期工作,你可以创建签名::
+
+ $ echo "Hello world" | gpg --clearsign > /tmp/test.asc
+ $ gpg --verify /tmp/test.asc
+
+在你的第一条命令执行时,应该会询问你智能卡的PIN,然后在你运行
+``gpg --verify`` 后显示"Good signature"。
+
+恭喜,你已成功使窃取你的数字开发者身份变得极其困难!
+
+其他常见的 GnuPG 操作
+---------------------
+
+以下是你需要使用 PGP 密钥执行的一些常见操作的快速参考。
+
+安装你的安全离线存储
+~~~~~~~~~~~~~~~~~~~~
+
+你将需要你的证书密钥来执行以下任何操作,因此你首先需要安装备份离线存储
+并告诉 GnuPG 使用它::
+
+ $ export GNUPGHOME=/media/disk/foo/gnupg-backup
+ $ gpg --list-secret-keys
+
+你需要确保你看到 ``sec`` 而不是 ``sec#`` 在输出中( ``#`` 意味着
+密钥不可用并且你仍在使用常规主目录位置)。
+
+延长密钥有效期
+~~~~~~~~~~~~~~
+
+证书密钥的默认到期日期为自创建之日起 2 年。这样做既是出于安全原因,也
+是为了使过时的密钥最终从密钥服务器中消失。
+
+要将密钥的有效期从当前日期延长一年,只需运行::
+
+ $ gpg --quick-set-expire [fpr] 1y
+
+如果更容易记住,你也可以使用特定日期(例如你的生日、1 月 1 日或加拿大
+国庆日)::
+
+ $ gpg --quick-set-expire [fpr] 2025-07-01
+
+请记住将更新后的密钥发送回密钥服务器::
+
+ $ gpg --send-key [fpr]
+
+进行任何更改后更新你的工作目录
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+使用离线存储对密钥进行任何更改后,你需要将这些更改导入回常规工作目录
+中::
+
+ $ gpg --export | gpg --homedir ~/.gnupg --import
+ $ unset GNUPGHOME
+
+通过 ssh 使用 gpg-agent
+~~~~~~~~~~~~~~~~~~~~~~~
+
+如果你需要在远程系统上签署标签或提交,你可以通过 ssh 转发你的
+gpg-agent。
+
+请参考 GnuPG wiki 上提供的说明:
+
+- `Agent通过SSH转发`_
+
+如果你可以修改远程端的 sshd 服务器设置,则工作会更顺利。
+
+.. _`Agent通过SSH转发`: https://wiki.gnupg.org/AgentForwarding
+
+将 PGP 与 Git 结合使用
+======================
+
+Git 的核心功能之一是它的分散性——一旦将仓库克隆到你的系统,你就拥有该
+项目的完整历史记录,包括其所有标签、提交和分支。然而,随着数百个克隆仓
+库的出现,人们如何验证他们的 linux.git 副本没有被恶意第三方篡改?
+
+或者,如果在代码中发现后门,并且提交中的“Author”行表示它是由你完成的,
+而你非常确定 `自己与它无关`_ ,会发生什么?
+
+为了解决这两个问题,Git 引入了 PGP 集成。签名的标签通过确保其内容与创
+建标签的开发人员的工作站上的内容完全相同来证明仓库的完整性,而签名的提
+交使其他人几乎不可能在无法访问你的 PGP 密钥的情况下冒充你。
+
+.. _`自己与它无关`: https://github.com/jayphelps/git-blame-someone-else
+
+配置 git 使用你的 PGP 密钥
+--------------------------
+
+如果你的密钥环中只有一个密钥,那么你实际上不需要执行任何额外操作,因为
+它会成为你的默认密钥。但是,如果你碰巧有多个密钥,你可以告诉 git 应该
+使用哪个密钥(``[fpr]`` 是你密钥的指纹)::
+
+ $ git config --global user.signingKey [fpr]
+
+如何使用签名标签
+----------------
+
+要创建签名标签,只需将 ``-s`` 开关传递给 tag 命令::
+
+ $ git tag -s [tagname]
+
+我们的建议是始终签署 git 标签,因为这可以让其他开发人员确保他们从中提
+取的 git 仓库没有被恶意更改。
+
+如何验证签名标签
+~~~~~~~~~~~~~~~~
+
+要验证签名标签,只需使用以下 ``verify-tag`` 命令::
+
+ $ git verify-tag [tagname]
+
+如果你从项目仓库的另一个分支中拉取标签,git 应该自动验证你拉取的顶
+部的签名,并在合并操作期间向你显示结果::
+
+ $ git pull [url] tags/sometag
+
+合并消息将包含如下内容::
+
+ Merge tag 'sometag' of [url]
+
+ [Tag message]
+
+ # gpg: Signature made [...]
+ # gpg: Good signature from [...]
+
+如果你正在验证其他人的 git 标签,那么你将需要导入他们的 PGP 密钥。
+请参阅下面的":ref:`身份验证`"部分。
+
+配置 git 始终对带注释的标签(annotated tags)进行签名annotated tags
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+如果你要创建带注释的标签,你很可能会想要对其进行签名。要强制 git 始终签
+署带注释的标签,你可以设置一个全局配置选项::
+
+ $ git config --global tag.forceSignAnnotated true
+
+如何使用签名的提交
+------------------
+
+创建签名提交很容易,但在 Linux 内核开发中使用它们要困难得多,因为它依赖
+于发送到邮件列表的补丁,并且此工作流程不保留 PGP 提交签名。此外,当重新
+调整仓库以匹配上游时,甚至你自己的 PGP 提交签名最终也会被丢弃。因此,大
+多数内核开发人员不会费心签署他们的提交,并且会忽略他们在工作中依赖的任何
+外部仓库中的签名提交。
+
+但是,如果你的工作 git 树在某些 git 托管服务(kernel.org、
+infradead.org、ozlabs.org 或其他)上公开可用,那么建议你签署所有 git
+提交,即使上游开发人员不直接受益于这种做法。
+
+我们推荐这样做的原因如下:
+
+1. 如果需要执行代码取证或跟踪代码来源,即使是外部维护的带有 PGP 提交签名
+ 的树对于此类问题也很有价值。
+2. 如果你需要重新克隆本地仓库(例如,在磁盘故障后),这可以让你在恢复工
+ 作之前轻松验证仓库的完整性。
+3. 如果有人需要挑选你的提交,这可以让他们在应用之前快速验证其完整性。
+
+创建签名提交
+~~~~~~~~~~~~
+
+要创建签名提交,你只需将 ``-S`` 标志传递给 ``git commit`` 命令(由于
+与另一个标志冲突,所以它是大写的 ``-S`` )::
+
+ $ git commit -S
+
+配置 git 始终对提交进行签名
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+你可以告诉 git 总是签署提交::
+
+ git config --global commit.gpgSign true
+
+.. note::
+
+ 确保 ``gpg-agent`` 在打开此功能之前进行配置。
+
+.. _身份验证:
+
+
+如何使用签名补丁
+----------------
+
+可以使用你的 PGP 密钥来签署发送到内核开发人员邮件列表的补丁。由于现有的
+电子邮件签名机制(PGP-Mime 或 PGP-inline)往往会导致常规代码审查任务
+出现问题,因此你应该使用为此创建的 kernel.org 工具,该工具将加密证明签
+名放入消息标头中(a-la DKIM):
+
+- `Patatt Patch Attestation`_
+
+.. _`Patatt Patch Attestation`: https://pypi.org/project/patatt/
+
+安装和配置 patatt
+~~~~~~~~~~~~~~~~~
+
+Patatt 已针对许多发行版进行了打包,因此请先检查那里。你还可以使用
+“ ``pip install patatt`` ”从 pypi 安装它。
+
+如果你已经使用 git 配置了 PGP 密钥(通过``user.signingKey`` 配置参数),
+则 patatt 不需要进一步配置。你可以通过在所需的仓库中安装 git-send-email
+钩子来开始签署补丁::
+
+ patatt install-hook
+
+现在,你使用 ``git send-email`` 发送的任何补丁都将自动使用你的加密签
+名进行签名
+
+检查 patatt 签名
+~~~~~~~~~~~~~~~~
+
+如果你用于 ``b4`` 检索和应用补丁,那么它将自动尝试验证它遇到的所有
+DKIM 和 patatt 签名,例如::
+
+ $ b4 am 20220720205013.890942-1-broonie@kernel.org
+ [...]
+ Checking attestation on all messages, may take a moment...
+ ---
+ ✓ [PATCH v1 1/3] kselftest/arm64: Correct buffer allocation for SVE Z registers
+ ✓ [PATCH v1 2/3] arm64/sve: Document our actual ABI for clearing registers on syscall
+ ✓ [PATCH v1 3/3] kselftest/arm64: Enforce actual ABI for SVE syscalls
+ ---
+ ✓ Signed: openpgp/broonie@kernel.org
+ ✓ Signed: DKIM/kernel.org
+
+.. note::
+
+ Patatt 和 b4 仍在积极开发中,你应该检查这些项目的最新文档以了解任
+ 何新功能或更新功能。
+
+如何验证内核开发者身份
+======================
+
+签署标签和提交很容易,但是如何验证用于签署某项内容的密钥是否属于实际的内
+核开发人员而不是恶意冒名顶替者?
+
+使用 WKD 和 DANE 配置auto-key-locate(自动密钥检索)
+----------------------------------------------------
+
+如果你还没有广泛收集其他开发人员的公钥,那么你可以依靠密钥自动发现和自动
+检索来快速启动你的密钥环。如果从头开始创建自己的信任 Web 的预期太令人畏
+惧, GnuPG 可以借助其他委托信任技术(即 DNSSEC 和 TLS)来帮助你继续前
+进。
+
+将以下内容添加到你的 ``~/.gnupg/gpg.conf``::
+
+ auto-key-locate wkd,dane,local
+ auto-key-retrieve
+
+基于 DNS 的命名实体身份验证(“DANE”)是一种在 DNS 中发布公钥并使用
+DNSSEC 签名区域保护它们的方法。Web 密钥目录(“WKD”)是使用 https
+查找来达到相同目的的替代方法。当使用 DANE 或 WKD 查找公钥时,GnuPG
+将分别验证 DNSSEC 或 TLS 证书,然后将自动检索的公钥添加到本地密钥环。
+
+Kernel.org 为所有拥有 kernel.org 帐户的开发人员发布 WKD。一旦你的
+``gpg.conf`` 中进行了上述更改,你就可以自动检索 Linus Torvalds 和
+Greg Kroah-Hartman 的密钥(如果你还没有它们)::
+
+ $ gpg --locate-keys torvalds@kernel.org gregkh@kernel.org
+
+如果你有 kernel.org 帐户,那么你应该 `添加 kernel.org UID 到你的密钥中`_
+添加到你的密钥中,以使 WKD 对其他内核开发人员更有用。
+
+.. _`添加 kernel.org UID 到你的密钥中`: https://korg.wiki.kernel.org/userdoc/mail#adding_a_kernelorg_uid_to_your_pgp_key
+
+信任网 (WOT) 与首次使用信任 (TOFU)
+-----------------------------------
+
+PGP 结合了称为“信任网”的信任委托机制。从本质上讲,这是一次尝试取代
+HTTPS/TLS 世界对集中式证书颁发机构的需求。PGP 将这一责任留给每个
+用户,而不是由各种软件制造商规定谁应该是你值得信赖的认证实体。
+
+不幸的是,很少有人了解信任网是如何运作的。虽然它仍然是 OpenPGP 规
+范的一个重要方面,但最新版本的 GnuPG(2.2 及更高版本)已经实现了
+一种称为“首次使用信任”(TOFU) 的替代机制。你可以将 TOFU 视为“类似
+SSH 的信任方法”。使用 SSH,第一次连接到远程系统时,其密钥指纹会被
+记录并记住。如果将来密钥发生变化,SSH 客户端将向你发出警报并拒绝连
+接,迫使你决定是否选择信任更改后的密钥。同样,第一次导入某人的 PGP
+密钥时,它被认为是有效的。如果将来的任何时候 GnuPG 遇到具有相同标
+识的另一个密钥,则先前导入的密钥和新密钥都将被标记为无效,你将需要手
+动确定保留哪一个。
+
+我们建议你使用 TOFU+PGP 组合信任模型(这是 GnuPG v2 中新默认的)。
+若要设置它,在 ``~/.gnupg/gpg.conf`` 中添加(或修改)
+``trust-model`` 设置::
+
+ trust-model tofu+pgp
+
+使用 kernel.org 信任网仓库
+--------------------------
+
+Kernel.org 维护着一个包含开发人员公钥的 git 仓库,作为复制密钥服
+务器网络的替代品,而在过去几年中,该网络几乎已经陷入黑暗。有关如何将
+该仓库设置为公钥来源的完整文档可以在此处找到:
+
+- `内核开发者密钥环`_
+
+如果你是内核开发人员,请考虑提交你的密钥以将其包含到该密钥环中。
+
+.. _`内核开发者密钥环`: https://korg.docs.kernel.org/pgpkeys.html
diff --git a/Documentation/translations/zh_CN/process/management-style.rst b/Documentation/translations/zh_CN/process/management-style.rst
index c6a5bb285797..8053ae474328 100644
--- a/Documentation/translations/zh_CN/process/management-style.rst
+++ b/Documentation/translations/zh_CN/process/management-style.rst
@@ -36,14 +36,14 @@ Linux内核管理风格
每个人都认为管理者做决定,而且决策很重要。决定越大越痛苦,管理者就必须越高级。
这很明显,但事实并非如此。
-游戏的名字是 **避免** 做出决定。尤其是,如果有人告诉你“选择(a)或(b),
+最重要的是 **避免** 做出决定。尤其是,如果有人告诉你“选择(a)或(b),
我们真的需要你来做决定”,你就是陷入麻烦的管理者。你管理的人比你更了解细节,
所以如果他们来找你做技术决策,你完蛋了。你显然没有能力为他们做这个决定。
(推论:如果你管理的人不比你更了解细节,你也会被搞砸,尽管原因完全不同。
也就是说,你的工作是错的,他们应该管理你的才智)
-所以游戏的名字是 **避免** 做出决定,至少是那些大而痛苦的决定。做一些小的
+所以最重要的是 **避免** 做出决定,至少是那些大而痛苦的决定。做一些小的
和非结果性的决定是很好的,并且使您看起来好像知道自己在做什么,所以内核管理者
需要做的是将那些大的和痛苦的决定变成那些没有人真正关心的小事情。
diff --git a/Documentation/translations/zh_CN/process/programming-language.rst b/Documentation/translations/zh_CN/process/programming-language.rst
index 2a47a1d2ec20..fabdc338dbfb 100644
--- a/Documentation/translations/zh_CN/process/programming-language.rst
+++ b/Documentation/translations/zh_CN/process/programming-language.rst
@@ -9,8 +9,7 @@
============
内核是用C语言 :ref:`c-language <cn_c-language>` 编写的。更准确地说,内核通常是用 :ref:`gcc <cn_gcc>`
-在 ``-std=gnu89`` :ref:`gcc-c-dialect-options <cn_gcc-c-dialect-options>` 下编译的:ISO C90的 GNU 方言(
-包括一些C99特性)
+在 ``-std=gnu11`` :ref:`gcc-c-dialect-options <cn_gcc-c-dialect-options>` 下编译的:ISO C11的 GNU 方言
这种方言包含对语言 :ref:`gnu-extensions <cn_gnu-extensions>` 的许多扩展,当然,它们许多都在内核中使用。
diff --git a/Documentation/translations/zh_CN/process/submit-checklist.rst b/Documentation/translations/zh_CN/process/submit-checklist.rst
index 8738c55e42a2..10536b74aeec 100644
--- a/Documentation/translations/zh_CN/process/submit-checklist.rst
+++ b/Documentation/translations/zh_CN/process/submit-checklist.rst
@@ -1,107 +1,110 @@
.. include:: ../disclaimer-zh_CN.rst
-:Original: :ref:`Documentation/process/submit-checklist.rst <submitchecklist>`
-:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+:Original: Documentation/process/submit-checklist.rst
+:Translator:
+ - Alex Shi <alexs@kernel.org>
+ - Wu XiangCheng <bobwxc@email.cn>
.. _cn_submitchecklist:
-Linux内核补丁提交清单
-~~~~~~~~~~~~~~~~~~~~~
+Linux内核补丁提交检查单
+~~~~~~~~~~~~~~~~~~~~~~~
如果开发人员希望看到他们的内核补丁提交更快地被接受,那么他们应该做一些基本
的事情。
-这些都是在
-:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
+这些都是在 Documentation/translations/zh_CN/process/submitting-patches.rst
和其他有关提交Linux内核补丁的文档中提供的。
-1) 如果使用工具,则包括定义/声明该工具的文件。不要依赖于其他头文件拉入您使用
+1) 如果使用工具,则包括定义/声明该工具的文件。不要依赖其他头文件来引入您使用
的头文件。
2) 干净的编译:
- a) 使用适用或修改的 ``CONFIG`` 选项 ``=y``、``=m`` 和 ``=n`` 。没有GCC
+ a) 使用合适的 ``CONFIG`` 选项 ``=y``、``=m`` 和 ``=n`` 。没有 ``gcc``
警告/错误,没有链接器警告/错误。
- b) 通过allnoconfig、allmodconfig
+ b) 通过 ``allnoconfig`` 、 ``allmodconfig``
c) 使用 ``O=builddir`` 时可以成功编译
-3) 通过使用本地交叉编译工具或其他一些构建场在多个CPU体系结构上构建。
+ d) 任何 Doucmentation/ 下的变更都能成功构建且不引入新警告/错误。
+ 用 ``make htmldocs`` 或 ``make pdfdocs`` 检验构建情况并修复问题。
+
+3) 通过使用本地交叉编译工具或其他一些构建设施在多个CPU体系结构上构建。
4) PPC64是一种很好的交叉编译检查体系结构,因为它倾向于对64位的数使用无符号
长整型。
-5) 如下所述 :ref:`Documentation/translations/zh_CN/process/coding-style.rst <cn_codingstyle>`.
- 检查您的补丁是否为常规样式。在提交( ``scripts/check patch.pl`` )之前,
- 使用补丁样式检查器检查是否有轻微的冲突。您应该能够处理您的补丁中存在的所有
+5) 按 Documentation/translations/zh_CN/process/coding-style.rst 所述检查您的
+ 补丁是否为常规样式。在提交之前使用补丁样式检查器 ``scripts/checkpatch.pl``
+ 检查是否有轻微的冲突。您应该能够处理您的补丁中存在的所有
违规行为。
-6) 任何新的或修改过的 ``CONFIG`` 选项都不会弄脏配置菜单,并默认为关闭,除非
- 它们符合 ``Documentation/kbuild/kconfig-language.rst`` 中记录的异常条件,
- 菜单属性:默认值.
+6) 任何新的或修改过的 ``CONFIG`` 选项都不应搞乱配置菜单,并默认为关闭,除非
+ 它们符合 ``Documentation/kbuild/kconfig-language.rst`` 菜单属性:默认值中
+ 记录的例外条件。
7) 所有新的 ``kconfig`` 选项都有帮助文本。
8) 已仔细审查了相关的 ``Kconfig`` 组合。这很难用测试来纠正——脑力在这里是有
回报的。
-9) 用 sparse 检查干净。
+9) 通过 sparse 清查。
+ (参见 Documentation/translations/zh_CN/dev-tools/sparse.rst )
-10) 使用 ``make checkstack`` 和 ``make namespacecheck`` 并修复他们发现的任何
- 问题。
+10) 使用 ``make checkstack`` 并修复他们发现的任何问题。
.. note::
- ``checkstack`` 并没有明确指出问题,但是任何一个在堆栈上使用超过512
+ ``checkstack`` 并不会明确指出问题,但是任何一个在堆栈上使用超过512
字节的函数都可以进行更改。
-11) 包括 :ref:`kernel-doc <kernel_doc>` 内核文档以记录全局内核API。(静态函数
- 不需要,但也可以。)使用 ``make htmldocs`` 或 ``make pdfdocs`` 检查
- :ref:`kernel-doc <kernel_doc>` 并修复任何问题。
+11) 包括 :ref:`kernel-doc <kernel_doc_zh>` 内核文档以记录全局内核API。(静态
+ 函数不需要,但也可以。)使用 ``make htmldocs`` 或 ``make pdfdocs`` 检查
+ :ref:`kernel-doc <kernel_doc_zh>` 并修复任何问题。
-12) 通过以下选项同时启用的测试 ``CONFIG_PREEMPT``, ``CONFIG_DEBUG_PREEMPT``,
+12) 通过以下选项同时启用的测试: ``CONFIG_PREEMPT``, ``CONFIG_DEBUG_PREEMPT``,
``CONFIG_DEBUG_SLAB``, ``CONFIG_DEBUG_PAGEALLOC``, ``CONFIG_DEBUG_MUTEXES``,
``CONFIG_DEBUG_SPINLOCK``, ``CONFIG_DEBUG_ATOMIC_SLEEP``,
- ``CONFIG_PROVE_RCU`` and ``CONFIG_DEBUG_OBJECTS_RCU_HEAD``
-
-13) 已经过构建和运行时测试,包括有或没有 ``CONFIG_SMP``, ``CONFIG_PREEMPT``.
+ ``CONFIG_PROVE_RCU`` 和 ``CONFIG_DEBUG_OBJECTS_RCU_HEAD`` 。
-14) 如果补丁程序影响IO/磁盘等:使用或不使用 ``CONFIG_LBDAF`` 进行测试。
+13) 在 ``CONFIG_SMP``, ``CONFIG_PREEMPT`` 开启和关闭的情况下都进行构建和运行
+ 时测试。
-15) 所有代码路径都已在启用所有lockdep功能的情况下运行。
+14) 所有代码路径都已在启用所有死锁检测(lockdep)功能的情况下运行。
-16) 所有新的/proc条目都记录在 ``Documentation/``
+15) 所有新的 ``/proc`` 条目都记录在 ``Documentation/``
-17) 所有新的内核引导参数都记录在
+16) 所有新的内核引导参数都记录在
Documentation/admin-guide/kernel-parameters.rst 中。
-18) 所有新的模块参数都记录在 ``MODULE_PARM_DESC()``
+17) 所有新的模块参数都记录在 ``MODULE_PARM_DESC()``
-19) 所有新的用户空间接口都记录在 ``Documentation/ABI/`` 中。有关详细信息,
+18) 所有新的用户空间接口都记录在 ``Documentation/ABI/`` 中。有关详细信息,
请参阅 ``Documentation/ABI/README`` 。更改用户空间接口的补丁应该抄送
linux-api@vger.kernel.org。
-20) 检查是否全部通过 ``make headers_check`` 。
-
-21) 已通过至少注入slab和page分配失败进行检查。请参阅 ``Documentation/fault-injection/``
+19) 已通过至少注入slab和page分配失败进行检查。请参阅 ``Documentation/fault-injection/`` 。
如果新代码是实质性的,那么添加子系统特定的故障注入可能是合适的。
-22) 新添加的代码已经用 ``gcc -W`` 编译(使用 ``make EXTRA-CFLAGS=-W`` )。这
+20) 新添加的代码已经用 ``gcc -W`` 编译(使用 ``make EXTRA-CFLAGS=-W`` )。这
将产生大量噪声,但对于查找诸如“警告:有符号和无符号之间的比较”之类的错误
很有用。
-23) 在它被合并到-mm补丁集中之后进行测试,以确保它仍然与所有其他排队的补丁以
+21) 在它被合并到-mm补丁集中之后进行测试,以确保它仍然与所有其他排队的补丁以
及VM、VFS和其他子系统中的各种更改一起工作。
-24) 所有内存屏障例如 ``barrier()``, ``rmb()``, ``wmb()`` 都需要源代码中的注
+22) 所有内存屏障(例如 ``barrier()``, ``rmb()``, ``wmb()`` )都需要源代码注
释来解释它们正在执行的操作及其原因的逻辑。
-25) 如果补丁添加了任何ioctl,那么也要更新 ``Documentation/ioctl/ioctl-number.rst``
+23) 如果补丁添加了任何ioctl,那么也要更新
+ ``Documentation/userspace-api/ioctl/ioctl-number.rst`` 。
-26) 如果修改后的源代码依赖或使用与以下 ``Kconfig`` 符号相关的任何内核API或
+24) 如果修改后的源代码依赖或使用与以下 ``Kconfig`` 符号相关的任何内核API或
功能,则在禁用相关 ``Kconfig`` 符号和/或 ``=m`` (如果该选项可用)的情况
下测试以下多个构建[并非所有这些都同时存在,只是它们的各种/随机组合]:
- ``CONFIG_SMP``, ``CONFIG_SYSFS``, ``CONFIG_PROC_FS``, ``CONFIG_INPUT``, ``CONFIG_PCI``, ``CONFIG_BLOCK``, ``CONFIG_PM``, ``CONFIG_MAGIC_SYSRQ``,
- ``CONFIG_NET``, ``CONFIG_INET=n`` (但是后者伴随 ``CONFIG_NET=y``).
+ ``CONFIG_SMP``, ``CONFIG_SYSFS``, ``CONFIG_PROC_FS``, ``CONFIG_INPUT``,
+ ``CONFIG_PCI``, ``CONFIG_BLOCK``, ``CONFIG_PM``, ``CONFIG_MAGIC_SYSRQ``,
+ ``CONFIG_NET``, ``CONFIG_INET=n`` (但是最后一个需要 ``CONFIG_NET=y`` )。
diff --git a/Documentation/translations/zh_CN/process/submitting-drivers.rst b/Documentation/translations/zh_CN/process/submitting-drivers.rst
deleted file mode 100644
index d99885c27aed..000000000000
--- a/Documentation/translations/zh_CN/process/submitting-drivers.rst
+++ /dev/null
@@ -1,160 +0,0 @@
-.. _cn_submittingdrivers:
-
-.. include:: ../disclaimer-zh_CN.rst
-
-:Original: :ref:`Documentation/process/submitting-drivers.rst
- <submittingdrivers>`
-
-如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
-交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
-译存在问题,请联系中文版维护者::
-
- 中文版维护者: 李阳 Li Yang <leoyang.li@nxp.com>
- 中文版翻译者: 李阳 Li Yang <leoyang.li@nxp.com>
- 中文版校译者: 陈琦 Maggie Chen <chenqi@beyondsoft.com>
- 王聪 Wang Cong <xiyou.wangcong@gmail.com>
- 张巍 Zhang Wei <wezhang@outlook.com>
-
-如何向 Linux 内核提交驱动程序
-=============================
-
-这篇文档将会解释如何向不同的内核源码树提交设备驱动程序。请注意,如果你感
-兴趣的是显卡驱动程序,你也许应该访问 XFree86 项目(http://www.xfree86.org/)
-和/或 X.org 项目 (http://x.org)。
-
-另请参阅 Documentation/translations/zh_CN/process/submitting-patches.rst 文档。
-
-
-分配设备号
-----------
-
-块设备和字符设备的主设备号与从设备号是由 Linux 命名编号分配权威 LANANA(
-现在是 Torben Mathiasen)负责分配。申请的网址是 http://www.lanana.org/。
-即使不准备提交到主流内核的设备驱动也需要在这里分配设备号。有关详细信息,
-请参阅 Documentation/admin-guide/devices.rst。
-
-如果你使用的不是已经分配的设备号,那么当你提交设备驱动的时候,它将会被强
-制分配一个新的设备号,即便这个设备号和你之前发给客户的截然不同。
-
-设备驱动的提交对象
-------------------
-
-Linux 2.0:
- 此内核源码树不接受新的驱动程序。
-
-Linux 2.2:
- 此内核源码树不接受新的驱动程序。
-
-Linux 2.4:
- 如果所属的代码领域在内核的 MAINTAINERS 文件中列有一个总维护者,
- 那么请将驱动程序提交给他。如果此维护者没有回应或者你找不到恰当的
- 维护者,那么请联系 Willy Tarreau <w@1wt.eu>。
-
-Linux 2.6:
- 除了遵循和 2.4 版内核同样的规则外,你还需要在 linux-kernel 邮件
- 列表上跟踪最新的 API 变化。向 Linux 2.6 内核提交驱动的顶级联系人
- 是 Andrew Morton <akpm@linux-foundation.org>。
-
-决定设备驱动能否被接受的条件
-----------------------------
-
-许可: 代码必须使用 GNU 通用公开许可证 (GPL) 提交给 Linux,但是
- 我们并不要求 GPL 是唯一的许可。你或许会希望同时使用多种
- 许可证发布,如果希望驱动程序可以被其他开源社区(比如BSD)
- 使用。请参考 include/linux/module.h 文件中所列出的可被
- 接受共存的许可。
-
-版权: 版权所有者必须同意使用 GPL 许可。最好提交者和版权所有者
- 是相同个人或实体。否则,必需列出授权使用 GPL 的版权所有
- 人或实体,以备验证之需。
-
-接口: 如果你的驱动程序使用现成的接口并且和其他同类的驱动程序行
- 为相似,而不是去发明无谓的新接口,那么它将会更容易被接受。
- 如果你需要一个 Linux 和 NT 的通用驱动接口,那么请在用
- 户空间实现它。
-
-代码: 请使用 Documentation/process/coding-style.rst 中所描述的 Linux 代码风
- 格。如果你的某些代码段(例如那些与 Windows 驱动程序包共
- 享的代码段)需要使用其他格式,而你却只希望维护一份代码,
- 那么请将它们很好地区分出来,并且注明原因。
-
-可移植性: 请注意,指针并不永远是 32 位的,不是所有的计算机都使用小
- 尾模式 (little endian) 存储数据,不是所有的人都拥有浮点
- 单元,不要随便在你的驱动程序里嵌入 x86 汇编指令。只能在
- x86 上运行的驱动程序一般是不受欢迎的。虽然你可能只有 x86
- 硬件,很难测试驱动程序在其他平台上是否可用,但是确保代码
- 可以被轻松地移植却是很简单的。
-
-清晰度: 做到所有人都能修补这个驱动程序将会很有好处,因为这样你将
- 会直接收到修复的补丁而不是 bug 报告。如果你提交一个试图
- 隐藏硬件工作机理的驱动程序,那么它将会被扔进废纸篓。
-
-电源管理: 因为 Linux 正在被很多移动设备和桌面系统使用,所以你的驱
- 动程序也很有可能被使用在这些设备上。它应该支持最基本的电
- 源管理,即在需要的情况下实现系统级休眠和唤醒要用到的
- .suspend 和 .resume 函数。你应该检查你的驱动程序是否能正
- 确地处理休眠与唤醒,如果实在无法确认,请至少把 .suspend
- 函数定义成返回 -ENOSYS(功能未实现)错误。你还应该尝试确
- 保你的驱动在什么都不干的情况下将耗电降到最低。要获得驱动
- 程序测试的指导,请参阅
- Documentation/power/drivers-testing.rst。有关驱动程序电
- 源管理问题相对全面的概述,请参阅
- Documentation/driver-api/pm/devices.rst。
-
-管理: 如果一个驱动程序的作者还在进行有效的维护,那么通常除了那
- 些明显正确且不需要任何检查的补丁以外,其他所有的补丁都会
- 被转发给作者。如果你希望成为驱动程序的联系人和更新者,最
- 好在代码注释中写明并且在 MAINTAINERS 文件中加入这个驱动
- 程序的条目。
-
-不影响设备驱动能否被接受的条件
-------------------------------
-
-供应商: 由硬件供应商来维护驱动程序通常是一件好事。不过,如果源码
- 树里已经有其他人提供了可稳定工作的驱动程序,那么请不要期
- 望“我是供应商”会成为内核改用你的驱动程序的理由。理想的情
- 况是:供应商与现有驱动程序的作者合作,构建一个统一完美的
- 驱动程序。
-
-作者: 驱动程序是由大的 Linux 公司研发还是由你个人编写,并不影
- 响其是否能被内核接受。没有人对内核源码树享有特权。只要你
- 充分了解内核社区,你就会发现这一点。
-
-
-资源列表
---------
-
-Linux 内核主源码树:
- ftp.??.kernel.org:/pub/linux/kernel/...
- ?? == 你的国家代码,例如 "cn"、"us"、"uk"、"fr" 等等
-
-Linux 内核邮件列表:
- linux-kernel@vger.kernel.org
- [可通过向majordomo@vger.kernel.org发邮件来订阅]
-
-Linux 设备驱动程序,第三版(探讨 2.6.10 版内核):
- http://lwn.net/Kernel/LDD3/ (免费版)
-
-LWN.net:
- 每周内核开发活动摘要 - http://lwn.net/
-
- 2.6 版中 API 的变更:
-
- http://lwn.net/Articles/2.6-kernel-api/
-
- 将旧版内核的驱动程序移植到 2.6 版:
-
- http://lwn.net/Articles/driver-porting/
-
-内核新手(KernelNewbies):
- 为新的内核开发者提供文档和帮助
- http://kernelnewbies.org/
-
-Linux USB项目:
- http://www.linux-usb.org/
-
-写内核驱动的“不要”(Arjan van de Ven著):
- http://www.fenrus.org/how-to-not-write-a-device-driver-paper.pdf
-
-内核清洁工 (Kernel Janitor):
- http://kernelnewbies.org/KernelJanitors
diff --git a/Documentation/translations/zh_CN/process/submitting-patches.rst b/Documentation/translations/zh_CN/process/submitting-patches.rst
index 1bb4271ab420..f8978f02057c 100644
--- a/Documentation/translations/zh_CN/process/submitting-patches.rst
+++ b/Documentation/translations/zh_CN/process/submitting-patches.rst
@@ -1,144 +1,92 @@
-.. _cn_submittingpatches:
+.. SPDX-License-Identifier: GPL-2.0-or-later
.. include:: ../disclaimer-zh_CN.rst
-:Original: :ref:`Documentation/process/submitting-patches.rst <submittingpatches>`
+.. _cn_submittingpatches:
+
+:Original: Documentation/process/submitting-patches.rst
-译者::
+:译者:
+ - 钟宇 TripleX Chung <xxx.phy@gmail.com>
+ - 时奎亮 Alex Shi <alexs@kernel.org>
+ - 吴想成 Wu XiangCheng <bobwxc@email.cn>
- 中文版维护者: 钟宇 TripleX Chung <xxx.phy@gmail.com>
- 中文版翻译者: 钟宇 TripleX Chung <xxx.phy@gmail.com>
- 时奎亮 Alex Shi <alex.shi@linux.alibaba.com>
- 中文版校译者: 李阳 Li Yang <leoyang.li@nxp.com>
- 王聪 Wang Cong <xiyou.wangcong@gmail.com>
+:校译:
+ - 李阳 Li Yang <leoyang.li@nxp.com>
+ - 王聪 Wang Cong <xiyou.wangcong@gmail.com>
-如何让你的改动进入内核
-======================
+提交补丁:如何让你的改动进入内核
+================================
对于想要将改动提交到 Linux 内核的个人或者公司来说,如果不熟悉“规矩”,
-提交的流程会让人畏惧。本文档收集了一系列建议,这些建议可以大大的提高你
+提交的流程会让人畏惧。本文档包含了一系列建议,可以大大提高你
的改动被接受的机会.
-以下文档含有大量简洁的建议, 具体请见:
-:ref:`Documentation/process <development_process_main>`
-同样,:ref:`Documentation/translations/zh_CN/process/submit-checklist.rst <cn_submitchecklist>`
-给出在提交代码前需要检查的项目的列表。如果你在提交一个驱动程序,那么
-同时阅读一下:
-:ref:`Documentation/process/submitting-drivers.rst <submittingdrivers>`
+本文档以较为简洁的行文给出了大量建议。关于内核开发流程如何进行的详细信息,
+参见: Documentation/translations/zh_CN/process/development-process.rst 。
+Documentation/translations/zh_CN/process/submit-checklist.rst 给出了一系列
+提交补丁之前要检查的事项。设备树相关的补丁,请参阅
+Documentation/devicetree/bindings/submitting-patches.rst 。
-其中许多步骤描述了Git版本控制系统的默认行为;如果您使用Git来准备补丁,
-您将发现它为您完成的大部分机械工作,尽管您仍然需要准备和记录一组合理的
-补丁。一般来说,使用git将使您作为内核开发人员的生活更轻松。
+本文档假设您正在使用 ``git`` 准备你的补丁。如果您不熟悉 ``git`` ,最好学习
+如何使用它,这将使您作为内核开发人员的生活变得更加轻松。
+部分子系统和维护人员的树有一些关于其工作流程和要求的额外信息,请参阅
+Documentation/process/maintainer-handbooks.rst 。
-0) 获取当前源码树
------------------
+获取当前源码树
+--------------
-如果您没有一个可以使用当前内核源代码的存储库,请使用git获取一个。您将要
-从主线存储库开始,它可以通过以下方式获取::
+如果您手头没有当前内核源代码的存储库,请使用 ``git`` 获取一份。您需要先获取
+主线存储库,它可以通过以下命令拉取::
- git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
+ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
-但是,请注意,您可能不希望直接针对主线树进行开发。大多数子系统维护人员运
+但是,请注意,您可能不想直接针对主线树进行开发。大多数子系统维护人员运
行自己的树,并希望看到针对这些树准备的补丁。请参见MAINTAINERS文件中子系
-统的 **T:** 项以查找该树,或者简单地询问维护者该树是否未在其中列出。
-
-仍然可以通过tarballs下载内核版本(如下一节所述),但这是进行内核开发的
-一种困难的方式。
-
-1) "diff -up"
--------------
-
-使用 "diff -up" 或者 "diff -uprN" 来创建补丁。
-
-所有内核的改动,都是以补丁的形式呈现的,补丁由 diff(1) 生成。创建补丁的
-时候,要确认它是以 "unified diff" 格式创建的,这种格式由 diff(1) 的 '-u'
-参数生成。而且,请使用 '-p' 参数,那样会显示每个改动所在的C函数,使得
-产生的补丁容易读得多。补丁应该基于内核源代码树的根目录,而不是里边的任
-何子目录。
-
-为一个单独的文件创建补丁,一般来说这样做就够了::
-
- SRCTREE=linux
- MYFILE=drivers/net/mydriver.c
+统的 **T:** 项以查找该树,或者直接询问维护者该树是否未在其中列出。
- cd $SRCTREE
- cp $MYFILE $MYFILE.orig
- vi $MYFILE # make your change
- cd ..
- diff -up $SRCTREE/$MYFILE{.orig,} > /tmp/patch
+.. _zh_describe_changes:
-为多个文件创建补丁,你可以解开一个没有修改过的内核源代码树,然后和你自
-己的代码树之间做 diff 。例如::
-
- MYSRC=/devel/linux
-
- tar xvfz linux-3.19.tar.gz
- mv linux-3.19 linux-3.19-vanilla
- diff -uprN -X linux-3.19-vanilla/Documentation/dontdiff \
- linux-3.19-vanilla $MYSRC > /tmp/patch
-
-"dontdiff" 是内核在编译的时候产生的文件的列表,列表中的文件在 diff(1)
-产生的补丁里会被跳过。
-
-确定你的补丁里没有包含任何不属于这次补丁提交的额外文件。记得在用diff(1)
-生成补丁之后,审阅一次补丁,以确保准确。
-
-如果你的改动很散乱,你应该研究一下如何将补丁分割成独立的部分,将改动分
-割成一系列合乎逻辑的步骤。这样更容易让其他内核开发者审核,如果你想你的
-补丁被接受,这是很重要的。请参阅:
-:ref:`cn_split_changes`
-
-如果你用 ``git`` , ``git rebase -i`` 可以帮助你这一点。如果你不用 ``git``,
-``quilt`` <http://savannah.nongnu.org/projects/quilt> 另外一个流行的选择。
-
-.. _cn_describe_changes:
-
-2) 描述你的改动
----------------
+描述你的改动
+------------
描述你的问题。无论您的补丁是一行错误修复还是5000行新功能,都必须有一个潜在
-的问题激励您完成这项工作。让审稿人相信有一个问题值得解决,让他们读完第一段
-是有意义的。
+的问题激励您完成这项工作。说服审阅者相信有一个问题值得解决,让他们读完第一段
+后就能明白这一点。
描述用户可见的影响。直接崩溃和锁定是相当有说服力的,但并不是所有的错误都那么
-明目张胆。即使在代码审查期间发现了这个问题,也要描述一下您认为它可能对用户产
+明目张胆。即使在代码审阅期间发现了这个问题,也要描述一下您认为它可能对用户产
生的影响。请记住,大多数Linux安装运行的内核来自二级稳定树或特定于供应商/产品
的树,只从上游精选特定的补丁,因此请包含任何可以帮助您将更改定位到下游的内容:
触发的场景、DMESG的摘录、崩溃描述、性能回归、延迟尖峰、锁定等。
-量化优化和权衡。如果您声称在性能、内存消耗、堆栈占用空间或二进制大小方面有所
-改进,请包括支持它们的数字。但也要描述不明显的成本。优化通常不是免费的,而是
-在CPU、内存和可读性之间进行权衡;或者,探索性的工作,在不同的工作负载之间进
+质量优化和权衡。如果您声称在性能、内存消耗、堆栈占用空间或二进制大小方面有所
+改进,请包括支持它们的数据。但也要描述不明显的成本。优化通常不是零成本的,而是
+在CPU、内存和可读性之间进行权衡;或者,做探索性的工作,在不同的工作负载之间进
行权衡。请描述优化的预期缺点,以便审阅者可以权衡成本和收益。
-一旦问题建立起来,就要详细地描述一下您实际在做什么。对于审阅者来说,用简单的
-英语描述代码的变化是很重要的,以验证代码的行为是否符合您的意愿。
+提出问题之后,就要详细地描述一下您实际在做的技术细节。对于审阅者来说,用简练的
+英语描述代码的变化是很重要的,以验证代码的行为是否符合您的意图。
-如果您将补丁描述写在一个表单中,这个表单可以很容易地作为“提交日志”放入Linux
-的源代码管理系统git中,那么维护人员将非常感谢您。见 :ref:`cn_explicit_in_reply_to`.
+如果您将补丁描述写成“标准格式”,可以很容易地作为“提交日志”放入Linux的源代
+码管理系统 ``git`` 中,那么维护人员将非常感谢您。
+参见 :ref:`zh_the_canonical_patch_format` 。
每个补丁只解决一个问题。如果你的描述开始变长,这就表明你可能需要拆分你的补丁。
-请见 :ref:`cn_split_changes`
+请见 :ref:`zh_split_changes` 。
-提交或重新提交修补程序或修补程序系列时,请包括完整的修补程序说明和理由。不要
+提交或重新提交补丁或补丁系列时,请包括完整的补丁说明和理由。不要
只说这是补丁(系列)的第几版。不要期望子系统维护人员引用更早的补丁版本或引用
URL来查找补丁描述并将其放入补丁中。也就是说,补丁(系列)及其描述应该是独立的。
-这对维护人员和审查人员都有好处。一些评审者可能甚至没有收到补丁的早期版本。
+这对维护人员和审阅者都有好处。一些审阅者可能甚至没有收到补丁的早期版本。
-描述你在命令语气中的变化,例如“make xyzzy do frotz”而不是“[这个补丁]make
-xyzzy do frotz”或“[我]changed xyzzy to do frotz”,就好像你在命令代码库改变
+用祈使句描述你的变更,例如“make xyzzy do frotz”而不是“[This patch]make
+xyzzy do frotz”或“[I]changed xyzzy to do frotz”,就好像你在命令代码库改变
它的行为一样。
-如果修补程序修复了一个记录的bug条目,请按编号和URL引用该bug条目。如果补丁来
-自邮件列表讨论,请给出邮件列表存档的URL;使用带有 ``Message-ID`` 的
-https://lkml.kernel.org/ 重定向,以确保链接不会过时。
-
-但是,在没有外部资源的情况下,尽量让你的解释可理解。除了提供邮件列表存档或
-bug的URL之外,还要总结需要提交补丁的相关讨论要点。
-
-如果您想要引用一个特定的提交,不要只引用提交的 SHA-1 ID。还请包括提交的一行
+如果您想要引用一个特定的提交,不要只引用提交的SHA-1 ID。还请包括提交的一行
摘要,以便于审阅者了解它是关于什么的。例如::
Commit e21d2170f36602ae2708 ("video: remove unnecessary
@@ -146,82 +94,104 @@ bug的URL之外,还要总结需要提交补丁的相关讨论要点。
platform_set_drvdata(), but left the variable "dev" unused,
delete it.
-您还应该确保至少使用前12位 SHA-1 ID. 内核存储库包含*许多*对象,使与较短的ID
+您还应该确保至少使用前12位SHA-1 ID。内核存储库包含 *许多* 对象,使较短的ID
发生冲突的可能性很大。记住,即使现在不会与您的六个字符ID发生冲突,这种情况
-可能五年后改变。
+也可能在五年后改变。
+
+如果该变更的相关讨论或背景信息可以在网上查阅,请加上“Link:”标签指向它。例如
+你的补丁修复了一个缺陷,需要添加一个带有URL的标签指向邮件列表存档或缺陷跟踪器
+的相关报告;如果该补丁是由一些早先邮件列表讨论或网络上的记录引起的,请指向它。
+
+当链接到邮件列表存档时,请首选lore.kernel.org邮件存档服务。用邮件中的
+``Message-ID`` 头(去掉尖括号)可以创建链接URL。例如::
+
+ Link: https://lore.kernel.org/r/30th.anniversary.repost@klaava.Helsinki.FI/
+
+请检查该链接以确保可用且指向正确的邮件。
-如果修补程序修复了特定提交中的错误,例如,使用 ``git bisct`` ,请使用带有前
-12个字符SHA-1 ID 的"Fixes:"标记和单行摘要。为了简化不要将标记拆分为多个,
-行、标记不受分析脚本“75列换行”规则的限制。例如::
+不过,在没有外部资源的情况下,也要尽量让你的解释可理解。除了提供邮件列表存档或
+缺陷的URL之外,还要需要总结该补丁的相关讨论要点。
- Fixes: 54a4f0239f2e ("KVM: MMU: make kvm_mmu_zap_page() return the number of pages it actually freed")
+如果补丁修复了特定提交中的错误,例如使用 ``git bisct`` 发现了一个问题,请使用
+带有前12个字符SHA-1 ID的“Fixes:”标签和单行摘要。为了简化解析脚本,不要将该
+标签拆分为多行,标签不受“75列换行”规则的限制。例如::
-下列 ``git config`` 设置可以添加让 ``git log``, ``git show`` 漂亮的显示格式::
+ Fixes: 54a4f0239f2e ("KVM: MMU: make kvm_mmu_zap_page() return the number of pages it actually freed")
+
+下列 ``git config`` 设置可以让 ``git log``, ``git show`` 增加上述风格的显示格式::
[core]
abbrev = 12
[pretty]
fixes = Fixes: %h (\"%s\")
-.. _cn_split_changes:
+使用示例::
+
+ $ git log -1 --pretty=fixes 54a4f0239f2e
+ Fixes: 54a4f0239f2e ("KVM: MMU: make kvm_mmu_zap_page() return the number of pages it actually freed")
-3) 拆分你的改动
----------------
+.. _zh_split_changes:
-将每个逻辑更改分隔成一个单独的补丁。
+拆分你的改动
+------------
+
+将每个 **逻辑更改** 拆分成一个单独的补丁。
例如,如果你的改动里同时有bug修正和性能优化,那么把这些改动拆分到两个或
-者更多的补丁文件中。如果你的改动包含对API的修改,并且修改了驱动程序来适
-应这些新的API,那么把这些修改分成两个补丁。
+者更多的补丁文件中。如果你的改动包含对API的修改,并且增加了一个使用该新API
+的驱动,那么把这些修改分成两个补丁。
另一方面,如果你将一个单独的改动做成多个补丁文件,那么将它们合并成一个
单独的补丁文件。这样一个逻辑上单独的改动只被包含在一个补丁文件里。
-如果有一个补丁依赖另外一个补丁来完成它的改动,那没问题。简单的在你的补
-丁描述里指出“这个补丁依赖某补丁”就好了。
+需要记住的一点是,每个补丁的更改都应易于理解,以便审阅者验证。每个补丁都应该
+对其价值进行阐述。
+
+如果有一个补丁依赖另外一个补丁来完成它的改动,那没问题。直接在你的补
+丁描述里指出 **“这个补丁依赖某补丁”** 就好了。
-在将您的更改划分为一系列补丁时,要特别注意确保内核在系列中的每个补丁之后
-都能正常构建和运行。使用 ``git bisect`` 来追踪问题的开发者可能会在任何时
-候分割你的补丁系列;如果你在中间引入错误,他们不会感谢你。
+在将您的更改划分为一系列补丁时,要特别注意确保内核在应用系列中的每个补丁之后
+都能正常构建和运行。使用 ``git bisect`` 来追踪问题的开发者可能会在任何地方分
+割你的补丁系列;如果你在中间引入错误,他们不会感谢你。
-如果你不能将补丁浓缩成更少的文件,那么每次大约发送出15个,然后等待审查
+如果你不能将补丁系列浓缩得更小,那么每次大约发送出15个补丁,然后等待审阅
和集成。
-4) 检查你的更改风格
--------------------
+检查你的更改风格
+----------------
-检查您的补丁是否存在基本样式冲突,详细信息可在
-:ref:`Documentation/translations/zh_CN/process/coding-style.rst <cn_codingstyle>`
-中找到。如果不这样做,只会浪费审稿人的时间,并且会导致你的补丁被拒绝,甚至
+检查您的补丁是否违反了基本样式规定,详细信息参见
+Documentation/translations/zh_CN/process/coding-style.rst
+中找到。如果不这样做,只会浪费审阅者的时间,并且会导致你的补丁被拒绝,甚至
可能没有被阅读。
一个重要的例外是在将代码从一个文件移动到另一个文件时——在这种情况下,您不应
该在移动代码的同一个补丁中修改移动的代码。这清楚地描述了移动代码和您的更改
-的行为。这大大有助于审查实际差异,并允许工具更好地跟踪代码本身的历史。
+的行为。这大大有助于审阅实际差异,并允许工具更好地跟踪代码本身的历史。
在提交之前,使用补丁样式检查程序检查补丁(scripts/check patch.pl)。不过,
请注意,样式检查程序应该被视为一个指南,而不是作为人类判断的替代品。如果您
-的代码看起来更好,但有违规行为,那么最好不要使用它。
+的代码看起来更好,但有违规行为,那么最好别管它。
检查者报告三个级别:
- ERROR:很可能出错的事情
- - WARNING:需要仔细审查的事项
+ - WARNING:需要仔细审阅的事项
- CHECK:需要思考的事情
您应该能够判断您的补丁中存在的所有违规行为。
-5) 选择补丁收件人
------------------
+选择补丁收件人
+--------------
-您应该总是在任何补丁上复制相应的子系统维护人员,以获得他们维护的代码;查看
+您应该总是知会任何补丁相应代码的子系统维护人员;查看
维护人员文件和源代码修订历史记录,以了解这些维护人员是谁。脚本
-scripts/get_Maintainer.pl在这个步骤中非常有用。如果您找不到正在工作的子系统
+scripts/get_maintainer.pl在这个步骤中非常有用。如果您找不到正在工作的子系统
的维护人员,那么Andrew Morton(akpm@linux-foundation.org)将充当最后的维护
人员。
-您通常还应该选择至少一个邮件列表来接收补丁集的。linux-kernel@vger.kernel.org
-作为最后一个解决办法的列表,但是这个列表上的体积已经引起了许多开发人员的拒绝。
+您通常还应该选择至少一个邮件列表来接收补丁集的副本。linux-kernel@vger.kernel.org
+是所有补丁的默认列表,但是这个列表的流量已经导致了许多开发人员不再看它。
在MAINTAINERS文件中查找子系统特定的列表;您的补丁可能会在那里得到更多的关注。
不过,请不要发送垃圾邮件到无关的列表。
@@ -231,212 +201,170 @@ http://vger.kernel.org/vger-lists.html 上找到它们的列表。不过,也
不要一次发送超过15个补丁到vger邮件列表!!!!
-Linus Torvalds 是决定改动能否进入 Linux 内核的最终裁决者。他的 e-mail
-地址是 <torvalds@linux-foundation.org> 。他收到的 e-mail 很多,所以一般
-的说,最好别给他发 e-mail。
-
-如果您有修复可利用安全漏洞的补丁,请将该补丁发送到 security@kernel.org。对于
-严重的bug,可以考虑短期暂停以允许分销商向用户发布补丁;在这种情况下,显然不应
-将补丁发送到任何公共列表。
+Linus Torvalds是决定改动能否进入 Linux 内核的最终裁决者。他的邮件地址是
+torvalds@linux-foundation.org 。他收到的邮件很多,所以一般来说最好 **别**
+给他发邮件。
-修复已发布内核中严重错误的补丁程序应该指向稳定版维护人员,方法是放这样的一行::
+如果您有修复可利用安全漏洞的补丁,请将该补丁发送到 security@kernel.org 。对于
+严重的bug,可以考虑短期禁令以允许分销商(有时间)向用户发布补丁;在这种情况下,
+显然不应将补丁发送到任何公共列表。
+参见 Documentation/translations/zh_CN/admin-guide/security-bugs.rst 。
- Cc: stable@vger.kernel.org
+修复已发布内核中严重错误的补丁程序应该抄送给稳定版维护人员,方法是把以下列行
+放进补丁的签准区(注意,不是电子邮件收件人)::
-进入补丁的签准区(注意,不是电子邮件收件人)。除了这个文件之外,您还应该阅读
-:ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
+ Cc: stable@vger.kernel.org
-但是,请注意,一些子系统维护人员希望得出他们自己的结论,即哪些补丁应该被放到
-稳定的树上。尤其是网络维护人员,不希望看到单个开发人员在补丁中添加像上面这样
-的行。
+除了本文件之外,您还应该阅读
+Documentation/translations/zh_CN/process/stable-kernel-rules.rst 。
-如果更改影响到用户和内核接口,请向手册页维护人员(如维护人员文件中所列)发送
+如果更改影响到用户侧内核接口,请向手册页维护人员(如维护人员文件中所列)发送
手册页补丁,或至少发送更改通知,以便一些信息进入手册页。还应将用户空间API
-更改复制到 linux-api@vger.kernel.org。
-
-对于小的补丁,你也许会CC到搜集琐碎补丁的邮件列表(Trivial Patch Monkey)
-trivial@kernel.org,那里专门收集琐碎的补丁。下面这样的补丁会被看作“琐碎的”
-补丁:
-
- - 文档的拼写修正。
- - 修正会影响到 grep(1) 的拼写。
- - 警告信息修正(频繁的打印无用的警告是不好的。)
- - 编译错误修正(代码逻辑的确是对的,只是编译有问题。)
- - 运行时修正(只要真的修正了错误。)
- - 移除使用了被废弃的函数/宏的代码(例如 check_region。)
- - 联系方式和文档修正。
- - 用可移植的代码替换不可移植的代码(即使在体系结构相关的代码中,既然有
- - 人拷贝,只要它是琐碎的)
- - 任何文件的作者/维护者对该文件的改动(例如 patch monkey 在重传模式下)
-
-(译注,关于“琐碎补丁”的一些说明:因为原文的这一部分写得比较简单,所以不得不
-违例写一下译注。"trivial"这个英文单词的本意是“琐碎的,不重要的。”但是在这里
-有稍微有一些变化,例如对一些明显的NULL指针的修正,属于运行时修正,会被归类
-到琐碎补丁里。虽然NULL指针的修正很重要,但是这样的修正往往很小而且很容易得到
-检验,所以也被归入琐碎补丁。琐碎补丁更精确的归类应该是
-“simple, localized & easy to verify”,也就是说简单的,局部的和易于检验的。
-trivial@kernel.org邮件列表的目的是针对这样的补丁,为提交者提供一个中心,来
-降低提交的门槛。)
-
-6) 没有 MIME 编码,没有链接,没有压缩,没有附件,只有纯文本
------------------------------------------------------------
+更改抄送到 linux-api@vger.kernel.org 。
+
+
+不要MIME编码,不要链接,不要压缩,不要附件,只要纯文本
+------------------------------------------------------
Linus 和其他的内核开发者需要阅读和评论你提交的改动。对于内核开发者来说
-,可以“引用”你的改动很重要,使用一般的 e-mail 工具,他们就可以在你的
+,可以“引用”你的改动很重要,使用一般的邮件工具,他们就可以在你的
代码的任何位置添加评论。
-因为这个原因,所有的提交的补丁都是 e-mail 中“内嵌”的。
+因为这个原因,所有的提交的补丁都是邮件中“内嵌”的。最简单(和推荐)的方法就
+是使用 ``git send-email`` 。https://git-send-email.io 有 ``git send-email``
+的交互式教程。
+
+如果你选择不用 ``git send-email`` :
.. warning::
- 如果你使用剪切-粘贴你的补丁,小心你的编辑器的自动换行功能破坏你的补丁
-不要将补丁作为 MIME 编码的附件,不管是否压缩。很多流行的 e-mail 软件不
-是任何时候都将 MIME 编码的附件当作纯文本发送的,这会使得别人无法在你的
-代码中加评论。另外,MIME 编码的附件会让 Linus 多花一点时间来处理,这就
-降低了你的改动被接受的可能性。
+ 如果你使用剪切-粘贴你的补丁,小心你的编辑器的自动换行功能破坏你的补丁
-例外:如果你的邮递员弄坏了补丁,那么有人可能会要求你使用mime重新发送补丁
+不要将补丁作为MIME编码的附件,不管是否压缩。很多流行的邮件软件不
+是任何时候都将MIME编码的附件当作纯文本发送的,这会使得别人无法在你的
+代码中加评论。另外,MIME编码的附件会让Linus多花一点时间来处理,这就
+降低了你的改动被接受的可能性。
-请参阅 :ref:`Documentation/translations/zh_CN/process/email-clients.rst <cn_email_clients>`
-以获取有关配置电子邮件客户端以使其不受影响地发送修补程序的提示。
+例外:如果你的邮路损坏了补丁,那么有人可能会要求你使用MIME重新发送补丁。
-7) e-mail 的大小
-----------------
+请参阅 Documentation/translations/zh_CN/process/email-clients.rst
+以获取有关配置电子邮件客户端以使其不受影响地发送补丁的提示。
-大的改动对邮件列表不合适,对某些维护者也不合适。如果你的补丁,在不压缩
-的情况下,超过了300kB,那么你最好将补丁放在一个能通过 internet 访问的服
-务器上,然后用指向你的补丁的 URL 替代。但是请注意,如果您的补丁超过了
-300kb,那么它几乎肯定需要被破坏。
+回复审阅意见
+------------
-8)回复评审意见
----------------
+你的补丁几乎肯定会得到审阅者对补丁改进方法的评论(以回复邮件的形式)。您必须
+对这些评论作出回应;让补丁被忽略的一个好办法就是忽略审阅者的意见。直接回复邮
+件来回应意见即可。不会导致代码更改的意见或问题几乎肯定会带来注释或变更日志的
+改变,以便下一个审阅者更好地了解正在发生的事情。
-你的补丁几乎肯定会得到评审者对补丁改进方法的评论。您必须对这些评论作出
-回应;让补丁被忽略的一个好办法就是忽略审阅者的意见。不会导致代码更改的
-意见或问题几乎肯定会带来注释或变更日志的改变,以便下一个评审者更好地了解
-正在发生的事情。
+一定要告诉审阅者你在做什么改变,并感谢他们的时间。代码审阅是一个累人且耗时的
+过程,审阅者有时会变得暴躁。即使在这种情况下,也要礼貌地回应并解决他们指出的
+问题。当发送下一版时,在封面邮件或独立补丁里加上 ``patch changelog`` 说明与
+前一版本的不同之处(参见 :ref:`zh_the_canonical_patch_format` )。
-一定要告诉审稿人你在做什么改变,并感谢他们的时间。代码审查是一个累人且
-耗时的过程,审查人员有时会变得暴躁。即使在这种情况下,也要礼貌地回应并
-解决他们指出的问题。
+.. _zh_resend_reminders:
-9)不要泄气或不耐烦
--------------------
+不要泄气或不耐烦
+----------------
-提交更改后,请耐心等待。审阅者是忙碌的人,可能无法立即访问您的修补程序。
+提交更改后,请耐心等待。审阅者是大忙人,可能无法立即审阅您的补丁。
-曾几何时,补丁曾在没有评论的情况下消失在空白中,但开发过程比现在更加顺利。
+曾几何时,补丁曾在没收到评论的情况下消失在虚空中,但现在开发过程应该更加顺利了。
您应该在一周左右的时间内收到评论;如果没有收到评论,请确保您已将补丁发送
-到正确的位置。在重新提交或联系审阅者之前至少等待一周-在诸如合并窗口之类的
+到正确的位置。在重新提交或联系审阅者之前至少等待一周——在诸如合并窗口之类的
繁忙时间可能更长。
-10)主题中包含 PATCH
---------------------
+在等了几个星期后,用带RESEND的主题重发补丁也是可以的::
-由于到linus和linux内核的电子邮件流量很高,通常会在主题行前面加上[PATCH]
-前缀. 这使Linus和其他内核开发人员更容易将补丁与其他电子邮件讨论区分开。
+ [PATCH Vx RESEND] sub/sys: Condensed patch summary
-11)签署你的作品-开发者原始认证
--------------------------------
+当你发布补丁(系列)修改版的时候,不要加上“RESEND”——“RESEND”只适用于重
+新提交之前未经修改的补丁(系列)。
-为了加强对谁做了何事的追踪,尤其是对那些透过好几层的维护者的补丁,我们
-建议在发送出去的补丁上加一个 “sign-off” 的过程。
+主题中包含 PATCH
+----------------
+
+由于到Linus和linux-kernel的电子邮件流量很高,通常会在主题行前面加上[PATCH]
+前缀。这使Linus和其他内核开发人员更容易将补丁与其他电子邮件讨论区分开。
+
+``git send-email`` 会自动为你加上。
+
+签署你的作品——开发者来源认证
+------------------------------
+
+为了加强对谁做了何事的追踪,尤其是对那些透过好几层维护者才最终到达的补丁,我
+们在通过邮件发送的补丁上引入了“签署(sign-off)”流程。
-"sign-off" 是在补丁的注释的最后的简单的一行文字,认证你编写了它或者其他
+“签署”是在补丁注释最后的一行简单文字,认证你编写了它或者其他
人有权力将它作为开放源代码的补丁传递。规则很简单:如果你能认证如下信息:
-开发者来源证书 1.1
+开发者来源认证 1.1
^^^^^^^^^^^^^^^^^^
对于本项目的贡献,我认证如下信息:
- (a)这些贡献是完全或者部分的由我创建,我有权利以文件中指出
+ (a) 这些贡献是完全或者部分的由我创建,我有权利以文件中指出
的开放源代码许可证提交它;或者
- (b)这些贡献基于以前的工作,据我所知,这些以前的工作受恰当的开放
- 源代码许可证保护,而且,根据许可证,我有权提交修改后的贡献,
+
+ (b) 这些贡献基于以前的工作,据我所知,这些以前的工作受恰当的开放
+ 源代码许可证保护,而且,根据文件中指出的许可证,我有权提交修改后的贡献,
无论是完全还是部分由我创造,这些贡献都使用同一个开放源代码许可证
- (除非我被允许用其它的许可证),正如文件中指出的;或者
- (c)这些贡献由认证(a),(b)或者(c)的人直接提供给我,而
+ (除非我被允许用其它的许可证);或者
+
+ (c) 这些贡献由认证(a),(b)或者(c)的人直接提供给我,而
且我没有修改它。
- (d)我理解并同意这个项目和贡献是公开的,贡献的记录(包括我
- 一起提交的个人记录,包括 sign-off )被永久维护并且可以和这个项目
+
+ (d) 我理解并同意这个项目和贡献是公开的,贡献的记录(包括我
+ 一起提交的个人记录,包括sign-off)被永久维护并且可以和这个项目
或者开放源代码的许可证同步地再发行。
那么加入这样一行::
- Signed-off-by: Random J Developer <random@developer.example.org>
-
-使用你的真名(抱歉,不能使用假名或者匿名。)
-
-有人在最后加上标签。现在这些东西会被忽略,但是你可以这样做,来标记公司
-内部的过程,或者只是指出关于 sign-off 的一些特殊细节。
-
-如果您是子系统或分支维护人员,有时需要稍微修改收到的补丁,以便合并它们,
-因为树和提交者中的代码不完全相同。如果你严格遵守规则(c),你应该要求提交者
-重新发布,但这完全是在浪费时间和精力。规则(b)允许您调整代码,但是更改一个
-提交者的代码并让他认可您的错误是非常不礼貌的。要解决此问题,建议在最后一个
-由签名行和您的行之间添加一行,指示更改的性质。虽然这并不是强制性的,但似乎
-在描述前加上您的邮件和/或姓名(全部用方括号括起来),这足以让人注意到您对最
-后一分钟的更改负有责任。例如::
-
- Signed-off-by: Random J Developer <random@developer.example.org>
- [lucky@maintainer.example.org: struct foo moved from foo.c to foo.h]
- Signed-off-by: Lucky K Maintainer <lucky@maintainer.example.org>
-
-如果您维护一个稳定的分支机构,同时希望对作者进行致谢、跟踪更改、合并修复并
-保护提交者不受投诉,那么这种做法尤其有用。请注意,在任何情况下都不能更改作者
-的ID(From 头),因为它是出现在更改日志中的标识。
-
-对回合(back-porters)的特别说明:在提交消息的顶部(主题行之后)插入一个补丁
-的起源指示似乎是一种常见且有用的实践,以便于跟踪。例如,下面是我们在3.x稳定
-版本中看到的内容::
-
- Date: Tue Oct 7 07:26:38 2014 -0400
-
- libata: Un-break ATA blacklist
-
- commit 1c40279960bcd7d52dbdf1d466b20d24b99176c8 upstream.
-
-还有, 这里是一个旧版内核中的一个回合补丁::
+ Signed-off-by: Random J Developer <random@developer.example.org>
- Date: Tue May 13 22:12:27 2008 +0200
+使用你的真名(抱歉,不能使用假名或者匿名。)如果使用 ``git commit -s`` 的话
+将会自动完成。撤销也应当包含“Signed-off-by”, ``git revert -s`` 会帮你搞定。
- wireless, airo: waitbusy() won't delay
+有些人会在最后加上额外的标签。现在这些东西会被忽略,但是你可以这样做,来标记
+公司内部的过程,或者只是指出关于签署的一些特殊细节。
- [backport of 2.6 commit b7acbdfbd1f277c1eb23f344f899cfa4cd0bf36a]
+作者签署之后的任何其他签署(Signed-off-by:'s)均来自处理和传递补丁的人员,但
+未参与其开发。签署链应当反映补丁传播到维护者并最终传播到Linus所经过的 **真实**
+路径,首个签署指明单个作者的主要作者身份。
-12)何时使用Acked-by:,CC:,和Co-Developed by:
-----------------------------------------------
+何时使用Acked-by:,CC:,和Co-Developed by:
+------------------------------------------
-Singed-off-by: 标记表示签名者参与了补丁的开发,或者他/她在补丁的传递路径中。
+Singed-off-by: 标签表示签名者参与了补丁的开发,或者他/她在补丁的传递路径中。
-如果一个人没有直接参与补丁的准备或处理,但希望表示并记录他们对补丁的批准,
-那么他们可以要求在补丁的变更日志中添加一个 Acked-by:
+如果一个人没有直接参与补丁的准备或处理,但希望表示并记录他们对补丁的批准/赞成,
+那么他们可以要求在补丁的变更日志中添加一个Acked-by:。
-Acked-by:通常由受影响代码的维护者使用,当该维护者既没有贡献也没有转发补丁时。
+Acked-by: 通常由受影响代码的维护者使用,当该维护者既没有贡献也没有转发补丁时。
-Acked-by: 不像签字人那样正式。这是一个记录,确认人至少审查了补丁,并表示接受。
-因此,补丁合并有时会手动将Acker的“Yep,looks good to me”转换为 Acked-By:(但
+Acked-by: 不像签署那样正式。这是一个记录,确认人至少审阅了补丁,并表示接受。
+因此,补丁合并有时会手动将Acker的“Yep,looks good to me”转换为 Acked-By:(但
请注意,通常最好要求一个明确的Ack)。
Acked-by:不一定表示对整个补丁的确认。例如,如果一个补丁影响多个子系统,并且
-有一个:来自一个子系统维护者,那么这通常表示只确认影响维护者代码的部分。这里
-应该仔细判断。如有疑问,应参考邮件列表档案中的原始讨论。
+有一个来自某个子系统维护者的Acked-By:,那么这通常表示只确认影响维护者代码的部
+分。这里应该仔细判断。如有疑问,应参考邮件列表存档中的原始讨论。
-如果某人有机会对补丁进行评论,但没有提供此类评论,您可以选择在补丁中添加 ``Cc:``
-这是唯一一个标签,它可以在没有被它命名的人显式操作的情况下添加,但它应该表明
-这个人是在补丁上抄送的。讨论中包含了潜在利益相关方。
+如果某人本应有机会对补丁进行评论,但没有提供此类评论,您可以选择在补丁中添加
+``Cc:`` 这是唯一可以在没有被该人明确同意的情况下添加的标签——但它应该表明
+这个人是在补丁上抄送的。此标签记录了讨论中包含的潜在利益相关方。
Co-developed-by: 声明补丁是由多个开发人员共同创建的;当几个人在一个补丁上工
-作时,它用于将属性赋予共同作者(除了 From: 所赋予的作者之外)。因为
-Co-developed-by: 表示作者身份,所以每个共同开发人:必须紧跟在相关合作作者的
-签名之后。标准的签核程序要求:标记的签核顺序应尽可能反映补丁的时间历史,而不
-管作者是通过 From :还是由 Co-developed-by: 共同开发的。值得注意的是,最后一
-个签字人:必须始终是提交补丁的开发人员。
+作时,它用于给出共同作者(除了From:所给出的作者之外)。因为Co-developed-by:
+表示作者身份,所以每个Co-developed-by:必须紧跟在相关合作作者的签署之后。标准
+签署程序要求Singed-off-by:标签的顺序应尽可能反映补丁的时间历史,无论作者是通
+过From:还是Co-developed-by:表明。值得注意的是,最后一个Singed-off-by:必须是
+提交补丁的开发人员。
-注意,当作者也是电子邮件标题“发件人:”行中列出的人时,“From: ” 标记是可选的。
+注意,如果From:作者也是电子邮件标题的From:行中列出的人,则From:标签是可选的。
-作者提交的补丁程序示例::
+被From:作者提交的补丁示例::
<changelog>
@@ -446,7 +374,7 @@ Co-developed-by: 表示作者身份,所以每个共同开发人:必须紧跟
Signed-off-by: Second Co-Author <second@coauthor.example.org>
Signed-off-by: From Author <from@author.example.org>
-合作开发者提交的补丁示例::
+被合作开发者提交的补丁示例::
From: From Author <from@author.example.org>
@@ -459,76 +387,85 @@ Co-developed-by: 表示作者身份,所以每个共同开发人:必须紧跟
Signed-off-by: Submitting Co-Author <sub@coauthor.example.org>
-13)使用报告人:、测试人:、审核人:、建议人:、修复人:
---------------------------------------------------------
+使用Reported-by:、Tested-by:、Reviewed-by:、Suggested-by:和Fixes:
+-----------------------------------------------------------------
Reported-by: 给那些发现错误并报告错误的人致谢,它希望激励他们在将来再次帮助
-我们。请注意,如果bug是以私有方式报告的,那么在使用Reported-by标记之前,请
-先请求权限。
+我们。请注意,如果bug是以私有方式报告的,那么在使用Reported-by标签之前,请
+先请求许可。此标签是为Bug设计的;请不要将其用于感谢功能请求。
-Tested-by: 标记表示补丁已由指定的人(在某些环境中)成功测试。这个标签通知
-维护人员已经执行了一些测试,为将来的补丁提供了一种定位测试人员的方法,并确
-保测试人员的信誉。
+Tested-by: 标签表示补丁已由指定的人(在某些环境中)成功测试。这个标签通知
+维护人员已经执行了一些测试,为将来的补丁提供了一种定位测试人员的方法,并彰显测试人员的功劳。
-Reviewed-by:相反,根据审查人的声明,表明该补丁已被审查并被认为是可接受的:
+Reviewed-by:根据审阅者的监督声明,表明该补丁已被审阅并被认为是可接受的:
-审查人的监督声明
+审阅者的监督声明
^^^^^^^^^^^^^^^^
-通过提供我的 Reviewed-by,我声明:
+通过提供我的Reviewed-by:标签,我声明:
- (a) 我已经对这个补丁进行了一次技术审查,以评估它是否适合被包含到
+ (a) 我已经对这个补丁进行了一次技术审阅,以评估它是否适合被包含到
主线内核中。
(b) 与补丁相关的任何问题、顾虑或问题都已反馈给提交者。我对提交者对
我的评论的回应感到满意。
- (c) 虽然这一提交可能会改进一些东西,但我相信,此时,(1)对内核
+ (c) 虽然这一提交可能仍可被改进,但我相信,此时,(1)对内核
进行了有价值的修改,(2)没有包含争论中涉及的已知问题。
- (d) 虽然我已经审查了补丁并认为它是健全的,但我不会(除非另有明确
- 说明)作出任何保证或保证它将在任何给定情况下实现其规定的目的
+ (d) 虽然我已经审阅了补丁并认为它是健全的,但我不会(除非另有明确
+ 说明)作出任何保证或担保它会在任何给定情况下实现其规定的目的
或正常运行。
-Reviewed-by 是一种观点声明,即补丁是对内核的适当修改,没有任何遗留的严重技术
-问题。任何感兴趣的审阅者(完成工作的人)都可以为一个补丁提供一个 Review-by
-标签。此标签用于向审阅者提供致谢,并通知维护者已在修补程序上完成的审阅程度。
-Reviewed-by: 当由已知了解主题区域并执行彻底检查的审阅者提供时,通常会增加
+Reviewed-by是一种观点声明,即补丁是对内核的适当修改,没有任何遗留的严重技术
+问题。任何感兴趣的审阅者(完成工作的人)都可以为一个补丁提供一个Reviewed-by
+标签。此标签用于向审阅者提供致谢,并通知维护者补丁的审阅进度。
+当Reviewed-by:标签由已知了解主题区域并执行彻底检查的审阅者提供时,通常会增加
补丁进入内核的可能性。
+一旦从测试人员或审阅者的“Tested-by”和“Reviewed-by”标签出现在邮件列表中,
+作者应在发送下一个版本时将其添加到适用的补丁中。但是,如果补丁在以下版本中发
+生了实质性更改,这些标签可能不再适用,因此应该删除。通常,在补丁更改日志中
+(在 ``---`` 分隔符之后)应该提到删除某人的测试者或审阅者标签。
+
Suggested-by: 表示补丁的想法是由指定的人提出的,并确保将此想法归功于指定的
人。请注意,未经许可,不得添加此标签,特别是如果该想法未在公共论坛上发布。
-这就是说,如果我们勤快地致谢我们的创意者,他们很有希望在未来得到鼓舞,再次
+也就是说,如果我们勤快地致谢创意提供者,他们将受到鼓舞,很有希望在未来再次
帮助我们。
-Fixes: 指示补丁在以前的提交中修复了一个问题。它可以很容易地确定错误的来源,
-这有助于检查错误修复。这个标记还帮助稳定内核团队确定应该接收修复的稳定内核
-版本。这是指示补丁修复的错误的首选方法。请参阅 :ref:`cn_describe_changes`
-描述您的更改以了解更多详细信息。
+Fixes: 指示补丁修复了之前提交的一个问题。它可以便于确定错误的来源,这有助于
+检查错误修复。这个标签还帮助稳定内核团队确定应该接收修复的稳定内核版本。这是
+指示补丁修复的错误的首选方法。请参阅 :ref:`zh_describe_changes` 了解更多信息。
-.. _cn_the_canonical_patch_format:
+.. note::
-12)标准补丁格式
-----------------
+ 附加Fixes:标签不会改变稳定内核规则流程,也不改变所有稳定版补丁抄送
+ stable@vger.kernel.org的要求。有关更多信息,请阅读
+ Documentation/translations/zh_CN/process/stable-kernel-rules.rst 。
+
+.. _zh_the_canonical_patch_format:
+
+标准补丁格式
+------------
本节描述如何格式化补丁本身。请注意,如果您的补丁存储在 ``Git`` 存储库中,则
-可以使用 ``git format-patch`` 进行正确的补丁格式设置。但是,这些工具无法创建
+可以使用 ``git format-patch`` 进行正确的补丁格式化。但是,这些工具无法创建
必要的文本,因此请务必阅读下面的说明。
-标准的补丁,标题行是::
+标准的补丁标题行是::
Subject: [PATCH 001/123] 子系统:一句话概述
-标准补丁的信体存在如下部分:
+标准补丁的信体包含如下部分:
- - 一个 "from" 行指出补丁作者。后跟空行(仅当发送修补程序的人不是作者时才需要)。
+ - 一个 ``from`` 行指出补丁作者。后跟空行(仅当发送补丁的人不是作者时才需要)。
- - 解释的正文,行以75列包装,这将被复制到永久变更日志来描述这个补丁。
+ - 说明文字,每行最长75列,这将被复制到永久变更日志来描述这个补丁。
- 一个空行
- - 上面描述的“Signed-off-by” 行,也将出现在更改日志中。
+ - 上述的 ``Signed-off-by:`` 行,也将出现在更改日志中。
- 只包含 ``---`` 的标记线。
@@ -536,29 +473,29 @@ Fixes: 指示补丁在以前的提交中修复了一个问题。它可以很容
- 实际补丁( ``diff`` 输出)。
-标题行的格式,使得对标题行按字母序排序非常的容易 - 很多 e-mail 客户端都
-可以支持 - 因为序列号是用零填充的,所以按数字排序和按字母排序是一样的。
+标题行的格式,使得对标题行按字母序排序非常的容易——很多邮件客户端都
+可以支持——因为序列号是用零填充的,所以按数字排序和按字母排序是一样的。
-e-mail 标题中的“子系统”标识哪个内核子系统将被打补丁。
+邮件标题中的“子系统”标识哪个内核子系统将被打补丁。
-e-mail 标题中的“一句话概述”扼要的描述 e-mail 中的补丁。“一句话概述”
+邮件标题中的“一句话概述”扼要的描述邮件中的补丁。“一句话概述”
不应该是一个文件名。对于一个补丁系列(“补丁系列”指一系列的多个相关补
丁),不要对每个补丁都使用同样的“一句话概述”。
-记住 e-mail 的“一句话概述”会成为该补丁的全局唯一标识。它会蔓延到 git
+记住邮件的“一句话概述”会成为该补丁的全局唯一标识。它会进入 ``git``
的改动记录里。然后“一句话概述”会被用在开发者的讨论里,用来指代这个补
-丁。用户将希望通过 google 来搜索"一句话概述"来找到那些讨论这个补丁的文
+丁。用户将希望通过搜索引擎搜索“一句话概述”来找到那些讨论这个补丁的文
章。当人们在两三个月后使用诸如 ``gitk`` 或 ``git log --oneline`` 之类
的工具查看数千个补丁时,也会很快看到它。
出于这些原因,概述必须不超过70-75个字符,并且必须描述补丁的更改以及为
-什么需要补丁。既要简洁又要描述性很有挑战性,但写得好的概述应该这样做。
+什么需要补丁。既要简洁又要描述性很有挑战性,但写得好的概述应该这样。
概述的前缀可以用方括号括起来:“Subject: [PATCH <tag>...] <概述>”。标记
不被视为概述的一部分,而是描述应该如何处理补丁。如果补丁的多个版本已发
-送出来以响应评审(即“v1,v2,v3”)或“rfc”,以指示评审请求,那么通用标记
-可能包括版本描述符。如果一个补丁系列中有四个补丁,那么各个补丁可以这样
-编号:1/4、2/4、3/4、4/4。这可以确保开发人员了解补丁应用的顺序,并且他们
+送出来以响应评审(即“v1,v2,v3”)则必须包含版本号,或包含“RFC”以指示
+评审请求。如果一个补丁系列中有四个补丁,那么各个补丁可以这样编号:1/4、2/4、
+3/4、4/4。这可以确保开发人员了解补丁应用的顺序,且
已经查看或应用了补丁系列中的所有补丁。
一些标题的例子::
@@ -566,95 +503,134 @@ e-mail 标题中的“一句话概述”扼要的描述 e-mail 中的补丁。
Subject: [patch 2/5] ext2: improve scalability of bitmap searching
Subject: [PATCHv2 001/207] x86: fix eflags tracking
-"From" 行是信体里的最上面一行,具有如下格式:
+``From`` 行是信体里的最上面一行,具有如下格式::
+
From: Patch Author <author@example.com>
-"From" 行指明在永久改动日志里,谁会被确认为作者。如果没有 "From" 行,那
-么邮件头里的 "From: " 行会被用来决定改动日志中的作者。
+``From`` 行指明在永久改动日志里,谁会被确认为作者。如果没有 ``From`` 行,那
+么邮件头里的 ``From:`` 行会被用来决定改动日志中的作者。
-说明的主题将会被提交到永久的源代码改动日志里,因此对那些早已经不记得和
-这个补丁相关的讨论细节的有能力的读者来说,是有意义的。包括补丁程序定位
-错误的(内核日志消息、OOPS消息等)症状,对于搜索提交日志以寻找适用补丁的人
-尤其有用。如果一个补丁修复了一个编译失败,那么可能不需要包含所有编译失败;
+说明文字将会被提交到永久的源代码改动日志里,因此应针对那些早已经不记得和这
+个补丁相关的讨论细节的读者。包括补丁处理的故障症状(内核日志消息、oops消息
+等),这对于可能正在搜索提交日志以查找适用补丁的人特别有用。文本应该写得如
+此详细,以便在数周、数月甚至数年后阅读时,能够为读者提供所需的细节信息,以
+掌握创建补丁的 **原因** 。
+
+如果一个补丁修复了一个编译失败,那么可能不需要包含 *所有* 编译失败;
只要足够让搜索补丁的人能够找到它就行了。与概述一样,既要简洁又要描述性。
-"---" 标记行对于补丁处理工具要找到哪里是改动日志信息的结束,是不可缺少
+``---`` 标记行对于补丁处理工具要找到哪里是改动日志信息的结束,是不可缺少
的。
-对于 "---" 标记之后的额外注解,一个好的用途就是用来写 diffstat,用来显
-示修改了什么文件和每个文件都增加和删除了多少行。diffstat 对于比较大的补
-丁特别有用。其余那些只是和时刻或者开发者相关的注解,不合适放到永久的改
-动日志里的,也应该放这里。
-使用 diffstat的选项 "-p 1 -w 70" 这样文件名就会从内核源代码树的目录开始
+对于 ``---`` 标记之后的额外注解,一个好的用途就是用来写 ``diffstat`` ,用来显
+示修改了什么文件和每个文件都增加和删除了多少行。 ``diffstat`` 对于比较大的补
+丁特别有用。
+使用 ``diffstat`` 的选项 ``-p 1 -w 70`` 这样文件名就会从内核源代码树的目录开始
,不会占用太宽的空间(很容易适合80列的宽度,也许会有一些缩进。)
+( ``git`` 默认会生成合适的diffstat。)
-在后面的参考资料中能看到适当的补丁格式的更多细节。
+其余那些只适用于当时或者与维护者相关的注解,不合适放到永久的改动日志里的,也
+应该放这里。较好的例子就是 ``补丁更改记录`` ,记录了v1和v2版本补丁之间的差异。
-.. _cn_explicit_in_reply_to:
+请将此信息放在将变更日志与补丁的其余部分分隔开的 ``---`` 行 **之后** 。版本
+信息不是提交到git树的变更日志的一部分。只是供审阅人员使用的附加信息。如果将
+其放置在提交标记上方,则需要手动交互才能将其删除。如果它位于分隔线以下,则在
+应用补丁时会自动剥离::
-15) 明确回复邮件头(In-Reply-To)
--------------------------------
+ <commit message>
+ ...
+ Signed-off-by: Author <author@mail>
+ ---
+ V2 -> V3: Removed redundant helper function
+ V1 -> V2: Cleaned up coding style and addressed review comments
-手动添加回复补丁的的标题头(In-Reply_To:) 是有帮助的(例如,使用 ``git send-email`` )
-将补丁与以前的相关讨论关联起来,例如,将bug修复程序链接到电子邮件和bug报告。
-但是,对于多补丁系列,最好避免在回复时使用链接到该系列的旧版本。这样,
-补丁的多个版本就不会成为电子邮件客户端中无法管理的引用序列。如果链接有用,
-可以使用 https://lkml.kernel.org/ 重定向器(例如,在封面电子邮件文本中)
-链接到补丁系列的早期版本。
+ path/to/file | 5+++--
+ ...
+
+在后面的参考资料中能看到正确补丁格式的更多细节。
-16) 发送git pull请求
---------------------
+.. _zh_backtraces:
-如果您有一系列补丁,那么让维护人员通过git pull操作将它们直接拉入子系统存储
-库可能是最方便的。但是,请注意,从开发人员那里获取补丁比从邮件列表中获取补
-丁需要更高的信任度。因此,许多子系统维护人员不愿意接受请求,特别是来自新的
-未知开发人员的请求。如果有疑问,您可以在封面邮件中使用pull 请求作为补丁系列
-正常发布的一个选项,让维护人员可以选择使用其中之一。
+提交消息中的回溯(Backtraces)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+回溯有助于记录导致问题的调用链。然而,并非所有回溯都有帮助。例如,早期引导调
+用链是独特而明显的。而逐字复制完整的dmesg输出则会增加时间戳、模块列表、寄存
+器和堆栈转储等分散注意力的信息。
+
+因此,最有用的回溯应该从转储中提取相关信息,以更容易集中在真实问题上。下面是
+一个剪裁良好的回溯示例::
+
+ unchecked MSR access error: WRMSR to 0xd51 (tried to write 0x0000000000000064)
+ at rIP: 0xffffffffae059994 (native_write_msr+0x4/0x20)
+ Call Trace:
+ mba_wrmsr
+ update_domains
+ rdtgroup_mkdir
+
+.. _zh_explicit_in_reply_to:
+
+明确回复邮件头(In-Reply-To)
+-----------------------------
+
+手动添加回复补丁的的邮件头(In-Reply_To:)是有用的(例如,使用 ``git send-email`` ),
+可以将补丁与以前的相关讨论关联起来,例如,将bug补丁链接到电子邮件和bug报告。
+但是,对于多补丁系列,最好避免在回复时使用链接到该系列的旧版本。这样,
+补丁的多个版本就不会成为电子邮件客户端中无法管理的引用树。如果链接有用,
+可以使用 https://lore.kernel.org/ 重定向器(例如,在封面电子邮件文本中)
+链接到补丁系列的早期版本。
-pull 请求的主题行中应该有[Git Pull]。请求本身应该在一行中包含存储库名称和
-感兴趣的分支;它应该看起来像::
+给出基础树信息
+--------------
- Please pull from
+当其他开发人员收到您的补丁并开始审阅时,知道应该将您的工作放到代码树历史记录
+中的什么位置通常很有用。这对于自动化持续集成流水(CI)特别有用,这些流水线试
+图运行一系列测试,以便在维护人员开始审阅之前确定提交的质量。
- git://jdelvare.pck.nerim.net/jdelvare-2.6 i2c-for-linus
+如果您使用 ``git format-patch`` 生成补丁,则可以通过 ``--base`` 标志在提交中
+自动包含基础树信息。使用此选项最简单、最方便的方法是配合主题分支::
- to get these changes:
+ $ git checkout -t -b my-topical-branch master
+ Branch 'my-topical-branch' set up to track local branch 'master'.
+ Switched to a new branch 'my-topical-branch'
+ [perform your edits and commits]
-pull 请求还应该包含一条整体消息,说明请求中将包含什么,一个补丁本身的 ``Git shortlog``
-以及一个显示补丁系列整体效果的 ``diffstat`` 。当然,将所有这些信息收集在一起
-的最简单方法是让 ``git`` 使用 ``git request-pull`` 命令为您完成这些工作。
+ $ git format-patch --base=auto --cover-letter -o outgoing/ master
+ outgoing/0000-cover-letter.patch
+ outgoing/0001-First-Commit.patch
+ outgoing/...
-一些维护人员(包括Linus)希望看到来自已签名提交的请求;这增加了他们对你的
-请求信心。特别是,在没有签名标签的情况下,Linus 不会从像 Github 这样的公共
-托管站点拉请求。
+当你编辑 ``outgoing/0000-cover-letter.patch`` 时,您会注意到在它的最底部有一
+行 ``base-commit:`` 尾注,它为审阅者和CI工具提供了足够的信息以正确执行
+``git am`` 而不必担心冲突::
-创建此类签名的第一步是生成一个 GNRPG 密钥,并由一个或多个核心内核开发人员对
-其进行签名。这一步对新开发人员来说可能很困难,但没有办法绕过它。参加会议是
-找到可以签署您的密钥的开发人员的好方法。
+ $ git checkout -b patch-review [base-commit-id]
+ Switched to a new branch 'patch-review'
+ $ git am patches.mbox
+ Applying: First Commit
+ Applying: ...
-一旦您在Git 中准备了一个您希望有人拉的补丁系列,就用 ``git tag -s`` 创建一
-个签名标记。这将创建一个新标记,标识该系列中的最后一次提交,并包含用您的私
-钥创建的签名。您还可以将changelog样式的消息添加到标记中;这是一个描述拉请求
-整体效果的理想位置。
+有关此选项的更多信息,请参阅 ``man git-format-patch`` 。
-如果维护人员将要从中提取的树不是您正在使用的存储库,请不要忘记将已签名的标记
-显式推送到公共树。
+.. note::
-生成拉请求时,请使用已签名的标记作为目标。这样的命令可以实现::
+ ``--base`` 功能是在2.9.0版git中引入的。
- git request-pull master git://my.public.tree/linux.git my-signed-tag
+如果您不使用git格式化补丁,仍然可以包含相同的 ``base-commit`` 尾注,以指示您
+的工作所基于的树的提交哈希。你应该在封面邮件或系列的第一个补丁中添加它,它应
+该放在 ``---`` 行的下面或所有其他内容之后,即只在你的电子邮件签名之前。
参考文献
--------
-Andrew Morton, "The perfect patch" (tpp).
- <http://www.ozlabs.org/~akpm/stuff/tpp.txt>
+Andrew Morton,“完美的补丁”(tpp)
+ <https://www.ozlabs.org/~akpm/stuff/tpp.txt>
-Jeff Garzik, "Linux kernel patch submission format".
+Jeff Garzik,“Linux内核补丁提交格式”
<https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html>
-Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer".
+Greg Kroah-Hartman,“如何惹恼内核子系统维护人员”
<http://www.kroah.com/log/linux/maintainer.html>
<http://www.kroah.com/log/linux/maintainer-02.html>
@@ -667,16 +643,15 @@ Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer".
<http://www.kroah.com/log/linux/maintainer-06.html>
-NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people!
- <https://lkml.org/lkml/2005/7/11/336>
+不!!!别再发巨型补丁炸弹给linux-kernel@vger.kernel.org的人们了!
+ <https://lore.kernel.org/r/20050711.125305.08322243.davem@davemloft.net>
-Kernel Documentation/process/coding-style.rst:
- :ref:`Documentation/translations/zh_CN/process/coding-style.rst <cn_codingstyle>`
+内核 Documentation/translations/zh_CN/process/coding-style.rst
-Linus Torvalds's mail on the canonical patch format:
- <http://lkml.org/lkml/2005/4/7/183>
+Linus Torvalds关于标准补丁格式的邮件
+ <https://lore.kernel.org/r/Pine.LNX.4.58.0504071023190.28951@ppc970.osdl.org>
-Andi Kleen, "On submitting kernel patches"
- Some strategies to get difficult or controversial changes in.
+Andi Kleen,“提交补丁之路”
+ 一些帮助合入困难或有争议的变更的策略。
http://halobates.de/on-submitting-patches.pdf
diff --git a/Documentation/translations/zh_CN/process/volatile-considered-harmful.rst b/Documentation/translations/zh_CN/process/volatile-considered-harmful.rst
index 48b32ce58ef1..ded3b5d0c9a8 100644
--- a/Documentation/translations/zh_CN/process/volatile-considered-harmful.rst
+++ b/Documentation/translations/zh_CN/process/volatile-considered-harmful.rst
@@ -94,8 +94,8 @@ bug并且需要对这样的代码额外仔细检查。那些试图使用volatile
注释
----
-[1] http://lwn.net/Articles/233481/
-[2] http://lwn.net/Articles/233482/
+[1] https://lwn.net/Articles/233481/
+[2] https://lwn.net/Articles/233482/
致谢
----
diff --git a/Documentation/translations/zh_CN/rust/arch-support.rst b/Documentation/translations/zh_CN/rust/arch-support.rst
new file mode 100644
index 000000000000..afbd02afec45
--- /dev/null
+++ b/Documentation/translations/zh_CN/rust/arch-support.rst
@@ -0,0 +1,23 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/rust/arch-support.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+架构支持
+========
+
+目前,Rust编译器(``rustc``)使用LLVM进行代码生成,这限制了可以支持的目标架构。此外,对
+使用LLVM/Clang构建内核的支持也有所不同(请参见 Documentation/kbuild/llvm.rst )。这
+种支持对于使用 ``libclang`` 的 ``bindgen`` 来说是必需的。
+
+下面是目前可以工作的架构的一般总结。支持程度与 ``MAINTAINERS`` 文件中的``S`` 值相对应:
+
+============ ================ ==============================================
+架构 支持水平 限制因素
+============ ================ ==============================================
+``x86`` Maintained 只有 ``x86_64``
+============ ================ ==============================================
diff --git a/Documentation/translations/zh_CN/rust/coding-guidelines.rst b/Documentation/translations/zh_CN/rust/coding-guidelines.rst
new file mode 100644
index 000000000000..6c0bdbbc5a2a
--- /dev/null
+++ b/Documentation/translations/zh_CN/rust/coding-guidelines.rst
@@ -0,0 +1,192 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/rust/coding-guidelines.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+编码指南
+========
+
+本文档描述了如何在内核中编写Rust代码。
+
+
+风格和格式化
+------------
+
+代码应该使用 ``rustfmt`` 进行格式化。这样一来,一个不时为内核做贡献的人就不需要再去学
+习和记忆一个样式指南了。更重要的是,审阅者和维护者不需要再花时间指出风格问题,这样就可以
+减少补丁落地所需的邮件往返。
+
+.. note:: ``rustfmt`` 不检查注释和文档的约定。因此,这些仍然需要照顾到。
+
+使用 ``rustfmt`` 的默认设置。这意味着遵循Rust的习惯性风格。例如,缩进时使用4个空格而
+不是制表符。
+
+在输入、保存或提交时告知编辑器/IDE进行格式化是很方便的。然而,如果因为某些原因需要在某
+个时候重新格式化整个内核Rust的源代码,可以运行以下程序::
+
+ make LLVM=1 rustfmt
+
+也可以检查所有的东西是否都是格式化的(否则就打印一个差异),例如对于一个CI,用::
+
+ make LLVM=1 rustfmtcheck
+
+像内核其他部分的 ``clang-format`` 一样, ``rustfmt`` 在单个文件上工作,并且不需要
+内核配置。有时,它甚至可以与破碎的代码一起工作。
+
+
+注释
+----
+
+“普通”注释(即以 ``//`` 开头,而不是 ``///`` 或 ``//!`` 开头的代码文档)的写法与文
+档注释相同,使用Markdown语法,尽管它们不会被渲染。这提高了一致性,简化了规则,并允许在
+这两种注释之间更容易地移动内容。比如说:
+
+.. code-block:: rust
+
+ // `object` is ready to be handled now.
+ f(object);
+
+此外,就像文档一样,注释在句子的开头要大写,并以句号结束(即使是单句)。这包括 ``// SAFETY:``,
+``// TODO:`` 和其他“标记”的注释,例如:
+
+.. code-block:: rust
+
+ // FIXME: The error should be handled properly.
+
+注释不应该被用于文档的目的:注释是为了实现细节,而不是为了用户。即使源文件的读者既是API
+的实现者又是用户,这种区分也是有用的。事实上,有时同时使用注释和文档是很有用的。例如,用
+于 ``TODO`` 列表或对文档本身的注释。对于后一种情况,注释可以插在中间;也就是说,离要注
+释的文档行更近。对于其他情况,注释会写在文档之后,例如:
+
+.. code-block:: rust
+
+ /// Returns a new [`Foo`].
+ ///
+ /// # Examples
+ ///
+ // TODO: Find a better example.
+ /// ```
+ /// let foo = f(42);
+ /// ```
+ // FIXME: Use fallible approach.
+ pub fn f(x: i32) -> Foo {
+ // ...
+ }
+
+一种特殊的注释是 ``// SAFETY:`` 注释。这些注释必须出现在每个 ``unsafe`` 块之前,它们
+解释了为什么该块内的代码是正确/健全的,即为什么它在任何情况下都不会触发未定义行为,例如:
+
+.. code-block:: rust
+
+ // SAFETY: `p` is valid by the safety requirements.
+ unsafe { *p = 0; }
+
+``// SAFETY:`` 注释不能与代码文档中的 ``# Safety`` 部分相混淆。 ``# Safety`` 部
+分指定了(函数)调用者或(特性)实现者需要遵守的契约。
+``// SAFETY:`` 注释显示了为什么一个(函数)调用者或(特性)实现者实际上尊重了
+``# Safety`` 部分或语言参考中的前提条件。
+
+
+代码文档
+--------
+
+Rust内核代码不像C内核代码那样被记录下来(即通过kernel-doc)。取而代之的是用于记录Rust
+代码的常用系统:rustdoc工具,它使用Markdown(一种轻量级的标记语言)。
+
+要学习Markdown,外面有很多指南。例如:
+
+https://commonmark.org/help/
+
+一个记录良好的Rust函数可能是这样的:
+
+.. code-block:: rust
+
+ /// Returns the contained [`Some`] value, consuming the `self` value,
+ /// without checking that the value is not [`None`].
+ ///
+ /// # Safety
+ ///
+ /// Calling this method on [`None`] is *[undefined behavior]*.
+ ///
+ /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = Some("air");
+ /// assert_eq!(unsafe { x.unwrap_unchecked() }, "air");
+ /// ```
+ pub unsafe fn unwrap_unchecked(self) -> T {
+ match self {
+ Some(val) => val,
+
+ // SAFETY: The safety contract must be upheld by the caller.
+ None => unsafe { hint::unreachable_unchecked() },
+ }
+ }
+
+这个例子展示了一些 ``rustdoc`` 的特性和内核中遵循的一些惯例:
+
+ - 第一段必须是一个简单的句子,简要地描述被记录的项目的作用。进一步的解释必须放在额
+ 外的段落中。
+
+ - 不安全的函数必须在 ``# Safety`` 部分记录其安全前提条件。
+
+ - 虽然这里没有显示,但如果一个函数可能会恐慌,那么必须在 ``# Panics`` 部分描述发
+ 生这种情况的条件。
+
+ 请注意,恐慌应该是非常少见的,只有在有充分理由的情况下才会使用。几乎在所有的情况下,
+ 都应该使用一个可失败的方法,通常是返回一个 ``Result``。
+
+ - 如果提供使用实例对读者有帮助的话,必须写在一个叫做``# Examples``的部分。
+
+ - Rust项目(函数、类型、常量……)必须有适当的链接(``rustdoc`` 会自动创建一个
+ 链接)。
+
+ - 任何 ``unsafe`` 的代码块都必须在前面加上一个 ``// SAFETY:`` 的注释,描述里面
+ 的代码为什么是正确的。
+
+ 虽然有时原因可能看起来微不足道,但写这些注释不仅是记录已经考虑到的问题的好方法,
+ 最重要的是,它提供了一种知道没有额外隐含约束的方法。
+
+要了解更多关于如何编写Rust和拓展功能的文档,请看看 ``rustdoc`` 这本书,网址是:
+
+ https://doc.rust-lang.org/rustdoc/how-to-write-documentation.html
+
+
+命名
+----
+
+Rust内核代码遵循通常的Rust命名空间:
+
+ https://rust-lang.github.io/api-guidelines/naming.html
+
+当现有的C语言概念(如宏、函数、对象......)被包装成Rust抽象时,应该使用尽可能接近C语
+言的名称,以避免混淆,并在C语言和Rust语言之间来回切换时提高可读性。例如,C语言中的
+``pr_info`` 这样的宏在Rust中的命名是一样的。
+
+说到这里,应该调整大小写以遵循Rust的命名惯例,模块和类型引入的命名间隔不应该在项目名称
+中重复。例如,在包装常量时,如:
+
+.. code-block:: c
+
+ #define GPIO_LINE_DIRECTION_IN 0
+ #define GPIO_LINE_DIRECTION_OUT 1
+
+在Rust中的等价物可能是这样的(忽略文档)。:
+
+.. code-block:: rust
+
+ pub mod gpio {
+ pub enum LineDirection {
+ In = bindings::GPIO_LINE_DIRECTION_IN as _,
+ Out = bindings::GPIO_LINE_DIRECTION_OUT as _,
+ }
+ }
+
+也就是说, ``GPIO_LINE_DIRECTION_IN`` 的等价物将被称为 ``gpio::LineDirection::In`` 。
+特别是,它不应该被命名为 ``gpio::gpio_line_direction::GPIO_LINE_DIRECTION_IN`` 。
diff --git a/Documentation/translations/zh_CN/rust/general-information.rst b/Documentation/translations/zh_CN/rust/general-information.rst
new file mode 100644
index 000000000000..6b91dfe1834a
--- /dev/null
+++ b/Documentation/translations/zh_CN/rust/general-information.rst
@@ -0,0 +1,75 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/rust/general-information.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+
+基本信息
+========
+
+本文档包含了在内核中使用Rust支持时需要了解的有用信息。
+
+
+代码文档
+--------
+
+Rust内核代码使用其内置的文档生成器 ``rustdoc`` 进行记录。
+
+生成的HTML文档包括集成搜索、链接项(如类型、函数、常量)、源代码等。它们可以在以下地址阅读
+(TODO:当在主线中时链接,与其他文档一起生成):
+
+ http://kernel.org/
+
+这些文档也可以很容易地在本地生成和阅读。这相当快(与编译代码本身的顺序相同),而且不需要特
+殊的工具或环境。这有一个额外的好处,那就是它们将根据所使用的特定内核配置进行定制。要生成它
+们,请使用 ``rustdoc`` 目标,并使用编译时使用的相同调用,例如::
+
+ make LLVM=1 rustdoc
+
+要在你的网络浏览器中本地阅读该文档,请运行如::
+
+ xdg-open rust/doc/kernel/index.html
+
+要了解如何编写文档,请看 coding-guidelines.rst 。
+
+
+额外的lints
+-----------
+
+虽然 ``rustc`` 是一个非常有用的编译器,但一些额外的lints和分析可以通过 ``clippy``
+(一个Rust linter)来实现。要启用它,请将CLIPPY=1传递到用于编译的同一调用中,例如::
+
+ make LLVM=1 CLIPPY=1
+
+请注意,Clippy可能会改变代码生成,因此在构建产品内核时不应该启用它。
+
+抽象和绑定
+----------
+
+抽象是用Rust代码包装来自C端的内核功能。
+
+为了使用来自C端的函数和类型,需要创建绑定。绑定是Rust对那些来自C端的函数和类型的声明。
+
+例如,人们可以在Rust中写一个 ``Mutex`` 抽象,它从C端包装一个 ``Mutex结构体`` ,并
+通过绑定调用其函数。
+
+抽象并不能用于所有的内核内部API和概念,但随着时间的推移,我们打算扩大覆盖范围。“Leaf”
+模块(例如,驱动程序)不应该直接使用C语言的绑定。相反,子系统应该根据需要提供尽可能安
+全的抽象。
+
+
+有条件的编译
+------------
+
+Rust代码可以访问基于内核配置的条件性编译:
+
+.. code-block:: rust
+
+ #[cfg(CONFIG_X)] // Enabled (`y` or `m`)
+ #[cfg(CONFIG_X="y")] // Enabled as a built-in (`y`)
+ #[cfg(CONFIG_X="m")] // Enabled as a module (`m`)
+ #[cfg(not(CONFIG_X))] // Disabled
diff --git a/Documentation/translations/zh_CN/rust/index.rst b/Documentation/translations/zh_CN/rust/index.rst
new file mode 100644
index 000000000000..b01f887e7167
--- /dev/null
+++ b/Documentation/translations/zh_CN/rust/index.rst
@@ -0,0 +1,28 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/rust/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+Rust
+====
+
+与内核中的Rust有关的文档。若要开始在内核中使用Rust,请阅读quick-start.rst指南。
+
+.. toctree::
+ :maxdepth: 1
+
+ quick-start
+ general-information
+ coding-guidelines
+ arch-support
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
diff --git a/Documentation/translations/zh_CN/rust/quick-start.rst b/Documentation/translations/zh_CN/rust/quick-start.rst
new file mode 100644
index 000000000000..a4b8e8a50a89
--- /dev/null
+++ b/Documentation/translations/zh_CN/rust/quick-start.rst
@@ -0,0 +1,211 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/rust/quick-start.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+
+快速入门
+========
+
+本文介绍了如何开始使用Rust进行内核开发。
+
+
+构建依赖
+--------
+
+本节描述了如何获取构建所需的工具。
+
+其中一些依赖也许可以从Linux发行版中获得,包名可能是 ``rustc`` , ``rust-src`` ,
+``rust-bindgen`` 等。然而,在写这篇文章的时候,它们很可能还不够新,除非发行版跟踪最
+新的版本。
+
+为了方便检查是否满足要求,可以使用以下目标::
+
+ make LLVM=1 rustavailable
+
+这会触发与Kconfig用来确定是否应该启用 ``RUST_IS_AVAILABLE`` 相同的逻辑;不过,如
+果Kconfig认为不该启用,它会列出未满足的条件。
+
+
+rustc
+*****
+
+需要一个特定版本的Rust编译器。较新的版本可能会也可能不会工作,因为就目前而言,内核依赖
+于一些不稳定的Rust特性。
+
+如果使用的是 ``rustup`` ,请进入检出的源代码目录并运行::
+
+ rustup override set $(scripts/min-tool-version.sh rustc)
+
+或者从以下网址获取一个独立的安装程序或安装 ``rustup`` :
+
+ https://www.rust-lang.org
+
+
+Rust标准库源代码
+****************
+
+Rust标准库的源代码是必需的,因为构建系统会交叉编译 ``core`` 和 ``alloc`` 。
+
+如果正在使用 ``rustup`` ,请运行::
+
+ rustup component add rust-src
+
+这些组件是按工具链安装的,因此以后升级Rust编译器版本需要重新添加组件。
+
+否则,如果使用独立的安装程序,可以将Rust仓库克隆到工具链的安装文件夹中::
+
+ git clone --recurse-submodules \
+ --branch $(scripts/min-tool-version.sh rustc) \
+ https://github.com/rust-lang/rust \
+ $(rustc --print sysroot)/lib/rustlib/src/rust
+
+在这种情况下,以后升级Rust编译器版本需要手动更新这个克隆的仓库。
+
+
+libclang
+********
+
+``bindgen`` 使用 ``libclang`` (LLVM的一部分)来理解内核中的C代码,这意味着需要安
+装LLVM;同在开启 ``CC=clang`` 或 ``LLVM=1`` 时编译内核一样。
+
+Linux发行版中可能会有合适的包,所以最好先检查一下。
+
+适用于部分系统和架构的二进制文件也可到以下网址下载:
+
+ https://releases.llvm.org/download.html
+
+或者自行构建LLVM,这需要相当长的时间,但并不是一个复杂的过程:
+
+ https://llvm.org/docs/GettingStarted.html#getting-the-source-code-and-building-llvm
+
+请参阅 Documentation/kbuild/llvm.rst 了解更多信息,以及获取预构建版本和发行包
+的进一步方法。
+
+
+bindgen
+*******
+
+内核的C端绑定是在构建时使用 ``bindgen`` 工具生成的。这需要特定的版本。
+
+通过以下方式安装它(注意,这将从源码下载并构建该工具)::
+
+ cargo install --locked --version $(scripts/min-tool-version.sh bindgen) bindgen
+
+
+开发依赖
+--------
+
+本节解释了如何获取开发所需的工具。也就是说,在构建内核时不需要这些工具。
+
+
+rustfmt
+*******
+
+``rustfmt`` 工具被用来自动格式化所有的Rust内核代码,包括生成的C绑定(详情请见
+coding-guidelines.rst )。
+
+如果使用的是 ``rustup`` ,它的 ``默认`` 配置文件已经安装了这个工具,因此不需要做什么。
+如果使用的是其他配置文件,可以手动安装该组件::
+
+ rustup component add rustfmt
+
+独立的安装程序也带有 ``rustfmt`` 。
+
+
+clippy
+******
+
+``clippy`` 是一个Rust linter。运行它可以为Rust代码提供额外的警告。它可以通过向 ``make``
+传递 ``CLIPPY=1`` 来运行(关于细节,详见 general-information.rst )。
+
+如果正在使用 ``rustup`` ,它的 ``默认`` 配置文件已经安装了这个工具,因此不需要做什么。
+如果使用的是另一个配置文件,该组件可以被手动安装::
+
+ rustup component add clippy
+
+独立的安装程序也带有 ``clippy`` 。
+
+
+cargo
+*****
+
+``cargo`` 是Rust的本地构建系统。目前需要它来运行测试,因为它被用来构建一个自定义的标准
+库,其中包含了内核中自定义 ``alloc`` 所提供的设施。测试可以使用 ``rusttest`` Make 目标
+来运行。
+
+如果使用的是 ``rustup`` ,所有的配置文件都已经安装了该工具,因此不需要再做什么。
+
+独立的安装程序也带有 ``cargo`` 。
+
+
+rustdoc
+*******
+
+``rustdoc`` 是Rust的文档工具。它为Rust代码生成漂亮的HTML文档(详情请见 general-information.rst )。
+
+``rustdoc`` 也被用来测试文档化的Rust代码中提供的例子(称为doctests或文档测试)。
+``rusttest`` 是本功能的Make目标。
+
+如果使用的是 ``rustup`` ,所有的配置文件都已经安装了这个工具,因此不需要做什么。
+
+独立的安装程序也带有 ``rustdoc`` 。
+
+
+rust-analyzer
+*************
+
+`rust-analyzer <https://rust-analyzer.github.io/>`_ 语言服务器可以和许多编辑器
+一起使用,以实现语法高亮、补全、转到定义和其他功能。
+
+``rust-analyzer`` 需要一个配置文件, ``rust-project.json``, 它可以由 ``rust-analyzer``
+Make 目标生成。
+
+
+配置
+----
+
+Rust支持(CONFIG_RUST)需要在 ``General setup`` 菜单中启用。在其他要求得到满足的情
+况下,该选项只有在找到合适的Rust工具链时才会显示(见上文)。相应的,这将使依赖Rust的其
+他选项可见。
+
+之后,进入::
+
+ Kernel hacking
+ -> Sample kernel code
+ -> Rust samples
+
+并启用一些内置或可加载的样例模块。
+
+
+构建
+----
+
+用完整的LLVM工具链构建内核是目前支持的最佳设置。即::
+
+ make LLVM=1
+
+对于不支持完整LLVM工具链的架构,使用::
+
+ make CC=clang
+
+使用GCC对某些配置也是可行的,但目前它是非常试验性的。
+
+
+折腾
+----
+
+要想深入了解,请看 ``samples/rust/`` 下的样例源代码、 ``rust/`` 下的Rust支持代码和
+``Kernel hacking`` 下的 ``Rust hacking`` 菜单。
+
+如果使用的是GDB/Binutils,而Rust符号没有被demangled,原因是工具链还不支持Rust的新v0
+mangling方案。有几个办法可以解决:
+
+ - 安装一个较新的版本(GDB >= 10.2, Binutils >= 2.36)。
+
+ - 一些版本的GDB(例如vanilla GDB 10.1)能够使用嵌入在调试信息(``CONFIG_DEBUG_INFO``)
+ 中的pre-demangled的名字。
diff --git a/Documentation/translations/zh_CN/scheduler/completion.rst b/Documentation/translations/zh_CN/scheduler/completion.rst
new file mode 100644
index 000000000000..bc8218514e0a
--- /dev/null
+++ b/Documentation/translations/zh_CN/scheduler/completion.rst
@@ -0,0 +1,256 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/scheduler/completion.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+=======================================
+完成 - "等待完成" 屏障应用程序接口(API)
+=======================================
+
+简介:
+-----
+
+如果你有一个或多个线程必须等待某些内核活动达到某个点或某个特定的状态,完成可以为这
+个问题提供一个无竞争的解决方案。从语义上讲,它们有点像pthread_barrier(),并且使
+用的案例类似
+
+完成是一种代码同步机制,它比任何滥用锁/信号量和忙等待循环的行为都要好。当你想用yield()
+或一些古怪的msleep(1)循环来允许其它代码继续运行时,你可能想用wait_for_completion*()
+调用和completion()来代替。
+
+使用“完成”的好处是,它们有一个良好定义、聚焦的目标,这不仅使得我们很容易理解代码的意图,
+而且它们也会生成更高效的代码,因为所有线程都可以继续执行,直到真正需要结果的时刻。而且等
+待和信号都高效的使用了低层调度器的睡眠/唤醒设施。
+
+完成是建立在Linux调度器的等待队列和唤醒基础设施之上的。等待队列中的线程所等待的
+事件被简化为 ``struct completion`` 中的一个简单标志,被恰如其名地称为‘done’。
+
+由于完成与调度有关,代码可以在kernel/sched/completion.c中找到。
+
+
+用法:
+-----
+
+使用完成需要三个主要部分:
+
+ - 'struct completion' 同步对象的初始化
+ - 通过调用wait_for_completion()的一个变体来实现等待部分。
+ - 通过调用complete()或complete_all()实现发信端。
+
+也有一些辅助函数用于检查完成的状态。请注意,虽然必须先做初始化,但等待和信号部分可以
+按任何时间顺序出现。也就是说,一个线程在另一个线程检查是否需要等待它之前,已经将一个
+完成标记为 "done",这是完全正常的。
+
+要使用完成API,你需要#include <linux/completion.h>并创建一个静态或动态的
+``struct completion`` 类型的变量,它只有两个字段::
+
+ struct completion {
+ unsigned int done;
+ wait_queue_head_t wait;
+ };
+
+结构体提供了->wait等待队列来放置任务进行等待(如果有的话),以及->done完成标志来表明它
+是否完成。
+
+完成的命名应当与正在被同步的事件名一致。一个好的例子是::
+
+ wait_for_completion(&early_console_added);
+
+ complete(&early_console_added);
+
+好的、直观的命名(一如既往地)有助于代码的可读性。将一个完成命名为 ``complete``
+是没有帮助的,除非其目的是超级明显的...
+
+
+初始化完成:
+-----------
+
+动态分配的完成对象最好被嵌入到数据结构中,以确保在函数/驱动的生命周期内存活,以防
+止与异步complete()调用发生竞争。
+
+在使用wait_for_completion()的_timeout()或_killable()/_interruptible()变体
+时应特别小心,因为必须保证在所有相关活动(complete()或reinit_completion())发生
+之前不会发生内存解除分配,即使这些等待函数由于超时或信号触发而过早返回。
+
+动态分配的完成对象的初始化是通过调用init_completion()来完成的::
+
+ init_completion(&dynamic_object->done);
+
+在这个调用中,我们初始化 waitqueue 并将 ->done 设置为 0,即“not completed”或
+“not done”。
+
+重新初始化函数reinit_completion(),只是将->done字段重置为0(“not done”),而
+不触及等待队列。这个函数的调用者必须确保没有任何令人讨厌的wait_for_completion()
+调用在并行进行。
+
+在同一个完成对象上调用init_completion()两次很可能是一个bug,因为它将队列重新初始
+化为一个空队列,已排队的任务可能会“丢失”--在这种情况下使用reinit_completion(),但
+要注意其他竞争。
+
+对于静态声明和初始化,可以使用宏。
+
+对于文件范围内的静态(或全局)声明,你可以使用 DECLARE_COMPLETION()::
+
+ static DECLARE_COMPLETION(setup_done);
+ DECLARE_COMPLETION(setup_done);
+
+注意,在这种情况下,完成在启动时(或模块加载时)被初始化为“not done”,不需要调用
+init_completion()。
+
+当完成被声明为一个函数中的局部变量时,那么应该总是明确地使用
+DECLARE_COMPLETION_ONSTACK()来初始化,这不仅仅是为了让lockdep正确运行,也是明确表
+名它有限的使用范围是有意为之并被仔细考虑的::
+
+ DECLARE_COMPLETION_ONSTACK(setup_done)
+
+请注意,当使用完成对象作为局部变量时,你必须敏锐地意识到函数堆栈的短暂生命期:在所有
+活动(如等待的线程)停止并且完成对象完全未被使用之前,函数不得返回到调用上下文。
+
+再次强调这一点:特别是在使用一些具有更复杂结果的等待API变体时,比如超时或信号
+(_timeout(), _killable()和_interruptible())变体,等待可能会提前完成,而对象可
+能仍在被其他线程使用 - 从wait_on_completion*()调用者函数的返回会取消分配函数栈,如
+果complete()在其它某线程中完成调用,会引起微小的数据损坏。简单的测试可能不会触发这
+些类型的竞争。
+
+如果不确定的话,使用动态分配的完成对象, 最好是嵌入到其它一些生命周期长的对象中,长到
+超过使用完成对象的任何辅助线程的生命周期,或者有一个锁或其他同步机制来确保complete()
+不会在一个被释放的对象中调用。
+
+在堆栈上单纯地调用DECLARE_COMPLETION()会触发一个lockdep警告。
+
+等待完成:
+---------
+
+对于一个线程来说,要等待一些并发活动的完成,它要在初始化的完成结构体上调用
+wait_for_completion()::
+
+ void wait_for_completion(struct completion *done)
+
+一个典型的使用场景是::
+
+ CPU#1 CPU#2
+
+ struct completion setup_done;
+
+ init_completion(&setup_done);
+ initialize_work(...,&setup_done,...);
+
+ /* run non-dependent code */ /* do setup */
+
+ wait_for_completion(&setup_done); complete(setup_done);
+
+这并不意味着调用wait_for_completion()和complete()有任何特定的时间顺序--如果调
+用complete()发生在调用wait_for_completion()之前,那么等待方将立即继续执行,因为
+所有的依赖都得到了满足;如果没有,它将阻塞,直到complete()发出完成的信号。
+
+注意,wait_for_completion()是在调用spin_lock_irq()/spin_unlock_irq(),所以
+只有当你知道中断被启用时才能安全地调用它。从IRQs-off的原子上下文中调用它将导致难以检
+测的错误的中断启用。
+
+默认行为是不带超时的等待,并将任务标记为“UNINTERRUPTIBLE”状态。wait_for_completion()
+及其变体只有在进程上下文中才是安全的(因为它们可以休眠),但在原子上下文、中断上下文、IRQ
+被禁用或抢占被禁用的情况下是不安全的--关于在原子/中断上下文中处理完成的问题,还请看下面的
+try_wait_for_completion()。
+
+由于wait_for_completion()的所有变体都可能(很明显)阻塞很长时间,这取决于它们所等
+待的活动的性质,所以在大多数情况下,你可能不想在持有mutex锁的情况下调用它。
+
+
+wait_for_completion*()可用的变体:
+---------------------------------
+
+下面的变体都会返回状态,在大多数(/所有)情况下都应该检查这个状态--在故意不检查状态的情
+况下,你可能要做一个说明(例如,见arch/arm/kernel/smp.c:__cpu_up())。
+
+一个常见的问题是不准确的返回类型赋值,所以要注意将返回值赋值给适当类型的变量。
+
+检查返回值的具体含义也可能被发现是相当不准确的,例如,像这样的构造::
+
+ if (!wait_for_completion_interruptible_timeout(...))
+
+...会在成功完成和中断的情况下执行相同的代码路径--这可能不是你想要的结果::
+
+ int wait_for_completion_interruptible(struct completion *done)
+
+这个函数在任务等待时标记为TASK_INTERRUPTIBLE。如果在等待期间收到信号,它将返回
+-ERESTARTSYS;否则为0::
+
+ unsigned long wait_for_completion_timeout(struct completion *done, unsigned long timeout)
+
+该任务被标记为TASK_UNINTERRUPTIBLE,并将最多超时等待“timeout”个jiffies。如果超时发生,则
+返回0,否则返回剩余的时间(但至少是1)。
+
+超时最好用msecs_to_jiffies()或usecs_to_jiffies()计算,以使代码在很大程度上不受
+HZ的影响。
+
+如果返回的超时值被故意忽略,那么注释应该解释原因
+(例如,见drivers/mfd/wm8350-core.c wm8350_read_auxadc()::
+
+ long wait_for_completion_interruptible_timeout(struct completion *done, unsigned long timeout)
+
+这个函数传递一个以jiffies为单位的超时,并将任务标记为TASK_INTERRUPTIBLE。如果收到
+信号,则返回-ERESTARTSYS;否则,如果完成超时,则返回0;如果完成了,则返回剩余的时间
+(jiffies)。
+
+更多的变体包括_killable,它使用TASK_KILLABLE作为指定的任务状态,如果它被中断,将返
+回-ERESTARTSYS,如果完成了,则返回0。它也有一个_timeout变体::
+
+ long wait_for_completion_killable(struct completion *done)
+ long wait_for_completion_killable_timeout(struct completion *done, unsigned long timeout)
+
+wait_for_completion_io()的_io变体的行为与非_io变体相同,只是将等待时间计为“IO等待”,
+这对任务在调度/IO统计中的计算方式有影响::
+
+ void wait_for_completion_io(struct completion *done)
+ unsigned long wait_for_completion_io_timeout(struct completion *done, unsigned long timeout)
+
+
+对完成发信号:
+-------------
+
+一个线程想要发出信号通知继续的条件已经达到,就会调用complete(),向其中一个等待者发出信
+号表明它可以继续::
+
+ void complete(struct completion *done)
+
+... or calls complete_all() to signal all current and future waiters::
+
+ void complete_all(struct completion *done)
+
+即使在线程开始等待之前就发出了完成的信号,信号传递也会继续进行。这是通过等待者
+“consuming”(递减)“struct completion” 的完成字段来实现的。等待的线程唤醒的顺序
+与它们被排队的顺序相同(FIFO顺序)。
+
+如果多次调用complete(),那么这将允许该数量的等待者继续进行--每次调用complete()将
+简单地增加已完成的字段。但多次调用complete_all()是一个错误。complete()和
+complete_all()都可以在IRQ/atomic上下文中安全调用。
+
+在任何时候,只能有一个线程在一个特定的 “struct completion”上调用 complete() 或
+complete_all() - 通过等待队列自旋锁进行序列化。任何对 complete() 或
+complete_all() 的并发调用都可能是一个设计错误。
+
+从IRQ上下文中发出完成信号 是可行的,因为它将正确地用
+spin_lock_irqsave()/spin_unlock_irqrestore()执行锁操作
+
+
+try_wait_for_completion()/completion_done():
+--------------------------------------------
+
+try_wait_for_completion()函数不会将线程放在等待队列中,而是在需要排队(阻塞)线
+程时返回false,否则会消耗一个已发布的完成并返回true::
+
+ bool try_wait_for_completion(struct completion *done)
+
+最后,为了在不以任何方式改变完成的情况下检查完成的状态,可以调用completion_done(),
+如果没有发布的完成尚未被等待者消耗,则返回false(意味着存在等待者),否则返回true::
+
+ bool completion_done(struct completion *done)
+
+try_wait_for_completion()和completion_done()都可以在IRQ或原子上下文中安全调用。
diff --git a/Documentation/translations/zh_CN/scheduler/index.rst b/Documentation/translations/zh_CN/scheduler/index.rst
new file mode 100644
index 000000000000..a8eaa7325f54
--- /dev/null
+++ b/Documentation/translations/zh_CN/scheduler/index.rst
@@ -0,0 +1,45 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/scheduler/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+:校译:
+
+
+
+===============
+Linux调度器
+===============
+
+.. toctree::
+ :maxdepth: 1
+
+ completion
+ sched-arch
+ sched-bwc
+ sched-design-CFS
+ sched-domains
+ sched-capacity
+ sched-energy
+ schedutil
+ sched-nice-design
+ sched-stats
+ sched-debug
+
+TODOList:
+
+ sched-deadline
+ sched-rt-group
+
+ text_files
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
diff --git a/Documentation/translations/zh_CN/scheduler/sched-arch.rst b/Documentation/translations/zh_CN/scheduler/sched-arch.rst
new file mode 100644
index 000000000000..b2ac3c743a3a
--- /dev/null
+++ b/Documentation/translations/zh_CN/scheduler/sched-arch.rst
@@ -0,0 +1,71 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/scheduler/sched-arch.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+
+===============================
+架构特定代码的CPU调度器实现提示
+===============================
+
+ Nick Piggin, 2005
+
+上下文切换
+==========
+1. 运行队列锁
+默认情况下,switch_to arch函数在调用时锁定了运行队列。这通常不是一个问题,除非
+switch_to可能需要获取运行队列锁。这通常是由于上下文切换中的唤醒操作造成的。
+
+为了要求调度器在运行队列解锁的情况下调用switch_to,你必须在头文件
+中`#define __ARCH_WANT_UNLOCKED_CTXSW`(通常是定义switch_to的那个文件)。
+
+在CONFIG_SMP的情况下,解锁的上下文切换对核心调度器的实现只带来了非常小的性能损
+失。
+
+CPU空转
+=======
+你的cpu_idle程序需要遵守以下规则:
+
+1. 现在抢占应该在空闲的例程上禁用。应该只在调用schedule()时启用,然后再禁用。
+
+2. need_resched/TIF_NEED_RESCHED 只会被设置,并且在运行任务调用 schedule()
+ 之前永远不会被清除。空闲线程只需要查询need_resched,并且永远不会设置或清除它。
+
+3. 当cpu_idle发现(need_resched() == 'true'),它应该调用schedule()。否则
+ 它不应该调用schedule()。
+
+4. 在检查need_resched时,唯一需要禁用中断的情况是,我们要让处理器休眠到下一个中
+ 断(这并不对need_resched提供任何保护,它可以防止丢失一个中断):
+
+ 4a. 这种睡眠类型的常见问题似乎是::
+
+ local_irq_disable();
+ if (!need_resched()) {
+ local_irq_enable();
+ *** resched interrupt arrives here ***
+ __asm__("sleep until next interrupt");
+ }
+
+5. 当need_resched变为高电平时,TIF_POLLING_NRFLAG可以由不需要中断来唤醒它们
+ 的空闲程序设置。换句话说,它们必须定期轮询need_resched,尽管做一些后台工作或
+ 进入低CPU优先级可能是合理的。
+
+ - 5a. 如果TIF_POLLING_NRFLAG被设置,而我们确实决定进入一个中断睡眠,那
+ 么需要清除它,然后发出一个内存屏障(接着测试need_resched,禁用中断,如3中解释)。
+
+arch/x86/kernel/process.c有轮询和睡眠空闲函数的例子。
+
+
+可能出现的arch/问题
+===================
+
+我发现的可能的arch问题(并试图解决或没有解决)。:
+
+sparc - 在这一点上,IRQ是开着的(?),把local_irq_save改为_disable。
+ - 待办事项: 需要第二个CPU来禁用抢占 (参考 #1)
diff --git a/Documentation/translations/zh_CN/scheduler/sched-bwc.rst b/Documentation/translations/zh_CN/scheduler/sched-bwc.rst
new file mode 100644
index 000000000000..90e931f4ceed
--- /dev/null
+++ b/Documentation/translations/zh_CN/scheduler/sched-bwc.rst
@@ -0,0 +1,204 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/scheduler/sched-bwc.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+
+
+============
+CFS 带宽控制
+============
+
+.. note::
+ 本文只讨论了SCHED_NORMAL的CPU带宽控制。
+ SCHED_RT的情况在Documentation/scheduler/sched-rt-group.rst中有涉及。
+
+CFS带宽控制是一个CONFIG_FAIR_GROUP_SCHED扩展,它允许指定一个组或层次的最大CPU带宽。
+
+一个组允许的带宽是用配额和周期指定的。在每个给定的”周期“(微秒)内,一个任务组被分配多
+达“配额”微秒的CPU时间。当cgroup中的线程可运行时,该配额以时间片段的方式被分配到每个cpu
+运行队列中。一旦所有的配额被分配,任何额外的配额请求将导致这些线程被限流。被限流的线程将不
+能再次运行,直到下一个时期的配额得到补充。
+
+一个组的未分配配额是全局跟踪的,在每个周期边界被刷新为cfs_quota单元。当线程消耗这个带宽时,
+它以需求为基础被转移到cpu-local“筒仓”,在每次更新中转移的数量是可调整的,被描述为“片“(时
+间片)。
+
+突发特性
+--------
+现在这个功能借来的时间是用于防范我们对未来的低估,代价是对其他系统用户的干扰增加。所有这些都
+有很好的限制。
+
+传统的(UP-EDF)带宽控制是这样的:
+
+ (U = \Sum u_i) <= 1
+
+这既保证了每个最后期限的实现,也保证了系统的稳定。毕竟,如果U>1,那么每一秒钟的壁钟时间,我
+们就必须运行超过一秒钟的程序时间,显然会错过我们的最后期限,但下一个最后期限会更远,永远没有
+时间赶上,无边无界的失败。
+
+突发特性观察到工作负载并不总是执行全部配额;这使得人们可以将u_i描述为一个统计分布。
+
+例如,让u_i = {x,e}_i,其中x是p(95)和x+e p(100)(传统的WCET)。这实际上允许u更小,提
+高了效率(我们可以在系统中打包更多的任务),但代价是当所有的概率都一致时,会错过最后期限。然
+而,它确实保持了稳定性,因为只要我们的x高于平均水平,每一次超限都必须与低估相匹配。
+
+也就是说,假设我们有两个任务,都指定了一个p(95)值,那么我们有一个p(95)*p(95)=90.25%的机
+会,两个任务都在他们的配额内,一切都很好。同时,我们有一个p(5)p(5)=0.25%的机会,两个任务同
+时超过他们的配额(保证最后期限失败)。在这两者之间有一个阈值,其中一个超过了,而另一个没有不足,
+无法补偿;这取决于具体的CDFs。
+
+同时,我们可以说,最坏的情况下的截止日期失败,将是Sum e_i;也就是说,有一个有界的迟延(在假
+设x+e确实是WCET的情况下)。
+
+使用突发时的干扰是由错过最后期限的可能性和平均WCET来评价的。测试结果表明,当有许多cgroup或
+CPU未被充分利用时,干扰是有限的。更多的细节显示在:
+https://lore.kernel.org/lkml/5371BD36-55AE-4F71-B9D7-B86DC32E3D2B@linux.alibaba.com/
+
+管理
+----
+配额、周期和突发是在cpu子系统内通过cgroupfs管理的。
+
+.. note::
+ 本节描述的cgroupfs文件只适用于cgroup v1.对于cgroup v2,请参阅Control Group v2。
+ :ref:`Documentation/admin-guide/cgroup-v2.rst <cgroup-v2-cpu>`.
+
+- cpu.cfs_quota_us:在一个时期内补充的运行时间(微秒)。
+- cpu.cfs_period_us:一个周期的长度(微秒)。
+- cpu.stat: 输出节流统计数据[下面进一步解释]
+- cpu.cfs_burst_us:最大累积运行时间(微秒)。
+
+默认值是::
+
+ cpu.cfs_period_us=100ms
+ cpu.cfs_quota_us=-1
+ cpu.cfs_burst_us=0
+
+cpu.cfs_quota_us的值为-1表示该组没有任何带宽限制,这样的组被描述为无限制的带宽组。这代表
+了CFS的传统工作保护行为。
+
+写入不小于cpu.cfs_burst_us的任何(有效的)正值将配发指定的带宽限制。该配额或周期允许的最
+小配额是1ms。周期长度也有一个1s的上限。当带宽限制以分层方式使用时,存在额外的限制,这些在下
+面有更详细的解释。
+
+向cpu.cfs_quota_us写入任何负值都会移除带宽限制,并使组再次回到无限制的状态。
+
+cpu.cfs_burst_us的值为0表示该组不能积累任何未使用的带宽。它使得CFS的传统带宽控制行为没有
+改变。将不大于 cpu.cfs_quota_us 的任何(有效的)正值写入 cpu.cfs_burst_us 将配发未使用
+带宽累积的上限。
+
+如果一个组处于受限状态,对该组带宽规格的任何更新都将导致其成为无限流状态。
+
+系统范围设置
+------------
+为了提高效率,运行时间在全局池和CPU本地“筒仓”之间以批处理方式转移。这大大减少了大型系统的全
+局核算压力。每次需要进行这种更新时,传输的数量被描述为 "片"。
+
+这是可以通过procfs调整的::
+
+ /proc/sys/kernel/sched_cfs_bandwidth_slice_us (default=5ms)
+
+较大的时间片段值将减少传输开销,而较小的值则允许更精细的消费。
+
+统计
+----
+一个组的带宽统计数据通过cpu.stat的5个字段导出。
+
+cpu.stat:
+
+- nr_periods:已经过去的执行间隔的数量。
+- nr_throttled: 该组已被节流/限制的次数。
+- throttled_time: 该组的实体被限流的总时间长度(纳秒)。
+- nr_bursts:突发发生的周期数。
+- burst_time: 任何CPU在各个时期使用超过配额的累计壁钟时间(纳秒)。
+
+这个接口是只读的。
+
+分层考虑
+--------
+该接口强制要求单个实体的带宽总是可以达到的,即:max(c_i) <= C。然而,在总体情况下,是明确
+允许过度订阅的,以便在一个层次结构中实现工作保护语义:
+
+ 例如,Sum (c_i)可能超过C
+
+[ 其中C是父方的带宽,c_i是其子方的带宽。 ]
+
+.. note::
+ 译文中的父亲/孩子指的是cgroup parent, cgroup children。
+
+有两种方式可以使一个组变得限流:
+
+ a. 它在一段时期内完全消耗自己的配额
+ b. 父方的配额在其期间内全部用完
+
+在上述b)情况下,即使孩子可能有剩余的运行时间,它也不会被允许,直到父亲的运行时间被刷新。
+
+CFS带宽配额的注意事项
+---------------------
+一旦一个片断被分配给一个cpu,它就不会过期。然而,如果该cpu上的所有线程都无法运行,那么除了
+1ms以外的所有时间片都可以返回到全局池中。这是在编译时由min_cfs_rq_runtime变量配置的。这
+是一个性能调整,有助于防止对全局锁的额外争夺。
+
+cpu-local分片不会过期的事实导致了一些有趣的罕见案例,应该被理解。
+
+对于cgroup cpu限制的应用程序来说,这是一个相对有意义的问题,因为他们自然会消耗他们的全部配
+额,以及每个cpu-本地片在每个时期的全部。因此,预计nr_periods大致等于nr_throttled,并且
+cpuacct.用量的增加大致等于cfs_quota_us在每个周期的增加。
+
+对于高线程、非cpu绑定的应用程序,这种非过期的细微差别允许应用程序短暂地突破他们的配额限制,
+即任务组正在运行的每个cpu上未使用的片断量(通常每个cpu最多1ms或由min_cfs_rq_runtime定
+义)。这种轻微的突发只适用于配额已经分配给cpu,然后没有完全使用或在以前的时期返回。这个突发
+量不会在核心之间转移。因此,这种机制仍然严格限制任务组的配额平均使用量,尽管是在比单一时期更
+长的时间窗口。这也限制了突发能力,每个cpu不超过1ms。这为在高核数机器上有小配额限制的高线程
+应用提供了更好的更可预测的用户体验。它还消除了在使用低于配额的cpu时对这些应用进行节流的倾向。
+另一种说法是,通过允许一个片断的未使用部分在不同时期保持有效,我们减少了在不需要整个片断的cpu
+时间的cpu-local 筒仓上浪费配额的可能性。
+
+绑定cpu和非绑定cpu的交互式应用之间的互动也应该被考虑,特别是当单核使用率达到100%时。如果你
+给了这些应用程序一半的cpu-core,并且它们都被安排在同一个CPU上,理论上非cpu绑定的应用程序有
+可能在某些时期使用多达1ms的额外配额,从而阻止cpu绑定的应用程序完全使用其配额,这也是同样的数
+量。在这些情况下,将由CFS算法(见CFS调度器)来决定选择哪个应用程序来运行,因为它们都是可运行
+的,并且有剩余的配额。这个运行时间的差异将在接下来的交互式应用程序空闲期间得到弥补。
+
+例子
+----
+1. 限制一个组的运行时间为1个CPU的价值::
+
+ 如果周期是250ms,配额也是250ms,那么该组将每250ms获得价值1个CPU的运行时间。
+
+ # echo 250000 > cpu.cfs_quota_us /* quota = 250ms */
+ # echo 250000 > cpu.cfs_period_us /* period = 250ms */
+
+2. 在多CPU机器上,将一个组的运行时间限制为2个CPU的价值
+
+ 在500ms周期和1000ms配额的情况下,该组每500ms可以获得2个CPU的运行时间::
+
+ # echo 1000000 > cpu.cfs_quota_us /* quota = 1000ms */
+ # echo 500000 > cpu.cfs_period_us /* period = 500ms */
+
+ 这里较大的周期允许增加突发能力。
+
+3. 将一个组限制在1个CPU的20%。
+
+ 在50ms周期内,10ms配额将相当于1个CPU的20%。::
+
+ # echo 10000 > cpu.cfs_quota_us /* quota = 10ms */
+ # echo 50000 > cpu.cfs_period_us /* period = 50ms */
+
+ 通过在这里使用一个小的周期,我们以牺牲突发容量为代价来确保稳定的延迟响应。
+
+4. 将一个组限制在1个CPU的40%,并允许累积到1个CPU的20%,如果已经累积了的话。
+
+ 在50ms周期内,20ms配额将相当于1个CPU的40%。而10毫秒的突发将相当于1个
+ CPU的20%::
+
+ # echo 20000 > cpu.cfs_quota_us /* quota = 20ms */
+ # echo 50000 > cpu.cfs_period_us /* period = 50ms */
+ # echo 10000 > cpu.cfs_burst_us /* burst = 10ms */
+
+ 较大的缓冲区设置(不大于配额)允许更大的突发容量。
diff --git a/Documentation/translations/zh_CN/scheduler/sched-capacity.rst b/Documentation/translations/zh_CN/scheduler/sched-capacity.rst
new file mode 100644
index 000000000000..8cba135dcd1a
--- /dev/null
+++ b/Documentation/translations/zh_CN/scheduler/sched-capacity.rst
@@ -0,0 +1,390 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/scheduler/sched-capacity.rst
+
+:翻译:
+
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+:校译:
+
+ 时奎亮 Alex Shi <alexs@kernel.org>
+
+=============
+算力感知调度
+=============
+
+1. CPU算力
+==========
+
+1.1 简介
+--------
+
+一般来说,同构的SMP平台由完全相同的CPU构成。异构的平台则由性能特征不同的CPU构成,在这样的
+平台中,CPU不能被认为是相同的。
+
+我们引入CPU算力(capacity)的概念来测量每个CPU能达到的性能,它的值相对系统中性能最强的CPU
+做过归一化处理。异构系统也被称为非对称CPU算力系统,因为它们由不同算力的CPU组成。
+
+最大可达性能(换言之,最大CPU算力)的差异有两个主要来源:
+
+- 不是所有CPU的微架构都相同。
+- 在动态电压频率升降(Dynamic Voltage and Frequency Scaling,DVFS)框架中,不是所有的CPU都
+ 能达到一样高的操作性能值(Operating Performance Points,OPP。译注,也就是“频率-电压”对)。
+
+Arm大小核(big.LITTLE)系统是同时具有两种差异的一个例子。相较小核,大核面向性能(拥有更多的
+流水线层级,更大的缓存,更智能的分支预测器等),通常可以达到更高的操作性能值。
+
+CPU性能通常由每秒百万指令(Millions of Instructions Per Second,MIPS)表示,也可表示为
+per Hz能执行的指令数,故::
+
+ capacity(cpu) = work_per_hz(cpu) * max_freq(cpu)
+
+1.2 调度器术语
+--------------
+
+调度器使用了两种不同的算力值。CPU的 ``capacity_orig`` 是它的最大可达算力,即最大可达性能等级。
+CPU的 ``capacity`` 是 ``capacity_orig`` 扣除了一些性能损失(比如处理中断的耗时)的值。
+
+注意CPU的 ``capacity`` 仅仅被设计用于CFS调度类,而 ``capacity_orig`` 是不感知调度类的。为
+简洁起见,本文档的剩余部分将不加区分的使用术语 ``capacity`` 和 ``capacity_orig`` 。
+
+1.3 平台示例
+------------
+
+1.3.1 操作性能值相同
+~~~~~~~~~~~~~~~~~~~~
+
+考虑一个假想的双核非对称CPU算力系统,其中
+
+- work_per_hz(CPU0) = W
+- work_per_hz(CPU1) = W/2
+- 所有CPU以相同的固定频率运行
+
+根据上文对算力的定义:
+
+- capacity(CPU0) = C
+- capacity(CPU1) = C/2
+
+若这是Arm大小核系统,那么CPU0是大核,而CPU1是小核。
+
+考虑一种周期性产生固定工作量的工作负载,你将会得到类似下图的执行轨迹::
+
+ CPU0 work ^
+ | ____ ____ ____
+ | | | | | | |
+ +----+----+----+----+----+----+----+----+----+----+-> time
+
+ CPU1 work ^
+ | _________ _________ ____
+ | | | | | |
+ +----+----+----+----+----+----+----+----+----+----+-> time
+
+CPU0在系统中具有最高算力(C),它使用T个单位时间完成固定工作量W。另一方面,CPU1只有CPU0一半
+算力,因此在T个单位时间内仅完成工作量W/2。
+
+1.3.2 最大操作性能值不同
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+具有不同算力值的CPU,通常来说最大操作性能值也不同。考虑上一小节提到的CPU(也就是说,
+work_per_hz()相同):
+
+- max_freq(CPU0) = F
+- max_freq(CPU1) = 2/3 * F
+
+这将推出:
+
+- capacity(CPU0) = C
+- capacity(CPU1) = C/3
+
+执行1.3.1节描述的工作负载,每个CPU按最大频率运行,结果为::
+
+ CPU0 work ^
+ | ____ ____ ____
+ | | | | | | |
+ +----+----+----+----+----+----+----+----+----+----+-> time
+
+ workload on CPU1
+ CPU1 work ^
+ | ______________ ______________ ____
+ | | | | | |
+ +----+----+----+----+----+----+----+----+----+----+-> time
+
+1.4 关于计算方式的注意事项
+--------------------------
+
+需要注意的是,使用单一值来表示CPU性能的差异是有些争议的。两个不同的微架构的相对性能差异应该
+描述为:X%整数运算差异,Y%浮点数运算差异,Z%分支跳转差异,等等。尽管如此,使用简单计算方式
+的结果目前还是令人满意的。
+
+2. 任务使用率
+=============
+
+2.1 简介
+--------
+
+算力感知调度要求描述任务需求,描述方式要和CPU算力相关。每个调度类可以用不同的方式描述它。
+任务使用率是CFS独有的描述方式,不过在这里介绍它有助于引入更多一般性的概念。
+
+任务使用率是一种用百分比来描述任务吞吐率需求的方式。一个简单的近似是任务的占空比,也就是说::
+
+ task_util(p) = duty_cycle(p)
+
+在频率固定的SMP系统中,100%的利用率意味着任务是忙等待循环。反之,10%的利用率暗示这是一个
+小周期任务,它在睡眠上花费的时间比执行更多。
+
+2.2 频率不变性
+--------------
+
+一个需要考虑的议题是,工作负载的占空比受CPU正在运行的操作性能值直接影响。考虑以给定的频率F
+执行周期性工作负载::
+
+ CPU work ^
+ | ____ ____ ____
+ | | | | | | |
+ +----+----+----+----+----+----+----+----+----+----+-> time
+
+可以算出 duty_cycle(p) == 25%。
+
+现在,考虑以给定频率F/2执行 *同一个* 工作负载::
+
+ CPU work ^
+ | _________ _________ ____
+ | | | | | |
+ +----+----+----+----+----+----+----+----+----+----+-> time
+
+可以算出 duty_cycle(p) == 50%,尽管两次执行中,任务的行为完全一致(也就是说,执行的工作量
+相同)。
+
+任务利用率信号可按下面公式处理成频率不变的(译注:这里的术语用到了信号与系统的概念)::
+
+ task_util_freq_inv(p) = duty_cycle(p) * (curr_frequency(cpu) / max_frequency(cpu))
+
+对上面两个例子运用该公式,可以算出频率不变的任务利用率均为25%。
+
+2.3 CPU不变性
+-------------
+
+CPU算力与任务利用率具有类型的效应,在算力不同的CPU上执行完全相同的工作负载,将算出不同的
+占空比。
+
+考虑1.3.2节提到的系统,也就是说::
+
+- capacity(CPU0) = C
+- capacity(CPU1) = C/3
+
+每个CPU按最大频率执行指定周期性工作负载,结果为::
+
+ CPU0 work ^
+ | ____ ____ ____
+ | | | | | | |
+ +----+----+----+----+----+----+----+----+----+----+-> time
+
+ CPU1 work ^
+ | ______________ ______________ ____
+ | | | | | |
+ +----+----+----+----+----+----+----+----+----+----+-> time
+
+也就是说,
+
+- duty_cycle(p) == 25%,如果任务p在CPU0上按最大频率运行。
+- duty_cycle(p) == 75%,如果任务p在CPU1上按最大频率运行。
+
+任务利用率信号可按下面公式处理成CPU算力不变的::
+
+ task_util_cpu_inv(p) = duty_cycle(p) * (capacity(cpu) / max_capacity)
+
+其中 ``max_capacity`` 是系统中最高的CPU算力。对上面的例子运用该公式,可以算出CPU算力不变
+的任务利用率均为25%。
+
+2.4 任务利用率不变量
+--------------------
+
+频率和CPU算力不变性都需要被应用到任务利用率的计算中,以便求出真正的不变信号。
+任务利用率的伪计算公式是同时具备CPU和频率不变性的,也就是说,对于指定任务p::
+
+ curr_frequency(cpu) capacity(cpu)
+ task_util_inv(p) = duty_cycle(p) * ------------------- * -------------
+ max_frequency(cpu) max_capacity
+
+也就是说,任务利用率不变量假定任务在系统中最高算力CPU上以最高频率运行,以此描述任务的行为。
+
+在接下来的章节中提到的任何任务利用率,均是不变量的形式。
+
+2.5 利用率估算
+--------------
+
+由于预测未来的水晶球不存在,当任务第一次变成可运行时,任务的行为和任务利用率均不能被准确预测。
+CFS调度类基于实体负载跟踪机制(Per-Entity Load Tracking, PELT)维护了少量CPU和任务信号,
+其中之一可以算出平均利用率(与瞬时相反)。
+
+这意味着,尽管运用“真实的”任务利用率(凭借水晶球)写出算力感知调度的准则,但是它的实现将只能
+用任务利用率的估算值。
+
+3. 算力感知调度的需求
+=====================
+
+3.1 CPU算力
+-----------
+
+当前,Linux无法凭自身算出CPU算力,因此必须要有把这个信息传递给Linux的方式。每个架构必须为此
+定义arch_scale_cpu_capacity()函数。
+
+arm、arm64和RISC-V架构直接把这个信息映射到arch_topology驱动的CPU scaling数据中(译注:参考
+arch_topology.h的percpu变量cpu_scale),它是从capacity-dmips-mhz CPU binding中衍生计算
+出来的。参见Documentation/devicetree/bindings/cpu/cpu-capacity.txt。
+
+3.2 频率不变性
+--------------
+
+如2.2节所述,算力感知调度需要频率不变的任务利用率。每个架构必须为此定义
+arch_scale_freq_capacity(cpu)函数。
+
+实现该函数要求计算出每个CPU当前以什么频率在运行。实现它的一种方式是利用硬件计数器(x86的
+APERF/MPERF,arm64的AMU),它能按CPU当前频率动态可扩展地升降递增计数器的速率。另一种方式是
+在cpufreq频率变化时直接使用钩子函数,内核此时感知到将要被切换的频率(也被arm/arm64实现了)。
+
+4. 调度器拓扑结构
+=================
+
+在构建调度域时,调度器将会发现系统是否表现为非对称CPU算力。如果是,那么:
+
+- sched_asym_cpucapacity静态键(static key)将使能。
+- SD_ASYM_CPUCAPACITY_FULL标志位将在尽量最低调度域层级中被设置,同时要满足条件:调度域恰好
+ 完整包含某个CPU算力值的全部CPU。
+- SD_ASYM_CPUCAPACITY标志将在所有包含非对称CPU的调度域中被设置。
+
+sched_asym_cpucapacity静态键的设计意图是,保护为非对称CPU算力系统所准备的代码。不过要注意的
+是,这个键是系统范围可见的。想象下面使用了cpuset的步骤::
+
+ capacity C/2 C
+ ________ ________
+ / \ / \
+ CPUs 0 1 2 3 4 5 6 7
+ \__/ \______________/
+ cpusets cs0 cs1
+
+可以通过下面的方式创建:
+
+.. code-block:: sh
+
+ mkdir /sys/fs/cgroup/cpuset/cs0
+ echo 0-1 > /sys/fs/cgroup/cpuset/cs0/cpuset.cpus
+ echo 0 > /sys/fs/cgroup/cpuset/cs0/cpuset.mems
+
+ mkdir /sys/fs/cgroup/cpuset/cs1
+ echo 2-7 > /sys/fs/cgroup/cpuset/cs1/cpuset.cpus
+ echo 0 > /sys/fs/cgroup/cpuset/cs1/cpuset.mems
+
+ echo 0 > /sys/fs/cgroup/cpuset/cpuset.sched_load_balance
+
+由于“这是”非对称CPU算力系统,sched_asym_cpucapacity静态键将使能。然而,CPU 0--1对应的
+调度域层级,算力值仅有一个,该层级中SD_ASYM_CPUCAPACITY未被设置,它描述的是一个SMP区域,也
+应该被以此处理。
+
+因此,“典型的”保护非对称CPU算力代码路径的代码模式是:
+
+- 检查sched_asym_cpucapacity静态键
+- 如果它被使能,接着检查调度域层级中SD_ASYM_CPUCAPACITY标志位是否出现
+
+5. 算力感知调度的实现
+=====================
+
+5.1 CFS
+-------
+
+5.1.1 算力适应性(fitness)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+CFS最主要的算力调度准则是::
+
+ task_util(p) < capacity(task_cpu(p))
+
+它通常被称为算力适应性准则。也就是说,CFS必须保证任务“适合”在某个CPU上运行。如果准则被违反,
+任务将要更长地消耗该CPU,任务是CPU受限的(CPU-bound)。
+
+此外,uclamp允许用户空间指定任务的最小和最大利用率,要么以sched_setattr()的方式,要么以
+cgroup接口的方式(参阅Documentation/admin-guide/cgroup-v2.rst)。如其名字所暗示,uclamp
+可以被用在前一条准则中限制task_util()。
+
+5.1.2 被唤醒任务的CPU选择
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+CFS任务唤醒的CPU选择,遵循上面描述的算力适应性准则。在此之上,uclamp被用来限制任务利用率,
+这令用户空间对CFS任务的CPU选择有更多的控制。也就是说,CFS被唤醒任务的CPU选择,搜索满足以下
+条件的CPU::
+
+ clamp(task_util(p), task_uclamp_min(p), task_uclamp_max(p)) < capacity(cpu)
+
+通过使用uclamp,举例来说,用户空间可以允许忙等待循环(100%使用率)在任意CPU上运行,只要给
+它设置低的uclamp.max值。相反,uclamp能强制一个小的周期性任务(比如,10%利用率)在最高性能
+的CPU上运行,只要给它设置高的uclamp.min值。
+
+.. note::
+
+ CFS的被唤醒的任务的CPU选择,可被能耗感知调度(Energy Aware Scheduling,EAS)覆盖,在
+ Documentation/scheduler/sched-energy.rst中描述。
+
+5.1.3 负载均衡
+~~~~~~~~~~~~~~
+
+被唤醒任务的CPU选择的一个病理性的例子是,任务几乎不睡眠,那么也几乎不发生唤醒。考虑::
+
+ w == wakeup event
+
+ capacity(CPU0) = C
+ capacity(CPU1) = C / 3
+
+ workload on CPU0
+ CPU work ^
+ | _________ _________ ____
+ | | | | | |
+ +----+----+----+----+----+----+----+----+----+----+-> time
+ w w w
+
+ workload on CPU1
+ CPU work ^
+ | ____________________________________________
+ | |
+ +----+----+----+----+----+----+----+----+----+----+->
+ w
+
+该工作负载应该在CPU0上运行,不过如果任务满足以下条件之一:
+
+- 一开始发生不合适的调度(不准确的初始利用率估计)
+- 一开始调度正确,但突然需要更多的处理器功率
+
+则任务可能变为CPU受限的,也就是说 ``task_util(p) > capacity(task_cpu(p))`` ;CPU算力
+调度准则被违反,将不会有任何唤醒事件来修复这个错误的CPU选择。
+
+这种场景下的任务被称为“不合适的”(misfit)任务,处理这个场景的机制同样也以此命名。Misfit
+任务迁移借助CFS负载均衡器,更明确的说,是主动负载均衡的部分(用来迁移正在运行的任务)。
+当发生负载均衡时,如果一个misfit任务可以被迁移到一个相较当前运行的CPU具有更高算力的CPU上,
+那么misfit任务的主动负载均衡将被触发。
+
+5.2 实时调度
+------------
+
+5.2.1 被唤醒任务的CPU选择
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+实时任务唤醒时的CPU选择,搜索满足以下条件的CPU::
+
+ task_uclamp_min(p) <= capacity(task_cpu(cpu))
+
+同时仍然允许接着使用常规的优先级限制。如果没有CPU能满足这个算力准则,那么将使用基于严格
+优先级的调度,CPU算力将被忽略。
+
+5.3 最后期限调度
+----------------
+
+5.3.1 被唤醒任务的CPU选择
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+最后期限任务唤醒时的CPU选择,搜索满足以下条件的CPU::
+
+ task_bandwidth(p) < capacity(task_cpu(p))
+
+同时仍然允许接着使用常规的带宽和截止期限限制。如果没有CPU能满足这个算力准则,那么任务依然
+在当前CPU队列中。
diff --git a/Documentation/translations/zh_CN/scheduler/sched-debug.rst b/Documentation/translations/zh_CN/scheduler/sched-debug.rst
new file mode 100644
index 000000000000..5e17740c2bf3
--- /dev/null
+++ b/Documentation/translations/zh_CN/scheduler/sched-debug.rst
@@ -0,0 +1,51 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/scheduler/sched-debug.rst
+
+:翻译:
+
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+=============
+调度器debugfs
+=============
+
+用配置项CONFIG_SCHED_DEBUG=y启动内核后,将可以访问/sys/kernel/debug/sched
+下的调度器专用调试文件。其中一些文件描述如下。
+
+numa_balancing
+==============
+
+`numa_balancing` 目录用来存放控制非统一内存访问(NUMA)平衡特性的相关文件。
+如果该特性导致系统负载太高,那么可以通过 `scan_period_min_ms, scan_delay_ms,
+scan_period_max_ms, scan_size_mb` 文件控制NUMA缺页的内核采样速率。
+
+
+scan_period_min_ms, scan_delay_ms, scan_period_max_ms, scan_size_mb
+-------------------------------------------------------------------
+
+自动NUMA平衡会扫描任务地址空间,检测页面是否被正确放置,或者数据是否应该被
+迁移到任务正在运行的本地内存结点,此时需解映射页面。每个“扫描延迟”(scan delay)
+时间之后,任务扫描其地址空间中下一批“扫描大小”(scan size)个页面。若抵达
+内存地址空间末尾,扫描器将从头开始重新扫描。
+
+结合来看,“扫描延迟”和“扫描大小”决定扫描速率。当“扫描延迟”减小时,扫描速率
+增加。“扫描延迟”和每个任务的扫描速率都是自适应的,且依赖历史行为。如果页面被
+正确放置,那么扫描延迟就会增加;否则扫描延迟就会减少。“扫描大小”不是自适应的,
+“扫描大小”越大,扫描速率越高。
+
+更高的扫描速率会产生更高的系统开销,因为必须捕获缺页异常,并且潜在地必须迁移
+数据。然而,当扫描速率越高,若工作负载模式发生变化,任务的内存将越快地迁移到
+本地结点,由于远程内存访问而产生的性能影响将降到最低。下面这些文件控制扫描延迟
+的阈值和被扫描的页面数量。
+
+``scan_period_min_ms`` 是扫描一个任务虚拟内存的最小时间,单位是毫秒。它有效地
+控制了每个任务的最大扫描速率。
+
+``scan_delay_ms`` 是一个任务初始化创建(fork)时,第一次使用的“扫描延迟”。
+
+``scan_period_max_ms`` 是扫描一个任务虚拟内存的最大时间,单位是毫秒。它有效地
+控制了每个任务的最小扫描速率。
+
+``scan_size_mb`` 是一次特定的扫描中,要扫描多少兆字节(MB)对应的页面数。
diff --git a/Documentation/translations/zh_CN/scheduler/sched-design-CFS.rst b/Documentation/translations/zh_CN/scheduler/sched-design-CFS.rst
new file mode 100644
index 000000000000..abc6709ec3b2
--- /dev/null
+++ b/Documentation/translations/zh_CN/scheduler/sched-design-CFS.rst
@@ -0,0 +1,205 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/scheduler/sched-design-CFS.rst
+
+:翻译:
+
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+===============
+完全公平调度器
+===============
+
+
+1. 概述
+=======
+
+CFS表示“完全公平调度器”,它是为桌面新设计的进程调度器,由Ingo Molnar实现并合入Linux
+2.6.23。它替代了之前原始调度器中SCHED_OTHER策略的交互式代码。
+
+CFS 80%的设计可以总结为一句话:CFS在真实硬件上建模了一个“理想的,精确的多任务CPU”。
+
+“理想的多任务CPU”是一种(不存在的 :-))具有100%物理算力的CPU,它能让每个任务精确地以
+相同的速度并行运行,速度均为1/nr_running。举例来说,如果有两个任务正在运行,那么每个
+任务获得50%物理算力。 --- 也就是说,真正的并行。
+
+在真实的硬件上,一次只能运行一个任务,所以我们需要介绍“虚拟运行时间”的概念。任务的虚拟
+运行时间表明,它的下一个时间片将在上文描述的理想多任务CPU上开始执行。在实践中,任务的
+虚拟运行时间由它的真实运行时间相较正在运行的任务总数归一化计算得到。
+
+
+
+2. 一些实现细节
+===============
+
+在CFS中,虚拟运行时间由每个任务的p->se.vruntime(单位为纳秒)的值表达和跟踪。因此,
+精确地计时和测量一个任务应得的“预期的CPU时间”是可能的。
+
+ 一些细节:在“理想的”硬件上,所有的任务在任何时刻都应该具有一样的p->se.vruntime值,
+ --- 也就是说,任务应当同时执行,没有任务会在“理想的”CPU分时中变得“不平衡”。
+
+CFS的任务选择逻辑基于p->se.vruntime的值,因此非常简单:总是试图选择p->se.vruntime值
+最小的任务运行(也就是说,至今执行时间最少的任务)。CFS总是尽可能尝试按“理想多任务硬件”
+那样将CPU时间在可运行任务中均分。
+
+CFS剩下的其它设计,一般脱离了这个简单的概念,附加的设计包括nice级别,多处理,以及各种
+用来识别已睡眠任务的算法变体。
+
+
+
+3. 红黑树
+=========
+
+CFS的设计非常激进:它不使用运行队列的旧数据结构,而是使用按时间排序的红黑树,构建出
+任务未来执行的“时间线”。因此没有任何“数组切换”的旧包袱(之前的原始调度器和RSDL/SD都
+被它影响)。
+
+CFS同样维护了rq->cfs.min_vruntime值,它是单调递增的,跟踪运行队列中的所有任务的最小
+虚拟运行时间值。系统做的全部工作是:使用min_vruntime跟踪,然后用它的值将新激活的调度
+实体尽可能地放在红黑树的左侧。
+
+运行队列中正在运行的任务的总数由rq->cfs.load计数,它是运行队列中的任务的权值之和。
+
+CFS维护了一个按时间排序的红黑树,所有可运行任务以p->se.vruntime为键值排序。CFS从这颗
+树上选择“最左侧”的任务并运行。系统继续运行,被执行过的任务越来越被放到树的右侧 --- 缓慢,
+但很明确每个任务都有成为“最左侧任务”的机会,因此任务将确定性地获得一定量CPU时间。
+
+总结一下,CFS工作方式像这样:它运行一个任务一会儿,当任务发生调度(或者调度器时钟滴答
+tick产生),就会考虑任务的CPU使用率:任务刚刚花在物理CPU上的(少量)时间被加到
+p->se.vruntime。一旦p->se.vruntime变得足够大,其它的任务将成为按时间排序的红黑树的
+“最左侧任务”(相较最左侧的任务,还要加上一个很小的“粒度”量,使得我们不会对任务过度调度,
+导致缓存颠簸),然后新的最左侧任务将被选中,当前任务被抢占。
+
+
+
+
+4. CFS的一些特征
+================
+
+CFS使用纳秒粒度的计时,不依赖于任何jiffies或HZ的细节。因此CFS并不像之前的调度器那样
+有“时间片”的概念,也没有任何启发式的设计。唯一可调的参数(你需要打开CONFIG_SCHED_DEBUG)是:
+
+ /sys/kernel/debug/sched/base_slice_ns
+
+它可以用来将调度器从“桌面”模式(也就是低时延)调节为“服务器”(也就是高批处理)模式。
+它的默认设置是适合桌面的工作负载。SCHED_BATCH也被CFS调度器模块处理。
+
+CFS的设计不易受到当前存在的任何针对stock调度器的“攻击”的影响,包括fiftyp.c,thud.c,
+chew.c,ring-test.c,massive_intr.c,它们都能很好地运行,不会影响交互性,将产生
+符合预期的行为。
+
+CFS调度器处理nice级别和SCHED_BATCH的能力比之前的原始调度器更强:两种类型的工作负载
+都被更激进地隔离了。
+
+SMP负载均衡被重做/清理过:遍历运行队列的假设已经从负载均衡的代码中移除,使用调度模块
+的迭代器。结果是,负载均衡代码变得简单不少。
+
+
+
+5. 调度策略
+===========
+
+CFS实现了三种调度策略:
+
+ - SCHED_NORMAL:(传统被称为SCHED_OTHER):该调度策略用于普通任务。
+
+ - SCHED_BATCH:抢占不像普通任务那样频繁,因此允许任务运行更长时间,更好地利用缓存,
+ 不过要以交互性为代价。它很适合批处理工作。
+
+ - SCHED_IDLE:它比nice 19更弱,不过它不是真正的idle定时器调度器,因为要避免给机器
+ 带来死锁的优先级反转问题。
+
+SCHED_FIFO/_RR被实现在sched/rt.c中,它们由POSIX具体说明。
+
+util-linux-ng 2.13.1.1中的chrt命令可以设置以上所有策略,除了SCHED_IDLE。
+
+
+
+6. 调度类
+=========
+
+新的CFS调度器被设计成支持“调度类”,一种调度模块的可扩展层次结构。这些模块封装了调度策略
+细节,由调度器核心代码处理,且无需对它们做太多假设。
+
+sched/fair.c 实现了上文描述的CFS调度器。
+
+sched/rt.c 实现了SCHED_FIFO和SCHED_RR语义,且比之前的原始调度器更简洁。它使用了100个
+运行队列(总共100个实时优先级,替代了之前调度器的140个),且不需要过期数组(expired
+array)。
+
+调度类由sched_class结构体实现,它包括一些函数钩子,当感兴趣的事件发生时,钩子被调用。
+
+这是(部分)钩子的列表:
+
+ - enqueue_task(...)
+
+ 当任务进入可运行状态时,被调用。它将调度实体(任务)放到红黑树中,增加nr_running变量
+ 的值。
+
+ - dequeue_task(...)
+
+ 当任务不再可运行时,这个函数被调用,对应的调度实体被移出红黑树。它减少nr_running变量
+ 的值。
+
+ - yield_task(...)
+
+ 这个函数的行为基本上是出队,紧接着入队,除非compat_yield sysctl被开启。在那种情况下,
+ 它将调度实体放在红黑树的最右端。
+
+ - wakeup_preempt(...)
+
+ 这个函数检查进入可运行状态的任务能否抢占当前正在运行的任务。
+
+ - pick_next_task(...)
+
+ 这个函数选择接下来最适合运行的任务。
+
+ - set_next_task(...)
+
+ 这个函数在任务改变调度类,改变任务组时,或者任务被调度时被调用。
+
+ - task_tick(...)
+
+ 这个函数最常被时间滴答函数调用,它可能导致进程切换。这驱动了运行时抢占。
+
+
+
+
+7. CFS的组调度扩展
+==================
+
+通常,调度器操作粒度为任务,努力为每个任务提供公平的CPU时间。有时可能希望将任务编组,
+并为每个组提供公平的CPU时间。举例来说,可能首先希望为系统中的每个用户提供公平的CPU
+时间,接下来才是某个用户的每个任务。
+
+CONFIG_CGROUP_SCHED 力求实现它。它将任务编组,并为这些组公平地分配CPU时间。
+
+CONFIG_RT_GROUP_SCHED 允许将实时(也就是说,SCHED_FIFO和SCHED_RR)任务编组。
+
+CONFIG_FAIR_GROUP_SCHED 允许将CFS(也就是说,SCHED_NORMAL和SCHED_BATCH)任务编组。
+
+ 这些编译选项要求CONFIG_CGROUPS被定义,然后管理员能使用cgroup伪文件系统任意创建任务组。
+ 关于该文件系统的更多信息,参见Documentation/admin-guide/cgroup-v1/cgroups.rst
+
+当CONFIG_FAIR_GROUP_SCHED被定义后,通过伪文件系统,每个组被创建一个“cpu.shares”文件。
+参见下面的例子来创建任务组,并通过“cgroup”伪文件系统修改它们的CPU份额::
+
+ # mount -t tmpfs cgroup_root /sys/fs/cgroup
+ # mkdir /sys/fs/cgroup/cpu
+ # mount -t cgroup -ocpu none /sys/fs/cgroup/cpu
+ # cd /sys/fs/cgroup/cpu
+
+ # mkdir multimedia # 创建 "multimedia" 任务组
+ # mkdir browser # 创建 "browser" 任务组
+
+ # #配置multimedia组,令其获得browser组两倍CPU带宽
+
+ # echo 2048 > multimedia/cpu.shares
+ # echo 1024 > browser/cpu.shares
+
+ # firefox & # 启动firefox并把它移到 "browser" 组
+ # echo <firefox_pid> > browser/tasks
+
+ # #启动gmplayer(或者你最喜欢的电影播放器)
+ # echo <movie_player_pid> > multimedia/tasks
diff --git a/Documentation/translations/zh_CN/scheduler/sched-domains.rst b/Documentation/translations/zh_CN/scheduler/sched-domains.rst
new file mode 100644
index 000000000000..e814d4c01141
--- /dev/null
+++ b/Documentation/translations/zh_CN/scheduler/sched-domains.rst
@@ -0,0 +1,72 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/scheduler/sched-domains.rst
+
+:翻译:
+
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+:校译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+======
+调度域
+======
+
+每个CPU有一个“基”调度域(struct sched_domain)。调度域层次结构从基调度域构建而来,可
+通过->parent指针自下而上遍历。->parent必须以NULL结尾,调度域结构体必须是per-CPU的,
+因为它们无锁更新。
+
+每个调度域管辖数个CPU(存储在->span字段中)。一个调度域的span必须是它的子调度域span的
+超集(如有需求出现,这个限制可以放宽)。CPU i的基调度域必须至少管辖CPU i。每个CPU的
+顶层调度域通常将会管辖系统中的全部CPU,尽管严格来说这不是必须的,假如是这样,会导致某些
+CPU出现永远不会被指定任务运行的情况,直到允许的CPU掩码被显式设定。调度域的span字段意味
+着“在这些CPU中做进程负载均衡”。
+
+每个调度域必须具有一个或多个CPU调度组(struct sched_group),它们以单向循环链表的形式
+组织,存储在->groups指针中。这些组的CPU掩码的并集必须和调度域span字段一致。->groups
+指针指向的这些组包含的CPU,必须被调度域管辖。组包含的是只读数据,被创建之后,可能被多个
+CPU共享。任意两个组的CPU掩码的交集不一定为空,如果是这种情况,对应调度域的SD_OVERLAP
+标志位被设置,它管辖的调度组可能不能在多个CPU中共享。
+
+调度域中的负载均衡发生在调度组中。也就是说,每个组被视为一个实体。组的负载被定义为它
+管辖的每个CPU的负载之和。仅当组的负载不均衡后,任务才在组之间发生迁移。
+
+在kernel/sched/core.c中,trigger_load_balance()在每个CPU上通过scheduler_tick()
+周期执行。在当前运行队列下一个定期调度再平衡事件到达后,它引发一个软中断。负载均衡真正
+的工作由run_rebalance_domains()->rebalance_domains()完成,在软中断上下文中执行
+(SCHED_SOFTIRQ)。
+
+后一个函数有两个入参:当前CPU的运行队列、它在scheduler_tick()调用时是否空闲。函数会从
+当前CPU所在的基调度域开始迭代执行,并沿着parent指针链向上进入更高层级的调度域。在迭代
+过程中,函数会检查当前调度域是否已经耗尽了再平衡的时间间隔,如果是,它在该调度域运行
+load_balance()。接下来它检查父调度域(如果存在),再后来父调度域的父调度域,以此类推。
+
+起初,load_balance()查找当前调度域中最繁忙的调度组。如果成功,在该调度组管辖的全部CPU
+的运行队列中找出最繁忙的运行队列。如能找到,对当前的CPU运行队列和新找到的最繁忙运行
+队列均加锁,并把任务从最繁忙队列中迁移到当前CPU上。被迁移的任务数量等于在先前迭代执行
+中计算出的该调度域的调度组的不均衡值。
+
+实现调度域
+==========
+
+基调度域会管辖CPU层次结构中的第一层。对于超线程(SMT)而言,基调度域将会管辖同一个物理
+CPU的全部虚拟CPU,每个虚拟CPU对应一个调度组。
+
+在SMP中,基调度域的父调度域将会管辖同一个结点中的全部物理CPU,每个调度组对应一个物理CPU。
+接下来,如果是非统一内存访问(NUMA)系统,SMP调度域的父调度域将管辖整个机器,一个结点的
+CPU掩码对应一个调度组。亦或,你可以使用多级NUMA;举例来说Opteron处理器,可能仅用一个
+调度域来覆盖它的一个NUMA层级。
+
+实现者需要阅读include/linux/sched/sd_flags.h的注释:读SD_*来了解具体情况以及调度域的
+SD标志位调节了哪些东西。
+
+体系结构可以把指定的拓扑层级的通用调度域构建器和默认的SD标志位覆盖掉,方法是创建一个
+sched_domain_topology_level数组,并以该数组作为入参调用set_sched_topology()。
+
+调度域调试基础设施可以通过CONFIG_SCHED_DEBUG开启,并在开机启动命令行中增加
+“sched_verbose”。如果你忘记调整开机启动命令行了,也可以打开
+/sys/kernel/debug/sched/verbose开关。这将开启调度域错误检查的解析,它应该能捕获(上文
+描述过的)绝大多数错误,同时以可视化格式打印调度域的结构。
diff --git a/Documentation/translations/zh_CN/scheduler/sched-energy.rst b/Documentation/translations/zh_CN/scheduler/sched-energy.rst
new file mode 100644
index 000000000000..fdbf6cfeea93
--- /dev/null
+++ b/Documentation/translations/zh_CN/scheduler/sched-energy.rst
@@ -0,0 +1,351 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/scheduler/sched-energy.rst
+
+:翻译:
+
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+============
+能量感知调度
+============
+
+1. 简介
+-------
+
+能量感知调度(EAS)使调度器有能力预测其决策对CPU所消耗的能量的影响。EAS依靠
+一个能量模型(EM)来为每个任务选择一个节能的CPU,同时最小化对吞吐率的影响。
+本文档致力于介绍介绍EAS是如何工作的,它背后的主要设计决策是什么,以及使其运行
+所需的条件细节。
+
+在进一步阅读之前,请注意,在撰写本文时::
+
+ /!\ EAS不支持对称CPU拓扑的平台 /!\
+
+EAS只在异构CPU拓扑结构(如Arm大小核,big.LITTLE)上运行。因为在这种情况下,
+通过调度来节约能量的潜力是最大的。
+
+EAS实际使用的EM不是由调度器维护的,而是一个专门的框架。关于这个框架的细节和
+它提供的内容,请参考其文档(见Documentation/power/energy-model.rst)。
+
+
+2. 背景和术语
+-------------
+
+从一开始就说清楚定义:
+ - 能量 = [焦耳] (比如供电设备上的电池提供的资源)
+ - 功率 = 能量/时间 = [焦耳/秒] = [瓦特]
+
+ EAS的目标是最小化能量消耗,同时仍能将工作完成。也就是说,我们要最大化::
+
+ 性能 [指令数/秒]
+ ----------------
+ 功率 [瓦特]
+
+它等效于最小化::
+
+ 能量 [焦耳]
+ -----------
+ 指令数
+
+同时仍然获得“良好”的性能。当前调度器只考虑性能目标,因此该式子本质上是一个
+可选的优化目标,它同时考虑了两个目标:能量效率和性能。
+
+引入EM的想法是为了让调度器评估其决策的影响,而不是盲目地应用可能仅在部分
+平台有正面效果的节能技术。同时,EM必须尽可能的简单,以最小化调度器的时延
+影响。
+
+简而言之,EAS改变了CFS任务分配给CPU的方式。当调度器决定一个任务应该在哪里
+运行时(在唤醒期间),EM被用来在不损害系统吞吐率的情况下,从几个较好的候选
+CPU中挑选一个经预测能量消耗最优的CPU。EAS的预测依赖于对平台拓扑结构特定元素
+的了解,包括CPU的“算力”,以及它们各自的能量成本。
+
+
+3. 拓扑信息
+-----------
+
+EAS(以及调度器的剩余部分)使用“算力”的概念来区分不同计算吞吐率的CPU。一个
+CPU的“算力”代表了它在最高频率下运行时能完成的工作量,且这个值是相对系统中
+算力最大的CPU而言的。算力值被归一化为1024以内,并且可与由实体负载跟踪
+(PELT)机制算出的利用率信号做对比。由于有算力值和利用率值,EAS能够估计一个
+任务/CPU有多大/有多忙,并在评估性能与能量时将其考虑在内。CPU算力由特定体系
+结构实现的arch_scale_cpu_capacity()回调函数提供。
+
+EAS使用的其余平台信息是直接从能量模型(EM)框架中读取的。一个平台的EM是一张
+表,表中每项代表系统中一个“性能域”的功率成本。(若要了解更多关于性能域的细节,
+见Documentation/power/energy-model.rst)
+
+当调度域被建立或重新建立时,调度器管理对拓扑代码中EM对象的引用。对于每个根域
+(rd),调度器维护一个与当前rd->span相交的所有性能域的单向链表。链表中的每个
+节点都包含一个指向EM框架所提供的结构体em_perf_domain的指针。
+
+链表被附加在根域上,以应对独占的cpuset的配置。由于独占的cpuset的边界不一定与
+性能域的边界一致,不同根域的链表可能包含重复的元素。
+
+示例1
+ 让我们考虑一个有12个CPU的平台,分成3个性能域,(pd0,pd4和pd8),按以下
+ 方式组织::
+
+ CPUs: 0 1 2 3 4 5 6 7 8 9 10 11
+ PDs: |--pd0--|--pd4--|---pd8---|
+ RDs: |----rd1----|-----rd2-----|
+
+ 现在,考虑用户空间决定将系统分成两个独占的cpusets,因此创建了两个独立的根域,
+ 每个根域包含6个CPU。这两个根域在上图中被表示为rd1和rd2。由于pd4与rd1和rd2
+ 都有交集,它将同时出现于附加在这两个根域的“->pd”链表中:
+
+ * rd1->pd: pd0 -> pd4
+ * rd2->pd: pd4 -> pd8
+
+ 请注意,调度器将为pd4创建两个重复的链表节点(每个链表中各一个)。然而这
+ 两个节点持有指向同一个EM框架的共享数据结构的指针。
+
+由于对这些链表的访问可能与热插拔及其它事件并发发生,因此它们受RCU锁保护,就像
+被调度器操控的拓扑结构体中剩下字段一样。
+
+EAS同样维护了一个静态键(sched_energy_present),当至少有一个根域满足EAS
+启动的所有条件时,这个键就会被启动。在第6节中总结了这些条件。
+
+
+4. 能量感知任务放置
+-------------------
+
+EAS覆盖了CFS的任务唤醒平衡代码。在唤醒平衡时,它使用平台的EM和PELT信号来选择节能
+的目标CPU。当EAS被启用时,select_task_rq_fair()调用find_energy_efficient_cpu()
+来做任务放置决定。这个函数寻找在每个性能域中寻找具有最高剩余算力(CPU算力 - CPU
+利用率)的CPU,因为它能让我们保持最低的频率。然后,该函数检查将任务放在新CPU相较
+依然放在之前活动的prev_cpu是否可以节省能量。
+
+如果唤醒的任务被迁移,find_energy_efficient_cpu()使用compute_energy()来估算
+系统将消耗多少能量。compute_energy()检查各CPU当前的利用率情况,并尝试调整来
+“模拟”任务迁移。EM框架提供了API em_pd_energy()计算每个性能域在给定的利用率条件
+下的预期能量消耗。
+
+下面详细介绍一个优化能量消耗的任务放置决策的例子。
+
+示例2
+ 让我们考虑一个有两个独立性能域的(伪)平台,每个性能域含有2个CPU。CPU0和CPU1
+ 是小核,CPU2和CPU3是大核。
+
+ 调度器必须决定将任务P放在哪个CPU上,这个任务的util_avg = 200(平均利用率),
+ prev_cpu = 0(上一次运行在CPU0)。
+
+ 目前CPU的利用率情况如下图所示。CPU 0-3的util_avg分别为400、100、600和500。
+ 每个性能域有三个操作性能值(OPP)。与每个OPP相关的CPU算力和功率成本列在能量
+ 模型表中。P的util_avg在图中显示为"PP"::
+
+ CPU util.
+ 1024 - - - - - - - Energy Model
+ +-----------+-------------+
+ | Little | Big |
+ 768 ============= +-----+-----+------+------+
+ | Cap | Pwr | Cap | Pwr |
+ +-----+-----+------+------+
+ 512 =========== - ##- - - - - | 170 | 50 | 512 | 400 |
+ ## ## | 341 | 150 | 768 | 800 |
+ 341 -PP - - - - ## ## | 512 | 300 | 1024 | 1700 |
+ PP ## ## +-----+-----+------+------+
+ 170 -## - - - - ## ##
+ ## ## ## ##
+ ------------ -------------
+ CPU0 CPU1 CPU2 CPU3
+
+ Current OPP: ===== Other OPP: - - - util_avg (100 each): ##
+
+
+ find_energy_efficient_cpu()将首先在两个性能域中寻找具有最大剩余算力的CPU。
+ 在这个例子中是CPU1和CPU3。然后,它将估算,当P被放在它们中的任意一个时,系统的
+ 能耗,并检查这样做是否会比把P放在CPU0上节省一些能量。EAS假定OPPs遵循利用率
+ (这与CPUFreq监管器schedutil的行为一致。关于这个问题的更多细节,见第6节)。
+
+ **情况1. P被迁移到CPU1**::
+
+ 1024 - - - - - - -
+
+ Energy calculation:
+ 768 ============= * CPU0: 200 / 341 * 150 = 88
+ * CPU1: 300 / 341 * 150 = 131
+ * CPU2: 600 / 768 * 800 = 625
+ 512 - - - - - - - ##- - - - - * CPU3: 500 / 768 * 800 = 520
+ ## ## => total_energy = 1364
+ 341 =========== ## ##
+ PP ## ##
+ 170 -## - - PP- ## ##
+ ## ## ## ##
+ ------------ -------------
+ CPU0 CPU1 CPU2 CPU3
+
+
+ **情况2. P被迁移到CPU3**::
+
+ 1024 - - - - - - -
+
+ Energy calculation:
+ 768 ============= * CPU0: 200 / 341 * 150 = 88
+ * CPU1: 100 / 341 * 150 = 43
+ PP * CPU2: 600 / 768 * 800 = 625
+ 512 - - - - - - - ##- - -PP - * CPU3: 700 / 768 * 800 = 729
+ ## ## => total_energy = 1485
+ 341 =========== ## ##
+ ## ##
+ 170 -## - - - - ## ##
+ ## ## ## ##
+ ------------ -------------
+ CPU0 CPU1 CPU2 CPU3
+
+ **情况3. P依旧留在prev_cpu/CPU0**::
+
+ 1024 - - - - - - -
+
+ Energy calculation:
+ 768 ============= * CPU0: 400 / 512 * 300 = 234
+ * CPU1: 100 / 512 * 300 = 58
+ * CPU2: 600 / 768 * 800 = 625
+ 512 =========== - ##- - - - - * CPU3: 500 / 768 * 800 = 520
+ ## ## => total_energy = 1437
+ 341 -PP - - - - ## ##
+ PP ## ##
+ 170 -## - - - - ## ##
+ ## ## ## ##
+ ------------ -------------
+ CPU0 CPU1 CPU2 CPU3
+
+ 从这些计算结果来看,情况1的总能量最低。所以从节约能量的角度看,CPU1是最佳候选
+ 者。
+
+大核通常比小核更耗电,因此主要在任务不适合在小核运行时使用。然而,小核并不总是比
+大核节能。举例来说,对于某些系统,小核的高OPP可能比大核的低OPP能量消耗更高。因此,
+如果小核在某一特定时间点刚好有足够的利用率,在此刻被唤醒的小任务放在大核执行可能
+会更节能,尽管它在小核上运行也是合适的。
+
+即使在大核所有OPP都不如小核OPP节能的情况下,在某些特定条件下,令小任务运行在大核
+上依然可能节能。事实上,将一个任务放在一个小核上可能导致整个性能域的OPP提高,这将
+增加已经在该性能域运行的任务的能量成本。如果唤醒的任务被放在一个大核上,它的执行
+成本可能比放在小核上更高,但这不会影响小核上的其它任务,这些任务将继续以较低的OPP
+运行。因此,当考虑CPU消耗的总能量时,在大核上运行一个任务的额外成本可能小于为所有
+其它运行在小核的任务提高OPP的成本。
+
+上面的例子几乎不可能以一种通用的方式得到正确的结果;同时,对于所有平台,在不知道
+系统所有CPU每个不同OPP的运行成本时,也无法得到正确的结果。得益于基于EM的设计,
+EAS应该能够正确处理这些问题而不会引发太多麻烦。然而,为了确保对高利用率场景的
+吞吐率造成的影响最小化,EAS同样实现了另外一种叫“过度利用率”的机制。
+
+
+5. 过度利用率
+-------------
+
+从一般的角度来看,EAS能提供最大帮助的是那些涉及低、中CPU利用率的使用场景。每当CPU
+密集型的长任务运行,它们将需要所有的可用CPU算力,调度器将没有什么办法来节省能量同时
+又不损害吞吐率。为了避免EAS损害性能,一旦CPU被使用的算力超过80%,它将被标记为“过度
+利用”。只要根域中没有CPU是过度利用状态,负载均衡被禁用,而EAS将覆盖唤醒平衡代码。
+EAS很可能将负载放置在系统中能量效率最高的CPU而不是其它CPU上,只要不损害吞吐率。
+因此,负载均衡器被禁用以防止它打破EAS发现的节能任务放置。当系统未处于过度利用状态时,
+这样做是安全的,因为低于80%的临界点意味着:
+
+ a. 所有的CPU都有一些空闲时间,所以EAS使用的利用率信号很可能准确地代表各种任务
+ 的“大小”。
+ b. 所有任务,不管它们的nice值是多大,都应该被提供了足够多的CPU算力。
+ c. 既然有多余的算力,那么所有的任务都必须定期阻塞/休眠,在唤醒时进行平衡就足够
+ 了。
+
+只要一个CPU利用率超过80%的临界点,上述三个假设中至少有一个是不正确的。在这种情况下,
+整个根域的“过度利用”标志被设置,EAS被禁用,负载均衡器被重新启用。通过这样做,调度器
+又回到了在CPU密集的条件下基于负载的算法做负载均衡。这更好地尊重了任务的nice值。
+
+由于过度利用率的概念在很大程度上依赖于检测系统中是否有一些空闲时间,所以必须考虑
+(比CFS)更高优先级的调度类(以及中断)“窃取”的CPU算力。像这样,对过度使用率的检测
+不仅要考虑CFS任务使用的算力,还需要考虑其它调度类和中断。
+
+
+6. EAS的依赖和要求
+------------------
+
+能量感知调度依赖系统的CPU具有特定的硬件属性,以及内核中的其它特性被启用。本节列出
+了这些依赖,并对如何满足这些依赖提供了提示。
+
+
+6.1 - 非对称CPU拓扑
+^^^^^^^^^^^^^^^^^^^
+
+
+如简介所提,目前只有非对称CPU拓扑结构的平台支持EAS。通过在运行时查询
+SD_ASYM_CPUCAPACITY_FULL标志位是否在创建调度域时已设置来检查这一要求是否满足。
+
+参阅Documentation/scheduler/sched-capacity.rst以了解在sched_domain层次结构
+中设置此标志位所需满足的要求。
+
+请注意,EAS并非从根本上与SMP不兼容,但在SMP平台上还没有观察到明显的节能。这一
+限制可以在将来进行修改,如果被证明不是这样的话。
+
+
+6.2 - 当前的能量模型
+^^^^^^^^^^^^^^^^^^^^
+
+EAS使用一个平台的EM来估算调度决策对能量的影响。因此,你的平台必须向EM框架提供
+能量成本表,以启动EAS。要做到这一点,请参阅文档
+Documentation/power/energy-model.rst中的独立EM框架部分。
+
+另请注意,调度域需要在EM注册后重建,以便启动EAS。
+
+EAS使用EM对能量使用率进行预测决策,因此它在检查任务放置的可能选项时更加注重
+差异。对于EAS来说,EM的功率值是以毫瓦还是以“抽象刻度”为单位表示并不重要。
+
+
+
+6.3 - 能量模型复杂度
+^^^^^^^^^^^^^^^^^^^^
+
+任务唤醒路径是时延敏感的。当一个平台的EM太复杂(太多CPU,太多性能域,太多状态
+等),在唤醒路径中使用它的成本就会升高到不可接受。能量感知唤醒算法的复杂度为:
+
+ C = Nd * (Nc + Ns)
+
+其中:Nd是性能域的数量;Nc是CPU的数量;Ns是OPP的总数(例如:对于两个性能域,
+每个域有4个OPP,则Ns = 8)。
+
+当调度域建立时,复杂性检查是在根域上进行的。如果一个根域的复杂度C恰好高于完全
+主观设定的EM_MAX_COMPLEXITY阈值(在本文写作时,是2048),则EAS不会在此根域
+启动。
+
+如果你的平台的能量模型的复杂度太高,EAS无法在这个根域上使用,但你真的想用,
+那么你就只剩下两个可能的选择:
+
+ 1. 将你的系统拆分成分离的、较小的、使用独占cpuset的根域,并在每个根域局部
+ 启用EAS。这个方案的好处是开箱即用,但缺点是无法在根域之间实现负载均衡,
+ 这可能会导致总体系统负载不均衡。
+ 2. 提交补丁以降低EAS唤醒算法的复杂度,从而使其能够在合理的时间内处理更大
+ 的EM。
+
+
+6.4 - Schedutil监管器
+^^^^^^^^^^^^^^^^^^^^^
+
+EAS试图预测CPU在不久的将来会在哪个OPP下运行,以估算它们的能量消耗。为了做到
+这一点,它假定CPU的OPP跟随CPU利用率变化而变化。
+
+尽管在实践中很难对这一假设的准确性提供硬性保证(因为,举例来说硬件可能不会做
+它被要求做的事情),相对于其他CPUFreq监管器,schedutil至少_请求_使用利用率
+信号计算的频率。因此,与EAS一起使用的唯一合理的监管器是schedutil,因为它是
+唯一一个在频率请求和能量预测之间提供某种程度的一致性的监管器。
+
+不支持将EAS与schedutil之外的任何其它监管器一起使用。
+
+
+6.5 刻度不变性使用率信号
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+为了对不同的CPU和所有的性能状态做出准确的预测,EAS需要频率不变的和CPU不变的
+PELT信号。这些信号可以通过每个体系结构定义的arch_scale{cpu,freq}_capacity()
+回调函数获取。
+
+不支持在没有实现这两个回调函数的平台上使用EAS。
+
+
+6.6 多线程(SMT)
+^^^^^^^^^^^^^^^^^
+
+当前实现的EAS是不感知SMT的,因此无法利用多线程硬件节约能量。EAS认为线程是独立的
+CPU,这实际上对性能和能量消耗都是不利的。
+
+不支持在SMT上使用EAS。
diff --git a/Documentation/translations/zh_CN/scheduler/sched-nice-design.rst b/Documentation/translations/zh_CN/scheduler/sched-nice-design.rst
new file mode 100644
index 000000000000..9107f0c0b979
--- /dev/null
+++ b/Documentation/translations/zh_CN/scheduler/sched-nice-design.rst
@@ -0,0 +1,99 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/scheduler/sched-nice-design.rst
+
+:翻译:
+
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+=====================
+调度器nice值设计
+=====================
+
+本文档解释了新的Linux调度器中修改和精简后的nice级别的实现思路。
+
+Linux的nice级别总是非常脆弱,人们持续不断地缠着我们,让nice +19的任务占用
+更少的CPU时间。
+
+不幸的是,在旧的调度器中,这不是那么容易实现的(否则我们早就做到了),因为对
+nice级别的支持在历史上是与时间片长度耦合的,而时间片单位是由HZ滴答驱动的,
+所以最小的时间片是1/HZ。
+
+在O(1)调度器中(2003年),我们改变了负的nice级别,使它们比2.4内核更强
+(人们对这一变化很满意),而且我们还故意校正了线性时间片准则,使得nice +19
+的级别 _正好_ 是1 jiffy。为了让大家更好地理解它,时间片的图会是这样的(质量
+不佳的ASCII艺术提醒!)::
+
+
+ A
+ \ | [timeslice length]
+ \ |
+ \ |
+ \ |
+ \ |
+ \|___100msecs
+ |^ . _
+ | ^ . _
+ | ^ . _
+ -*----------------------------------*-----> [nice level]
+ -20 | +19
+ |
+ |
+
+因此,如果有人真的想renice任务,相较线性规则,+19会给出更大的效果(改变
+ABI来扩展优先级的解决方案在早期就被放弃了)。
+
+这种方法在一定程度上奏效了一段时间,但后来HZ=1000时,它导致1 jiffy为
+1ms,这意味着0.1%的CPU使用率,我们认为这有点过度。过度 _不是_ 因为它表示
+的CPU使用率过小,而是因为它引发了过于频繁(每毫秒1次)的重新调度(因此会
+破坏缓存,等等。请记住,硬件更弱、cache更小是很久以前的事了,当时人们在
+nice +19级别运行数量颇多的应用程序)。
+
+因此,对于HZ=1000,我们将nice +19改为5毫秒,因为这感觉像是正确的最小
+粒度——这相当于5%的CPU利用率。但nice +19的根本的HZ敏感属性依然保持不变,
+我们没有收到过关于nice +19在CPU利用率方面太 _弱_ 的任何抱怨,我们只收到
+过它(依然)太 _强_ 的抱怨 :-)。
+
+总结一下:我们一直想让nice各级别一致性更强,但在HZ和jiffies的限制下,以及
+nice级别与时间片、调度粒度耦合是令人讨厌的设计,这一目标并不真正可行。
+
+第二个关于Linux nice级别支持的抱怨是(不那么频繁,但仍然定期发生),它
+在原点周围的不对称性(你可以在上面的图片中看到),或者更准确地说:事实上
+nice级别的行为取决于 _绝对的_ nice级别,而nice应用程序接口本身从根本上
+说是“相对”的:
+
+ int nice(int inc);
+
+ asmlinkage long sys_nice(int increment)
+
+(第一个是glibc的应用程序接口,第二个是syscall的应用程序接口)
+注意,“inc”是相对当前nice级别而言的,类似bash的“nice”命令等工具是这个
+相对性应用程序接口的镜像。
+
+在旧的调度器中,举例来说,如果你以nice +1启动一个任务,并以nice +2启动
+另一个任务,这两个任务的CPU分配将取决于父外壳程序的nice级别——如果它是
+nice -10,那么CPU的分配不同于+5或+10。
+
+第三个关于Linux nice级别支持的抱怨是,负数nice级别“不够有力”,以很多人
+不得不诉诸于实时调度优先级来运行音频(和其它多媒体)应用程序,比如
+SCHED_FIFO。但这也造成了其它问题:SCHED_FIFO未被证明是免于饥饿的,一个
+有问题的SCHED_FIFO应用程序也会锁住运行良好的系统。
+
+v2.6.23版内核的新调度器解决了这三种类型的抱怨:
+
+为了解决第一个抱怨(nice级别不够“有力”),调度器与“时间片”、HZ的概念
+解耦(调度粒度被处理成一个和nice级别独立的概念),因此有可能实现更好、
+更一致的nice +19支持:在新的调度器中,nice +19的任务得到一个HZ无关的
+1.5%CPU使用率,而不是旧版调度器中3%-5%-9%的可变范围。
+
+为了解决第二个抱怨(nice各级别不一致),新调度器令调用nice(1)对各任务的
+CPU利用率有相同的影响,无论其绝对nice级别如何。所以在新调度器上,运行一个
+nice +10和一个nice +11的任务会与运行一个nice -5和一个nice -4的任务的
+CPU利用率分割是相同的(一个会得到55%的CPU,另一个会得到45%)。这是为什么
+nice级别被改为“乘法”(或指数)——这样的话,不管你从哪个级别开始,“相对”
+结果将总是一样的。
+
+第三个抱怨(负数nice级别不够“有力”,并迫使音频应用程序在更危险的
+SCHED_FIFO调度策略下运行)几乎被新的调度器自动解决了:更强的负数级别
+具有重新校正nice级别动态范围的自动化副作用。
diff --git a/Documentation/translations/zh_CN/scheduler/sched-stats.rst b/Documentation/translations/zh_CN/scheduler/sched-stats.rst
new file mode 100644
index 000000000000..c5e0be663837
--- /dev/null
+++ b/Documentation/translations/zh_CN/scheduler/sched-stats.rst
@@ -0,0 +1,156 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/scheduler/sched-stats.rst
+
+:翻译:
+
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+==============
+调度器统计数据
+==============
+
+第15版schedstats去掉了sched_yield的一些计数器:yld_exp_empty,yld_act_empty
+和yld_both_empty。在其它方面和第14版完全相同。
+
+第14版schedstats包括对sched_domains(译注:调度域)的支持,该特性进入内核
+主线2.6.20,不过这一版schedstats与2.6.13-2.6.19内核的版本12的统计数据是完全
+相同的(内核未发布第13版)。有些计数器按每个运行队列统计是更有意义的,其它则
+按每个调度域统计是更有意义的。注意,调度域(以及它们的附属信息)仅在开启
+CONFIG_SMP的机器上是相关的和可用的。
+
+在第14版schedstat中,每个被列出的CPU至少会有一级域统计数据,且很可能有一个
+以上的域。在这个实现中,域没有特别的名字,但是编号最高的域通常在机器上所有的
+CPU上仲裁平衡,而domain0是最紧密聚焦的域,有时仅在一对CPU之间进行平衡。此时,
+没有任何体系结构需要3层以上的域。域统计数据中的第一个字段是一个位图,表明哪些
+CPU受该域的影响。
+
+这些字段是计数器,而且只能递增。使用这些字段的程序将需要从基线观测开始,然后在
+后续每一个观测中计算出计数器的变化。一个能以这种方式处理其中很多字段的perl脚本
+可见
+
+ http://eaglet.pdxhosts.com/rick/linux/schedstat/
+
+请注意,任何这样的脚本都必须是特定于版本的,改变版本的主要原因是输出格式的变化。
+对于那些希望编写自己的脚本的人,可以参考这里描述的各个字段。
+
+CPU统计数据
+-----------
+cpu<N> 1 2 3 4 5 6 7 8 9
+
+第一个字段是sched_yield()的统计数据:
+
+ 1) sched_yield()被调用了#次
+
+接下来的三个是schedule()的统计数据:
+
+ 2) 这个字段是一个过时的数组过期计数,在O(1)调度器中使用。为了ABI兼容性,
+ 我们保留了它,但它总是被设置为0。
+ 3) schedule()被调用了#次
+ 4) 调用schedule()导致处理器变为空闲了#次
+
+接下来的两个是try_to_wake_up()的统计数据:
+
+ 5) try_to_wake_up()被调用了#次
+ 6) 调用try_to_wake_up()导致本地CPU被唤醒了#次
+
+接下来的三个统计数据描述了调度延迟:
+
+ 7) 本处理器运行任务的总时间,单位是纳秒
+ 8) 本处理器任务等待运行的时间,单位是纳秒
+ 9) 本CPU运行了#个时间片
+
+域统计数据
+----------
+
+对于每个被描述的CPU,和它相关的每一个调度域均会产生下面一行数据(注意,如果
+CONFIG_SMP没有被定义,那么*没有*调度域被使用,这些行不会出现在输出中)。
+
+domain<N> <cpumask> 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
+
+第一个字段是一个位掩码,表明该域在操作哪些CPU。
+
+接下来的24个字段是load_balance()函数的各个统计数据,按空闲类型分组(空闲,
+繁忙,新空闲):
+
+
+ 1) 当CPU空闲时,load_balance()在这个调度域中被调用了#次
+ 2) 当CPU空闲时,load_balance()在这个调度域中被调用,但是发现负载无需
+ 均衡#次
+ 3) 当CPU空闲时,load_balance()在这个调度域中被调用,试图迁移1个或更多
+ 任务且失败了#次
+ 4) 当CPU空闲时,load_balance()在这个调度域中被调用,发现不均衡(如果有)
+ #次
+ 5) 当CPU空闲时,pull_task()在这个调度域中被调用#次
+ 6) 当CPU空闲时,尽管目标任务是热缓存状态,pull_task()依然被调用#次
+ 7) 当CPU空闲时,load_balance()在这个调度域中被调用,未能找到更繁忙的
+ 队列#次
+ 8) 当CPU空闲时,在调度域中找到了更繁忙的队列,但未找到更繁忙的调度组
+ #次
+ 9) 当CPU繁忙时,load_balance()在这个调度域中被调用了#次
+ 10) 当CPU繁忙时,load_balance()在这个调度域中被调用,但是发现负载无需
+ 均衡#次
+ 11) 当CPU繁忙时,load_balance()在这个调度域中被调用,试图迁移1个或更多
+ 任务且失败了#次
+ 12) 当CPU繁忙时,load_balance()在这个调度域中被调用,发现不均衡(如果有)
+ #次
+ 13) 当CPU繁忙时,pull_task()在这个调度域中被调用#次
+ 14) 当CPU繁忙时,尽管目标任务是热缓存状态,pull_task()依然被调用#次
+ 15) 当CPU繁忙时,load_balance()在这个调度域中被调用,未能找到更繁忙的
+ 队列#次
+ 16) 当CPU繁忙时,在调度域中找到了更繁忙的队列,但未找到更繁忙的调度组
+ #次
+ 17) 当CPU新空闲时,load_balance()在这个调度域中被调用了#次
+ 18) 当CPU新空闲时,load_balance()在这个调度域中被调用,但是发现负载无需
+ 均衡#次
+ 19) 当CPU新空闲时,load_balance()在这个调度域中被调用,试图迁移1个或更多
+ 任务且失败了#次
+ 20) 当CPU新空闲时,load_balance()在这个调度域中被调用,发现不均衡(如果有)
+ #次
+ 21) 当CPU新空闲时,pull_task()在这个调度域中被调用#次
+ 22) 当CPU新空闲时,尽管目标任务是热缓存状态,pull_task()依然被调用#次
+ 23) 当CPU新空闲时,load_balance()在这个调度域中被调用,未能找到更繁忙的
+ 队列#次
+ 24) 当CPU新空闲时,在调度域中找到了更繁忙的队列,但未找到更繁忙的调度组
+ #次
+
+接下来的3个字段是active_load_balance()函数的各个统计数据:
+
+ 25) active_load_balance()被调用了#次
+ 26) active_load_balance()被调用,试图迁移1个或更多任务且失败了#次
+ 27) active_load_balance()被调用,成功迁移了#次任务
+
+接下来的3个字段是sched_balance_exec()函数的各个统计数据:
+
+ 28) sbe_cnt不再被使用
+ 29) sbe_balanced不再被使用
+ 30) sbe_pushed不再被使用
+
+接下来的3个字段是sched_balance_fork()函数的各个统计数据:
+
+ 31) sbf_cnt不再被使用
+ 32) sbf_balanced不再被使用
+ 33) sbf_pushed不再被使用
+
+接下来的3个字段是try_to_wake_up()函数的各个统计数据:
+
+ 34) 在这个调度域中调用try_to_wake_up()唤醒任务时,任务在调度域中一个
+ 和上次运行不同的新CPU上运行了#次
+ 35) 在这个调度域中调用try_to_wake_up()唤醒任务时,任务被迁移到发生唤醒
+ 的CPU次数为#,因为该任务在原CPU是冷缓存状态
+ 36) 在这个调度域中调用try_to_wake_up()唤醒任务时,引发被动负载均衡#次
+
+/proc/<pid>/schedstat
+---------------------
+schedstats还添加了一个新的/proc/<pid>/schedstat文件,来提供一些进程级的
+相同信息。这个文件中,有三个字段与该进程相关:
+
+ 1) 在CPU上运行花费的时间(单位是纳秒)
+ 2) 在运行队列上等待的时间(单位是纳秒)
+ 3) 在CPU上运行了#个时间片
+
+可以很容易地编写一个程序,利用这些额外的字段来报告一个特定的进程或一组进程在
+调度器策略下的表现如何。这样的程序的一个简单版本可在下面的链接找到
+
+ http://eaglet.pdxhosts.com/rick/linux/schedstat/v12/latency.c
diff --git a/Documentation/translations/zh_CN/scheduler/schedutil.rst b/Documentation/translations/zh_CN/scheduler/schedutil.rst
new file mode 100644
index 000000000000..7c8d87f21c42
--- /dev/null
+++ b/Documentation/translations/zh_CN/scheduler/schedutil.rst
@@ -0,0 +1,164 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/scheduler/schedutil.rst
+
+:翻译:
+
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+=========
+Schedutil
+=========
+
+.. note::
+
+ 本文所有内容都假设频率和工作算力之间存在线性关系。我们知道这是有瑕疵的,
+ 但这是最可行的近似处理。
+
+PELT(实体负载跟踪,Per Entity Load Tracking)
+==============================================
+
+通过PELT,我们跟踪了各种调度器实体的一些指标,从单个任务到任务组分片到CPU
+运行队列。我们使用指数加权移动平均数(Exponentially Weighted Moving Average,
+EWMA)作为其基础,每个周期(1024us)都会衰减,衰减速率满足y^32 = 0.5。
+也就是说,最近的32ms贡献负载的一半,而历史上的其它时间则贡献另一半。
+
+具体而言:
+
+ ewma_sum(u) := u_0 + u_1*y + u_2*y^2 + ...
+
+ ewma(u) = ewma_sum(u) / ewma_sum(1)
+
+由于这本质上是一个无限几何级数的累加,结果是可组合的,即ewma(A) + ewma(B) = ewma(A+B)。
+这个属性是关键,因为它提供了在任务迁移时重新组合平均数的能力。
+
+请注意,阻塞态的任务仍然对累加值(任务组分片和CPU运行队列)有贡献,这反映了
+它们在恢复运行后的预期贡献。
+
+利用这一点,我们跟踪2个关键指标:“运行”和“可运行”。“运行”反映了一个调度实体
+在CPU上花费的时间,而“可运行”反映了一个调度实体在运行队列中花费的时间。当只有
+一个任务时,这两个指标是相同的,但一旦出现对CPU的争用,“运行”将减少以反映每个
+任务在CPU上花费的时间,而“可运行”将增加以反映争用的激烈程度。
+
+更多细节见:kernel/sched/pelt.c
+
+
+频率 / CPU不变性
+================
+
+因为CPU频率在1GHz时利用率为50%和CPU频率在2GHz时利用率为50%是不一样的,同样
+在小核上运行时利用率为50%和在大核上运行时利用率为50%是不一样的,我们允许架构
+以两个比率来伸缩时间差,其中一个是动态电压频率升降(Dynamic Voltage and
+Frequency Scaling,DVFS)比率,另一个是微架构比率。
+
+对于简单的DVFS架构(软件有完全控制能力),我们可以很容易地计算该比率为::
+
+ f_cur
+ r_dvfs := -----
+ f_max
+
+对于由硬件控制DVFS的更多动态系统,我们使用硬件计数器(Intel APERF/MPERF,
+ARMv8.4-AMU)来计算这一比率。具体到Intel,我们使用::
+
+ APERF
+ f_cur := ----- * P0
+ MPERF
+
+ 4C-turbo; 如果可用并且使能了turbo
+ f_max := { 1C-turbo; 如果使能了turbo
+ P0; 其它情况
+
+ f_cur
+ r_dvfs := min( 1, ----- )
+ f_max
+
+我们选择4C turbo而不是1C turbo,以使其更持久性略微更强。
+
+r_cpu被定义为当前CPU的最高性能水平与系统中任何其它CPU的最高性能水平的比率。
+
+ r_tot = r_dvfs * r_cpu
+
+其结果是,上述“运行”和“可运行”的指标变成DVFS无关和CPU型号无关了。也就是说,
+我们可以在CPU之间转移和比较它们。
+
+更多细节见:
+
+ - kernel/sched/pelt.h:update_rq_clock_pelt()
+ - arch/x86/kernel/smpboot.c:"APERF/MPERF frequency ratio computation."
+ - Documentation/translations/zh_CN/scheduler/sched-capacity.rst:"1. CPU Capacity + 2. Task utilization"
+
+
+UTIL_EST
+========
+
+由于周期性任务的平均数在睡眠时会衰减,而在运行时其预期利用率会和睡眠前相同,
+因此它们在再次运行后会面临(DVFS)的上涨。
+
+为了缓解这个问题,(一个默认使能的编译选项)UTIL_EST驱动一个无限脉冲响应
+(Infinite Impulse Response,IIR)的EWMA,“运行”值在出队时是最高的。
+UTIL_EST滤波使其在遇到更高值时立刻增加,而遇到低值时会缓慢衰减。
+
+进一步,运行队列的(可运行任务的)利用率之和由下式计算:
+
+ util_est := \Sum_t max( t_running, t_util_est_ewma )
+
+更多细节见: kernel/sched/fair.c:util_est_dequeue()
+
+
+UCLAMP
+======
+
+可以在每个CFS或RT任务上设置有效的u_min和u_max clamp值(译注:clamp可以理解
+为类似滤波器的能力,它定义了有效取值范围的最大值和最小值);运行队列为所有正在
+运行的任务保持这些clamp的最大聚合值。
+
+更多细节见: include/uapi/linux/sched/types.h
+
+
+Schedutil / DVFS
+================
+
+每当调度器的负载跟踪被更新时(任务唤醒、任务迁移、时间流逝),我们都会调用
+schedutil来更新硬件DVFS状态。
+
+其基础是CPU运行队列的“运行”指标,根据上面的内容,它是CPU的频率不变的利用率
+估计值。由此我们计算出一个期望的频率,如下::
+
+ max( running, util_est ); 如果使能UTIL_EST
+ u_cfs := { running; 其它情况
+
+ clamp( u_cfs + u_rt, u_min, u_max ); 如果使能UCLAMP_TASK
+ u_clamp := { u_cfs + u_rt; 其它情况
+
+ u := u_clamp + u_irq + u_dl; [估计值。更多细节见源代码]
+
+ f_des := min( f_max, 1.25 u * f_max )
+
+关于IO-wait的说明:当发生更新是因为任务从IO完成中唤醒时,我们提升上面的“u”。
+
+然后,这个频率被用来选择一个P-state或OPP,或者直接混入一个发给硬件的CPPC式
+请求。
+
+关于截止期限调度器的说明: 截止期限任务(偶发任务模型)使我们能够计算出满足
+工作负荷所需的硬f_min值。
+
+因为这些回调函数是直接来自调度器的,所以DVFS的硬件交互应该是“快速”和非阻塞的。
+在硬件交互缓慢和昂贵的时候,schedutil支持DVFS请求限速,不过会降低效率。
+
+更多信息见: kernel/sched/cpufreq_schedutil.c
+
+
+注意
+====
+
+ - 在低负载场景下,DVFS是最相关的,“运行”的值将密切反映利用率。
+
+ - 在负载饱和的场景下,任务迁移会导致一些瞬时性的使用率下降。假设我们有一个
+ CPU,有4个任务占用导致其饱和,接下来我们将一个任务迁移到另一个空闲CPU上,
+ 旧的CPU的“运行”值将为0.75,而新的CPU将获得0.25。这是不可避免的,而且随着
+ 时间流逝将自动修正。另注,由于没有空闲时间,我们还能保证f_max值吗?
+
+ - 上述大部分内容是关于避免DVFS下滑,以及独立的DVFS域发生负载迁移时不得不
+ 重新学习/提升频率。
+
diff --git a/Documentation/translations/zh_CN/sound/hd-audio/controls.rst b/Documentation/translations/zh_CN/sound/hd-audio/controls.rst
new file mode 100644
index 000000000000..54c028ab9a40
--- /dev/null
+++ b/Documentation/translations/zh_CN/sound/hd-audio/controls.rst
@@ -0,0 +1,102 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Chinese translator: Huang Jianghui <huangjianghui@uniontech.com>
+---------------------------------------------------------------------
+.. include:: ../../disclaimer-zh_CN.rst
+以下为正文
+---------------------------------------------------------------------
+======================================
+高清音频编解码器特定混音器控件
+======================================
+
+
+此文件解释特定于编解码器的混音器控件.
+
+瑞昱编解码器
+------------
+
+声道模式
+ 这是一个用于更改环绕声道设置的枚举控件,仅在环绕声道打开时显示出现。
+ 它给出要使用的通道数:"2ch","4ch","6ch",和"8ch"。根据配置,这还控
+ 制多I/O插孔的插孔重分配。
+
+自动静音模式
+ 这是一个枚举控件,用于更改耳机和线路输出插孔的自动静音行为。如果内
+ 置扬声器、耳机和/或线路输出插孔在机器上可用,则显示该控件。当只有
+ 耳机或者线路输出的时候,它给出”禁用“和”启用“状态。当启用后,插孔插
+ 入后扬声器会自动静音。
+
+ 当耳机和线路输出插孔都存在时,它给出”禁用“、”仅扬声器“和”线路输出+扬
+ 声器“。当”仅扬声器“被选择,插入耳机或者线路输出插孔可使扬声器静音,
+ 但不会使线路输出静音。当线路输出+扬声器被选择,插入耳机插孔会同时使扬
+ 声器和线路输出静音。
+
+
+矽玛特编解码器
+--------------
+
+模拟环回
+ 此控件启用/禁用模拟环回电路。只有在编解码器提示中将”lookback“设置为真
+ 时才会出现(见HD-Audio.txt)。请注意,在某些编解码器上,模拟环回和正常
+ PCM播放是独占的,即当此选项打开时,您将听不到任何PCM流。
+
+交换中置/低频
+ 交换中置和低频通道顺序,通常情况下,左侧对应中置,右侧对应低频,启动此
+ 项后,左边低频,右边中置。
+
+耳机作为线路输出
+ 当此控制开启时,将耳机视为线路输出插孔。也就是说,耳机不会自动静音其他
+ 线路输出,没有耳机放大器被设置到引脚上。
+
+麦克风插口模式、线路插孔模式等
+ 这些枚举控制输入插孔引脚的方向和偏置。根据插孔类型,它可以设置为”麦克风
+ 输入“和”线路输入“以确定输入偏置,或者当引脚是环绕声道的多I/O插孔时,它
+ 可以设置为”线路输出“。
+
+
+威盛编解码器
+------------
+
+智能5.1
+ 一个枚举控件,用于为环绕输出重新分配多个I/O插孔的任务。当它打开时,相应
+ 的输入插孔(通常是线路输入和麦克风输入)被切换为环绕和中央低频输出插孔。
+
+独立耳机
+ 启用此枚举控制时,耳机输出从单个流(第三个PCM,如hw:0,2)而不是主流路由。
+ 如果耳机DAC与侧边或中央低频通道DAC共享,则DAC将自动切换到耳机。
+
+环回混合
+ 一个用于确定是否启动了模拟环回路由的枚举控件。当它启用后,模拟环回路由到
+ 前置通道。同样,耳机与扬声器输出也采用相同的路径。作为一个副作用,当设置
+ 此模式后,单个音量控制将不再适用于耳机和扬声器,因为只有一个DAC连接到混
+ 音器小部件。
+
+动态电源控制
+ 此控件决定是否启动每个插孔的动态电源控制检测。启用时,根据插孔的插入情况
+ 动态更改组件的电源状态(D0/D3)以节省电量消耗。但是,如果您的系统没有提
+ 供正确的插孔检测,这将无法工作;在这种情况下,请关闭此控件。
+
+插孔检测
+ 此控件仅为VT1708编解码器提供,它不会为每个插孔插拔提供适当的未请求事件。
+ 当此控件打开,驱动将轮询插孔检测,以便耳机自动静音可以工作,而关闭此控
+ 件将降低功耗。
+
+
+科胜讯编解码器
+--------------
+
+自动静音模式
+ 见瑞昱解码器
+
+
+
+模拟编解码器
+------------
+
+通道模式
+ 这是一个用于更改环绕声道设置的枚举控件,仅在环绕声道可用时显示。它提供了能
+ 被使用的通道数:”2ch“、”4ch“和”6ch“。根据配置,这还控制多I/O插孔的插孔重
+ 分配。
+
+独立耳机
+ 启动此枚举控制后,耳机输出从单个流(第三个PCM,如hw:0,2)而不是主流路由。
diff --git a/Documentation/translations/zh_CN/sound/hd-audio/index.rst b/Documentation/translations/zh_CN/sound/hd-audio/index.rst
new file mode 100644
index 000000000000..d9885d53b069
--- /dev/null
+++ b/Documentation/translations/zh_CN/sound/hd-audio/index.rst
@@ -0,0 +1,14 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: :doc:`../../../../sound/hd-audio/index`
+:Translator: Huang Jianghui <huangjianghui@uniontech.com>
+
+
+高清音频
+========
+
+.. toctree::
+ :maxdepth: 2
+
+ controls
diff --git a/Documentation/translations/zh_CN/sound/index.rst b/Documentation/translations/zh_CN/sound/index.rst
new file mode 100644
index 000000000000..28d5dca34a63
--- /dev/null
+++ b/Documentation/translations/zh_CN/sound/index.rst
@@ -0,0 +1,22 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: :doc:`../../../sound/index`
+:Translator: Huang Jianghui <huangjianghui@uniontech.com>
+
+
+====================
+Linux 声音子系统文档
+====================
+
+.. toctree::
+ :maxdepth: 2
+
+ hd-audio/index
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
diff --git a/Documentation/translations/zh_CN/staging/index.rst b/Documentation/translations/zh_CN/staging/index.rst
new file mode 100644
index 000000000000..bb55c81c84a3
--- /dev/null
+++ b/Documentation/translations/zh_CN/staging/index.rst
@@ -0,0 +1,26 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/staging/index.rst
+
+:翻译:
+
+ 李睿 Rui Li <me@lirui.org>
+
+未分类文档
+==========
+
+.. toctree::
+ :maxdepth: 2
+
+ xz
+
+TODOList:
+
+* crc32
+* lzo
+* remoteproc
+* rpmsg
+* speculation
+* static-keys
+* tee
diff --git a/Documentation/translations/zh_CN/staging/xz.rst b/Documentation/translations/zh_CN/staging/xz.rst
new file mode 100644
index 000000000000..211c487bcb62
--- /dev/null
+++ b/Documentation/translations/zh_CN/staging/xz.rst
@@ -0,0 +1,100 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/staging/xz.rst
+
+:翻译:
+
+ 李睿 Rui Li <me@lirui.org>
+
+===================
+Linux中的XZ数据压缩
+===================
+
+介绍
+====
+
+XZ是一种通用的数据压缩格式,其具有高压缩率和相对快的解压速度。主要的压缩算法(
+过滤器)是LZMA2。额外的过滤器可以被用来进一步提高压缩率,比如用来提高可执行数据
+压缩率的Branch/Call/Jump (BCJ)过滤器。
+
+XZ解压器在Linux中被称作XZ Embedded。它支持LZMA2过滤器和可选的BCJ过滤器,并支持
+CRC32完整性校验。你可以在XZ Embedded的主页<https://tukaani.org/xz/embedded.html>
+中找到最新版本和关于在Linux内核之外使用源码的信息。
+
+对于用户空间来说,XZ Utils提供了类似于zlib的压缩库和类似于gzip的命令行工具。
+XZ Utils可以从<https://tukaani.org/xz/>下载。
+
+内核中的XZ相关组件
+==================
+
+xz_dec模块为XZ解压器提供了单次调用(缓冲区到缓冲区)和多次调用(有状态)的
+API。xz_dec模块的用法记录在include/linux/xz.h中。
+
+xz_dec_test模块用于测试xz_dec。除非你想魔改XZ解压器,否则xz_dec_test是
+没有用的。xz_dec_test会动态分配一个字符设备主设备号,你可以从用户空间向它
+写入.xz文件,解压的输出会被丢弃。关注dmesg可以找到xz_dec_test输出的诊断信息。
+详细内容请查看xz_dec_test的源码。
+
+为了解压内核镜像、初始ram文件系统和初始ram磁盘,lib/decompress_unxz.c实现
+了一个包装函数。它的API与其他 decompress_*.c 文件相同,那些API定义在
+include/linux/decompress/generic.h中。
+
+scripts/xz_wrap.sh是一个XZ Utils中的xz命令行工具包装器。这个包装器会
+设置合适的压缩选项来压缩内核镜像。
+
+在内核的makefiles中,提供了使用$(call if_needed)的两个命令。内核镜像应该
+使用$(call if_needed,xzkern)来压缩,它会使用BCJ过滤器和一个大LZMA2字典。
+它还会附加一个四字节的包含源文件大小的预告,这会在启动代码中被用到。其他文件
+应该使用$(call if_needed,xzmisc)来压缩,它会使用1 MiB的LZMA2字典并禁用
+BCJ过滤器。
+
+关于压缩选项的说明
+==================
+
+因为XZ Embedded只支持没有完整性校验的数据流或者CRC32,请确保你在编码未来将被
+内核解码的文件时没有使用其他完整性校验方式。使用liblzma时,你需要使用LZMA_CHECK_NONE
+或LZMA_CHECK_CRC32。使用xz命令行工具时,使用--check=none或--check=crc32。
+
+除非有其他环节会验证解压数据的完整性,否则强烈使用CRC32。双重验证可能会浪费
+CPU周期。请注意头部总是会包含用于解压器验证的CRC32,你只能修改或禁用解压后数据
+的完整性校验方式。
+
+在用户中间中,LZMA2通常使用几兆字节大小的字典。解码器需要在RAM中放置字典,
+因此大字典不能被用于那些意在被内核解码的文件。1 MiB在内核中大概是可接受的最大
+字典大小(可能对初始ram文件系统也适用)。XZ Utils中的预设值可能并不适合创建
+内核文件,所以请别犹豫使用自定义设置。比如::
+
+ xz --check=crc32 --lzma2=dict=512KiB inputfile
+
+使用上面字典大小的一个例外是在单一调用模式下使用解码器。解压内核自身就是一个例
+子。在单一调用模式下,内存用量并不和字典大小有关,这种情况就是使用大字典的好地
+方:为了最大化压缩,字典至少应该和解压后的数据一样大。
+
+未来计划
+========
+
+如果有人认为有用的话,可能会考虑创建一个受限的XZ编码器。LZMA2的压缩速率比Deflate
+或LZO等要慢,即使在最快的配置选项下。所以并不清楚LZMA2编码器是否需要并入内核。
+
+有计划在解压代码中支持有限的随机访问读数据。不知道这能否在内核中有任何用,但是我
+知道这会在一些Linux内核以外的嵌入式项目中有用。
+
+.xz文件格式规范的一致性
+=======================
+
+在一些边缘情况下,为了简化事情牺牲了尽早地检测错误。因为并不会导致安全问题,实际
+上是没有关系的。但在测试代码的时候知道这一点很好,比如测试来自XZ Utils的文件。
+
+报告错误
+========
+
+请在报告错误前确认是否已经在上游修复。可以从<https://tukaani.org/xz/embedded.html>
+获取最新的源码。
+
+可以通过联系<lasse.collin@tukaani.org>或者访问Freenode上的#tukaani
+联系Larhzu。我并不经常阅读LKML或者其他内核相关的邮件列表,所以如果要告知我什么事情
+,你应该通过我的私人邮箱或者IRC联系我。
+
+请不要因为内核中XZ的实现或关于XZ Utils的问题打扰Igor Pavlov。虽然这两种实现
+包含了建立在Igor Pavlov的代码上的重要源码,但并不由他维护和提供支持。
diff --git a/Documentation/translations/zh_CN/subsystem-apis.rst b/Documentation/translations/zh_CN/subsystem-apis.rst
new file mode 100644
index 000000000000..47780bb0772f
--- /dev/null
+++ b/Documentation/translations/zh_CN/subsystem-apis.rst
@@ -0,0 +1,110 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ./disclaimer-zh_CN.rst
+
+:Original: Documentation/subsystem-apis.rst
+
+:翻译:
+
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+
+==============
+内核子系统文档
+==============
+
+这些书籍从内核开发者的角度,详细介绍了特定内核子系统
+的如何工作。这里的大部分信息直接取自内核源代码,并
+根据需要添加了补充材料(或者至少是我们设法添加的 - 可
+能 *不是* 所有的材料都有需要)。
+
+核心子系统
+----------
+
+.. toctree::
+ :maxdepth: 1
+
+ core-api/index
+ driver-api/index
+ mm/index
+ power/index
+ scheduler/index
+ locking/index
+
+TODOList:
+
+* timers/index
+
+人机接口
+--------
+
+.. toctree::
+ :maxdepth: 1
+
+ sound/index
+
+TODOList:
+
+* input/index
+* hid/index
+* gpu/index
+* fb/index
+
+网络接口
+--------
+
+.. toctree::
+ :maxdepth: 1
+
+ infiniband/index
+
+TODOList:
+
+* networking/index
+* netlabel/index
+* isdn/index
+* mhi/index
+
+存储接口
+--------
+
+.. toctree::
+ :maxdepth: 1
+
+ filesystems/index
+
+TODOList:
+
+* block/index
+* cdrom/index
+* scsi/index
+* target/index
+
+**Fixme**: 这里还需要更多的分类组织工作。
+
+.. toctree::
+ :maxdepth: 1
+
+ accounting/index
+ cpu-freq/index
+ iio/index
+ virt/index
+ PCI/index
+ peci/index
+
+TODOList:
+
+* fpga/index
+* i2c/index
+* leds/index
+* pcmcia/index
+* spi/index
+* w1/index
+* watchdog/index
+* hwmon/index
+* accel/index
+* security/index
+* crypto/index
+* bpf/index
+* usb/index
+* misc-devices/index
+* wmi/index
diff --git a/Documentation/translations/zh_CN/userspace-api/accelerators/ocxl.rst b/Documentation/translations/zh_CN/userspace-api/accelerators/ocxl.rst
new file mode 100644
index 000000000000..845b932bf935
--- /dev/null
+++ b/Documentation/translations/zh_CN/userspace-api/accelerators/ocxl.rst
@@ -0,0 +1,168 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/userspace-api/accelerators/ocxl.rst
+
+:翻译:
+
+ 李睿 Rui Li <me@lirui.org>
+
+=====================================
+OpenCAPI (开放相干加速器处理器接口)
+=====================================
+
+*OpenCAPI: Open Coherent Accelerator Processor Interface*
+
+OpenCAPI是处理器和加速器之间的一个接口,致力于达到低延迟和高带宽。该规范
+由 `OpenCAPI Consortium <http://opencapi.org/>`_ 开发。
+
+它允许加速器(可以是FPGA、ASIC等)使用虚拟地址连贯地访问主机内存。一个OpenCAPI
+设备也可以托管它自己的内存,并可以由主机访问。
+
+OpenCAPI在Linux中称为“ocxl”,它作为“cxl”(用于powerpc的IBM CAPI接口的驱动)的
+开放、处理器无关的演进,这么命名是为了避免与ISDN CAPI子系统相混淆。
+
+
+高层视角
+========
+
+OpenCAPI定义了一个在物理链路层上实现的数据链路层(TL)和传输层(TL)。任何
+实现DL和TL的处理器或者设备都可以开始共享内存。
+
+::
+
+ +-----------+ +-------------+
+ | | | |
+ | | | Accelerated |
+ | Processor | | Function |
+ | | +--------+ | Unit | +--------+
+ | |--| Memory | | (AFU) |--| Memory |
+ | | +--------+ | | +--------+
+ +-----------+ +-------------+
+ | |
+ +-----------+ +-------------+
+ | TL | | TLX |
+ +-----------+ +-------------+
+ | |
+ +-----------+ +-------------+
+ | DL | | DLX |
+ +-----------+ +-------------+
+ | |
+ | PHY |
+ +---------------------------------------+
+
+ Processor:处理器
+ Memory:内存
+ Accelerated Function Unit:加速函数单元
+
+
+
+设备发现
+========
+
+OpenCAPI依赖一个在设备上实现的与PCI类似的配置空间。因此主机可以通过查询
+配置空间来发现AFU。
+
+OpenCAPI设备在Linux中被当作类PCI设备(有一些注意事项)。固件需要对硬件进行
+抽象,就好像它是一个PCI链路。许多已有的PCI架构被重用:在模拟标准PCI时,
+设备被扫描并且BAR(基址寄存器)被分配。像“lspci”的命令因此可以被用于查看
+哪些设备可用。
+
+配置空间定义了可以在物理适配器上可以被找到的AFU,比如它的名字、支持多少内
+存上下文、内存映射IO(MMIO)区域的大小等。
+
+
+
+MMIO
+====
+
+OpenCAPI为每个AFU定义了两个MMIO区域:
+
+* 全局MMIO区域,保存和整个AFU相关的寄存器。
+* 每个进程的MMIO区域,对于每个上下文固定大小。
+
+
+
+AFU中断
+=======
+
+OpenCAPI拥有AFU向主机进程发送中断的可能性。它通过定义在传输层的“intrp_req”
+来完成,指定一个定义中断的64位对象句柄。
+
+驱动允许一个进程分配中断并获取可以传递给AFU的64位对象句柄。
+
+
+
+字符设备
+========
+
+驱动为每个在物理设备上发现的AFU创建一个字符设备。一个物理设备可能拥有多个
+函数,一个函数可以拥有多个AFU。不过编写这篇文档之时,只对导出一个AFU的设备
+测试过。
+
+字符设备可以在 /dev/ocxl/ 中被找到,其命名为:
+/dev/ocxl/<AFU 名称>.<位置>.<索引>
+
+<AFU 名称> 是一个最长20个字符的名称,和在AFU配置空间中找到的相同。
+<位置>由驱动添加,可在系统有不止一个相同的OpenCAPI设备时帮助区分设备。
+<索引>也是为了在少见情况下帮助区分AFU,即设备携带多个同样的AFU副本时。
+
+
+
+Sysfs类
+=======
+
+添加了代表AFU的ocxl类。查看/sys/class/ocxl。布局在
+Documentation/ABI/testing/sysfs-class-ocxl 中描述。
+
+
+
+用户API
+=======
+
+打开
+----
+
+基于在配置空间中找到的AFU定义,AFU可能支持在多个内存上下文中工作,这种情况
+下相关的字符设备可以被不同进程多次打开。
+
+
+ioctl
+-----
+
+OCXL_IOCTL_ATTACH:
+
+ 附加调用进程的内存上下文到AFU,以允许AFU访问其内存。
+
+OCXL_IOCTL_IRQ_ALLOC:
+
+ 分配AFU中断,返回标识符。
+
+OCXL_IOCTL_IRQ_FREE:
+
+ 释放之前分配的AFU中断。
+
+OCXL_IOCTL_IRQ_SET_FD:
+
+ 将一个事件文件描述符和AFU中断关联,因此用户进程可以在AFU发送中断时收到通
+ 知。
+
+OCXL_IOCTL_GET_METADATA:
+
+ 从卡中获取配置信息,比如内存映射IO区域的大小、AFU版本和当前上下文的进程
+ 地址空间ID(PASID)。
+
+OCXL_IOCTL_ENABLE_P9_WAIT:
+
+ 允许AFU唤醒执行“等待”的用户空间进程。返回信息给用户空间,允许其配置AFU。
+ 注意这只在POWER9上可用。
+
+OCXL_IOCTL_GET_FEATURES:
+
+ 报告用户空间可用的影响OpenCAPI的CPU特性。
+
+
+mmap
+----
+
+一个进程可以mmap每个进程的MMIO区域来和AFU交互。
diff --git a/Documentation/translations/zh_CN/userspace-api/ebpf/index.rst b/Documentation/translations/zh_CN/userspace-api/ebpf/index.rst
new file mode 100644
index 000000000000..d52c7052f101
--- /dev/null
+++ b/Documentation/translations/zh_CN/userspace-api/ebpf/index.rst
@@ -0,0 +1,22 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/userspace-api/ebpf/index.rst
+
+:翻译:
+
+ 李睿 Rui Li <me@lirui.org>
+
+eBPF 用户空间API
+================
+
+eBPF是一种在Linux内核中提供沙箱化运行环境的机制,它可以在不改变内核源码或加载
+内核模块的情况下扩展运行时和编写工具。eBPF程序能够被附加到各种内核子系统中,包
+括网络,跟踪和Linux安全模块(LSM)等。
+
+关于eBPF的内部内核文档,请查看 Documentation/bpf/index.rst 。
+
+.. toctree::
+ :maxdepth: 1
+
+ syscall
diff --git a/Documentation/translations/zh_CN/userspace-api/ebpf/syscall.rst b/Documentation/translations/zh_CN/userspace-api/ebpf/syscall.rst
new file mode 100644
index 000000000000..47e2a59ae45d
--- /dev/null
+++ b/Documentation/translations/zh_CN/userspace-api/ebpf/syscall.rst
@@ -0,0 +1,29 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/userspace-api/ebpf/syscall.rst
+
+:翻译:
+
+ 李睿 Rui Li <me@lirui.org>
+
+eBPF Syscall
+------------
+
+:作者:
+ - Alexei Starovoitov <ast@kernel.org>
+ - Joe Stringer <joe@wand.net.nz>
+ - Michael Kerrisk <mtk.manpages@gmail.com>
+
+bpf syscall的主要信息可以在 `man-pages`_ 中的 `bpf(2)`_ 找到。
+
+bpf() 子命令参考
+~~~~~~~~~~~~~~~~
+
+子命令在以下内核代码中:
+
+include/uapi/linux/bpf.h
+
+.. Links:
+.. _man-pages: https://www.kernel.org/doc/man-pages/
+.. _bpf(2): https://man7.org/linux/man-pages/man2/bpf.2.html
diff --git a/Documentation/translations/zh_CN/userspace-api/futex2.rst b/Documentation/translations/zh_CN/userspace-api/futex2.rst
new file mode 100644
index 000000000000..04f9d62db1f7
--- /dev/null
+++ b/Documentation/translations/zh_CN/userspace-api/futex2.rst
@@ -0,0 +1,80 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/userspace-api/futex2.rst
+
+:翻译:
+
+ 李睿 Rui Li <me@lirui.org>
+
+======
+futex2
+======
+
+:作者: André Almeida <andrealmeid@collabora.com>
+
+futex,或者称为快速用户互斥锁(fast user mutex),是一组允许用户空间创建高性能同步
+机制的系统调用,比如用户空间中的互斥锁,信号量和条件变量。C标准库,如glibc,使用它作
+为实现更多高级接口的方式,如pthreads。
+
+futex2是初代futex系统调用的后续版本,旨在克服原有接口的限制。
+
+用户API
+=======
+
+``futex_waitv()``
+-----------------
+
+等待一个futex数组,可由其中任意一个唤醒::
+
+ futex_waitv(struct futex_waitv *waiters, unsigned int nr_futexes,
+ unsigned int flags, struct timespec *timeout, clockid_t clockid)
+
+ struct futex_waitv {
+ __u64 val;
+ __u64 uaddr;
+ __u32 flags;
+ __u32 __reserved;
+ };
+
+用户空间设置一个struct futex_waitv数组(最多128项),设置 ``uaddr`` 为等待的
+地址, ``val`` 为期望值, ``flags`` 为指定的类型(如private)和futex的大小。
+``__reserved`` 需要置为0,但是它可用作未来扩展。指向数组第一个元素的指针作为
+``waiters`` 传递。如果 ``waiters`` 或任何的 ``uaddr`` 地址无效,将返回 ``-EFAULT`` 。
+
+如果用户空间拥有32位的指针,那么需要做显式转换来保证高位清零。 ``uintptr_t`` 设计
+得很精巧,在32/64位的指针上都正常工作。
+
+``nr_futexes`` 指定了数组的大小。不在[1,128]区间内的值会使系统调用返回 ``-EINVAL`` 。
+
+系统调用的 ``flags`` 参数需要置0,但可用作未来扩展。
+
+对于每个 ``waiters`` 数组中的项,在 ``uaddr`` 的当前值会和 ``val`` 比较。如果
+不一致,系统调用会撤销截至目前完成的所有工作,并返回 ``-EAGAIN`` 。如果所有测试
+和验证都通过,系统调用会等待直到以下情况之一发生:
+
+- 指定的timeout超时,返回 ``-ETIMEOUT`` 。
+- 一个信号被传递给睡眠中的任务,返回 ``-ERESTARTSYS`` 。
+- 某个列表中的futex被唤醒,返回那个被唤醒的futex的索引。
+
+关于如何使用接口的例子可以在 ``tools/testing/selftests/futex/functional/futex_waitv.c``
+中找到。
+
+超时
+----
+
+``struct timespec *timeout`` 是一个指向绝对超时时间的可选参数。你需要在 ``clockid``
+参数中指定要使用的时钟类型。支持 ``CLOCK_MONOTONIC`` 和 ``CLOCK_REALTIME`` 。这个
+系统调用只接受64位的timespec结构体。
+
+futex的类型
+-----------
+
+futex既可以是私有的也可以是共享的。私有用于多个进程共享同样的内存空间,并且futex的虚拟
+地址对所有进程都是一样的。这允许在内核中进行优化。要使用私有futex,需要在futex标志中指定
+``FUTEX_PRIVATE_FLAG`` 。对于那些不在同一内存空间共享的进程,可以让同一个futex拥有不同
+的虚拟地址(例如使用基于文件的共享内存),这需要不同的内部机制来使得正确进入队列。这是默认
+的行为,而且对私有futex和共享futex都适用。
+
+futex可以是不同的大小:8,16,32或64位。目前只支持32位大小的futex,并且需要通过 ``FUTEX_32``
+标志指定。
diff --git a/Documentation/translations/zh_CN/userspace-api/index.rst b/Documentation/translations/zh_CN/userspace-api/index.rst
new file mode 100644
index 000000000000..5b14721c8264
--- /dev/null
+++ b/Documentation/translations/zh_CN/userspace-api/index.rst
@@ -0,0 +1,47 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/userspace-api/index.rst
+
+:翻译:
+
+ 李睿 Rui Li <me@lirui.org>
+
+=========================
+Linux 内核用户空间API指南
+=========================
+
+.. _man-pages: https://www.kernel.org/doc/man-pages/
+
+尽管许多用户空间API的文档被记录在别处(特别是在 man-pages_ 项目中),
+在代码树中仍然可以找到有关用户空间的部分信息。这个手册意在成为这些信息
+聚集的地方。
+
+.. toctree::
+ :caption: 目录
+ :maxdepth: 2
+
+ no_new_privs
+ seccomp_filter
+ accelerators/ocxl
+ ebpf/index
+ sysfs-platform_profile
+ futex2
+
+TODOList:
+
+* landlock
+* unshare
+* spec_ctrl
+* ioctl/index
+* iommu
+* media/index
+* netlink/index
+* vduse
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
diff --git a/Documentation/translations/zh_CN/userspace-api/no_new_privs.rst b/Documentation/translations/zh_CN/userspace-api/no_new_privs.rst
new file mode 100644
index 000000000000..81bd16ce3ad2
--- /dev/null
+++ b/Documentation/translations/zh_CN/userspace-api/no_new_privs.rst
@@ -0,0 +1,57 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/userspace-api/no_new_privs.rst
+
+:翻译:
+
+ 李睿 Rui Li <me@lirui.org>
+
+============
+无新权限标志
+============
+
+execve系统调用可以给一个新启动的程序授予它的父程序本没有的权限。最明显的两个
+例子就是setuid/setgid控制程序和文件的能力。为了避免父程序也获得这些权限,内
+核和用户代码必须小心避免任何父程序可以颠覆子程序的情况。比如:
+
+ - 程序在setuid后,动态装载器处理 ``LD_*`` 环境变量的不同方式。
+
+ - 对于非特权程序,chroot是不允许的,因为这会允许 ``/etc/passwd`` 在继承
+ chroot的程序眼中被替换。
+
+ - 执行代码对ptrace有特殊处理。
+
+这些都是临时性的修复。 ``no_new_privs`` 位(从 Linux 3.5 起)是一个新的通
+用的机制来保证一个进程安全地修改其执行环境并跨execve持久化。任何任务都可以设
+置 ``no_new_privs`` 。一旦该位被设置,它会在fork、clone和execve中继承下去
+,并且不能被撤销。在 ``no_new_privs`` 被设置的情况下, ``execve()`` 将保证
+不会授予权限去做任何没有execve调用就不能做的事情。比如, setuid 和 setgid
+位不会再改变 uid 或 gid;文件能力不会被添加到授权集合中,并且Linux安全模块(
+LSM)不会在execve调用后放松限制。
+
+设置 ``no_new_privs`` 使用::
+
+ prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+
+不过要小心,Linux安全模块(LSM)也可能不会在 ``no_new_privs`` 模式下收紧约束。
+(这意味着一个一般的服务启动器在执行守护进程前就去设置 ``no_new_privs`` 可能
+会干扰基于LSM的沙箱。)
+
+请注意, ``no_new_privs`` 并不能阻止不涉及 ``execve()`` 的权限变化。一个拥有
+适当权限的任务仍然可以调用 ``setuid(2)`` 并接收 SCM_RIGHTS 数据报。
+
+目前来说, ``no_new_privs`` 有两大使用场景:
+
+ - 为seccomp模式2沙箱安装的过滤器会跨execve持久化,并能够改变新执行程序的行为。
+ 非特权用户因此在 ``no_new_privs`` 被设置的情况下只允许安装这样的过滤器。
+
+ - ``no_new_privs`` 本身就能被用于减少非特权用户的攻击面。如果所有以某个 uid
+ 运行的程序都设置了 ``no_new_privs`` ,那么那个 uid 将无法通过攻击 setuid,
+ setgid 和使用文件能力的二进制来提权;它需要先攻击一些没有被设置 ``no_new_privs``
+ 位的东西。
+
+将来,其他潜在的危险的内核特性可能被非特权任务利用,即使 ``no_new_privs`` 被置位。
+原则上,当 ``no_new_privs`` 被置位时, ``unshare(2)`` 和 ``clone(2)`` 的几个选
+项将是安全的,并且 ``no_new_privs`` 加上 ``chroot`` 是可以被认为比 chroot本身危
+险性小得多的。
diff --git a/Documentation/translations/zh_CN/userspace-api/seccomp_filter.rst b/Documentation/translations/zh_CN/userspace-api/seccomp_filter.rst
new file mode 100644
index 000000000000..ede8b37c953f
--- /dev/null
+++ b/Documentation/translations/zh_CN/userspace-api/seccomp_filter.rst
@@ -0,0 +1,293 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/userspace-api/seccomp_filter.rst
+
+:翻译:
+
+ 李睿 Rui Li <me@lirui.org>
+
+==================================
+Seccomp BPF (基于过滤器的安全计算)
+==================================
+
+*Seccomp: SECure COMPuting*
+
+介绍
+====
+
+大量系统调用被暴露给每个用户空间进程,但其中又有许多系统调用在进程的整个生命
+周期中都没被使用。随着系统调用的改变和成熟,缺陷被找到并消除。允许某一部分应
+用程序仅能访问一部分系统调用是有好处的,这会缩小内核暴露给应用程序的面积。
+系统调用过滤器就是为这些应用程序而生的。
+
+Seccomp过滤提供了一种为进程指定一个处理系统调用的过滤器的方法。这个过滤器体
+现为一个伯克利包过滤器(BPF)程序,就像套接字过滤器一样,不同在于前者处理的
+数据和正在进行的系统调用有关:系统调用号和系统调用参数。这样使用一种长期与
+用户空间和直接数据打交道的语言来表达系统调用过滤成为了可能。
+
+此外,BPF让seccomp用户不再成为在系统调用干预框架(system call interposition
+frameworks)中常见的检查-使用竞态攻击(TOCTOU)的受害者。BPF程序可能无法解引
+用指针,这就限制了所有过滤器仅能直接评估系统调用参数。
+
+这不是什么
+==========
+
+系统调用过滤并不是一个沙箱。它提供了一种明确定义的机制来最小化内核暴露面。它
+旨在成为一个沙箱开发者使用的工具。除此之外,逻辑行为和信息流的策略应该结合其他
+系统加固手段或者可能由你选择的内核安全模块(LSM)来管理。易于表达的动态过滤器
+为这条路提供了更多选择(比如避免病态的大小或者选择允许 socketcall() 中的多路
+系统调用),但将其理解为更完整的沙箱解决方案是错误的。
+
+用法
+====
+
+添加了一个额外的seccomp模式,它可以使用和严格seccomp相同的 prctl(2) 调用来启用。
+如果架构有 ``CONFIG_HAVE_ARCH_SECCOMP_FILTER`` 标志,那么可以添加以下过滤器:
+
+``PR_SET_SECCOMP``:
+ 现在需要添加一个额外的参数来指定使用BPF程序的新过滤器。
+ BPF程序将在反应系统调用号、参数和其他元数据的seccomp_data结构体之上执行。
+ BPF程序必须返回允许的值之一来告知内核应该采取什么行动。
+
+ 用法::
+
+ prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, prog);
+
+ 'prog' 参数是一个指向 sock_fprog 结构体的指针,其中包含了过滤器程序。如
+ 果程序是无效的,该调用会返回 -1 并设置 errno 为 ``EINVAL`` 。
+
+ 如果 ``fork`` / ``clone`` 和 ``execve`` 被 @prog 所允许,任何子进程都将
+ 受到和父进程相同的过滤器和系统调用ABI的约束。
+
+ 在调用之前,进程必须调用 ``prctl(PR_SET_NO_NEW_PRIVS, 1)`` 或者在它的
+ 命名空间内以 ``CAP_SYS_ADMIN`` 权限运行。如果以上条件不满足,会返回
+ ``-EACCES`` 。这一要求保证了过滤器程序不能用于比安装过滤器的进程拥有更高
+ 权限的子进程。
+
+ 另外,如果 ``prctl(2)`` 被安装的过滤器所允许,就可以叠加额外的过滤器。这会增
+ 加评估时间,但是可以进一步降低执行进程时的攻击面。
+
+以上调用在成功时返回0,失败时返回一个非零的值。
+
+返回值
+======
+
+一个seccomp过滤器可能返回下列任意值。如果多个过滤器存在,评估一个指定系统调用的
+返回值总会使用最高优先级的值。(比如 ``SECCOMP_RET_KILL_PROCESS`` 总是被优先
+返回。)
+
+按照优先级排序,它们是:
+
+``SECCOMP_RET_KILL_PROCESS``:
+ 使得整个进程立即结束而不执行系统调用。进程的退出状态 (``status & 0x7f``) 将
+ 是 ``SIGSYS`` ,而不是 ``SIGKILL`` 。
+
+``SECCOMP_RET_KILL_THREAD``:
+ 使得线程立即结束而不执行系统调用。线程的退出状态 (``status & 0x7f``) 将是
+ 是 ``SIGSYS`` ,而不是 ``SIGKILL`` 。
+
+``SECCOMP_RET_TRAP``:
+ 使得内核向触发进程发送一个 ``SIGSYS`` 信号而不执行系统调用。
+ ``siginfo->si_call_addr`` 会展示系统调用指令的位置, ``siginfo->si_syscall``
+ 和 ``siginfo->si_arch`` 会指出试图进行的系统调用。程序计数器会和发生了系统
+ 调用的一样(即它不会指向系统调用指令)。返回值寄存器会包含一个与架构相关的值——
+ 如果恢复执行,需要将其设为合理的值。(架构依赖性是因为将其替换为 ``-ENOSYS``
+ 会导致一些有用的信息被覆盖。)
+
+ 返回值的 ``SECCOMP_RET_DATA`` 部分会作为 ``si_errno`` 传递。
+
+ 由seccomp触发的 ``SIGSYS`` 会有一个 ``SYS_SECCOMP`` 的 si_code 。
+
+``SECCOMP_RET_ERRNO``:
+ 使得返回值的低16位作为errno传递给用户空间,而不执行系统调用。
+
+``SECCOMP_RET_USER_NOTIF``:
+ 使得一个 ``struct seccomp_notif`` 消息被发送到已附加的用户空间通知文件描述
+ 符。如果没有被附加则返回 ``-ENOSYS`` 。下面会讨论如何处理用户通知。
+
+``SECCOMP_RET_TRACE``:
+ 当返回的时候,这个值会使得内核在执行系统调用前尝试去通知一个基于 ``ptrace()``
+ 的追踪器。如果没有追踪器, ``-ENOSYS`` 会返回给用户空间,并且系统调用不会执行。
+
+ 如果追踪器通过 ``ptrace(PTRACE_SETOPTIONS)`` 请求了 ``PTRACE_O_TRACESECCOMP``,
+ 那么它会收到 ``PTRACE_EVENT_SECCOMP`` 通知。BPF程序返回值的 ``SECCOMP_RET_DATA``
+ 部分会通过 ``PTRACE_GETEVENTMSG`` 提供给追踪器。
+
+ 追踪器可以通过改变系统调用号到-1来跳过系统调用。或者追踪器可以改变系统调用号到
+ 一个有效值来改变请求的系统调用。如果追踪器请求跳过系统调用,那么系统调用将返回
+ 追踪器放在返回值寄存器中的值。
+
+ 在追踪器被通知后,seccomp检查不会再次运行。(这意味着基于seccomp的沙箱必须禁止
+ ptrace的使用,甚至其他沙箱进程也不行,除非非常小心;ptrace可以通过这个机制来逃
+ 逸。)
+
+``SECCOMP_RET_LOG``:
+ 使得系统调用在被记录之后再运行。这应该被应用开发者用来检查他们的程序需要哪些
+ 系统调用,而不需要反复通过多个测试和开发周期来建立清单。
+
+ 只有在 actions_logged sysctl 字符串中出现 "log" 时,这个操作才会被记录。
+
+``SECCOMP_RET_ALLOW``:
+ 使得系统调用被执行。
+
+如果多个追踪器存在,评估系统调用的返回值将永远使用最高优先级的值。
+
+优先级只通过 ``SECCOMP_RET_ACTION`` 掩码来决定。当多个过滤器返回相同优先级的返回
+值时,只有来自最近安装的过滤器的 ``SECCOMP_RET_DATA`` 会被返回。
+
+隐患
+====
+
+最需要避免的隐患是在过滤系统调用号时却不检查架构值。因为在任何支持多个系统调用
+约定的架构上,系统调用号可能根据具体调用而不同。如果不同调用约定中的调用号有重叠,
+那么过滤器的检查可能被滥用。请总是检查架构值!
+
+例子
+====
+
+``samples/seccomp/`` 文件夹包含了x86专用和更通用的使用高层宏接口来生成BPF程序的
+例子。
+
+用户空间通知
+============
+
+``SECCOMP_RET_USER_NOTIF`` 返回值会让seccomp过滤器传递一个特定的系统调用给用户
+空间处理。这可能会对像容器管理器的程序有用,它们希望拦截特定的系统调用(如 ``mount()``,
+``finit_module()`` 等等)并改变其行为。
+
+传递 ``SECCOMP_FILTER_FLAG_NEW_LISTENER`` 参数给 ``seccomp()`` 系统调用可以取
+得通知文件描述符:
+
+.. code-block:: c
+
+ fd = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_NEW_LISTENER, &prog);
+
+成功情况下会返回一个对过滤器监听的文件描述符,然后可以通过 ``SCM_RIGHTS`` 或类似
+的方式传递。需要注意的是,过滤器文件描述符针对的是一个特定的过滤器而不是特定的进程。
+所以如果这个进程后来fork了,来自两个进程的通知都会出现在同一个过滤器文件描述符中。
+对于过滤器文件描述符的读写也是同步的,所以一个过滤器文件描述符可以安全地拥有多个读者。
+
+seccomp通知文件描述符由两个结构体组成:
+
+.. code-block:: c
+
+ struct seccomp_notif_sizes {
+ __u16 seccomp_notif;
+ __u16 seccomp_notif_resp;
+ __u16 seccomp_data;
+ };
+
+ struct seccomp_notif {
+ __u64 id;
+ __u32 pid;
+ __u32 flags;
+ struct seccomp_data data;
+ };
+
+ struct seccomp_notif_resp {
+ __u64 id;
+ __s64 val;
+ __s32 error;
+ __u32 flags;
+ };
+
+``struct seccomp_notif_sizes`` 结构体可以用于确定seccomp通知中各种结构体的大小。
+``struct seccomp_data`` 的大小可能未来会改变,所以需要使用下面的代码:
+
+.. code-block:: c
+
+ struct seccomp_notif_sizes sizes;
+ seccomp(SECCOMP_GET_NOTIF_SIZES, 0, &sizes);
+
+来决定需要分配的多种结构体的大小。请查看 samples/seccomp/user-trap.c 中的例子。
+
+用户可以通过 ``ioctl(SECCOMP_IOCTL_NOTIF_RECV)`` (或 ``poll()``) 读取seccomp
+通知文件描述符来接收一个 ``struct seccomp_notif`` ,其中包含五个成员:结构体的
+输入长度,每个过滤器唯一的 ``id`` , 触发请求进程的 ``pid`` (如果进程的pid命名空
+间对于监听者的pid命名空间不可见的话,可能为0)。通知还包含传递给seccomp的 ``data``
+和一个过滤器标志。在调用ioctl前结构体应该被清空。
+
+之后用户空间可以根据这些信息决定做什么,并通过 ``ioctl(SECCOMP_IOCTL_NOTIF_SEND)``
+发送一个响应,表示应该给用户空间返回什么。 ``struct seccomp_notif_resp`` 的 ``id``
+成员应该和 ``struct seccomp_notif`` 的 ``id`` 一致。
+
+用户空间也可以通过 ``ioctl(SECCOMP_IOCTL_NOTIF_ADDFD)`` 向通知进程添加文件描述
+符。 ``struct seccomp_notif_addfd`` 的 ``id`` 成员应该和 ``struct seccomp_notif``
+的 ``id`` 保持一致。 ``newfd_flags`` 标志可以被用于在通知进程的文件描述符上设置
+O_CLOEXEC 等标志。如果监督者(supervisor)向文件描述符注入一个特定的数字,可以使用
+``SECCOMP_ADDFD_FLAG_SETFD`` 标志,并设置 ``newfd`` 成员为要使用的特定数字。
+如果文件描述符已经在通知进程中打开,那它将被替换。监督者也可以添加一个文件描述符,
+并使用 ``SECCOMP_ADDFD_FLAG_SEND`` 标志原子响应,返回值将是注入的文件描述符编号。
+
+通知进程可以被抢占,导致通知被终止。这可能在尝试代表通知进程执行长时间且通常可重试
+(如挂载文件系统)的操作时导致问题。另外,在安装过滤器的时候,
+``SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV`` 可以被设置。这个标志使得当监督者收到用
+户通知时,通知进程会忽略非致命信号,直到响应被发送。在用户空间收到通知之前发出的信号
+将被正常处理。
+
+值得注意的是, ``struct seccomp_data`` 包含了系统调用寄存器参数的值,但是不包含指向
+内存的指针。进程的内存可以通过 ``ptrace()`` 或 ``/proc/pid/mem`` 由合适的特权跟踪
+访问。但是,需要注意避免之前提到的TOCTOU攻击:所有从被跟踪者内存中读到的参数都应该先
+读到追踪器的内存中,再做出策略决定。这样就可以对系统调用的参数做原子决定。
+
+Sysctls
+=======
+
+Seccomp的sysctl文件可以在 ``/proc/sys/kernel/seccomp/`` 文件夹中找到。这里有对文件
+夹中每个文件的描述:
+
+``actions_avail``:
+ 以字符串形式保存seccomp返回值(参考上文的 ``SECCOMP_RET_*`` 宏)的只读有序
+ 列表。从左往右按照最少许可返回值到最多许可返回值排序。
+
+ 这个列表代表了内核支持的seccomp返回值集合。一个用户空间程序可以使用这个列表来在
+ 程序建立时确定在 ``seccomp.h`` 中找到的动作是否和当前运行内核实际支持的动作有所
+ 不同。
+
+``actions_logged``:
+ 允许被记录的seccomp返回值(参考上文的 ``SECCOMP_RET_*`` 宏)的可读写有序列表。
+ 对文件写入不需要是有序的,但从文件读取将采用与actions_avail sysctl一致的方式排序。
+
+ ``allow`` 字符串在 ``actions_logged`` sysctl中不被接收,因为不可能记录
+ ``SECCOMP_RET_ALLOW`` 动作。尝试向sysctl写入 ``allow`` 会导致返回一个EINVAL。
+
+添加架构支持
+============
+
+请查看 ``arch/Kconfig`` 了解权威要求。总的来说如果一个架构同时支持ptrace_event和
+seccomp,那么它将可以通过较小的修改支持seccomp过滤器: ``SIGSYS`` 支持和seccomp
+返回值检查。然后必须将 ``CONFIG_HAVE_ARCH_SECCOMP_FILTER`` 添加到它的架构特定
+的Kconfig中。
+
+注意事项
+========
+
+vDSO可能导致一些系统调用完全在用户空间中运行,当你在不同机器上跑程序时可能导致回退
+到真正系统调用的意外发生。为了在x86上最小化这些意外的发生,请确保你在测试时把
+``/sys/devices/system/clocksource/clocksource0/current_clocksource`` 设置为
+``acpi_pm`` 之类的值。
+
+在x86-64上,vsyscall模拟默认开启。(vsyscalls是vDSO调用的传统变体。)目前,模拟
+vsyscalls会遵守seccomp,但是有一些奇怪情况:
+
+- ``SECCOMP_RET_TRAP`` 的返回值会设置一个指向给定vsyscall入口的 ``si_call_addr``,
+ 而不是'syscall'指令之后的地址。任何想重新开始调用的代码都需要注意 (a) ret指令
+ 已被模拟,(b) 试图恢复系统调用将再次触发标准vsyscall模拟安全检查,使得恢复系统
+ 调用在大部分情况下没有意义。
+
+- ``SECCOMP_RET_TRACE`` 的返回值将像往常一样给追踪器发出信号,但是系统调用可能不能
+ 使用orig_rax寄存器改变为另一个系统调用。可能只能改变为-1来跳过当前模拟的调用。
+ 任何其他改变都可能终止进程。追踪器看到的rip值将是系统调用的入口地址;这和正常行为
+ 不同。追踪器禁止修改rip或者rsp。(不要依赖其他改变来终止进程,它们可能正常工作。
+ 比如在一些内核中,选择一个只存在于未来内核中的系统调用将被正确模拟,返回一个
+ ``-ENOSYS`` 。)
+
+要检测这个古怪的行为,可以检查 ``addr & ~0x0C00 == 0xFFFFFFFFFF600000``。(对于
+``SECCOMP_RET_TRACE`` ,使用rip。对于 ``SECCOMP_RET_TRAP`` ,使用
+``siginfo->si_call_addr`` 。)不要检测其他条件:未来内核可能会改进vsyscall模拟,
+当前内核在vsyscall=native模式下会有不同表现,但在这些情况下, ``0xF...F600{0,4,8,C}00``
+处的指令将不是系统调用。
+
+请注意,现代系统根本不可能使用vsyscalls —— 它们是一种遗留功能,而且比标准系统调用
+慢得多。 新的代码将使用vDSO,而vDSO发出的系统调用与正常的系统调用没有区别。
diff --git a/Documentation/translations/zh_CN/userspace-api/sysfs-platform_profile.rst b/Documentation/translations/zh_CN/userspace-api/sysfs-platform_profile.rst
new file mode 100644
index 000000000000..7d21740db125
--- /dev/null
+++ b/Documentation/translations/zh_CN/userspace-api/sysfs-platform_profile.rst
@@ -0,0 +1,40 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/userspace-api/sysfs-platform_profile.rst
+
+:翻译:
+
+ 李睿 Rui Li <me@lirui.org>
+
+==========================================================
+平台配置文件选择(如 /sys/firmware/acpi/platform_profile)
+==========================================================
+
+现代系统中平台性能、温度、风扇和其他硬件相关的特性通常是可以动态配置的。平台
+配置通常会根据当前的状态由一些自动机制(很可能存在于内核之外)来自动调整。
+
+这些平台自动调整机制通常能够被配置成多个平台配置文件中的一个,要么偏向节能运
+行,要么偏向性能运行。
+
+platform_profile属性的目的是提供一个通用的sysfs API来选择这些平台自动配置
+机制的配置文件。
+
+需要注意的是,这个API只能用作选择平台配置文件,用来监测所产生的性能特征并不
+是其目标。监测性能最好使用设备/供应商提供的工具,比如turbostat。
+
+具体来说,当选择高性能配置文件时,真实能达到的性能可能受制于多种因素,比如:
+其他组件的发热,房间温度,笔记本底部的自由空气流动等。让用户空间知道任何阻碍
+达到要求性能水平的局部最优条件,显然不是这个API的目标。
+
+由于数字本身并不能代表一个配置文件会调整的多个变量(功耗,发热等),这个API
+使用字符串来描述多种配置文件。为了保证用户空间能够获得一致的体验,
+sysfs-platform_profile ABI 文档定义了一个固定的配置文件名集合。驱动程序
+*必须* 将它们内置的配置文件表示映射到这个固定的集合中。
+
+如果映射时没有很好的匹配,可以添加一个新的配置文件名称。驱动希望引入的新配置
+文件名称时必须:
+
+ 1. 解释为什么无法使用已有的配置文件名称。
+ 2. 添加一个新的配置文件名称,以及预期行为的清晰描述,保存到
+ sysfs-platform_profile ABI文档中。
diff --git a/Documentation/translations/zh_CN/video4linux/omap3isp.txt b/Documentation/translations/zh_CN/video4linux/omap3isp.txt
index e9f29375aa95..75e481985630 100644
--- a/Documentation/translations/zh_CN/video4linux/omap3isp.txt
+++ b/Documentation/translations/zh_CN/video4linux/omap3isp.txt
@@ -1,4 +1,4 @@
-Chinese translated version of Documentation/media/v4l-drivers/omap3isp.rst
+Chinese translated version of Documentation/admin-guide/media/omap3isp.rst
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
@@ -11,7 +11,7 @@ Maintainer: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
David Cohen <dacohen@gmail.com>
Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
---------------------------------------------------------------------
-Documentation/media/v4l-drivers/omap3isp.rst 的中文翻译
+Documentation/admin-guide/media/omap3isp.rst 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
diff --git a/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt b/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt
index 66c7c568bd86..9cc97ec75d7a 100644
--- a/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt
+++ b/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt
@@ -1,4 +1,4 @@
-Chinese translated version of Documentation/media/media_kapi.rst
+Chinese translated version of Documentation/driver-api/media/index.rst
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
@@ -9,7 +9,7 @@ or if there is a problem with the translation.
Maintainer: Mauro Carvalho Chehab <mchehab@kernel.org>
Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
---------------------------------------------------------------------
-Documentation/media/media_kapi.rst 的中文翻译
+Documentation/driver-api/media/index.rst 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
@@ -488,7 +488,7 @@ struct v4l2_subdev *sd = v4l2_i2c_new_subdev(v4l2_dev, adapter,
这个函数会加载给定的模块(如果没有模块需要加载,可以为 NULL),
并用给定的 i2c 适配器结构体指针(i2c_adapter)和 器件地址(chip/address)
-作为参数调用 i2c_new_device()。如果一切顺利,则就在 v4l2_device
+作为参数调用 i2c_new_client_device()。如果一切顺利,则就在 v4l2_device
中注册了子设备。
你也可以利用 v4l2_i2c_new_subdev()的最后一个参数,传递一个可能的
@@ -649,7 +649,7 @@ video_device注册
接下来你需要注册视频设备:这会为你创建一个字符设备。
- err = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+ err = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
if (err) {
video_device_release(vdev); /* or kfree(my_vdev); */
return err;
@@ -660,7 +660,7 @@ video_device注册
注册哪种设备是根据类型(type)参数。存在以下类型:
-VFL_TYPE_GRABBER: 用于视频输入/输出设备的 videoX
+VFL_TYPE_VIDEO: 用于视频输入/输出设备的 videoX
VFL_TYPE_VBI: 用于垂直消隐数据的 vbiX (例如,隐藏式字幕,图文电视)
VFL_TYPE_RADIO: 用于广播调谐器的 radioX
@@ -768,18 +768,6 @@ const char *video_device_node_name(struct video_device *vdev);
此功能,而非访问 video_device::num 和 video_device::minor 域。
-视频缓冲辅助函数
----------------
-
-v4l2 核心 API 提供了一个处理视频缓冲的标准方法(称为“videobuf”)。
-这些方法使驱动可以通过统一的方式实现 read()、mmap() 和 overlay()。
-目前在设备上支持视频缓冲的方法有分散/聚集 DMA(videobuf-dma-sg)、
-线性 DMA(videobuf-dma-contig)以及大多用于 USB 设备的用 vmalloc
-分配的缓冲(videobuf-vmalloc)。
-
-请参阅 Documentation/media/kapi/v4l2-videobuf.rst,以获得更多关于 videobuf
-层的使用信息。
-
v4l2_fh 结构体
-------------
diff --git a/Documentation/translations/zh_CN/virt/acrn/cpuid.rst b/Documentation/translations/zh_CN/virt/acrn/cpuid.rst
new file mode 100644
index 000000000000..6f7be545611b
--- /dev/null
+++ b/Documentation/translations/zh_CN/virt/acrn/cpuid.rst
@@ -0,0 +1,56 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/virt/acrn/cpuid.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 时奎亮 Alex Shi <alexs@kernel.org>
+
+.. _cn_virt_acrn_cpuid:
+
+==============
+ACRN CPUID位域
+==============
+
+在ACRN超级管理器上运行的客户虚拟机可以使用CPUID检查其一些功能。
+
+ACRN的cpuid函数是:
+
+函数: 0x40000000
+
+返回::
+
+ eax = 0x40000010
+ ebx = 0x4e524341
+ ecx = 0x4e524341
+ edx = 0x4e524341
+
+注意,ebx,ecx和edx中的这个值对应于字符串“ACRNACRNACRN”。eax中的值对应于这个叶子
+中存在的最大cpuid函数,如果将来有更多的函数加入,将被更新。
+
+函数: define ACRN_CPUID_FEATURES (0x40000001)
+
+返回::
+
+ ebx, ecx, edx
+ eax = an OR'ed group of (1 << flag)
+
+其中 ``flag`` 的定义如下:
+
+================================= =========== ================================
+标志 值 描述
+================================= =========== ================================
+ACRN_FEATURE_PRIVILEGED_VM 0 客户虚拟机是一个有特权的虚拟机
+================================= =========== ================================
+
+函数: 0x40000010
+
+返回::
+
+ ebx, ecx, edx
+ eax = (Virtual) TSC frequency in kHz.
diff --git a/Documentation/translations/zh_CN/virt/acrn/index.rst b/Documentation/translations/zh_CN/virt/acrn/index.rst
new file mode 100644
index 000000000000..34605d87f103
--- /dev/null
+++ b/Documentation/translations/zh_CN/virt/acrn/index.rst
@@ -0,0 +1,25 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/virt/acrn/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 时奎亮 Alex Shi <alexs@kernel.org>
+
+.. _cn_virt_acrn_index:
+
+==============
+ACRN超级管理器
+==============
+
+.. toctree::
+ :maxdepth: 1
+
+ introduction
+ io-request
+ cpuid
diff --git a/Documentation/translations/zh_CN/virt/acrn/introduction.rst b/Documentation/translations/zh_CN/virt/acrn/introduction.rst
new file mode 100644
index 000000000000..7182415cb087
--- /dev/null
+++ b/Documentation/translations/zh_CN/virt/acrn/introduction.rst
@@ -0,0 +1,52 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/virt/acrn/introduction.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 时奎亮 Alex Shi <alexs@kernel.org>
+
+.. _cn_virt_acrn_introduction:
+
+ACRN超级管理器介绍
+==================
+
+ACRN超级管理器是一个第一类超级管理器,直接在裸机硬件上运行。它有一个特权管理虚拟机,称为服
+务虚拟机,用于管理用户虚拟机和进行I/O仿真。
+
+ACRN用户空间是一个运行在服务虚拟机中的应用程序,它根据命令行配置为用户虚拟机仿真设备。
+ACRN管理程序服务模块(HSM)是服务虚拟机中的一个内核模块,为ACRN用户空间提供管理程序服
+务。
+
+下图展示了该架构。
+
+::
+
+ 服务端VM 用户端VM
+ +----------------------------+ | +------------------+
+ | +--------------+ | | | |
+ | |ACRN用户空间 | | | | |
+ | +--------------+ | | | |
+ |-----------------ioctl------| | | | ...
+ |内核空间 +----------+ | | | |
+ | | HSM | | | | 驱动 |
+ | +----------+ | | | |
+ +--------------------|-------+ | +------------------+
+ +---------------------hypercall----------------------------------------+
+ | ACRN超级管理器 |
+ +----------------------------------------------------------------------+
+ | 硬件 |
+ +----------------------------------------------------------------------+
+
+ACRN用户空间为用户虚拟机分配内存,配置和初始化用户虚拟机使用的设备,加载虚拟引导程序,
+初始化虚拟CPU状态,处理来自用户虚拟机的I/O请求访问。它使用ioctls来与HSM通信。HSM通过
+与ACRN超级管理器的hypercalls进行交互来实现管理服务。HSM向用户空间输出一个char设备接口
+(/dev/acrn_hsm)。
+
+ACRN超级管理器是开源的,任何人都可以贡献。源码库在
+https://github.com/projectacrn/acrn-hypervisor。
diff --git a/Documentation/translations/zh_CN/virt/acrn/io-request.rst b/Documentation/translations/zh_CN/virt/acrn/io-request.rst
new file mode 100644
index 000000000000..4b4e7186d9a5
--- /dev/null
+++ b/Documentation/translations/zh_CN/virt/acrn/io-request.rst
@@ -0,0 +1,99 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../disclaimer-zh_CN.rst
+
+:Original: Documentation/virt/acrn/io-request.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 时奎亮 Alex Shi <alexs@kernel.org>
+
+.. _cn_virt_acrn_io-request:
+
+I/O请求处理
+===========
+
+客户虚拟机的I/O请求由超级管理器构建,由ACRN超级管理器服务模块分发到与I/O请求的地址范
+围相对应的I/O客户端。I/O请求处理的细节将在以下章节描述。
+
+1. I/O请求
+----------
+
+对于每个客户虚拟机,有一个共享的4KB字节的内存区域,用于超级管理器和服务虚拟机之间的
+I/O请求通信。一个I/O请求是一个256字节的结构体缓冲区,它是 "acrn_io_request" 结构
+体,当客户虚拟机中发生被困的I/O访问时,由超级管理器的I/O处理器填充。服务虚拟机中的
+ACRN用户空间首先分配一个4KB字节的页面,并将缓冲区的GPA(客户物理地址)传递给管理平
+台。缓冲区被用作16个I/O请求槽的数组,每个I/O请求槽为256字节。这个数组是按vCPU ID
+索引的。
+
+2. I/O客户端
+------------
+
+一个I/O客户端负责处理客户虚拟机的I/O请求,其访问的GPA在一定范围内。每个客户虚拟机
+可以关联多个I/O客户端。每个客户虚拟机都有一个特殊的客户端,称为默认客户端,负责处理
+所有不在其他客户端范围内的I/O请求。ACRN用户空间充当每个客户虚拟机的默认客户端。
+
+下面的图示显示了I/O请求共享缓冲区、I/O请求和I/O客户端之间的关系。
+
+::
+
+ +------------------------------------------------------+
+ | 服务VM |
+ |+--------------------------------------------------+ |
+ || +----------------------------------------+ | |
+ || | 共享页 ACRN用户空间 | | |
+ || | +-----------------+ +------------+ | | |
+ || +----+->| acrn_io_request |<-+ 默认 | | | |
+ || | | | +-----------------+ | I/O客户端 | | | |
+ || | | | | ... | +------------+ | | |
+ || | | | +-----------------+ | | |
+ || | +-|--------------------------------------+ | |
+ ||---|----|-----------------------------------------| |
+ || | | 内核 | |
+ || | | +----------------------+ | |
+ || | | | +-------------+ HSM | | |
+ || | +--------------+ | | | |
+ || | | | I/O客户端 | | | |
+ || | | | | | | |
+ || | | +-------------+ | | |
+ || | +----------------------+ | |
+ |+---|----------------------------------------------+ |
+ +----|-------------------------------------------------+
+ |
+ +----|-------------------------------------------------+
+ | +-+-----------+ |
+ | | I/O处理 | ACRN超级管理器 |
+ | +-------------+ |
+ +------------------------------------------------------+
+
+3. I/O请求状态转换
+------------------
+
+一个ACRN I/O请求的状态转换如下。
+
+::
+
+ FREE -> PENDING -> PROCESSING -> COMPLETE -> FREE -> ...
+
+- FREE: 这个I/O请求槽是空的
+- PENDING: 在这个槽位上有一个有效的I/O请求正在等待
+- PROCESSING: 正在处理I/O请求
+- COMPLETE: 该I/O请求已被处理
+
+处于COMPLETE或FREE状态的I/O请求是由超级管理器拥有的。HSM和ACRN用户空间负责处理其
+他的。
+
+4. I/O请求的处理流程
+--------------------
+
+a. 当客户虚拟机中发生被陷入的I/O访问时,超级管理器的I/O处理程序将把I/O请求填充为
+ PENDING状态。
+b. 超级管理器向服务虚拟机发出一个向上调用,这是一个通知中断。
+c. upcall处理程序会安排一个工作者来调度I/O请求。
+d. 工作者寻找PENDING I/O请求,根据I/O访问的地址将其分配给不同的注册客户,将其
+ 状态更新为PROCESSING,并通知相应的客户进行处理。
+e. 被通知的客户端处理指定的I/O请求。
+f. HSM将I/O请求状态更新为COMPLETE,并通过hypercalls通知超级管理器完成。
diff --git a/Documentation/translations/zh_CN/virt/guest-halt-polling.rst b/Documentation/translations/zh_CN/virt/guest-halt-polling.rst
new file mode 100644
index 000000000000..b798d1cf0b48
--- /dev/null
+++ b/Documentation/translations/zh_CN/virt/guest-halt-polling.rst
@@ -0,0 +1,87 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/virt/guest-halt-polling.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 时奎亮 Alex Shi <alexs@kernel.org>
+
+.. _cn_virt_guest-halt-polling:
+
+========================================
+客户机停机轮询机制(Guest halt polling)
+========================================
+
+cpuidle_haltpoll驱动,与haltpoll管理器一起,允许客户机vcpus在停机前轮询
+一定的时间。
+
+这为物理机侧的轮询提供了以下好处:
+
+ 1) 在执行轮询时,POLL标志被设置,这允许远程vCPU在执行唤醒时避免发送
+ IPI(以及处理IPI的相关成本)。
+
+ 2) 可以避免虚拟机退出的成本。
+
+客户机侧轮询的缺点是,即使在物理机中的其他可运行任务中也会进行轮询。
+
+其基本逻辑如下。一个全局值,即guest_halt_poll_ns,是由用户配置的,表示允
+许轮询的最大时间量。这个值是固定的。
+
+每个vcpu都有一个可调整的guest_halt_poll_ns("per-cpu guest_halt_poll_ns"),
+它由算法响应事件进行调整(解释如下)。
+
+模块参数
+========
+
+haltpoll管理器有5个可调整的模块参数:
+
+1) guest_halt_poll_ns:
+
+轮询停机前执行的最大时间,以纳秒为单位。
+
+默认值: 200000
+
+2) guest_halt_poll_shrink:
+
+当唤醒事件发生在全局的guest_halt_poll_ns之后,用于缩减每个CPU的guest_halt_poll_ns
+的划分系数。
+
+默认值: 2
+
+3) guest_halt_poll_grow:
+
+当事件发生在per-cpu guest_halt_poll_ns之后但在global guest_halt_poll_ns之前,
+用于增长per-cpu guest_halt_poll_ns的乘法系数。
+
+默认值: 2
+
+4) guest_halt_poll_grow_start:
+
+在系统空闲的情况下,每个cpu guest_halt_poll_ns最终达到零。这个值设置了增长时的
+初始每cpu guest_halt_poll_ns。这个值可以从10000开始增加,以避免在最初的增长阶
+段出现失误。:
+
+10k, 20k, 40k, ... (例如,假设guest_halt_poll_grow=2).
+
+默认值: 50000
+
+5) guest_halt_poll_allow_shrink:
+
+允许缩减的Bool参数。设置为N以避免它(一旦达到全局的guest_halt_poll_ns值,每CPU的
+guest_halt_poll_ns将保持高位)。
+
+默认值: Y
+
+模块参数可以从Debugfs文件中设置,在::
+
+ /sys/module/haltpoll/parameters/
+
+进一步说明
+==========
+
+- 在设置guest_halt_poll_ns参数时应该小心,因为一个大的值有可能使几乎是完全空闲机
+ 器上的cpu使用率达到100%。
diff --git a/Documentation/translations/zh_CN/virt/index.rst b/Documentation/translations/zh_CN/virt/index.rst
new file mode 100644
index 000000000000..f8dd13681341
--- /dev/null
+++ b/Documentation/translations/zh_CN/virt/index.rst
@@ -0,0 +1,38 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/virt/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 时奎亮 Alex Shi <alexs@kernel.org>
+
+.. _cn_virt_index:
+
+===============
+Linux虚拟化支持
+===============
+
+.. toctree::
+ :maxdepth: 2
+
+ paravirt_ops
+ guest-halt-polling
+ ne_overview
+ acrn/index
+
+TODOLIST:
+
+ kvm/index
+ uml/user_mode_linux_howto_v2
+
+.. only:: html and subproject
+
+ Indices
+ =======
+
+ * :ref:`genindex`
diff --git a/Documentation/translations/zh_CN/virt/ne_overview.rst b/Documentation/translations/zh_CN/virt/ne_overview.rst
new file mode 100644
index 000000000000..2455b371abea
--- /dev/null
+++ b/Documentation/translations/zh_CN/virt/ne_overview.rst
@@ -0,0 +1,88 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/virt/ne_overview.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 时奎亮 Alex Shi <alexs@kernel.org>
+
+.. _cn_virt_ne_overview:
+
+==============
+Nitro Enclaves
+==============
+
+概述
+====
+
+Nitro Enclaves(NE)是亚马逊弹性计算云(EC2)的一项新功能,允许客户在EC2实
+例中划分出孤立的计算环境[1]。
+
+例如,一个处理敏感数据并在虚拟机中运行的应用程序,可以与在同一虚拟机中运行的
+其他应用程序分开。然后,这个应用程序在一个独立于主虚拟机的虚拟机中运行,即
+enclave。
+
+一个enclave与催生它的虚拟机一起运行。这种设置符合低延迟应用的需要。为enclave
+分配的资源,如内存和CPU,是从主虚拟机中分割出来的。每个enclave都被映射到一
+个运行在主虚拟机中的进程,该进程通过一个ioctl接口与NE驱动进行通信。
+
+在这个意义上,有两个组成部分。
+
+1. 一个enclave抽象进程——一个运行在主虚拟机客体中的用户空间进程,它使用NE驱动
+提供的ioctl接口来生成一个enclave虚拟机(这就是下面的2)。
+
+有一个NE模拟的PCI设备暴露给主虚拟机。这个新的PCI设备的驱动被包含在NE驱动中。
+
+ioctl逻辑被映射到PCI设备命令,例如,NE_START_ENCLAVE ioctl映射到一个enclave
+启动PCI命令。然后,PCI设备命令被翻译成在管理程序方面采取的行动;也就是在运
+行主虚拟机的主机上运行的Nitro管理程序。Nitro管理程序是基于KVM核心技术的。
+
+2. enclave本身——一个运行在与催生它的主虚拟机相同的主机上的虚拟机。内存和CPU
+从主虚拟机中分割出来,专门用于enclave虚拟机。enclave没有连接持久性存储。
+
+从主虚拟机中分割出来并给enclave的内存区域需要对齐2 MiB/1 GiB物理连续的内存
+区域(或这个大小的倍数,如8 MiB)。该内存可以通过使用hugetlbfs从用户空间分
+配[2][3]。一个enclave的内存大小需要至少64 MiB。enclave内存和CPU需要来自同
+一个NUMA节点。
+
+一个enclave在专用的核心上运行。CPU 0及其同级别的CPU需要保持对主虚拟机的可用
+性。CPU池必须由具有管理能力的用户为NE目的进行设置。关于CPU池的格式,请看内核
+文档[4]中的cpu list部分。
+
+enclave通过本地通信通道与主虚拟机进行通信,使用virtio-vsock[5]。主虚拟机有
+virtio-pci vsock模拟设备,而飞地虚拟机有virtio-mmio vsock模拟设备。vsock
+设备使用eventfd作为信令。enclave虚拟机看到通常的接口——本地APIC和IOAPIC——从
+virtio-vsock设备获得中断。virtio-mmio设备被放置在典型的4 GiB以下的内存中。
+
+在enclave中运行的应用程序需要和将在enclave虚拟机中运行的操作系统(如内核、
+ramdisk、init)一起被打包到enclave镜像中。enclave虚拟机有自己的内核并遵循标
+准的Linux启动协议[6]。
+
+内核bzImage、内核命令行、ramdisk(s)是enclave镜像格式(EIF)的一部分;另外
+还有一个EIF头,包括元数据,如magic number、eif版本、镜像大小和CRC。
+
+哈希值是为整个enclave镜像(EIF)、内核和ramdisk(s)计算的。例如,这被用来检
+查在enclave虚拟机中加载的enclave镜像是否是打算运行的那个。
+
+这些加密测量包括在由Nitro超级管理器成的签名证明文件中,并进一步用来证明enclave
+的身份;KMS是NE集成的服务的一个例子,它检查证明文件。
+
+enclave镜像(EIF)被加载到enclave内存中,偏移量为8 MiB。enclave中的初始进程
+连接到主虚拟机的vsock CID和一个预定义的端口--9000,以发送一个心跳值--0xb7。这
+个机制用于在主虚拟机中检查enclave是否已经启动。主虚拟机的CID是3。
+
+如果enclave虚拟机崩溃或优雅地退出,NE驱动会收到一个中断事件。这个事件会通过轮询
+通知机制进一步发送到运行在主虚拟机中的用户空间enclave进程。然后,用户空间enclave
+进程就可以退出了。
+
+[1] https://aws.amazon.com/ec2/nitro/nitro-enclaves/
+[2] https://www.kernel.org/doc/html/latest/admin-guide/mm/hugetlbpage.html
+[3] https://lwn.net/Articles/807108/
+[4] https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html
+[5] https://man7.org/linux/man-pages/man7/vsock.7.html
+[6] https://www.kernel.org/doc/html/latest/x86/boot.html
diff --git a/Documentation/translations/zh_CN/virt/paravirt_ops.rst b/Documentation/translations/zh_CN/virt/paravirt_ops.rst
new file mode 100644
index 000000000000..06b122bc915d
--- /dev/null
+++ b/Documentation/translations/zh_CN/virt/paravirt_ops.rst
@@ -0,0 +1,41 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/virt/paravirt_ops.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 陈飞杨 Feiyang Chen <chenfeiyang@loongson.cn>
+ 时奎亮 Alex Shi <alexs@kernel.org>
+
+.. _cn_virt_paravirt_ops:
+
+============
+半虚拟化操作
+============
+
+Linux提供了对不同管理程序虚拟化技术的支持。历史上,为了支持不同的虚拟机超级管理器
+(hypervisor,下文简称超级管理器),需要不同的二进制内核,这个限制已经被pv_ops移
+除了。Linux pv_ops是一个虚拟化API,它能够支持不同的管理程序。它允许每个管理程序
+优先于关键操作,并允许单一的内核二进制文件在所有支持的执行环境中运行,包括本机——没
+有任何管理程序。
+
+pv_ops提供了一组函数指针,代表了与低级关键指令和各领域高级功能相对应的操作。
+pv-ops允许在运行时进行优化,在启动时对低级关键操作进行二进制修补。
+
+pv_ops操作被分为三类:
+
+- 简单的间接调用
+ 这些操作对应于高水平的函数,众所周知,间接调用的开销并不十分重要。
+
+- 间接调用,允许用二进制补丁进行优化
+ 通常情况下,这些操作对应于低级别的关键指令。它们被频繁地调用,并且是对性能关
+ 键。开销是非常重要的。
+
+- 一套用于手写汇编代码的宏程序
+ 手写的汇编代码(.S文件)也需要半虚拟化,因为它们包括敏感指令或其中的一些代
+ 码路径对性能非常关键。
diff --git a/Documentation/translations/zh_TW/IRQ.txt b/Documentation/translations/zh_TW/IRQ.txt
new file mode 100644
index 000000000000..8115a7618307
--- /dev/null
+++ b/Documentation/translations/zh_TW/IRQ.txt
@@ -0,0 +1,41 @@
+Chinese translated version of Documentation/core-api/irq/index.rst
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly. However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help. Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Maintainer: Eric W. Biederman <ebiederman@xmission.com>
+Traditional Chinese maintainer: Hu Haowen <2023002089@link.tyut.edu.cn>
+---------------------------------------------------------------------
+Documentation/core-api/irq/index.rst 的繁體中文翻譯
+
+如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
+交流有困難的話,也可以向繁體中文版維護者求助。如果本翻譯更新不及時或
+者翻譯存在問題,請聯繫繁體中文版維護者。
+
+英文版維護者: Eric W. Biederman <ebiederman@xmission.com>
+繁體中文版維護者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+繁體中文版翻譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+
+以下爲正文
+---------------------------------------------------------------------
+何爲 IRQ?
+
+一個 IRQ 是來自某個設備的一個中斷請求。目前,它們可以來自一個硬體引腳,
+或來自一個數據包。多個設備可能連接到同個硬體引腳,從而共享一個 IRQ。
+
+一個 IRQ 編號是用於告知硬體中斷源的內核標識。通常情況下,這是一個
+全局 irq_desc 數組的索引,但是除了在 linux/interrupt.h 中的實現,
+具體的細節是體系結構特定的。
+
+一個 IRQ 編號是設備上某個可能的中斷源的枚舉。通常情況下,枚舉的編號是
+該引腳在系統內中斷控制器的所有輸入引腳中的編號。對於 ISA 總線中的情況,
+枚舉的是在兩個 i8259 中斷控制器中 16 個輸入引腳。
+
+架構可以對 IRQ 編號指定額外的含義,在硬體涉及任何手工配置的情況下,
+是被提倡的。ISA 的 IRQ 是一個分配這類額外含義的典型例子。
+
diff --git a/Documentation/translations/zh_TW/admin-guide/README.rst b/Documentation/translations/zh_TW/admin-guide/README.rst
new file mode 100644
index 000000000000..a6e34c200ea3
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/README.rst
@@ -0,0 +1,295 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/admin-guide/README.rst
+
+:譯者:
+
+ 吳想成 Wu XiangCheng <bobwxc@email.cn>
+ 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+Linux內核6.x版本 <http://kernel.org/>
+=========================================
+
+以下是Linux版本6的發行註記。仔細閱讀它們,
+它們會告訴你這些都是什麼,解釋如何安裝內核,以及遇到問題時該如何做。
+
+什麼是Linux?
+---------------
+
+ Linux是Unix操作系統的克隆版本,由Linus Torvalds在一個鬆散的網絡黑客
+ (Hacker,無貶義)團隊的幫助下從頭開始編寫。它旨在實現兼容POSIX和
+ 單一UNIX規範。
+
+ 它具有在現代成熟的Unix中應當具有的所有功能,包括真正的多任務處理、虛擬內存、
+ 共享庫、按需加載、共享的寫時拷貝(COW)可執行文件、恰當的內存管理以及包括
+ IPv4和IPv6在內的複合網絡棧。
+
+ Linux在GNU通用公共許可證,版本2(GNU GPLv2)下分發,詳見隨附的COPYING文件。
+
+它能在什麼樣的硬件上運行?
+-----------------------------
+
+ 雖然Linux最初是爲32位的x86 PC機(386或更高版本)開發的,但今天它也能運行在
+ (至少)Compaq Alpha AXP、Sun SPARC與UltraSPARC、Motorola 68000、PowerPC、
+ PowerPC64、ARM、Hitachi SuperH、Cell、IBM S/390、MIPS、HP PA-RISC、Intel
+ IA-64、DEC VAX、AMD x86-64 Xtensa和ARC架構上。
+
+ Linux很容易移植到大多數通用的32位或64位體系架構,只要它們有一個分頁內存管理
+ 單元(PMMU)和一個移植的GNU C編譯器(gcc;GNU Compiler Collection,GCC的一
+ 部分)。Linux也被移植到許多沒有PMMU的體系架構中,儘管功能顯然受到了一定的
+ 限制。
+ Linux也被移植到了其自己上。現在可以將內核作爲用戶空間應用程序運行——這被
+ 稱爲用戶模式Linux(UML)。
+
+文檔
+-----
+因特網上和書籍上都有大量的電子文檔,既有Linux專屬文檔,也有與一般UNIX問題相關
+的文檔。我建議在任何Linux FTP站點上查找LDP(Linux文檔項目)書籍的文檔子目錄。
+本自述文件並不是關於系統的文檔:有更好的可用資源。
+
+ - 因特網上和書籍上都有大量的(電子)文檔,既有Linux專屬文檔,也有與普通
+ UNIX問題相關的文檔。我建議在任何有LDP(Linux文檔項目)書籍的Linux FTP
+ 站點上查找文檔子目錄。本自述文件並不是關於系統的文檔:有更好的可用資源。
+
+ - 文檔/子目錄中有各種自述文件:例如,這些文件通常包含一些特定驅動程序的
+ 內核安裝說明。請閱讀
+ :ref:`Documentation/process/changes.rst <changes>` 文件,它包含了升級內核
+ 可能會導致的問題的相關信息。
+
+安裝內核源代碼
+---------------
+
+ - 如果您要安裝完整的源代碼,請把內核tar檔案包放在您有權限的目錄中(例如您
+ 的主目錄)並將其解包::
+
+ xz -cd linux-6.x.tar.xz | tar xvf -
+
+ 將“X”替換成最新內核的版本號。
+
+ 【不要】使用 /usr/src/linux 目錄!這裏有一組庫頭文件使用的內核頭文件
+ (通常是不完整的)。它們應該與庫匹配,而不是被內核的變化搞得一團糟。
+
+ - 您還可以通過打補丁在6.x版本之間升級。補丁以xz格式分發。要通過打補丁進行
+ 安裝,請獲取所有較新的補丁文件,進入內核源代碼(linux-6.x)的目錄並
+ 執行::
+
+ xz -cd ../patch-6.x.xz | patch -p1
+
+ 請【按順序】替換所有大於當前源代碼樹版本的“x”,這樣就可以了。您可能想要
+ 刪除備份文件(文件名類似xxx~ 或 xxx.orig),並確保沒有失敗的補丁(文件名
+ 類似xxx# 或 xxx.rej)。如果有,不是你就是我犯了錯誤。
+
+ 與6.x內核的補丁不同,6.x.y內核(也稱爲穩定版內核)的補丁不是增量的,而是
+ 直接應用於基本的6.x內核。例如,如果您的基本內核是6.0,並且希望應用6.0.3
+ 補丁,則不應先應用6.0.1和6.0.2的補丁。類似地,如果您運行的是6.0.2內核,
+ 並且希望跳轉到6.0.3,那麼在應用6.0.3補丁之前,必須首先撤銷6.0.2補丁
+ (即patch -R)。更多關於這方面的內容,請閱讀
+ :ref:`Documentation/process/applying-patches.rst <applying_patches>` 。
+
+ 或者,腳本 patch-kernel 可以用來自動化這個過程。它能確定當前內核版本並
+ 應用找到的所有補丁::
+
+ linux/scripts/patch-kernel linux
+
+ 上面命令中的第一個參數是內核源代碼的位置。補丁是在當前目錄應用的,但是
+ 可以將另一個目錄指定爲第二個參數。
+
+ - 確保沒有過時的 .o 文件和依賴項::
+
+ cd linux
+ make mrproper
+
+ 現在您應該已經正確安裝了源代碼。
+
+軟件要求
+---------
+
+ 編譯和運行6.x內核需要各種軟件包的最新版本。請參考
+ :ref:`Documentation/process/changes.rst <changes>`
+ 來了解最低版本要求以及如何升級軟件包。請注意,使用過舊版本的這些包可能會
+ 導致很難追蹤的間接錯誤,因此不要以爲在生成或操作過程中出現明顯問題時可以
+ 只更新包。
+
+爲內核建立目錄
+---------------
+
+ 編譯內核時,默認情況下所有輸出文件都將與內核源代碼放在一起。使用
+ ``make O=output/dir`` 選項可以爲輸出文件(包括 .config)指定備用位置。
+ 例如::
+
+ kernel source code: /usr/src/linux-6.x
+ build directory: /home/name/build/kernel
+
+ 要配置和構建內核,請使用::
+
+ cd /usr/src/linux-6.x
+ make O=/home/name/build/kernel menuconfig
+ make O=/home/name/build/kernel
+ sudo make O=/home/name/build/kernel modules_install install
+
+ 請注意:如果使用了 ``O=output/dir`` 選項,那麼它必須用於make的所有調用。
+
+配置內核
+---------
+
+ 即使只升級一個小版本,也不要跳過此步驟。每個版本中都會添加新的配置選項,
+ 如果配置文件沒有按預定設置,就會出現奇怪的問題。如果您想以最少的工作量
+ 將現有配置升級到新版本,請使用 ``make oldconfig`` ,它只會詢問您新配置
+ 選項的答案。
+
+ - 其他配置命令包括::
+
+ "make config" 純文本界面。
+
+ "make menuconfig" 基於文本的彩色菜單、選項列表和對話框。
+
+ "make nconfig" 增強的基於文本的彩色菜單。
+
+ "make xconfig" 基於Qt的配置工具。
+
+ "make gconfig" 基於GTK+的配置工具。
+
+ "make oldconfig" 基於現有的 ./.config 文件選擇所有選項,並詢問
+ 新配置選項。
+
+ "make olddefconfig"
+ 類似上一個,但不詢問直接將新選項設置爲默認值。
+
+ "make defconfig" 根據體系架構,使用arch/$arch/defconfig或
+ arch/$arch/configs/${PLATFORM}_defconfig中的
+ 默認選項值創建./.config文件。
+
+ "make ${PLATFORM}_defconfig"
+ 使用arch/$arch/configs/${PLATFORM}_defconfig中
+ 的默認選項值創建一個./.config文件。
+ 用“make help”來獲取您體系架構中所有可用平臺的列表。
+
+ "make allyesconfig"
+ 通過儘可能將選項值設置爲“y”,創建一個
+ ./.config文件。
+
+ "make allmodconfig"
+ 通過儘可能將選項值設置爲“m”,創建一個
+ ./.config文件。
+
+ "make allnoconfig" 通過儘可能將選項值設置爲“n”,創建一個
+ ./.config文件。
+
+ "make randconfig" 通過隨機設置選項值來創建./.config文件。
+
+ "make localmodconfig" 基於當前配置和加載的模塊(lsmod)創建配置。禁用
+ 已加載的模塊不需要的任何模塊選項。
+
+ 要爲另一臺計算機創建localmodconfig,請將該計算機
+ 的lsmod存儲到一個文件中,並將其作爲lsmod參數傳入。
+
+ 此外,通過在參數LMC_KEEP中指定模塊的路徑,可以將
+ 模塊保留在某些文件夾或kconfig文件中。
+
+ target$ lsmod > /tmp/mylsmod
+ target$ scp /tmp/mylsmod host:/tmp
+
+ host$ make LSMOD=/tmp/mylsmod \
+ LMC_KEEP="drivers/usb:drivers/gpu:fs" \
+ localmodconfig
+
+ 上述方法在交叉編譯時也適用。
+
+ "make localyesconfig" 與localmodconfig類似,只是它會將所有模塊選項轉換
+ 爲內置(=y)。你可以同時通過LMC_KEEP保留模塊。
+
+ "make kvm_guest.config"
+ 爲kvm客戶機內核支持啓用其他選項。
+
+ "make xen.config" 爲xen dom0客戶機內核支持啓用其他選項。
+
+ "make tinyconfig" 配置儘可能小的內核。
+
+ 更多關於使用Linux內核配置工具的信息,見文檔
+ Documentation/kbuild/kconfig.rst。
+
+ - ``make config`` 注意事項:
+
+ - 包含不必要的驅動程序會使內核變大,並且在某些情況下會導致問題:
+ 探測不存在的控制器卡可能會混淆其他控制器。
+
+ - 如果存在協處理器,則編譯了數學仿真的內核仍將使用協處理器:在
+ 這種情況下,數學仿真永遠不會被使用。內核會稍微大一點,但不管
+ 是否有數學協處理器,都可以在不同的機器上工作。
+
+ - “kernel hacking”配置細節通常會導致更大或更慢的內核(或兩者
+ 兼而有之),甚至可以通過配置一些例程來主動嘗試破壞壞代碼以發現
+ 內核問題,從而降低內核的穩定性(kmalloc())。因此,您可能應該
+ 用於研究“開發”、“實驗”或“調試”特性相關問題。
+
+編譯內核
+---------
+
+ - 確保您至少有gcc 5.1可用。
+ 有關更多信息,請參閱 :ref:`Documentation/process/changes.rst <changes>` 。
+
+ - 執行 ``make`` 來創建壓縮內核映像。如果您安裝了lilo以適配內核makefile,
+ 那麼也可以進行 ``make install`` ,但是您可能需要先檢查特定的lilo設置。
+
+ 實際安裝必須以root身份執行,但任何正常構建都不需要。
+ 無須徒然使用root身份。
+
+ - 如果您將內核的任何部分配置爲模塊,那麼還必須執行 ``make modules_install`` 。
+
+ - 詳細的內核編譯/生成輸出:
+
+ 通常,內核構建系統在相當安靜的模式下運行(但不是完全安靜)。但是有時您或
+ 其他內核開發人員需要看到編譯、鏈接或其他命令的執行過程。爲此,可使用
+ “verbose(詳細)”構建模式。
+ 向 ``make`` 命令傳遞 ``V=1`` 來實現,例如::
+
+ make V=1 all
+
+ 如需構建系統也給出內個目標重建的願意,請使用 ``V=2`` 。默認爲 ``V=0`` 。
+
+ - 準備一個備份內核以防出錯。對於開發版本尤其如此,因爲每個新版本都包含
+ 尚未調試的新代碼。也要確保保留與該內核對應的模塊的備份。如果要安裝
+ 與工作內核版本號相同的新內核,請在進行 ``make modules_install`` 安裝
+ 之前備份modules目錄。
+
+ 或者,在編譯之前,使用內核配置選項“LOCALVERSION”向常規內核版本附加
+ 一個唯一的後綴。LOCALVERSION可以在“General Setup”菜單中設置。
+
+ - 爲了引導新內核,您需要將內核映像(例如編譯後的
+ .../linux/arch/x86/boot/bzImage)複製到常規可引導內核的位置。
+
+ - 不再支持在沒有LILO等啓動裝載程序幫助的情況下直接從軟盤引導內核。
+
+ 如果從硬盤引導Linux,很可能使用LILO,它使用/etc/lilo.conf文件中
+ 指定的內核映像文件。內核映像文件通常是/vmlinuz、/boot/vmlinuz、
+ /bzImage或/boot/bzImage。使用新內核前,請保存舊映像的副本,並複製
+ 新映像覆蓋舊映像。然後您【必須重新運行LILO】來更新加載映射!否則,
+ 將無法啓動新的內核映像。
+
+ 重新安裝LILO通常需要運行/sbin/LILO。您可能希望編輯/etc/lilo.conf
+ 文件爲舊內核映像指定一個條目(例如/vmlinux.old)防止新的不能正常
+ 工作。有關更多信息,請參閱LILO文檔。
+
+ 重新安裝LILO之後,您應該就已經準備好了。關閉系統,重新啓動,盡情
+ 享受吧!
+
+ 如果需要更改內核映像中的默認根設備、視頻模式等,請在適當的地方使用
+ 啓動裝載程序的引導選項。無需重新編譯內核即可更改這些參數。
+
+ - 使用新內核重新啓動並享受它吧。
+
+若遇到問題
+-----------
+
+如果您發現了一些可能由於內核缺陷所導致的問題,請參閱:
+Documentation/translations/zh_CN/admin-guide/reporting-issues.rst 。
+
+想要理解內核錯誤報告,請參閱:
+Documentation/translations/zh_CN/admin-guide/bug-hunting.rst 。
+
+更多用GDB調試內核的信息,請參閱:
+Documentation/translations/zh_CN/dev-tools/gdb-kernel-debugging.rst
+和 Documentation/dev-tools/kgdb.rst 。
+
diff --git a/Documentation/translations/zh_TW/admin-guide/bootconfig.rst b/Documentation/translations/zh_TW/admin-guide/bootconfig.rst
new file mode 100644
index 000000000000..abac5aa60f67
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/bootconfig.rst
@@ -0,0 +1,294 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/admin-guide/bootconfig.rst
+
+:譯者: 吳想成 Wu XiangCheng <bobwxc@email.cn>
+
+========
+引導配置
+========
+
+:作者: Masami Hiramatsu <mhiramat@kernel.org>
+
+概述
+====
+
+引導配置擴展了現有的內核命令行,以一種更有效率的方式在引導內核時進一步支持
+鍵值數據。這允許管理員傳遞一份結構化關鍵字的配置文件。
+
+配置文件語法
+============
+
+引導配置文件的語法採用非常簡單的鍵值結構。每個關鍵字由點連接的單詞組成,鍵
+和值由 ``=`` 連接。值以分號( ``;`` )或換行符( ``\n`` )結尾。數組值中每
+個元素由逗號( ``,`` )分隔。::
+
+ KEY[.WORD[...]] = VALUE[, VALUE2[...]][;]
+
+與內核命令行語法不同,逗號和 ``=`` 周圍允許有空格。
+
+關鍵字只允許包含字母、數字、連字符( ``-`` )和下劃線( ``_`` )。值可包含
+可打印字符和空格,但分號( ``;`` )、換行符( ``\n`` )、逗號( ``,`` )、
+井號( ``#`` )和右大括號( ``}`` )等分隔符除外。
+
+如果你需要在值中使用這些分隔符,可以用雙引號( ``"VALUE"`` )或單引號
+( ``'VALUE'`` )括起來。注意,引號無法轉義。
+
+鍵的值可以爲空或不存在。這些鍵用於檢查該鍵是否存在(類似布爾值)。
+
+鍵值語法
+--------
+
+引導配置文件語法允許用戶通過大括號合併鍵名部分相同的關鍵字。例如::
+
+ foo.bar.baz = value1
+ foo.bar.qux.quux = value2
+
+也可以寫成::
+
+ foo.bar {
+ baz = value1
+ qux.quux = value2
+ }
+
+或者更緊湊一些,寫成::
+
+ foo.bar { baz = value1; qux.quux = value2 }
+
+在這兩種樣式中,引導解析時相同的關鍵字都會自動合併。因此可以追加類似的樹或
+鍵值。
+
+相同關鍵字的值
+--------------
+
+禁止兩個或多個值或數組共享同一個關鍵字。例如::
+
+ foo = bar, baz
+ foo = qux # !錯誤! 我們不可以重定義相同的關鍵字
+
+如果你想要更新值,必須顯式使用覆蓋操作符 ``:=`` 。例如::
+
+ foo = bar, baz
+ foo := qux
+
+這樣 ``foo`` 關鍵字的值就變成了 ``qux`` 。這對於通過添加(部分)自定義引導
+配置來覆蓋默認值非常有用,免於解析默認引導配置。
+
+如果你想對現有關鍵字追加值作爲數組成員,可以使用 ``+=`` 操作符。例如::
+
+ foo = bar, baz
+ foo += qux
+
+這樣, ``foo`` 關鍵字就同時擁有了 ``bar`` , ``baz`` 和 ``qux`` 。
+
+此外,父關鍵字下可同時存在值和子關鍵字。
+例如,下列配置是可行的。::
+
+ foo = value1
+ foo.bar = value2
+ foo := value3 # 這會更新foo的值。
+
+注意,裸值不能直接放進結構化關鍵字中,必須在大括號外定義它。例如::
+
+ foo {
+ bar = value1
+ bar {
+ baz = value2
+ qux = value3
+ }
+ }
+
+同時,關鍵字下值節點的順序是固定的。如果值和子關鍵字同時存在,值永遠是該關
+鍵字的第一個子節點。因此如果用戶先指定子關鍵字,如::
+
+ foo.bar = value1
+ foo = value2
+
+則在程序(和/proc/bootconfig)中,它會按如下顯示::
+
+ foo = value2
+ foo.bar = value1
+
+註釋
+----
+
+配置語法接受shell腳本風格的註釋。註釋以井號( ``#`` )開始,到換行符
+( ``\n`` )結束。
+
+::
+
+ # comment line
+ foo = value # value is set to foo.
+ bar = 1, # 1st element
+ 2, # 2nd element
+ 3 # 3rd element
+
+會被解析爲::
+
+ foo = value
+ bar = 1, 2, 3
+
+注意你不能把註釋放在值和分隔符( ``,`` 或 ``;`` )之間。如下配置語法是錯誤的::
+
+ key = 1 # comment
+ ,2
+
+
+/proc/bootconfig
+================
+
+/proc/bootconfig是引導配置的用戶空間接口。與/proc/cmdline不同,此文件內容以
+鍵值列表樣式顯示。
+每個鍵值對一行,樣式如下::
+
+ KEY[.WORDS...] = "[VALUE]"[,"VALUE2"...]
+
+
+用引導配置引導內核
+==================
+
+用引導配置引導內核有兩種方法:將引導配置附加到initrd鏡像或直接嵌入內核中。
+
+*initrd: initial RAM disk,初始內存磁盤*
+
+將引導配置附加到initrd
+----------------------
+
+由於默認情況下引導配置文件是用initrd加載的,因此它將被添加到initrd(initramfs)
+鏡像文件的末尾,其中包含填充、大小、校驗值和12字節幻數,如下所示::
+
+ [initrd][bootconfig][padding][size(le32)][checksum(le32)][#BOOTCONFIG\n]
+
+大小和校驗值爲小端序存放的32位無符號值。
+
+當引導配置被加到initrd鏡像時,整個文件大小會對齊到4字節。空字符( ``\0`` )
+會填補對齊空隙。因此 ``size`` 就是引導配置文件的長度+填充的字節。
+
+Linux內核在內存中解碼initrd鏡像的最後部分以獲取引導配置數據。由於這種“揹負式”
+的方法,只要引導加載器傳遞了正確的initrd文件大小,就無需更改或更新引導加載器
+和內核鏡像本身。如果引導加載器意外傳遞了更長的大小,內核將無法找到引導配置數
+據。
+
+Linux內核在tools/bootconfig下提供了 ``bootconfig`` 命令來完成此操作,管理員
+可以用它從initrd鏡像中刪除或追加配置文件。你可以用以下命令來構建它::
+
+ # make -C tools/bootconfig
+
+要向initrd鏡像添加你的引導配置文件,請按如下命令操作(舊數據會自動移除)::
+
+ # tools/bootconfig/bootconfig -a your-config /boot/initrd.img-X.Y.Z
+
+要從鏡像中移除配置,可以使用-d選項::
+
+ # tools/bootconfig/bootconfig -d /boot/initrd.img-X.Y.Z
+
+然後在內核命令行上添加 ``bootconfig`` 告訴內核去initrd文件末尾尋找內核配置。
+
+將引導配置嵌入內核
+------------------
+
+如果你不能使用initrd,也可以通過Kconfig選項將引導配置文件嵌入內核中。在此情
+況下,你需要用以下選項重新編譯內核::
+
+ CONFIG_BOOT_CONFIG_EMBED=y
+ CONFIG_BOOT_CONFIG_EMBED_FILE="/引導配置/文件/的/路徑"
+
+``CONFIG_BOOT_CONFIG_EMBED_FILE`` 需要從源碼樹或對象樹開始的引導配置文件的
+絕對/相對路徑。內核會將其嵌入作爲默認引導配置。
+
+與將引導配置附加到initrd一樣,你也需要在內核命令行上添加 ``bootconfig`` 告訴
+內核去啓用內嵌的引導配置。
+
+注意,即使你已經設置了此選項,仍可用附加到initrd的其他引導配置覆蓋內嵌的引導
+配置。
+
+通過引導配置傳遞內核參數
+========================
+
+除了內核命令行,引導配置也可以用於傳遞內核參數。所有 ``kernel`` 關鍵字下的鍵
+值對都將直接傳遞給內核命令行。此外, ``init`` 下的鍵值對將通過命令行傳遞給
+init進程。參數按以下順序與用戶給定的內核命令行字符串相連,因此命令行參數可以
+覆蓋引導配置參數(這取決於子系統如何處理參數,但通常前面的參數將被後面的參數
+覆蓋)::
+
+ [bootconfig params][cmdline params] -- [bootconfig init params][cmdline init params]
+
+如果引導配置文件給出的kernel/init參數是::
+
+ kernel {
+ root = 01234567-89ab-cdef-0123-456789abcd
+ }
+ init {
+ splash
+ }
+
+這將被複制到內核命令行字符串中,如下所示::
+
+ root="01234567-89ab-cdef-0123-456789abcd" -- splash
+
+如果用戶給出的其他命令行是::
+
+ ro bootconfig -- quiet
+
+則最後的內核命令行如下::
+
+ root="01234567-89ab-cdef-0123-456789abcd" ro bootconfig -- splash quiet
+
+
+配置文件的限制
+==============
+
+當前最大的配置大小是32KB,關鍵字總數(不是鍵值條目)必須少於1024個節點。
+注意:這不是條目數而是節點數,條目必須消耗超過2個節點(一個關鍵字和一個值)。
+所以從理論上講最多512個鍵值對。如果關鍵字平均包含3個單詞,則可有256個鍵值對。
+在大多數情況下,配置項的數量將少於100個條目,小於8KB,因此這應該足夠了。如果
+節點數超過1024,解析器將返回錯誤,即使文件大小小於32KB。(請注意,此最大尺寸
+不包括填充的空字符。)
+無論如何,因爲 ``bootconfig`` 命令在附加啓動配置到initrd映像時會驗證它,用戶
+可以在引導之前注意到它。
+
+
+引導配置API
+===========
+
+用戶可以查詢或遍歷鍵值對,也可以查找(前綴)根關鍵字節點,並在查找該節點下的
+鍵值。
+
+如果您有一個關鍵字字符串,則可以直接使用 xbc_find_value() 查詢該鍵的值。如果
+你想知道引導配置裏有哪些關鍵字,可以使用 xbc_for_each_key_value() 迭代鍵值對。
+請注意,您需要使用 xbc_array_for_each_value() 訪問數組的值,例如::
+
+ vnode = NULL;
+ xbc_find_value("key.word", &vnode);
+ if (vnode && xbc_node_is_array(vnode))
+ xbc_array_for_each_value(vnode, value) {
+ printk("%s ", value);
+ }
+
+如果您想查找具有前綴字符串的鍵,可以使用 xbc_find_node() 通過前綴字符串查找
+節點,然後用 xbc_node_for_each_key_value() 迭代前綴節點下的鍵。
+
+但最典型的用法是獲取前綴下的命名值或前綴下的命名數組,例如::
+
+ root = xbc_find_node("key.prefix");
+ value = xbc_node_find_value(root, "option", &vnode);
+ ...
+ xbc_node_for_each_array_value(root, "array-option", value, anode) {
+ ...
+ }
+
+這將訪問值“key.prefix.option”的值和“key.prefix.array-option”的數組。
+
+鎖是不需要的,因爲在初始化之後配置只讀。如果需要修改,必須複製所有數據和關鍵字。
+
+
+函數與結構體
+============
+
+相關定義的kernel-doc參見:
+
+ - include/linux/bootconfig.h
+ - lib/bootconfig.c
+
diff --git a/Documentation/translations/zh_TW/admin-guide/bug-bisect.rst b/Documentation/translations/zh_TW/admin-guide/bug-bisect.rst
new file mode 100644
index 000000000000..1efe913b8da0
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/bug-bisect.rst
@@ -0,0 +1,85 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :doc:`../../../admin-guide/bug-bisect`
+
+:譯者:
+
+ 吳想成 Wu XiangCheng <bobwxc@email.cn>
+ 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+二分(bisect)缺陷
++++++++++++++++++++
+
+(英文版)最後更新:2016年10月28日
+
+引言
+=====
+
+始終嘗試由來自kernel.org的源代碼構建的最新內核。如果您沒有信心這樣做,請將
+錯誤報告給您的發行版供應商,而不是內核開發人員。
+
+找到缺陷(bug)並不總是那麼容易,不過仍然得去找。如果你找不到它,不要放棄。
+儘可能多的向相關維護人員報告您發現的信息。請參閱MAINTAINERS文件以瞭解您所
+關注的子系統的維護人員。
+
+在提交錯誤報告之前,請閱讀“Documentation/admin-guide/reporting-issues.rst”。
+
+設備未出現(Devices not appearing)
+====================================
+
+這通常是由udev/systemd引起的。在將其歸咎於內核之前先檢查一下。
+
+查找導致缺陷的補丁
+===================
+
+使用 ``git`` 提供的工具可以很容易地找到缺陷,只要缺陷是可復現的。
+
+操作步驟:
+
+- 從git源代碼構建內核
+- 以此開始二分 [#f1]_::
+
+ $ git bisect start
+
+- 標記損壞的變更集::
+
+ $ git bisect bad [commit]
+
+- 標記正常工作的變更集::
+
+ $ git bisect good [commit]
+
+- 重新構建內核並測試
+- 使用以下任一與git bisect進行交互::
+
+ $ git bisect good
+
+ 或::
+
+ $ git bisect bad
+
+ 這取決於您測試的變更集上是否有缺陷
+- 在一些交互之後,git bisect將給出可能導致缺陷的變更集。
+
+- 例如,如果您知道當前版本有問題,而4.8版本是正常的,則可以執行以下操作::
+
+ $ git bisect start
+ $ git bisect bad # Current version is bad
+ $ git bisect good v4.8
+
+
+.. [#f1] 您可以(可選地)在開始git bisect的時候提供good或bad參數
+ ``git bisect start [BAD] [GOOD]``
+
+如需進一步參考,請閱讀:
+
+- ``git-bisect`` 的手冊頁
+- `Fighting regressions with git bisect(用git bisect解決迴歸)
+ <https://www.kernel.org/pub/software/scm/git/docs/git-bisect-lk2009.html>`_
+- `Fully automated bisecting with "git bisect run"(使用git bisect run
+ 來全自動二分) <https://lwn.net/Articles/317154>`_
+- `Using Git bisect to figure out when brokenness was introduced
+ (使用Git二分來找出何時引入了錯誤) <http://webchick.net/node/99>`_
+
diff --git a/Documentation/translations/zh_TW/admin-guide/bug-hunting.rst b/Documentation/translations/zh_TW/admin-guide/bug-hunting.rst
new file mode 100644
index 000000000000..c139ec99cab1
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/bug-hunting.rst
@@ -0,0 +1,344 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :doc:`../../../admin-guide/bug-hunting`
+
+:譯者:
+
+ 吳想成 Wu XiangCheng <bobwxc@email.cn>
+ 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+追蹤缺陷
+=========
+
+內核錯誤報告通常附帶如下堆棧轉儲::
+
+ ------------[ cut here ]------------
+ WARNING: CPU: 1 PID: 28102 at kernel/module.c:1108 module_put+0x57/0x70
+ Modules linked in: dvb_usb_gp8psk(-) dvb_usb dvb_core nvidia_drm(PO) nvidia_modeset(PO) snd_hda_codec_hdmi snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd soundcore nvidia(PO) [last unloaded: rc_core]
+ CPU: 1 PID: 28102 Comm: rmmod Tainted: P WC O 4.8.4-build.1 #1
+ Hardware name: MSI MS-7309/MS-7309, BIOS V1.12 02/23/2009
+ 00000000 c12ba080 00000000 00000000 c103ed6a c1616014 00000001 00006dc6
+ c1615862 00000454 c109e8a7 c109e8a7 00000009 ffffffff 00000000 f13f6a10
+ f5f5a600 c103ee33 00000009 00000000 00000000 c109e8a7 f80ca4d0 c109f617
+ Call Trace:
+ [<c12ba080>] ? dump_stack+0x44/0x64
+ [<c103ed6a>] ? __warn+0xfa/0x120
+ [<c109e8a7>] ? module_put+0x57/0x70
+ [<c109e8a7>] ? module_put+0x57/0x70
+ [<c103ee33>] ? warn_slowpath_null+0x23/0x30
+ [<c109e8a7>] ? module_put+0x57/0x70
+ [<f80ca4d0>] ? gp8psk_fe_set_frontend+0x460/0x460 [dvb_usb_gp8psk]
+ [<c109f617>] ? symbol_put_addr+0x27/0x50
+ [<f80bc9ca>] ? dvb_usb_adapter_frontend_exit+0x3a/0x70 [dvb_usb]
+ [<f80bb3bf>] ? dvb_usb_exit+0x2f/0xd0 [dvb_usb]
+ [<c13d03bc>] ? usb_disable_endpoint+0x7c/0xb0
+ [<f80bb48a>] ? dvb_usb_device_exit+0x2a/0x50 [dvb_usb]
+ [<c13d2882>] ? usb_unbind_interface+0x62/0x250
+ [<c136b514>] ? __pm_runtime_idle+0x44/0x70
+ [<c13620d8>] ? __device_release_driver+0x78/0x120
+ [<c1362907>] ? driver_detach+0x87/0x90
+ [<c1361c48>] ? bus_remove_driver+0x38/0x90
+ [<c13d1c18>] ? usb_deregister+0x58/0xb0
+ [<c109fbb0>] ? SyS_delete_module+0x130/0x1f0
+ [<c1055654>] ? task_work_run+0x64/0x80
+ [<c1000fa5>] ? exit_to_usermode_loop+0x85/0x90
+ [<c10013f0>] ? do_fast_syscall_32+0x80/0x130
+ [<c1549f43>] ? sysenter_past_esp+0x40/0x6a
+ ---[ end trace 6ebc60ef3981792f ]---
+
+這樣的堆棧跟蹤提供了足夠的信息來識別內核源代碼中發生錯誤的那一行。根據問題的
+嚴重性,它還可能包含 **“Oops”** 一詞,比如::
+
+ BUG: unable to handle kernel NULL pointer dereference at (null)
+ IP: [<c06969d4>] iret_exc+0x7d0/0xa59
+ *pdpt = 000000002258a001 *pde = 0000000000000000
+ Oops: 0002 [#1] PREEMPT SMP
+ ...
+
+儘管有 **Oops** 或其他類型的堆棧跟蹤,但通常需要找到出問題的行來識別和處理缺
+陷。在本章中,我們將參考“Oops”來了解需要分析的各種堆棧跟蹤。
+
+如果內核是用 ``CONFIG_DEBUG_INFO`` 編譯的,那麼可以使用文件:
+`scripts/decode_stacktrace.sh` 。
+
+鏈接的模塊
+-----------
+
+受到污染或正在加載/卸載的模塊用“(…)”標記,污染標誌在
+`Documentation/admin-guide/tainted-kernels.rst` 文件中進行了描述,“正在被加
+載”用“+”標註,“正在被卸載”用“-”標註。
+
+
+Oops消息在哪?
+---------------
+
+通常,Oops文本由klogd從內核緩衝區讀取,然後交給 ``syslogd`` ,後者將其寫入
+syslog文件,通常是 ``/var/log/messages`` (取決於 ``/etc/syslog.conf`` )。
+在使用systemd的系統上,它也可以由 ``journald`` 守護進程存儲,並通過運行
+``journalctl`` 命令進行訪問。
+
+有時 ``klogd`` 會掛掉,這種情況下您可以運行 ``dmesg > file`` 從內核緩衝區
+讀取數據並保存它。或者您可以 ``cat /proc/kmsg > file`` ,但是您必須適時
+中斷以停止傳輸,因爲 ``kmsg`` 是一個“永無止境的文件”。
+
+如果機器嚴重崩潰,無法輸入命令或磁盤不可用,那還有三個選項:
+
+(1) 手動複製屏幕上的文本,並在機器重新啓動後輸入。很難受,但這是突然崩潰下
+ 唯一的選擇。或者你可以用數碼相機拍下屏幕——雖然不那麼好,但總比什麼都沒
+ 有好。如果消息滾動超出控制檯頂部,使用更高分辨率(例如 ``vga=791`` )
+ 引導啓動將允許您閱讀更多文本。(警告:這需要 ``vesafb`` ,因此對“早期”
+ 的Oppses沒有幫助)
+
+(2) 從串口終端啓動(參見
+ :ref:`Documentation/admin-guide/serial-console.rst <serial_console>` ),
+ 在另一臺機器上運行調制解調器然後用你喜歡的通信程序捕獲輸出。
+ Minicom運行良好。
+
+(3) 使用Kdump(參閱 Documentation/admin-guide/kdump/kdump.rst ),使用
+ Documentation/admin-guide/kdump/gdbmacros.txt 中的dmesg gdbmacro從舊內存
+ 中提取內核環形緩衝區。
+
+找到缺陷位置
+-------------
+
+如果你能指出缺陷在內核源代碼中的位置,則報告缺陷的效果會非常好。這有兩種方法。
+通常來說使用 ``gdb`` 會比較容易,不過內核需要用調試信息來預編譯。
+
+gdb
+^^^^
+
+GNU 調試器(GNU debugger, ``gdb`` )是從 ``vmlinux`` 文件中找出OOPS的確切
+文件和行號的最佳方法。
+
+在使用 ``CONFIG_DEBUG_INFO`` 編譯的內核上使用gdb效果最好。可通過運行以下命令
+進行設置::
+
+ $ ./scripts/config -d COMPILE_TEST -e DEBUG_KERNEL -e DEBUG_INFO
+
+在用 ``CONFIG_DEBUG_INFO`` 編譯的內核上,你可以直接從OOPS複製EIP值::
+
+ EIP: 0060:[<c021e50e>] Not tainted VLI
+
+並使用GDB來將其翻譯成可讀形式::
+
+ $ gdb vmlinux
+ (gdb) l *0xc021e50e
+
+如果沒有啓用 ``CONFIG_DEBUG_INFO`` ,則使用OOPS的函數偏移::
+
+ EIP is at vt_ioctl+0xda8/0x1482
+
+並在啓用 ``CONFIG_DEBUG_INFO`` 的情況下重新編譯內核::
+
+ $ ./scripts/config -d COMPILE_TEST -e DEBUG_KERNEL -e DEBUG_INFO
+ $ make vmlinux
+ $ gdb vmlinux
+ (gdb) l *vt_ioctl+0xda8
+ 0x1888 is in vt_ioctl (drivers/tty/vt/vt_ioctl.c:293).
+ 288 {
+ 289 struct vc_data *vc = NULL;
+ 290 int ret = 0;
+ 291
+ 292 console_lock();
+ 293 if (VT_BUSY(vc_num))
+ 294 ret = -EBUSY;
+ 295 else if (vc_num)
+ 296 vc = vc_deallocate(vc_num);
+ 297 console_unlock();
+
+或者若您想要更詳細的顯示::
+
+ (gdb) p vt_ioctl
+ $1 = {int (struct tty_struct *, unsigned int, unsigned long)} 0xae0 <vt_ioctl>
+ (gdb) l *0xae0+0xda8
+
+您也可以使用對象文件作爲替代::
+
+ $ make drivers/tty/
+ $ gdb drivers/tty/vt/vt_ioctl.o
+ (gdb) l *vt_ioctl+0xda8
+
+如果你有調用跟蹤,類似::
+
+ Call Trace:
+ [<ffffffff8802c8e9>] :jbd:log_wait_commit+0xa3/0xf5
+ [<ffffffff810482d9>] autoremove_wake_function+0x0/0x2e
+ [<ffffffff8802770b>] :jbd:journal_stop+0x1be/0x1ee
+ ...
+
+這表明問題可能在 :jbd: 模塊中。您可以在gdb中加載該模塊並列出相關代碼::
+
+ $ gdb fs/jbd/jbd.ko
+ (gdb) l *log_wait_commit+0xa3
+
+.. note::
+
+ 您還可以對堆棧跟蹤處的任何函數調用執行相同的操作,例如::
+
+ [<f80bc9ca>] ? dvb_usb_adapter_frontend_exit+0x3a/0x70 [dvb_usb]
+
+ 上述調用發生的位置可以通過以下方式看到::
+
+ $ gdb drivers/media/usb/dvb-usb/dvb-usb.o
+ (gdb) l *dvb_usb_adapter_frontend_exit+0x3a
+
+objdump
+^^^^^^^^
+
+要調試內核,請使用objdump並從崩潰輸出中查找十六進制偏移,以找到有效的代碼/匯
+編行。如果沒有調試符號,您將看到所示例程的彙編程序代碼,但是如果內核有調試
+符號,C代碼也將可見(調試符號可以在內核配置菜單的hacking項中啓用)。例如::
+
+ $ objdump -r -S -l --disassemble net/dccp/ipv4.o
+
+.. note::
+
+ 您需要處於內核樹的頂層以便此獲得您的C文件。
+
+如果您無法訪問源代碼,仍然可以使用以下方法調試一些崩潰轉儲(如Dave Miller的
+示例崩潰轉儲輸出所示)::
+
+ EIP is at +0x14/0x4c0
+ ...
+ Code: 44 24 04 e8 6f 05 00 00 e9 e8 fe ff ff 8d 76 00 8d bc 27 00 00
+ 00 00 55 57 56 53 81 ec bc 00 00 00 8b ac 24 d0 00 00 00 8b 5d 08
+ <8b> 83 3c 01 00 00 89 44 24 14 8b 45 28 85 c0 89 44 24 18 0f 85
+
+ Put the bytes into a "foo.s" file like this:
+
+ .text
+ .globl foo
+ foo:
+ .byte .... /* bytes from Code: part of OOPS dump */
+
+ Compile it with "gcc -c -o foo.o foo.s" then look at the output of
+ "objdump --disassemble foo.o".
+
+ Output:
+
+ ip_queue_xmit:
+ push %ebp
+ push %edi
+ push %esi
+ push %ebx
+ sub $0xbc, %esp
+ mov 0xd0(%esp), %ebp ! %ebp = arg0 (skb)
+ mov 0x8(%ebp), %ebx ! %ebx = skb->sk
+ mov 0x13c(%ebx), %eax ! %eax = inet_sk(sk)->opt
+
+`scripts/decodecode` 文件可以用來自動完成大部分工作,這取決於正在調試的CPU
+體系結構。
+
+報告缺陷
+---------
+
+一旦你通過定位缺陷找到了其發生的地方,你可以嘗試自己修復它或者向上遊報告它。
+
+爲了向上遊報告,您應該找出用於開發受影響代碼的郵件列表。這可以使用 ``get_maintainer.pl`` 。
+
+
+例如,您在gspca的sonixj.c文件中發現一個缺陷,則可以通過以下方法找到它的維護者::
+
+ $ ./scripts/get_maintainer.pl -f drivers/media/usb/gspca/sonixj.c
+ Hans Verkuil <hverkuil@xs4all.nl> (odd fixer:GSPCA USB WEBCAM DRIVER,commit_signer:1/1=100%)
+ Mauro Carvalho Chehab <mchehab@kernel.org> (maintainer:MEDIA INPUT INFRASTRUCTURE (V4L/DVB),commit_signer:1/1=100%)
+ Tejun Heo <tj@kernel.org> (commit_signer:1/1=100%)
+ Bhaktipriya Shridhar <bhaktipriya96@gmail.com> (commit_signer:1/1=100%,authored:1/1=100%,added_lines:4/4=100%,removed_lines:9/9=100%)
+ linux-media@vger.kernel.org (open list:GSPCA USB WEBCAM DRIVER)
+ linux-kernel@vger.kernel.org (open list)
+
+請注意它將指出:
+
+- 最後接觸源代碼的開發人員(如果這是在git樹中完成的)。在上面的例子中是Tejun
+ 和Bhaktipriya(在這個特定的案例中,沒有人真正參與這個文件的開發);
+- 驅動維護人員(Hans Verkuil);
+- 子系統維護人員(Mauro Carvalho Chehab);
+- 驅動程序和/或子系統郵件列表(linux-media@vger.kernel.org);
+- Linux內核郵件列表(linux-kernel@vger.kernel.org)。
+
+通常,修復缺陷的最快方法是將它報告給用於開發相關代碼的郵件列表(linux-media
+ML),抄送驅動程序維護者(Hans)。
+
+如果你完全不知道該把報告寄給誰,且 ``get_maintainer.pl`` 也沒有提供任何有用
+的信息,請發送到linux-kernel@vger.kernel.org。
+
+感謝您的幫助,這使Linux儘可能穩定:-)
+
+修復缺陷
+---------
+
+如果你懂得編程,你不僅可以通過報告錯誤來幫助我們,還可以提供一個解決方案。
+畢竟,開源就是分享你的工作,你不想因爲你的天才而被認可嗎?
+
+如果你決定這樣做,請在制定解決方案後將其提交到上游。
+
+請務必閱讀
+:ref:`Documentation/process/submitting-patches.rst <submittingpatches>` ,
+以幫助您的代碼被接受。
+
+
+---------------------------------------------------------------------------
+
+用 ``klogd`` 進行Oops跟蹤的注意事項
+------------------------------------
+
+爲了幫助Linus和其他內核開發人員, ``klogd`` 對保護故障的處理提供了大量支持。
+爲了完整支持地址解析,至少應該使用 ``sysklogd`` 包的1.3-pl3版本。
+
+當發生保護故障時, ``klogd`` 守護進程會自動將內核日誌消息中的重要地址轉換爲
+它們的等效符號。然後通過 ``klogd`` 使用的任何報告機制來轉發這個已翻譯的內核
+消息。保護錯誤消息可以直接從消息文件中剪切出來並轉發給內核開發人員。
+
+``klogd`` 執行兩種類型的地址解析,靜態翻譯和動態翻譯。靜態翻譯使用System.map
+文件。爲了進行靜態轉換, ``klogd`` 守護進程必須能夠在守護進程初始化時找到系
+統映射文件。有關 ``klogd`` 如何搜索映射文件的信息,請參見klogd手冊頁。
+
+當使用內核可加載模塊時,動態地址轉換非常重要。由於內核模塊的內存是從內核的
+動態內存池中分配的,因此無論是模塊的開頭還是模塊中的函數和符號都沒有固定的
+位置。
+
+內核支持系統調用,允許程序確定加載哪些模塊及其在內存中的位置。klogd守護進程
+使用這些系統調用構建了一個符號表,可用於調試可加載內核模塊中發生的保護錯誤。
+
+klogd至少會提供產生保護故障的模塊的名稱。如果可加載模塊的開發人員選擇從模塊
+導出符號信息,則可能會有其他可用的符號信息。
+
+由於內核模塊環境可以是動態的,因此當模塊環境發生變化時,必須有一種通知
+``klogd`` 守護進程的機制。有一些可用的命令行選項允許klogd向當前正在執行的守
+護進程發出信號示意應該刷新符號信息。有關更多信息,請參閱 ``klogd`` 手冊頁。
+
+sysklogd發行版附帶了一個補丁,它修改了 ``modules-2.0.0`` 包,以便在加載或
+卸載模塊時自動向klogd發送信號。應用此補丁基本上可無縫支持調試內核可加載模塊
+發生的保護故障。
+
+以下是 ``klogd`` 處理的可加載模塊中的保護故障示例::
+
+ Aug 29 09:51:01 blizard kernel: Unable to handle kernel paging request at virtual address f15e97cc
+ Aug 29 09:51:01 blizard kernel: current->tss.cr3 = 0062d000, %cr3 = 0062d000
+ Aug 29 09:51:01 blizard kernel: *pde = 00000000
+ Aug 29 09:51:01 blizard kernel: Oops: 0002
+ Aug 29 09:51:01 blizard kernel: CPU: 0
+ Aug 29 09:51:01 blizard kernel: EIP: 0010:[oops:_oops+16/3868]
+ Aug 29 09:51:01 blizard kernel: EFLAGS: 00010212
+ Aug 29 09:51:01 blizard kernel: eax: 315e97cc ebx: 003a6f80 ecx: 001be77b edx: 00237c0c
+ Aug 29 09:51:01 blizard kernel: esi: 00000000 edi: bffffdb3 ebp: 00589f90 esp: 00589f8c
+ Aug 29 09:51:01 blizard kernel: ds: 0018 es: 0018 fs: 002b gs: 002b ss: 0018
+ Aug 29 09:51:01 blizard kernel: Process oops_test (pid: 3374, process nr: 21, stackpage=00589000)
+ Aug 29 09:51:01 blizard kernel: Stack: 315e97cc 00589f98 0100b0b4 bffffed4 0012e38e 00240c64 003a6f80 00000001
+ Aug 29 09:51:01 blizard kernel: 00000000 00237810 bfffff00 0010a7fa 00000003 00000001 00000000 bfffff00
+ Aug 29 09:51:01 blizard kernel: bffffdb3 bffffed4 ffffffda 0000002b 0007002b 0000002b 0000002b 00000036
+ Aug 29 09:51:01 blizard kernel: Call Trace: [oops:_oops_ioctl+48/80] [_sys_ioctl+254/272] [_system_call+82/128]
+ Aug 29 09:51:01 blizard kernel: Code: c7 00 05 00 00 00 eb 08 90 90 90 90 90 90 90 90 89 ec 5d c3
+
+---------------------------------------------------------------------------
+
+::
+
+ Dr. G.W. Wettstein Oncology Research Div. Computing Facility
+ Roger Maris Cancer Center INTERNET: greg@wind.rmcc.com
+ 820 4th St. N.
+ Fargo, ND 58122
+ Phone: 701-234-7556
+
diff --git a/Documentation/translations/zh_TW/admin-guide/clearing-warn-once.rst b/Documentation/translations/zh_TW/admin-guide/clearing-warn-once.rst
new file mode 100644
index 000000000000..a3e82ff9daac
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/clearing-warn-once.rst
@@ -0,0 +1,16 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Translator: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+清除 WARN_ONCE
+--------------
+
+WARN_ONCE / WARN_ON_ONCE / printk_once 僅僅打印一次消息.
+
+echo 1 > /sys/kernel/debug/clear_warn_once
+
+可以清除這種狀態並且再次允許打印一次告警信息,這對於運行測試集後重現問題
+很有用。
+
diff --git a/Documentation/translations/zh_TW/admin-guide/cpu-load.rst b/Documentation/translations/zh_TW/admin-guide/cpu-load.rst
new file mode 100644
index 000000000000..4c25a2105b39
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/cpu-load.rst
@@ -0,0 +1,112 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Translator: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+========
+CPU 負載
+========
+
+Linux通過``/proc/stat``和``/proc/uptime``導出各種信息,用戶空間工具
+如top(1)使用這些信息計算系統花費在某個特定狀態的平均時間。
+例如:
+
+ $ iostat
+ Linux 2.6.18.3-exp (linmac) 02/20/2007
+
+ avg-cpu: %user %nice %system %iowait %steal %idle
+ 10.01 0.00 2.92 5.44 0.00 81.63
+
+ ...
+
+這裏系統認爲在默認採樣週期內有10.01%的時間工作在用戶空間,2.92%的時
+間用在系統空間,總體上有81.63%的時間是空閒的。
+
+大多數情況下``/proc/stat``的信息幾乎真實反映了系統信息,然而,由於內
+核採集這些數據的方式/時間的特點,有時這些信息根本不可靠。
+
+那麼這些信息是如何被蒐集的呢?每當時間中斷觸發時,內核查看此刻運行的
+進程類型,並增加與此類型/狀態進程對應的計數器的值。這種方法的問題是
+在兩次時間中斷之間系統(進程)能夠在多種狀態之間切換多次,而計數器只
+增加最後一種狀態下的計數。
+
+舉例
+---
+
+假設系統有一個進程以如下方式週期性地佔用cpu::
+
+ 兩個時鐘中斷之間的時間線
+ |-----------------------|
+ ^ ^
+ |_ 開始運行 |
+ |_ 開始睡眠
+ (很快會被喚醒)
+
+在上面的情況下,根據``/proc/stat``的信息(由於當系統處於空閒狀態時,
+時間中斷經常會發生)系統的負載將會是0
+
+大家能夠想象內核的這種行爲會發生在許多情況下,這將導致``/proc/stat``
+中存在相當古怪的信息::
+
+ /* gcc -o hog smallhog.c */
+ #include <time.h>
+ #include <limits.h>
+ #include <signal.h>
+ #include <sys/time.h>
+ #define HIST 10
+
+ static volatile sig_atomic_t stop;
+
+ static void sighandler (int signr)
+ {
+ (void) signr;
+ stop = 1;
+ }
+ static unsigned long hog (unsigned long niters)
+ {
+ stop = 0;
+ while (!stop && --niters);
+ return niters;
+ }
+ int main (void)
+ {
+ int i;
+ struct itimerval it = { .it_interval = { .tv_sec = 0, .tv_usec = 1 },
+ .it_value = { .tv_sec = 0, .tv_usec = 1 } };
+ sigset_t set;
+ unsigned long v[HIST];
+ double tmp = 0.0;
+ unsigned long n;
+ signal (SIGALRM, &sighandler);
+ setitimer (ITIMER_REAL, &it, NULL);
+
+ hog (ULONG_MAX);
+ for (i = 0; i < HIST; ++i) v[i] = ULONG_MAX - hog (ULONG_MAX);
+ for (i = 0; i < HIST; ++i) tmp += v[i];
+ tmp /= HIST;
+ n = tmp - (tmp / 3.0);
+
+ sigemptyset (&set);
+ sigaddset (&set, SIGALRM);
+
+ for (;;) {
+ hog (n);
+ sigwait (&set, &i);
+ }
+ return 0;
+ }
+
+
+參考
+---
+
+- https://lore.kernel.org/r/loom.20070212T063225-663@post.gmane.org
+- Documentation/filesystems/proc.rst (1.8)
+
+
+謝謝
+---
+
+Con Kolivas, Pavel Machek
+
diff --git a/Documentation/translations/zh_TW/admin-guide/cputopology.rst b/Documentation/translations/zh_TW/admin-guide/cputopology.rst
new file mode 100644
index 000000000000..5c46d1b3b065
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/cputopology.rst
@@ -0,0 +1,97 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/admin-guide/cputopology.rst
+
+:翻譯:
+
+ 唐藝舟 Tang Yizhou <tangyeechou@gmail.com>
+
+==========================
+如何通過sysfs將CPU拓撲導出
+==========================
+
+CPU拓撲信息通過sysfs導出。顯示的項(屬性)和某些架構的/proc/cpuinfo輸出相似。它們位於
+/sys/devices/system/cpu/cpuX/topology/。請閱讀ABI文件:
+Documentation/ABI/stable/sysfs-devices-system-cpu。
+
+drivers/base/topology.c是體系結構中性的,它導出了這些屬性。然而,die、cluster、book、
+draw這些層次結構相關的文件僅在體系結構提供了下文描述的宏的條件下被創建。
+
+對於支持這個特性的體系結構,它必須在include/asm-XXX/topology.h中定義這些宏中的一部分::
+
+ #define topology_physical_package_id(cpu)
+ #define topology_die_id(cpu)
+ #define topology_cluster_id(cpu)
+ #define topology_core_id(cpu)
+ #define topology_book_id(cpu)
+ #define topology_drawer_id(cpu)
+ #define topology_sibling_cpumask(cpu)
+ #define topology_core_cpumask(cpu)
+ #define topology_cluster_cpumask(cpu)
+ #define topology_die_cpumask(cpu)
+ #define topology_book_cpumask(cpu)
+ #define topology_drawer_cpumask(cpu)
+
+``**_id macros`` 的類型是int。
+``**_cpumask macros`` 的類型是 ``(const) struct cpumask *`` 。後者和恰當的
+``**_siblings`` sysfs屬性對應(除了topology_sibling_cpumask(),它和thread_siblings
+對應)。
+
+爲了在所有體系結構上保持一致,include/linux/topology.h提供了上述所有宏的默認定義,以防
+它們未在include/asm-XXX/topology.h中定義:
+
+1) topology_physical_package_id: -1
+2) topology_die_id: -1
+3) topology_cluster_id: -1
+4) topology_core_id: 0
+5) topology_book_id: -1
+6) topology_drawer_id: -1
+7) topology_sibling_cpumask: 僅入參CPU
+8) topology_core_cpumask: 僅入參CPU
+9) topology_cluster_cpumask: 僅入參CPU
+10) topology_die_cpumask: 僅入參CPU
+11) topology_book_cpumask: 僅入參CPU
+12) topology_drawer_cpumask: 僅入參CPU
+
+此外,CPU拓撲信息由/sys/devices/system/cpu提供,包含下述文件。輸出對應的內部數據源放在
+方括號("[]")中。
+
+ =========== ==================================================================
+ kernel_max: 內核配置允許的最大CPU下標值。[NR_CPUS-1]
+
+ offline: 由於熱插拔移除或者超過內核允許的CPU上限(上文描述的kernel_max)
+ 導致未上線的CPU。[~cpu_online_mask + cpus >= NR_CPUS]
+
+ online: 在線的CPU,可供調度使用。[cpu_online_mask]
+
+ possible: 已被分配資源的CPU,如果它們CPU實際存在,可以上線。
+ [cpu_possible_mask]
+
+ present: 被系統識別實際存在的CPU。[cpu_present_mask]
+ =========== ==================================================================
+
+上述輸出的格式和cpulist_parse()兼容[參見 <linux/cpumask.h>]。下面給些例子。
+
+在本例中,系統中有64個CPU,但是CPU 32-63超過了kernel_max值,因爲NR_CPUS配置項是32,
+取值範圍被限制爲0..31。此外注意CPU2和4-31未上線,但是可以上線,因爲它們同時存在於
+present和possible::
+
+ kernel_max: 31
+ offline: 2,4-31,32-63
+ online: 0-1,3
+ possible: 0-31
+ present: 0-31
+
+在本例中,NR_CPUS配置項是128,但內核啓動時設置possible_cpus=144。系統中有4個CPU,
+CPU2被手動設置下線(也是唯一一個可以上線的CPU)::
+
+ kernel_max: 127
+ offline: 2,4-127,128-143
+ online: 0-1,3
+ possible: 0-127
+ present: 0-3
+
+閱讀Documentation/core-api/cpu_hotplug.rst可瞭解開機參數possible_cpus=NUM,同時還
+可以瞭解各種cpumask的信息。
+
diff --git a/Documentation/translations/zh_TW/admin-guide/index.rst b/Documentation/translations/zh_TW/admin-guide/index.rst
new file mode 100644
index 000000000000..9335c0e9105d
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/index.rst
@@ -0,0 +1,136 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :doc:`../../../admin-guide/index`
+:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+ 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+Linux 內核用戶和管理員指南
+==========================
+
+下面是一組隨時間添加到內核中的面向用戶的文檔的集合。到目前爲止,還沒有一個
+整體的順序或組織 - 這些材料不是一個單一的,連貫的文件!幸運的話,情況會隨着
+時間的推移而迅速改善。
+
+這個初始部分包含總體信息,包括描述內核的README, 關於內核參數的文檔等。
+
+.. toctree::
+ :maxdepth: 1
+
+ README
+
+Todolist:
+
+* kernel-parameters
+* devices
+* sysctl/index
+
+本節介紹CPU漏洞及其緩解措施。
+
+Todolist:
+
+* hw-vuln/index
+
+下面的一組文檔,針對的是試圖跟蹤問題和bug的用戶。
+
+.. toctree::
+ :maxdepth: 1
+
+ reporting-issues
+ reporting-regressions
+ security-bugs
+ bug-hunting
+ bug-bisect
+ tainted-kernels
+ init
+
+Todolist:
+
+* ramoops
+* dynamic-debug-howto
+* kdump/index
+* perf/index
+
+這是應用程序開發人員感興趣的章節的開始。可以在這裏找到涵蓋內核ABI各個
+方面的文檔。
+
+Todolist:
+
+* sysfs-rules
+
+本手冊的其餘部分包括各種指南,介紹如何根據您的喜好配置內核的特定行爲。
+
+
+.. toctree::
+ :maxdepth: 1
+
+ bootconfig
+ clearing-warn-once
+ cpu-load
+ cputopology
+ lockup-watchdogs
+ unicode
+ sysrq
+ mm/index
+
+Todolist:
+
+* acpi/index
+* aoe/index
+* auxdisplay/index
+* bcache
+* binderfs
+* binfmt-misc
+* blockdev/index
+* braille-console
+* btmrvl
+* cgroup-v1/index
+* cgroup-v2
+* cifs/index
+* dell_rbu
+* device-mapper/index
+* edid
+* efi-stub
+* ext4
+* nfs/index
+* gpio/index
+* highuid
+* hw_random
+* initrd
+* iostats
+* java
+* jfs
+* kernel-per-CPU-kthreads
+* laptops/index
+* lcd-panel-cgram
+* ldm
+* LSM/index
+* md
+* media/index
+* module-signing
+* mono
+* namespaces/index
+* numastat
+* parport
+* perf-security
+* pm/index
+* pnp
+* rapidio
+* ras
+* rtc
+* serial-console
+* svga
+* thunderbolt
+* ufs
+* vga-softcursor
+* video-output
+* xfs
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
+
diff --git a/Documentation/translations/zh_TW/admin-guide/init.rst b/Documentation/translations/zh_TW/admin-guide/init.rst
new file mode 100644
index 000000000000..4cef1994c650
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/init.rst
@@ -0,0 +1,58 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :doc:`../../../admin-guide/init`
+
+:譯者:
+
+ 吳想成 Wu XiangCheng <bobwxc@email.cn>
+ 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+解釋“No working init found.”啓動掛起消息
+=========================================
+
+:作者:
+
+ Andreas Mohr <andi at lisas period de>
+
+ Cristian Souza <cristianmsbr at gmail period com>
+
+本文檔提供了加載初始化二進制(init binary)失敗的一些高層級原因(大致按執行
+順序列出)。
+
+1) **無法掛載根文件系統Unable to mount root FS** :請設置“debug”內核參數(在
+ 引導加載程序bootloader配置文件或CONFIG_CMDLINE)以獲取更詳細的內核消息。
+
+2) **初始化二進制不存在於根文件系統上init binary doesn't exist on rootfs** :
+ 確保您的根文件系統類型正確(並且 ``root=`` 內核參數指向正確的分區);擁有
+ 所需的驅動程序,例如SCSI或USB等存儲硬件;文件系統(ext3、jffs2等)是內建的
+ (或者作爲模塊由initrd預加載)。
+
+3) **控制檯設備損壞Broken console device** : ``console= setup`` 中可能存在
+ 衝突 --> 初始控制檯不可用(initial console unavailable)。例如,由於串行
+ IRQ問題(如缺少基於中斷的配置)導致的某些串行控制檯不可靠。嘗試使用不同的
+ ``console= device`` 或像 ``netconsole=`` 。
+
+4) **二進制存在但依賴項不可用Binary exists but dependencies not available** :
+ 例如初始化二進制的必需庫依賴項,像 ``/lib/ld-linux.so.2`` 丟失或損壞。使用
+ ``readelf -d <INIT>|grep NEEDED`` 找出需要哪些庫。
+
+5) **無法加載二進制Binary cannot be loaded** :請確保二進制的體系結構與您的
+ 硬件匹配。例如i386不匹配x86_64,或者嘗試在ARM硬件上加載x86。如果您嘗試在
+ 此處加載非二進制文件(shell腳本?),您應該確保腳本在其工作頭(shebang
+ header)行 ``#!/...`` 中指定能正常工作的解釋器(包括其庫依賴項)。在處理
+ 腳本之前,最好先測試一個簡單的非腳本二進制文件,比如 ``/bin/sh`` ,並確認
+ 它能成功執行。要了解更多信息,請將代碼添加到 ``init/main.c`` 以顯示
+ kernel_execve()的返回值。
+
+當您發現新的失敗原因時,請擴展本解釋(畢竟加載初始化二進制是一個 **關鍵** 且
+艱難的過渡步驟,需要儘可能無痛地進行),然後向LKML提交一個補丁。
+
+待辦事項:
+
+- 通過一個可以存儲 ``kernel_execve()`` 結果值的結構體數組實現各種
+ ``run_init_process()`` 調用,並在失敗時通過迭代 **所有** 結果來記錄一切
+ (非常重要的可用性修復)。
+- 試着使實現本身在一般情況下更有幫助,例如在受影響的地方提供額外的錯誤消息。
+
diff --git a/Documentation/translations/zh_TW/admin-guide/lockup-watchdogs.rst b/Documentation/translations/zh_TW/admin-guide/lockup-watchdogs.rst
new file mode 100644
index 000000000000..f65b0c96e8e3
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/lockup-watchdogs.rst
@@ -0,0 +1,67 @@
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/admin-guide/lockup-watchdogs.rst
+:Translator: Hailong Liu <liu.hailong6@zte.com.cn>
+
+.. _tw_lockup-watchdogs:
+
+
+=================================================
+Softlockup與hardlockup檢測機制(又名:nmi_watchdog)
+=================================================
+
+Linux中內核實現了一種用以檢測系統發生softlockup和hardlockup的看門狗機制。
+
+Softlockup是一種會引發系統在內核態中一直循環超過20秒(詳見下面“實現”小節)導致
+其他任務沒有機會得到運行的BUG。一旦檢測到'softlockup'發生,默認情況下系統會打
+印當前堆棧跟蹤信息並進入鎖定狀態。也可配置使其在檢測到'softlockup'後進入panic
+狀態;通過sysctl命令設置“kernel.softlockup_panic”、使用內核啓動參數
+“softlockup_panic”(詳見Documentation/admin-guide/kernel-parameters.rst)以及使
+能內核編譯選項“BOOTPARAM_SOFTLOCKUP_PANIC”都可實現這種配置。
+
+而'hardlockup'是一種會引發系統在內核態一直循環超過10秒鐘(詳見"實現"小節)導致其
+他中斷沒有機會運行的缺陷。與'softlockup'情況類似,除了使用sysctl命令設置
+'hardlockup_panic'、使能內核選項“BOOTPARAM_HARDLOCKUP_PANIC”以及使用內核參數
+"nmi_watchdog"(詳見:”Documentation/admin-guide/kernel-parameters.rst“)外,一旦檢
+測到'hardlockup'默認情況下系統打印當前堆棧跟蹤信息,然後進入鎖定狀態。
+
+這個panic選項也可以與panic_timeout結合使用(這個panic_timeout是通過稍具迷惑性的
+sysctl命令"kernel.panic"來設置),使系統在panic指定時間後自動重啓。
+
+實現
+====
+
+Softlockup和hardlockup分別建立在hrtimer(高精度定時器)和perf兩個子系統上而實現。
+這也就意味着理論上任何架構只要實現了這兩個子系統就支持這兩種檢測機制。
+
+Hrtimer用於週期性產生中斷並喚醒watchdog線程;NMI perf事件則以”watchdog_thresh“
+(編譯時默認初始化爲10秒,也可通過”watchdog_thresh“這個sysctl接口來進行配置修改)
+爲間隔週期產生以檢測 hardlockups。如果一個CPU在這個時間段內沒有檢測到hrtimer中
+斷髮生,'hardlockup 檢測器'(即NMI perf事件處理函數)將會視系統配置而選擇產生內核
+警告或者直接panic。
+
+而watchdog線程本質上是一個高優先級內核線程,每調度一次就對時間戳進行一次更新。
+如果時間戳在2*watchdog_thresh(這個是softlockup的觸發門限)這段時間都未更新,那麼
+"softlocup 檢測器"(內部hrtimer定時器回調函數)會將相關的調試信息打印到系統日誌中,
+然後如果系統配置了進入panic流程則進入panic,否則內核繼續執行。
+
+Hrtimer定時器的週期是2*watchdog_thresh/5,也就是說在hardlockup被觸發前hrtimer有
+2~3次機會產生時鐘中斷。
+
+如上所述,內核相當於爲系統管理員提供了一個可調節hrtimer定時器和perf事件週期長度
+的調節旋鈕。如何通過這個旋鈕爲特定使用場景配置一個合理的週期值要對lockups檢測的
+響應速度和lockups檢測開銷這二者之間進行權衡。
+
+默認情況下所有在線cpu上都會運行一個watchdog線程。不過在內核配置了”NO_HZ_FULL“的
+情況下watchdog線程默認只會運行在管家(housekeeping)cpu上,而”nohz_full“啓動參數指
+定的cpu上則不會有watchdog線程運行。試想,如果我們允許watchdog線程在”nohz_full“指
+定的cpu上運行,這些cpu上必須得運行時鐘定時器來激發watchdog線程調度;這樣一來就會
+使”nohz_full“保護用戶程序免受內核干擾的功能失效。當然,副作用就是”nohz_full“指定
+的cpu即使在內核產生了lockup問題我們也無法檢測到。不過,至少我們可以允許watchdog
+線程在管家(non-tickless)核上繼續運行以便我們能繼續正常的監測這些cpus上的lockups
+事件。
+
+不論哪種情況都可以通過sysctl命令kernel.watchdog_cpumask來對沒有運行watchdog線程
+的cpu集合進行調節。對於nohz_full而言,如果nohz_full cpu上有異常掛住的情況,通過
+這種方式打開這些cpu上的watchdog進行調試可能會有所作用。
+
diff --git a/Documentation/translations/zh_TW/admin-guide/mm/damon/index.rst b/Documentation/translations/zh_TW/admin-guide/mm/damon/index.rst
new file mode 100644
index 000000000000..a472eb3c708b
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/mm/damon/index.rst
@@ -0,0 +1,30 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../../disclaimer-zh_TW.rst
+
+:Original: Documentation/admin-guide/mm/damon/index.rst
+
+:翻譯:
+
+ 司延騰 Yanteng Si <siyanteng@loongson.cn>
+
+:校譯:
+
+============
+監測數據訪問
+============
+
+:doc:`DAMON </mm/damon/index>` 允許輕量級的數據訪問監測。使用DAMON,
+用戶可以分析他們系統的內存訪問模式,並優化它們。
+
+.. toctree::
+ :maxdepth: 2
+
+ start
+ usage
+ reclaim
+ lru_sort
+
+
+
+
+
diff --git a/Documentation/translations/zh_TW/admin-guide/mm/damon/lru_sort.rst b/Documentation/translations/zh_TW/admin-guide/mm/damon/lru_sort.rst
new file mode 100644
index 000000000000..1ffc4b6b1d12
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/mm/damon/lru_sort.rst
@@ -0,0 +1,264 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../../disclaimer-zh_TW.rst
+
+:Original: Documentation/admin-guide/mm/damon/lru_sort.rst
+
+:翻譯:
+
+ 臧雷剛 Leigang Zang <zangleigang@hisilicon.com>
+
+:校譯:
+
+==================
+基於DAMON的LRU排序
+==================
+
+基於DAMON的LRU排序是一個靜態的內核模塊,旨在用於以主動的、輕量級的數據訪問模型
+爲基礎的頁面優先級處理的LRU鏈表上,以使得LRU上的數據訪問模型更爲可信。
+
+哪裏需要主動的LRU排序
+=====================
+
+在一個大型系統中,以頁爲粒度的訪問檢測會有比較顯著的開銷,LRU通常不會主動去排序,
+而是對部分特殊事件進行部分的、響應式的排序,例如:特殊的用戶請求,系統調用或者
+內存壓力。這導致,在有些場景下,LRU不能夠完美的作爲一個可信的數據訪問模型,比如
+在內存壓力下對目標內存進行回收。
+
+因爲DAMON能夠儘可能準確的識別數據訪問模型,同時只引起用戶指定範圍的開銷,主動的
+執行DAMON_LRU_SORT讓LRU變得更爲可信是有益的,而且這隻需要較少和可控的開銷。
+
+這是如何工作的
+==============
+
+DAMON_LRU_SORT使用DAMON尋找熱頁(範圍內的頁面訪問頻率高於用戶指定的閾值)和冷頁
+(範圍內的頁面在超過用戶指定的時間無訪問),並提高熱頁和降低冷頁在LRU中的優先級。
+爲了避免在排序過程佔用更多的CPU計算資源,可以設置一個CPU佔用時間的約束值。在約
+束下,分別提升或者降低更多的熱頁和冷頁。系統管理員也可以配置三個內存水位以控制
+在何種條件下自動激活或者停止這種機制。
+
+冷熱閾值和CPU約束的默認值是比較保守的。這意味着,在默認參數下,模塊可以廣泛且無
+負作用的使用在常見環境中,同時在只消耗一小部分CPU時間的情況下,給有內存壓力的系
+統提供一定水平的冷熱識別。
+
+接口:模塊參數
+==============
+
+使用此特性,你首先需要確認你的系統中運行的內核在編譯時啓用了
+``CONFIG_DAMON_LRU_SORT=y``.
+
+爲了讓系統管理員打開或者關閉並且調節指定的系統,DAMON_LRU_SORT設計了模塊參數。
+這意味着,你可以添加 ``damon_lru_sort.<parameter>=<value>`` 到內核的啓動命令行
+參數,或者在 ``/sys/modules/damon_lru_sort/parameters/<parameter>`` 寫入正確的
+值。
+
+下邊是每個參數的描述
+
+enabled
+-------
+
+打開或者關閉DAMON_LRU_SORT.
+
+你可以通過設置這個參數爲 ``Y`` 來打開DAMON_LRU_SORT。設置爲 ``N`` 關閉
+DAMON_LRU_SORT。注意,在基於水位的激活的情況下,DAMON_LRU_SORT有可能不會真正去
+監測或者做LRU排序。對這種情況,參考下方關於水位的描述。
+
+commit_inputs
+-------------
+
+讓DAMON_LRU_SORT再次讀取輸入參數,除了 ``enabled`` 。
+
+在DAMON_LRU_SORT運行時,新的輸入參數默認不會被應用。一旦這個參數被設置爲 ``Y``
+,DAMON_LRU_SORT會再次讀取除了 ``enabled`` 之外的參數。讀取完成後,這個參數會被
+設置爲 ``N`` 。如果在讀取時發現有無效參數,DAMON_LRU_SORT會被關閉。
+
+hot_thres_access_freq
+---------------------
+
+熱點內存區域的訪問頻率閾值,千分比。
+
+如果一個內存區域的訪問頻率大於等於這個值,DAMON_LRU_SORT把這個區域看作熱區,並
+在LRU上把這個區域標記爲已訪問,因些在內存壓力下這部分內存不會被回收。默認爲50%。
+
+cold_min_age
+------------
+
+用於識別冷內存區域的時間閾值,單位是微秒。
+
+如果一個內存區域在這個時間內未被訪問過,DAMON_LRU_SORT把這個區域看作冷區,並在
+LRU上把這個區域標記爲未訪問,因此在內存壓力下這些內存會首先被回收。默認值爲120
+秒。
+
+quota_ms
+--------
+
+嘗試LRU鏈表排序的時間限制,單位是毫秒。
+
+DAMON_LRU_SORT在一個時間窗口內(quota_reset_interval_ms)內最多嘗試這麼長時間來
+對LRU進行排序。這個可以用來作爲CPU計算資源的約束。如果值爲0,則表示無限制。
+
+默認10毫秒。
+
+quota_reset_interval_ms
+-----------------------
+
+配額計時重置週期,毫秒。
+
+配額計時重置週期。即,在quota_reset_interval_ms毫秒內,DAMON_LRU_SORT對LRU進行
+排序不會超過quota_ms或者quota_sz。
+
+默認1秒。
+
+wmarks_interval
+---------------
+
+水位的檢查週期,單位是微秒。
+
+當DAMON_LRU_SORT使能但是由於水位而不活躍時檢查水位前最小的等待時間。默認值5秒。
+
+wmarks_high
+-----------
+
+空閒內存高水位,千分比。
+
+如果空閒內存水位高於這個值,DAMON_LRU_SORT停止工作,不做任何事,除了週期性的檢
+查水位。默認200(20%)。
+
+wmarks_mid
+----------
+
+空閒內存中間水位,千分比。
+
+如果空閒內存水位在這個值與低水位之間,DAMON_LRU_SORT開始工作,開始檢測並對LRU鏈
+表進行排序。默認150(15%)。
+
+wmarks_low
+----------
+
+空閒內存低水位,千分比。
+
+如果空閒內存小於這個值,DAMON_LRU_SORT不再工作,不做任何事,除了週期性的檢查水
+線。默認50(5%)。
+
+sample_interval
+---------------
+
+監測的採樣週期,微秒。
+
+DAMON對冷內存監測的採樣週期。更多細節請參考DAMON文檔 (:doc:`usage`) 。默認5
+毫秒。
+
+aggr_interval
+-------------
+
+監測的收集週期,微秒。
+
+DAMON對冷內存進行收集的時間週期。更多細節請參考DAMON文檔 (:doc:`usage`) 。默認
+100毫秒。
+
+min_nr_regions
+--------------
+
+最小監測區域數量。
+
+對冷內存區域監測的最小數量。這個值可以作爲監測質量的下限。不過,這個值設置的過
+大會增加開銷。更多細節請參考DAMON文檔 (:doc:`usage`) 。默認值爲10。
+
+max_nr_regions
+--------------
+
+最大監測區域數量。
+
+對冷內存區域監測的最大數量。這個值可以作爲監測質量的上限。然而,這個值設置的過
+低會導致監測結果變差。更多細節請參考DAMON文檔 (:doc:`usage`) 。默認值爲1000。
+
+monitor_region_start
+--------------------
+
+目標內存區域的起始物理地址。
+
+DAMON_LRU_SORT要處理的目標內存區域的起始物理地址。默認,使用系統最大內存。
+
+monitor_region_end
+------------------
+
+目標內存區域的結束物理地址。
+
+DAMON_LRU_SORT要處理的目標內存區域的結束物理地址。默認,使用系統最大內存。
+
+kdamond_pid
+-----------
+
+DAMON線程的PID。
+
+如果DAMON_LRU_SORT是使能的,這個表示任務線程的PID。其它情況爲-1。
+
+nr_lru_sort_tried_hot_regions
+-----------------------------
+
+被嘗試進行LRU排序的熱內存區域的數量。
+
+bytes_lru_sort_tried_hot_regions
+--------------------------------
+
+被嘗試進行LRU排序的熱內存區域的大小(字節)。
+
+nr_lru_sorted_hot_regions
+-------------------------
+
+成功進行LRU排序的熱內存區域的數量。
+
+bytes_lru_sorted_hot_regions
+----------------------------
+
+成功進行LRU排序的熱內存區域的大小(字節)。
+
+nr_hot_quota_exceeds
+--------------------
+
+熱區域時間約束超過限制的次數。
+
+nr_lru_sort_tried_cold_regions
+------------------------------
+
+被嘗試進行LRU排序的冷內存區域的數量。
+
+bytes_lru_sort_tried_cold_regions
+---------------------------------
+
+被嘗試進行LRU排序的冷內存區域的大小(字節)。
+
+nr_lru_sorted_cold_regions
+--------------------------
+
+成功進行LRU排序的冷內存區域的數量。
+
+bytes_lru_sorted_cold_regions
+-----------------------------
+
+成功進行LRU排序的冷內存區域的大小(字節)。
+
+nr_cold_quota_exceeds
+---------------------
+
+冷區域時間約束超過限制的次數。
+
+Example
+=======
+
+如下是一個運行時的命令示例,使DAMON_LRU_SORT查找訪問頻率超過50%的區域並對其進行
+LRU的優先級的提升,同時降低那些超過120秒無人訪問的內存區域的優先級。優先級的處
+理被限制在最多1%的CPU以避免DAMON_LRU_SORT消費過多CPU時間。在系統空閒內存超過50%
+時DAMON_LRU_SORT停止工作,並在低於40%時重新開始工作。如果DAMON_RECLAIM沒有取得
+進展且空閒內存低於20%,再次讓DAMON_LRU_SORT停止工作,以此回退到以LRU鏈表爲基礎
+以頁面爲單位的內存回收上。 ::
+
+ # cd /sys/modules/damon_lru_sort/parameters
+ # echo 500 > hot_thres_access_freq
+ # echo 120000000 > cold_min_age
+ # echo 10 > quota_ms
+ # echo 1000 > quota_reset_interval_ms
+ # echo 500 > wmarks_high
+ # echo 400 > wmarks_mid
+ # echo 200 > wmarks_low
+ # echo Y > enabled
+
diff --git a/Documentation/translations/zh_TW/admin-guide/mm/damon/reclaim.rst b/Documentation/translations/zh_TW/admin-guide/mm/damon/reclaim.rst
new file mode 100644
index 000000000000..efed29c40e44
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/mm/damon/reclaim.rst
@@ -0,0 +1,229 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../../disclaimer-zh_TW.rst
+
+:Original: Documentation/admin-guide/mm/damon/reclaim.rst
+
+:翻譯:
+
+ 司延騰 Yanteng Si <siyanteng@loongson.cn>
+
+:校譯:
+
+===============
+基於DAMON的回收
+===============
+
+基於DAMON的回收(DAMON_RECLAIM)是一個靜態的內核模塊,旨在用於輕度內存壓力下的主動和輕
+量級的回收。它的目的不是取代基於LRU列表的頁面回收,而是有選擇地用於不同程度的內存壓力和要
+求。
+
+哪些地方需要主動回收?
+======================
+
+在一般的內存超量使用(over-committed systems,虛擬化相關術語)的系統上,主動回收冷頁
+有助於節省內存和減少延遲高峯,這些延遲是由直接回收進程或kswapd的CPU消耗引起的,同時只產
+生最小的性能下降 [1]_ [2]_ 。
+
+基於空閒頁報告 [3]_ 的內存過度承諾的虛擬化系統就是很好的例子。在這樣的系統中,客戶機
+向主機報告他們的空閒內存,而主機則將報告的內存重新分配給其他客戶。因此,系統的內存得到了充
+分的利用。然而,客戶可能不那麼節省內存,主要是因爲一些內核子系統和用戶空間應用程序被設計爲
+使用盡可能多的內存。然後,客戶機可能只向主機報告少量的內存是空閒的,導致系統的內存利用率下降。
+在客戶中運行主動回收可以緩解這個問題。
+
+它是如何工作的?
+================
+
+DAMON_RECLAIM找到在特定時間內沒有被訪問的內存區域並分頁。爲了避免它在分頁操作中消耗過多
+的CPU,可以配置一個速度限制。在這個速度限制下,它首先分頁出那些沒有被訪問過的內存區域。系
+統管理員還可以配置在什麼情況下這個方案應該自動激活和停用三個內存壓力水位。
+
+接口: 模塊參數
+==============
+
+要使用這個功能,你首先要確保你的系統運行在一個以 ``CONFIG_DAMON_RECLAIM=y`` 構建的內
+核上。
+
+爲了讓系統管理員啓用或禁用它,併爲給定的系統進行調整,DAMON_RECLAIM利用了模塊參數。也就
+是說,你可以把 ``damon_reclaim.<parameter>=<value>`` 放在內核啓動命令行上,或者把
+適當的值寫入 ``/sys/module/damon_reclaim/parameters/<parameter>`` 文件。
+
+下面是每個參數的描述。
+
+enabled
+-------
+
+啓用或禁用DAMON_RECLAIM。
+
+你可以通過把這個參數的值設置爲 ``Y`` 來啓用DAMON_RCLAIM,把它設置爲 ``N`` 可以禁用
+DAMON_RECLAIM。注意,由於基於水位的激活條件,DAMON_RECLAIM不能進行真正的監測和回收。
+這一點請參考下面關於水位參數的描述。
+
+min_age
+-------
+
+識別冷內存區域的時間閾值,單位是微秒。
+
+如果一個內存區域在這個時間或更長的時間內沒有被訪問,DAMON_RECLAIM會將該區域識別爲冷的,
+並回收它。
+
+默認爲120秒。
+
+quota_ms
+--------
+
+回收的時間限制,以毫秒爲單位。
+
+DAMON_RECLAIM 試圖在一個時間窗口(quota_reset_interval_ms)內只使用到這個時間,以
+嘗試回收冷頁。這可以用來限制DAMON_RECLAIM的CPU消耗。如果該值爲零,則該限制被禁用。
+
+默認爲10ms。
+
+quota_sz
+--------
+
+回收的內存大小限制,單位爲字節。
+
+DAMON_RECLAIM 收取在一個時間窗口(quota_reset_interval_ms)內試圖回收的內存量,並
+使其不超過這個限制。這可以用來限制CPU和IO的消耗。如果該值爲零,則限制被禁用。
+
+默認情況下是128 MiB。
+
+quota_reset_interval_ms
+-----------------------
+
+時間/大小配額收取重置間隔,單位爲毫秒。
+
+時間(quota_ms)和大小(quota_sz)的配額的目標重置間隔。也就是說,DAMON_RECLAIM在
+嘗試回收‘不’超過quota_ms毫秒或quota_sz字節的內存。
+
+默認爲1秒。
+
+wmarks_interval
+---------------
+
+當DAMON_RECLAIM被啓用但由於其水位規則而不活躍時,在檢查水位之前的最小等待時間。
+
+wmarks_high
+-----------
+
+高水位的可用內存率(每千字節)。
+
+如果系統的可用內存(以每千字節爲單位)高於這個數值,DAMON_RECLAIM就會變得不活躍,所以
+它什麼也不做,只是定期檢查水位。
+
+wmarks_mid
+----------
+
+中間水位的可用內存率(每千字節)。
+
+如果系統的空閒內存(以每千字節爲單位)在這個和低水位線之間,DAMON_RECLAIM就會被激活,
+因此開始監測和回收。
+
+wmarks_low
+----------
+
+低水位的可用內存率(每千字節)。
+
+如果系統的空閒內存(以每千字節爲單位)低於這個數值,DAMON_RECLAIM就會變得不活躍,所以
+它除了定期檢查水位外什麼都不做。在這種情況下,系統會退回到基於LRU列表的頁面粒度回收邏輯。
+
+sample_interval
+---------------
+
+監測的採樣間隔,單位是微秒。
+
+DAMON用於監測冷內存的採樣間隔。更多細節請參考DAMON文檔 (:doc:`usage`) 。
+
+aggr_interval
+-------------
+
+監測的聚集間隔,單位是微秒。
+
+DAMON對冷內存監測的聚集間隔。更多細節請參考DAMON文檔 (:doc:`usage`)。
+
+min_nr_regions
+--------------
+
+監測區域的最小數量。
+
+DAMON用於冷內存監測的最小監測區域數。這可以用來設置監測質量的下限。但是,設
+置的太高可能會導致監測開銷的增加。更多細節請參考DAMON文檔 (:doc:`usage`) 。
+
+max_nr_regions
+--------------
+
+監測區域的最大數量。
+
+DAMON用於冷內存監測的最大監測區域數。這可以用來設置監測開銷的上限值。但是,
+設置得太低可能會導致監測質量不好。更多細節請參考DAMON文檔 (:doc:`usage`) 。
+
+monitor_region_start
+--------------------
+
+目標內存區域的物理地址起點。
+
+DAMON_RECLAIM將對其進行工作的內存區域的起始物理地址。也就是說,DAMON_RECLAIM
+將在這個區域中找到冷的內存區域並進行回收。默認情況下,該區域使用最大系統內存區。
+
+monitor_region_end
+------------------
+
+目標內存區域的結束物理地址。
+
+DAMON_RECLAIM將對其進行工作的內存區域的末端物理地址。也就是說,DAMON_RECLAIM將
+在這個區域內找到冷的內存區域並進行回收。默認情況下,該區域使用最大系統內存區。
+
+kdamond_pid
+-----------
+
+DAMON線程的PID。
+
+如果DAMON_RECLAIM被啓用,這將成爲工作線程的PID。否則,爲-1。
+
+nr_reclaim_tried_regions
+------------------------
+
+試圖通過DAMON_RECLAIM回收的內存區域的數量。
+
+bytes_reclaim_tried_regions
+---------------------------
+
+試圖通過DAMON_RECLAIM回收的內存區域的總字節數。
+
+nr_reclaimed_regions
+--------------------
+
+通過DAMON_RECLAIM成功回收的內存區域的數量。
+
+bytes_reclaimed_regions
+-----------------------
+
+通過DAMON_RECLAIM成功回收的內存區域的總字節數。
+
+nr_quota_exceeds
+----------------
+
+超過時間/空間配額限制的次數。
+
+例子
+====
+
+下面的運行示例命令使DAMON_RECLAIM找到30秒或更長時間沒有訪問的內存區域並“回收”?
+爲了避免DAMON_RECLAIM在分頁操作中消耗過多的CPU時間,回收被限制在每秒1GiB以內。
+它還要求DAMON_RECLAIM在系統的可用內存率超過50%時不做任何事情,但如果它低於40%時
+就開始真正的工作。如果DAMON_RECLAIM沒有取得進展,因此空閒內存率低於20%,它會要求
+DAMON_RECLAIM再次什麼都不做,這樣我們就可以退回到基於LRU列表的頁面粒度回收了::
+
+ # cd /sys/module/damon_reclaim/parameters
+ # echo 30000000 > min_age
+ # echo $((1 * 1024 * 1024 * 1024)) > quota_sz
+ # echo 1000 > quota_reset_interval_ms
+ # echo 500 > wmarks_high
+ # echo 400 > wmarks_mid
+ # echo 200 > wmarks_low
+ # echo Y > enabled
+
+.. [1] https://research.google/pubs/pub48551/
+.. [2] https://lwn.net/Articles/787611/
+.. [3] https://www.kernel.org/doc/html/latest/mm/free_page_reporting.html
+
diff --git a/Documentation/translations/zh_TW/admin-guide/mm/damon/start.rst b/Documentation/translations/zh_TW/admin-guide/mm/damon/start.rst
new file mode 100644
index 000000000000..1822956be0e0
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/mm/damon/start.rst
@@ -0,0 +1,125 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../../disclaimer-zh_TW.rst
+
+:Original: Documentation/admin-guide/mm/damon/start.rst
+
+:翻譯:
+
+ 司延騰 Yanteng Si <siyanteng@loongson.cn>
+
+:校譯:
+
+========
+入門指南
+========
+
+本文通過演示DAMON的默認用戶空間工具,簡要地介紹瞭如何使用DAMON。請注意,爲了簡潔
+起見,本文檔只描述了它的部分功能。更多細節請參考該工具的使用文檔。
+`doc <https://github.com/awslabs/damo/blob/next/USAGE.md>`_ .
+
+
+前提條件
+========
+
+內核
+----
+
+首先,你要確保你當前系統中跑的內核構建時選定了這個功能選項 ``CONFIG_DAMON_*=y``.
+
+
+用戶空間工具
+------------
+
+在演示中,我們將使用DAMON的默認用戶空間工具,稱爲DAMON Operator(DAMO)。它可以在
+https://github.com/awslabs/damo找到。下面的例子假設DAMO在你的$PATH上。當然,但
+這並不是強制性的。
+
+因爲DAMO使用了DAMON的sysfs接口(詳情請參考:doc:`usage`),你應該確保
+:doc:`sysfs </filesystems/sysfs>` 被掛載。
+
+記錄數據訪問模式
+================
+
+下面的命令記錄了一個程序的內存訪問模式,並將監測結果保存到文件中。 ::
+
+ $ git clone https://github.com/sjp38/masim
+ $ cd masim; make; ./masim ./configs/zigzag.cfg &
+ $ sudo damo record -o damon.data $(pidof masim)
+
+命令的前兩行下載了一個人工內存訪問生成器程序並在後臺運行。生成器將重複地逐一訪問兩個
+100 MiB大小的內存區域。你可以用你的真實工作負載來代替它。最後一行要求 ``damo`` 將
+訪問模式記錄在 ``damon.data`` 文件中。
+
+
+將記錄的模式可視化
+==================
+
+你可以在heatmap中直觀地看到這種模式,顯示哪個內存區域(X軸)何時被訪問(Y軸)以及訪
+問的頻率(數字)。::
+
+ $ sudo damo report heats --heatmap stdout
+ 22222222222222222222222222222222222222211111111111111111111111111111111111111100
+ 44444444444444444444444444444444444444434444444444444444444444444444444444443200
+ 44444444444444444444444444444444444444433444444444444444444444444444444444444200
+ 33333333333333333333333333333333333333344555555555555555555555555555555555555200
+ 33333333333333333333333333333333333344444444444444444444444444444444444444444200
+ 22222222222222222222222222222222222223355555555555555555555555555555555555555200
+ 00000000000000000000000000000000000000288888888888888888888888888888888888888400
+ 00000000000000000000000000000000000000288888888888888888888888888888888888888400
+ 33333333333333333333333333333333333333355555555555555555555555555555555555555200
+ 88888888888888888888888888888888888888600000000000000000000000000000000000000000
+ 88888888888888888888888888888888888888600000000000000000000000000000000000000000
+ 33333333333333333333333333333333333333444444444444444444444444444444444444443200
+ 00000000000000000000000000000000000000288888888888888888888888888888888888888400
+ [...]
+ # access_frequency: 0 1 2 3 4 5 6 7 8 9
+ # x-axis: space (139728247021568-139728453431248: 196.848 MiB)
+ # y-axis: time (15256597248362-15326899978162: 1 m 10.303 s)
+ # resolution: 80x40 (2.461 MiB and 1.758 s for each character)
+
+你也可以直觀地看到工作集的大小分佈,按大小排序。::
+
+ $ sudo damo report wss --range 0 101 10
+ # <percentile> <wss>
+ # target_id 18446632103789443072
+ # avr: 107.708 MiB
+ 0 0 B | |
+ 10 95.328 MiB |**************************** |
+ 20 95.332 MiB |**************************** |
+ 30 95.340 MiB |**************************** |
+ 40 95.387 MiB |**************************** |
+ 50 95.387 MiB |**************************** |
+ 60 95.398 MiB |**************************** |
+ 70 95.398 MiB |**************************** |
+ 80 95.504 MiB |**************************** |
+ 90 190.703 MiB |********************************************************* |
+ 100 196.875 MiB |***********************************************************|
+
+在上述命令中使用 ``--sortby`` 選項,可以顯示工作集的大小是如何按時間順序變化的。::
+
+ $ sudo damo report wss --range 0 101 10 --sortby time
+ # <percentile> <wss>
+ # target_id 18446632103789443072
+ # avr: 107.708 MiB
+ 0 3.051 MiB | |
+ 10 190.703 MiB |***********************************************************|
+ 20 95.336 MiB |***************************** |
+ 30 95.328 MiB |***************************** |
+ 40 95.387 MiB |***************************** |
+ 50 95.332 MiB |***************************** |
+ 60 95.320 MiB |***************************** |
+ 70 95.398 MiB |***************************** |
+ 80 95.398 MiB |***************************** |
+ 90 95.340 MiB |***************************** |
+ 100 95.398 MiB |***************************** |
+
+
+數據訪問模式感知的內存管理
+==========================
+
+以下三個命令使每一個大小>=4K的內存區域在你的工作負載中沒有被訪問>=60秒,就會被換掉。 ::
+
+ $ echo "#min-size max-size min-acc max-acc min-age max-age action" > test_scheme
+ $ echo "4K max 0 0 60s max pageout" >> test_scheme
+ $ damo schemes -c test_scheme <pid of your workload>
+
diff --git a/Documentation/translations/zh_TW/admin-guide/mm/damon/usage.rst b/Documentation/translations/zh_TW/admin-guide/mm/damon/usage.rst
new file mode 100644
index 000000000000..6dee719a32ea
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/mm/damon/usage.rst
@@ -0,0 +1,592 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../../disclaimer-zh_TW.rst
+
+:Original: Documentation/admin-guide/mm/damon/usage.rst
+
+:翻譯:
+
+ 司延騰 Yanteng Si <siyanteng@loongson.cn>
+
+:校譯:
+
+========
+詳細用法
+========
+
+DAMON 爲不同的用戶提供了下面這些接口。
+
+- *DAMON用戶空間工具。*
+ `這 <https://github.com/awslabs/damo>`_ 爲有這特權的人, 如系統管理員,希望有一個剛好
+ 可以工作的人性化界面。
+ 使用它,用戶可以以人性化的方式使用DAMON的主要功能。不過,它可能不會爲特殊情況進行高度調整。
+ 它同時支持虛擬和物理地址空間的監測。更多細節,請參考它的 `使用文檔
+ <https://github.com/awslabs/damo/blob/next/USAGE.md>`_。
+- *sysfs接口。*
+ :ref:`這 <sysfs_interface>` 是爲那些希望更高級的使用DAMON的特權用戶空間程序員準備的。
+ 使用它,用戶可以通過讀取和寫入特殊的sysfs文件來使用DAMON的主要功能。因此,你可以編寫和使
+ 用你個性化的DAMON sysfs包裝程序,代替你讀/寫sysfs文件。 `DAMON用戶空間工具
+ <https://github.com/awslabs/damo>`_ 就是這種程序的一個例子 它同時支持虛擬和物理地址
+ 空間的監測。注意,這個界面只提供簡單的監測結果 :ref:`統計 <damos_stats>`。對於詳細的監測
+ 結果,DAMON提供了一個:ref:`跟蹤點 <tracepoint>`。
+- *debugfs interface.*
+ :ref:`這 <debugfs_interface>` 幾乎與:ref:`sysfs interface <sysfs_interface>` 接
+ 口相同。這將在下一個LTS內核發佈後被移除,所以用戶應該轉移到
+ :ref:`sysfs interface <sysfs_interface>`。
+- *內核空間編程接口。*
+ :doc:`這 </mm/damon/api>` 這是爲內核空間程序員準備的。使用它,用戶可以通過爲你編寫內
+ 核空間的DAMON應用程序,最靈活有效地利用DAMON的每一個功能。你甚至可以爲各種地址空間擴展DAMON。
+ 詳細情況請參考接口 :doc:`文件 </mm/damon/api>`。
+
+sysfs接口
+=========
+DAMON的sysfs接口是在定義 ``CONFIG_DAMON_SYSFS`` 時建立的。它在其sysfs目錄下創建多
+個目錄和文件, ``<sysfs>/kernel/mm/damon/`` 。你可以通過對該目錄下的文件進行寫入和
+讀取來控制DAMON。
+
+對於一個簡短的例子,用戶可以監測一個給定工作負載的虛擬地址空間,如下所示::
+
+ # cd /sys/kernel/mm/damon/admin/
+ # echo 1 > kdamonds/nr_kdamonds && echo 1 > kdamonds/0/contexts/nr_contexts
+ # echo vaddr > kdamonds/0/contexts/0/operations
+ # echo 1 > kdamonds/0/contexts/0/targets/nr_targets
+ # echo $(pidof <workload>) > kdamonds/0/contexts/0/targets/0/pid_target
+ # echo on > kdamonds/0/state
+
+文件層次結構
+------------
+
+DAMON sysfs接口的文件層次結構如下圖所示。在下圖中,父子關係用縮進表示,每個目錄有
+``/`` 後綴,每個目錄中的文件用逗號(",")分開。 ::
+
+ /sys/kernel/mm/damon/admin
+ │ kdamonds/nr_kdamonds
+ │ │ 0/state,pid
+ │ │ │ contexts/nr_contexts
+ │ │ │ │ 0/operations
+ │ │ │ │ │ monitoring_attrs/
+ │ │ │ │ │ │ intervals/sample_us,aggr_us,update_us
+ │ │ │ │ │ │ nr_regions/min,max
+ │ │ │ │ │ targets/nr_targets
+ │ │ │ │ │ │ 0/pid_target
+ │ │ │ │ │ │ │ regions/nr_regions
+ │ │ │ │ │ │ │ │ 0/start,end
+ │ │ │ │ │ │ │ │ ...
+ │ │ │ │ │ │ ...
+ │ │ │ │ │ schemes/nr_schemes
+ │ │ │ │ │ │ 0/action
+ │ │ │ │ │ │ │ access_pattern/
+ │ │ │ │ │ │ │ │ sz/min,max
+ │ │ │ │ │ │ │ │ nr_accesses/min,max
+ │ │ │ │ │ │ │ │ age/min,max
+ │ │ │ │ │ │ │ quotas/ms,bytes,reset_interval_ms
+ │ │ │ │ │ │ │ │ weights/sz_permil,nr_accesses_permil,age_permil
+ │ │ │ │ │ │ │ watermarks/metric,interval_us,high,mid,low
+ │ │ │ │ │ │ │ stats/nr_tried,sz_tried,nr_applied,sz_applied,qt_exceeds
+ │ │ │ │ │ │ │ tried_regions/
+ │ │ │ │ │ │ │ │ 0/start,end,nr_accesses,age
+ │ │ │ │ │ │ │ │ ...
+ │ │ │ │ │ │ ...
+ │ │ │ │ ...
+ │ │ ...
+
+根
+--
+
+DAMON sysfs接口的根是 ``<sysfs>/kernel/mm/damon/`` ,它有一個名爲 ``admin`` 的
+目錄。該目錄包含特權用戶空間程序控制DAMON的文件。擁有根權限的用戶空間工具或deamons可以
+使用這個目錄。
+
+kdamonds/
+---------
+
+與監測相關的信息包括請求規格和結果被稱爲DAMON上下文。DAMON用一個叫做kdamond的內核線程
+執行每個上下文,多個kdamonds可以並行運行。
+
+在 ``admin`` 目錄下,有一個目錄,即``kdamonds``,它有控制kdamonds的文件存在。在開始
+時,這個目錄只有一個文件,``nr_kdamonds``。向該文件寫入一個數字(``N``),就會創建名爲
+``0`` 到 ``N-1`` 的子目錄數量。每個目錄代表每個kdamond。
+
+kdamonds/<N>/
+-------------
+
+在每個kdamond目錄中,存在兩個文件(``state`` 和 ``pid`` )和一個目錄( ``contexts`` )。
+
+讀取 ``state`` 時,如果kdamond當前正在運行,則返回 ``on`` ,如果沒有運行則返回 ``off`` 。
+寫入 ``on`` 或 ``off`` 使kdamond處於狀態。向 ``state`` 文件寫 ``update_schemes_stats`` ,
+更新kdamond的每個基於DAMON的操作方案的統計文件的內容。關於統計信息的細節,請參考
+:ref:`stats section <sysfs_schemes_stats>`. 將 ``update_schemes_tried_regions`` 寫到
+``state`` 文件,爲kdamond的每個基於DAMON的操作方案,更新基於DAMON的操作方案動作的嘗試區域目錄。
+將`clear_schemes_tried_regions`寫入`state`文件,清除kdamond的每個基於DAMON的操作方案的動作
+嘗試區域目錄。 關於基於DAMON的操作方案動作嘗試區域目錄的細節,請參考:ref:tried_regions 部分
+<sysfs_schemes_tried_regions>`。
+
+如果狀態爲 ``on``,讀取 ``pid`` 顯示kdamond線程的pid。
+
+``contexts`` 目錄包含控制這個kdamond要執行的監測上下文的文件。
+
+kdamonds/<N>/contexts/
+----------------------
+
+在開始時,這個目錄只有一個文件,即 ``nr_contexts`` 。向該文件寫入一個數字( ``N`` ),就會創
+建名爲``0`` 到 ``N-1`` 的子目錄數量。每個目錄代表每個監測背景。目前,每個kdamond只支持
+一個上下文,所以只有 ``0`` 或 ``1`` 可以被寫入文件。
+
+contexts/<N>/
+-------------
+
+在每個上下文目錄中,存在一個文件(``operations``)和三個目錄(``monitoring_attrs``,
+``targets``, 和 ``schemes``)。
+
+DAMON支持多種類型的監測操作,包括對虛擬地址空間和物理地址空間的監測。你可以通過向文件
+中寫入以下關鍵詞之一,並從文件中讀取,來設置和獲取DAMON將爲上下文使用何種類型的監測操作。
+
+ - vaddr: 監測特定進程的虛擬地址空間
+ - paddr: 監視系統的物理地址空間
+
+contexts/<N>/monitoring_attrs/
+------------------------------
+
+用於指定監測屬性的文件,包括所需的監測質量和效率,都在 ``monitoring_attrs`` 目錄中。
+具體來說,這個目錄下有兩個目錄,即 ``intervals`` 和 ``nr_regions`` 。
+
+在 ``intervals`` 目錄下,存在DAMON的採樣間隔(``sample_us``)、聚集間隔(``aggr_us``)
+和更新間隔(``update_us``)三個文件。你可以通過寫入和讀出這些文件來設置和獲取微秒級的值。
+
+在 ``nr_regions`` 目錄下,有兩個文件分別用於DAMON監測區域的下限和上限(``min`` 和 ``max`` ),
+這兩個文件控制着監測的開銷。你可以通過向這些文件的寫入和讀出來設置和獲取這些值。
+
+關於間隔和監測區域範圍的更多細節,請參考設計文件 (:doc:`/mm/damon/design`)。
+
+contexts/<N>/targets/
+---------------------
+
+在開始時,這個目錄只有一個文件 ``nr_targets`` 。向該文件寫入一個數字(``N``),就可以創建
+名爲 ``0`` 到 ``N-1`` 的子目錄的數量。每個目錄代表每個監測目標。
+
+targets/<N>/
+------------
+
+在每個目標目錄中,存在一個文件(``pid_target``)和一個目錄(``regions``)。
+
+如果你把 ``vaddr`` 寫到 ``contexts/<N>/operations`` 中,每個目標應該是一個進程。你
+可以通過將進程的pid寫到 ``pid_target`` 文件中來指定DAMON的進程。
+
+targets/<N>/regions
+-------------------
+
+當使用 ``vaddr`` 監測操作集時( ``vaddr`` 被寫入 ``contexts/<N>/operations`` 文
+件),DAMON自動設置和更新監測目標區域,這樣就可以覆蓋目標進程的整個內存映射。然而,用戶可
+能希望將初始監測區域設置爲特定的地址範圍。
+
+相反,當使用 ``paddr`` 監測操作集時,DAMON不會自動設置和更新監測目標區域( ``paddr``
+被寫入 ``contexts/<N>/operations`` 中)。因此,在這種情況下,用戶應該自己設置監測目標
+區域。
+
+在這種情況下,用戶可以按照自己的意願明確設置初始監測目標區域,將適當的值寫入該目錄下的文件。
+
+開始時,這個目錄只有一個文件, ``nr_regions`` 。向該文件寫入一個數字(``N``),就可以創
+建名爲 ``0`` 到 ``N-1`` 的子目錄。每個目錄代表每個初始監測目標區域。
+
+regions/<N>/
+------------
+
+在每個區域目錄中,你會發現兩個文件( ``start`` 和 ``end`` )。你可以通過向文件寫入
+和從文件中讀出,分別設置和獲得初始監測目標區域的起始和結束地址。
+
+每個區域不應該與其他區域重疊。 目錄“N”的“結束”應等於或小於目錄“N+1”的“開始”。
+
+contexts/<N>/schemes/
+---------------------
+
+對於一版的基於DAMON的數據訪問感知的內存管理優化,用戶通常希望系統對特定訪問模式的內存區
+域應用內存管理操作。DAMON從用戶那裏接收這種形式化的操作方案,並將這些方案應用於目標內存
+區域。用戶可以通過讀取和寫入這個目錄下的文件來獲得和設置這些方案。
+
+在開始時,這個目錄只有一個文件,``nr_schemes``。向該文件寫入一個數字(``N``),就可以
+創建名爲``0``到``N-1``的子目錄的數量。每個目錄代表每個基於DAMON的操作方案。
+
+schemes/<N>/
+------------
+
+在每個方案目錄中,存在五個目錄(``access_pattern``、``quotas``、``watermarks``、
+``stats`` 和 ``tried_regions``)和一個文件(``action``)。
+
+``action`` 文件用於設置和獲取你想應用於具有特定訪問模式的內存區域的動作。可以寫入文件
+和從文件中讀取的關鍵詞及其含義如下。
+
+ - ``willneed``: 對有 ``MADV_WILLNEED`` 的區域調用 ``madvise()`` 。
+ - ``cold``: 對具有 ``MADV_COLD`` 的區域調用 ``madvise()`` 。
+ - ``pageout``: 爲具有 ``MADV_PAGEOUT`` 的區域調用 ``madvise()`` 。
+ - ``hugepage``: 爲帶有 ``MADV_HUGEPAGE`` 的區域調用 ``madvise()`` 。
+ - ``nohugepage``: 爲帶有 ``MADV_NOHUGEPAGE`` 的區域調用 ``madvise()``。
+ - ``lru_prio``: 在其LRU列表上對區域進行優先排序。
+ - ``lru_deprio``: 對區域的LRU列表進行降低優先處理。
+ - ``stat``: 什麼都不做,只計算統計數據
+
+schemes/<N>/access_pattern/
+---------------------------
+
+每個基於DAMON的操作方案的目標訪問模式由三個範圍構成,包括以字節爲單位的區域大小、每個
+聚合區間的監測訪問次數和區域年齡的聚合區間數。
+
+在 ``access_pattern`` 目錄下,存在三個目錄( ``sz``, ``nr_accesses``, 和 ``age`` ),
+每個目錄有兩個文件(``min`` 和 ``max`` )。你可以通過向 ``sz``, ``nr_accesses``, 和
+``age`` 目錄下的 ``min`` 和 ``max`` 文件分別寫入和讀取來設置和獲取給定方案的訪問模式。
+
+schemes/<N>/quotas/
+-------------------
+
+每個 ``動作`` 的最佳 ``目標訪問模式`` 取決於工作負載,所以不容易找到。更糟糕的是,將某些動作
+的方案設置得過於激進會造成嚴重的開銷。爲了避免這種開銷,用戶可以爲每個方案限制時間和大小配額。
+具體來說,用戶可以要求DAMON儘量只使用特定的時間(``時間配額``)來應用動作,並且在給定的時間間
+隔(``重置間隔``)內,只對具有目標訪問模式的內存區域應用動作,而不使用特定數量(``大小配額``)。
+
+當預計超過配額限制時,DAMON會根據 ``目標訪問模式`` 的大小、訪問頻率和年齡,對找到的內存區域
+進行優先排序。爲了進行個性化的優先排序,用戶可以爲這三個屬性設置權重。
+
+在 ``quotas`` 目錄下,存在三個文件(``ms``, ``bytes``, ``reset_interval_ms``)和一個
+目錄(``weights``),其中有三個文件(``sz_permil``, ``nr_accesses_permil``, 和
+``age_permil``)。
+
+你可以設置以毫秒爲單位的 ``時間配額`` ,以字節爲單位的 ``大小配額`` ,以及以毫秒爲單位的 ``重
+置間隔`` ,分別向這三個文件寫入數值。你還可以通過向 ``weights`` 目錄下的三個文件寫入數值來設
+置大小、訪問頻率和年齡的優先權,單位爲千分之一。
+
+schemes/<N>/watermarks/
+-----------------------
+
+爲了便於根據系統狀態激活和停用每個方案,DAMON提供了一個稱爲水位的功能。該功能接收五個值,稱爲
+``度量`` 、``間隔`` 、``高`` 、``中`` 、``低`` 。``度量值`` 是指可以測量的系統度量值,如
+自由內存比率。如果系統的度量值 ``高`` 於memoent的高值或 ``低`` 於低值,則該方案被停用。如果
+該值低於 ``中`` ,則該方案被激活。
+
+在水位目錄下,存在五個文件(``metric``, ``interval_us``,``high``, ``mid``, and ``low``)
+用於設置每個值。你可以通過向這些文件的寫入來分別設置和獲取這五個值。
+
+可以寫入 ``metric`` 文件的關鍵詞和含義如下。
+
+ - none: 忽略水位
+ - free_mem_rate: 系統的自由內存率(千分比)。
+
+``interval`` 應以微秒爲單位寫入。
+
+schemes/<N>/stats/
+------------------
+
+DAMON統計每個方案被嘗試應用的區域的總數量和字節數,每個方案被成功應用的區域的兩個數字,以及
+超過配額限制的總數量。這些統計數據可用於在線分析或調整方案。
+
+可以通過讀取 ``stats`` 目錄下的文件(``nr_tried``, ``sz_tried``, ``nr_applied``,
+``sz_applied``, 和 ``qt_exceeds``))分別檢索這些統計數據。這些文件不是實時更新的,所以
+你應該要求DAMON sysfs接口通過在相關的 ``kdamonds/<N>/state`` 文件中寫入一個特殊的關鍵字
+``update_schemes_stats`` 來更新統計信息的文件內容。
+
+schemes/<N>/tried_regions/
+--------------------------
+
+當一個特殊的關鍵字 ``update_schemes_tried_regions`` 被寫入相關的 ``kdamonds/<N>/state``
+文件時,DAMON會在這個目錄下創建從 ``0`` 開始命名的整數目錄。每個目錄包含的文件暴露了關於每個
+內存區域的詳細信息,在下一個 :ref:`聚集區間 <sysfs_monitoring_attrs>`,相應的方案的 ``動作``
+已經嘗試在這個目錄下應用。這些信息包括地址範圍、``nr_accesses`` 以及區域的 ``年齡`` 。
+
+當另一個特殊的關鍵字 ``clear_schemes_tried_regions`` 被寫入相關的 ``kdamonds/<N>/state``
+文件時,這些目錄將被刪除。
+
+tried_regions/<N>/
+------------------
+
+在每個區域目錄中,你會發現四個文件(``start``, ``end``, ``nr_accesses``, and ``age``)。
+讀取這些文件將顯示相應的基於DAMON的操作方案 ``動作`` 試圖應用的區域的開始和結束地址、``nr_accesses``
+和 ``年齡`` 。
+
+用例
+~~~~
+
+下面的命令應用了一個方案:”如果一個大小爲[4KiB, 8KiB]的內存區域在[10, 20]的聚合時間間隔內
+顯示出每一個聚合時間間隔[0, 5]的訪問量,請分頁該區域。對於分頁,每秒最多隻能使用10ms,而且每
+秒分頁不能超過1GiB。在這一限制下,首先分頁出具有較長年齡的內存區域。另外,每5秒鐘檢查一次系統
+的可用內存率,當可用內存率低於50%時開始監測和分頁,但如果可用內存率大於60%,或低於30%,則停
+止監測。“ ::
+
+ # cd <sysfs>/kernel/mm/damon/admin
+ # # populate directories
+ # echo 1 > kdamonds/nr_kdamonds; echo 1 > kdamonds/0/contexts/nr_contexts;
+ # echo 1 > kdamonds/0/contexts/0/schemes/nr_schemes
+ # cd kdamonds/0/contexts/0/schemes/0
+ # # set the basic access pattern and the action
+ # echo 4096 > access_pattern/sz/min
+ # echo 8192 > access_pattern/sz/max
+ # echo 0 > access_pattern/nr_accesses/min
+ # echo 5 > access_pattern/nr_accesses/max
+ # echo 10 > access_pattern/age/min
+ # echo 20 > access_pattern/age/max
+ # echo pageout > action
+ # # set quotas
+ # echo 10 > quotas/ms
+ # echo $((1024*1024*1024)) > quotas/bytes
+ # echo 1000 > quotas/reset_interval_ms
+ # # set watermark
+ # echo free_mem_rate > watermarks/metric
+ # echo 5000000 > watermarks/interval_us
+ # echo 600 > watermarks/high
+ # echo 500 > watermarks/mid
+ # echo 300 > watermarks/low
+
+請注意,我們強烈建議使用用戶空間的工具,如 `damo <https://github.com/awslabs/damo>`_ ,
+而不是像上面那樣手動讀寫文件。以上只是一個例子。
+
+debugfs接口
+===========
+
+.. note::
+
+ DAMON debugfs接口將在下一個LTS內核發佈後被移除,所以用戶應該轉移到
+ :ref:`sysfs接口<sysfs_interface>`。
+
+DAMON導出了八個文件, ``attrs``, ``target_ids``, ``init_regions``,
+``schemes``, ``monitor_on``, ``kdamond_pid``, ``mk_contexts`` 和
+``rm_contexts`` under its debugfs directory, ``<debugfs>/damon/``.
+
+
+屬性
+----
+
+用戶可以通過讀取和寫入 ``attrs`` 文件獲得和設置 ``採樣間隔`` 、 ``聚集間隔`` 、 ``更新間隔``
+以及監測目標區域的最小/最大數量。要詳細瞭解監測屬性,請參考 `:doc:/mm/damon/design` 。例如,
+下面的命令將這些值設置爲5ms、100ms、1000ms、10和1000,然後再次檢查::
+
+ # cd <debugfs>/damon
+ # echo 5000 100000 1000000 10 1000 > attrs
+ # cat attrs
+ 5000 100000 1000000 10 1000
+
+
+目標ID
+------
+
+一些類型的地址空間支持多個監測目標。例如,虛擬內存地址空間的監測可以有多個進程作爲監測目標。用戶
+可以通過寫入目標的相關id值來設置目標,並通過讀取 ``target_ids`` 文件來獲得當前目標的id。在監
+測虛擬地址空間的情況下,這些值應該是監測目標進程的pid。例如,下面的命令將pid爲42和4242的進程設
+爲監測目標,並再次檢查::
+
+ # cd <debugfs>/damon
+ # echo 42 4242 > target_ids
+ # cat target_ids
+ 42 4242
+
+用戶還可以通過在文件中寫入一個特殊的關鍵字 "paddr\n" 來監測系統的物理內存地址空間。因爲物理地
+址空間監測不支持多個目標,讀取文件會顯示一個假值,即 ``42`` ,如下圖所示::
+
+ # cd <debugfs>/damon
+ # echo paddr > target_ids
+ # cat target_ids
+ 42
+
+請注意,設置目標ID並不啓動監測。
+
+
+初始監測目標區域
+----------------
+
+在虛擬地址空間監測的情況下,DAMON自動設置和更新監測的目標區域,這樣就可以覆蓋目標進程的整個
+內存映射。然而,用戶可能希望將監測區域限制在特定的地址範圍內,如堆、棧或特定的文件映射區域。
+或者,一些用戶可以知道他們工作負載的初始訪問模式,因此希望爲“自適應區域調整”設置最佳初始區域。
+
+相比之下,DAMON在物理內存監測的情況下不會自動設置和更新監測目標區域。因此,用戶應該自己設置
+監測目標區域。
+
+在這種情況下,用戶可以通過在 ``init_regions`` 文件中寫入適當的值,明確地設置他們想要的初
+始監測目標區域。輸入應該是一個由三個整數組成的隊列,用空格隔開,代表一個區域的形式如下::
+
+ <target idx> <start address> <end address>
+
+目標idx應該是 ``target_ids`` 文件中目標的索引,從 ``0`` 開始,區域應該按照地址順序傳遞。
+例如,下面的命令將設置幾個地址範圍, ``1-100`` 和 ``100-200`` 作爲pid 42的初始監測目標
+區域,這是 ``target_ids`` 中的第一個(索引 ``0`` ),另外幾個地址範圍, ``20-40`` 和
+``50-100`` 作爲pid 4242的地址,這是 ``target_ids`` 中的第二個(索引 ``1`` )::
+
+ # cd <debugfs>/damon
+ # cat target_ids
+ 42 4242
+ # echo "0 1 100 \
+ 0 100 200 \
+ 1 20 40 \
+ 1 50 100" > init_regions
+
+請注意,這只是設置了初始的監測目標區域。在虛擬內存監測的情況下,DAMON會在一個 ``更新間隔``
+後自動更新區域的邊界。因此,在這種情況下,如果用戶不希望更新的話,應該把 ``更新間隔`` 設
+置得足夠大。
+
+
+方案
+----
+
+對於通常的基於DAMON的數據訪問感知的內存管理優化,用戶只是希望系統對特定訪問模式的內存區域應用內
+存管理操作。DAMON從用戶那裏接收這種形式化的操作方案,並將這些方案應用到目標進程中。
+
+用戶可以通過讀取和寫入 ``scheme`` debugfs文件來獲得和設置這些方案。讀取該文件還可以顯示每個
+方案的統計數據。在文件中,每一個方案都應該在每一行中以下列形式表示出來::
+
+ <target access pattern> <action> <quota> <watermarks>
+
+你可以通過簡單地在文件中寫入一個空字符串來禁用方案。
+
+目標訪問模式
+~~~~~~~~~~~~
+
+``<目標訪問模式>`` 是由三個範圍構成的,形式如下::
+
+ min-size max-size min-acc max-acc min-age max-age
+
+具體來說,區域大小的字節數( `min-size` 和 `max-size` ),訪問頻率的每聚合區間的監測訪問次
+數( `min-acc` 和 `max-acc` ),區域年齡的聚合區間數( `min-age` 和 `max-age` )都被指定。
+請注意,這些範圍是封閉區間。
+
+動作
+~~~~
+
+``<action>`` 是一個預定義的內存管理動作的整數,DAMON將應用於具有目標訪問模式的區域。支持
+的數字和它們的含義如下::
+
+ - 0: Call ``madvise()`` for the region with ``MADV_WILLNEED``
+ - 1: Call ``madvise()`` for the region with ``MADV_COLD``
+ - 2: Call ``madvise()`` for the region with ``MADV_PAGEOUT``
+ - 3: Call ``madvise()`` for the region with ``MADV_HUGEPAGE``
+ - 4: Call ``madvise()`` for the region with ``MADV_NOHUGEPAGE``
+ - 5: Do nothing but count the statistics
+
+配額
+~~~~
+
+每個 ``動作`` 的最佳 ``目標訪問模式`` 取決於工作負載,所以不容易找到。更糟糕的是,將某個
+動作的方案設置得過於激進會導致嚴重的開銷。爲了避免這種開銷,用戶可以通過下面表格中的 ``<quota>``
+來限制方案的時間和大小配額::
+
+ <ms> <sz> <reset interval> <priority weights>
+
+這使得DAMON在 ``<reset interval>`` 毫秒內,儘量只用 ``<ms>`` 毫秒的時間對 ``目標訪
+問模式`` 的內存區域應用動作,並在 ``<reset interval>`` 內只對最多<sz>字節的內存區域應
+用動作。將 ``<ms>`` 和 ``<sz>`` 都設置爲零,可以禁用配額限制。
+
+當預計超過配額限制時,DAMON會根據 ``目標訪問模式`` 的大小、訪問頻率和年齡,對發現的內存
+區域進行優先排序。爲了實現個性化的優先級,用戶可以在 ``<優先級權重>`` 中設置這三個屬性的
+權重,具體形式如下::
+
+ <size weight> <access frequency weight> <age weight>
+
+水位
+~~~~
+
+有些方案需要根據系統特定指標的當前值來運行,如自由內存比率。對於這種情況,用戶可以爲該條
+件指定水位。::
+
+ <metric> <check interval> <high mark> <middle mark> <low mark>
+
+``<metric>`` 是一個預定義的整數,用於要檢查的度量。支持的數字和它們的含義如下。
+
+ - 0: 忽視水位
+ - 1: 系統空閒內存率 (千分比)
+
+每隔 ``<檢查間隔>`` 微秒檢查一次公制的值。
+
+如果該值高於 ``<高標>`` 或低於 ``<低標>`` ,該方案被停用。如果該值低於 ``<中標>`` ,
+該方案將被激活。
+
+統計數據
+~~~~~~~~
+
+它還統計每個方案被嘗試應用的區域的總數量和字節數,每個方案被成功應用的區域的兩個數量,以
+及超過配額限制的總數量。這些統計數據可用於在線分析或調整方案。
+
+統計數據可以通過讀取方案文件來顯示。讀取該文件將顯示你在每一行中輸入的每個 ``方案`` ,
+統計的五個數字將被加在每一行的末尾。
+
+例子
+~~~~
+
+下面的命令應用了一個方案:”如果一個大小爲[4KiB, 8KiB]的內存區域在[10, 20]的聚合時間
+間隔內顯示出每一個聚合時間間隔[0, 5]的訪問量,請分頁出該區域。對於分頁,每秒最多隻能使
+用10ms,而且每秒分頁不能超過1GiB。在這一限制下,首先分頁出具有較長年齡的內存區域。另外,
+每5秒鐘檢查一次系統的可用內存率,當可用內存率低於50%時開始監測和分頁,但如果可用內存率
+大於60%,或低於30%,則停止監測“::
+
+ # cd <debugfs>/damon
+ # scheme="4096 8192 0 5 10 20 2" # target access pattern and action
+ # scheme+=" 10 $((1024*1024*1024)) 1000" # quotas
+ # scheme+=" 0 0 100" # prioritization weights
+ # scheme+=" 1 5000000 600 500 300" # watermarks
+ # echo "$scheme" > schemes
+
+
+開關
+----
+
+除非你明確地啓動監測,否則如上所述的文件設置不會產生效果。你可以通過寫入和讀取 ``monitor_on``
+文件來啓動、停止和檢查監測的當前狀態。寫入 ``on`` 該文件可以啓動對有屬性的目標的監測。寫入
+``off`` 該文件則停止這些目標。如果每個目標進程被終止,DAMON也會停止。下面的示例命令開啓、關
+閉和檢查DAMON的狀態::
+
+ # cd <debugfs>/damon
+ # echo on > monitor_on
+ # echo off > monitor_on
+ # cat monitor_on
+ off
+
+請注意,當監測開啓時,你不能寫到上述的debugfs文件。如果你在DAMON運行時寫到這些文件,將會返
+回一個錯誤代碼,如 ``-EBUSY`` 。
+
+
+監測線程PID
+-----------
+
+DAMON通過一個叫做kdamond的內核線程來進行請求監測。你可以通過讀取 ``kdamond_pid`` 文件獲
+得該線程的 ``pid`` 。當監測被 ``關閉`` 時,讀取該文件不會返回任何信息::
+
+ # cd <debugfs>/damon
+ # cat monitor_on
+ off
+ # cat kdamond_pid
+ none
+ # echo on > monitor_on
+ # cat kdamond_pid
+ 18594
+
+
+使用多個監測線程
+----------------
+
+每個監測上下文都會創建一個 ``kdamond`` 線程。你可以使用 ``mk_contexts`` 和 ``rm_contexts``
+文件爲多個 ``kdamond`` 需要的用例創建和刪除監測上下文。
+
+將新上下文的名稱寫入 ``mk_contexts`` 文件,在 ``DAMON debugfs`` 目錄上創建一個該名稱的目錄。
+該目錄將有該上下文的 ``DAMON debugfs`` 文件::
+
+ # cd <debugfs>/damon
+ # ls foo
+ # ls: cannot access 'foo': No such file or directory
+ # echo foo > mk_contexts
+ # ls foo
+ # attrs init_regions kdamond_pid schemes target_ids
+
+如果不再需要上下文,你可以通過把上下文的名字放到 ``rm_contexts`` 文件中來刪除它和相應的目錄::
+
+ # echo foo > rm_contexts
+ # ls foo
+ # ls: cannot access 'foo': No such file or directory
+
+注意, ``mk_contexts`` 、 ``rm_contexts`` 和 ``monitor_on`` 文件只在根目錄下。
+
+
+監測結果的監測點
+================
+
+DAMON通過一個tracepoint ``damon:damon_aggregated`` 提供監測結果. 當監測開啓時,你可
+以記錄追蹤點事件,並使用追蹤點支持工具如perf顯示結果。比如說::
+
+ # echo on > monitor_on
+ # perf record -e damon:damon_aggregated &
+ # sleep 5
+ # kill 9 $(pidof perf)
+ # echo off > monitor_on
+ # perf script
+
diff --git a/Documentation/translations/zh_TW/admin-guide/mm/index.rst b/Documentation/translations/zh_TW/admin-guide/mm/index.rst
new file mode 100644
index 000000000000..0b04d925b68c
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/mm/index.rst
@@ -0,0 +1,50 @@
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: Documentation/admin-guide/mm/index.rst
+
+:翻譯:
+
+ 徐鑫 xu xin <xu.xin16@zte.com.cn>
+
+
+========
+內存管理
+========
+
+Linux內存管理子系統,顧名思義,是負責系統中的內存管理。它包括了虛擬內存與請求
+分頁的實現,內核內部結構和用戶空間程序的內存分配、將文件映射到進程地址空間以
+及許多其他很酷的事情。
+
+Linux內存管理是一個具有許多可配置設置的複雜系統, 且這些設置中的大多數都可以通
+過 ``/proc`` 文件系統獲得,並且可以使用 ``sysctl`` 進行查詢和調整。這些API接
+口被描述在Documentation/admin-guide/sysctl/vm.rst文件和 `man 5 proc`_ 中。
+
+.. _man 5 proc: http://man7.org/linux/man-pages/man5/proc.5.html
+
+Linux內存管理有它自己的術語,如果你還不熟悉它,請考慮閱讀下面參考:
+Documentation/admin-guide/mm/concepts.rst.
+
+在此目錄下,我們詳細描述瞭如何與Linux內存管理中的各種機制交互。
+
+.. toctree::
+ :maxdepth: 1
+
+ damon/index
+ ksm
+
+Todolist:
+* concepts
+* cma_debugfs
+* hugetlbpage
+* idle_page_tracking
+* memory-hotplug
+* nommu-mmap
+* numa_memory_policy
+* numaperf
+* pagemap
+* soft-dirty
+* swap_numa
+* transhuge
+* userfaultfd
+* zswap
+
diff --git a/Documentation/translations/zh_TW/admin-guide/mm/ksm.rst b/Documentation/translations/zh_TW/admin-guide/mm/ksm.rst
new file mode 100644
index 000000000000..1b4944b3cf61
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/mm/ksm.rst
@@ -0,0 +1,199 @@
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: Documentation/admin-guide/mm/ksm.rst
+
+:翻譯:
+
+ 徐鑫 xu xin <xu.xin16@zte.com.cn>
+
+
+============
+內核同頁合併
+============
+
+
+概述
+====
+
+KSM是一種能節省內存的數據去重功能,由CONFIG_KSM=y啓用,並在2.6.32版本時被添
+加到Linux內核。詳見 ``mm/ksm.c`` 的實現,以及http://lwn.net/Articles/306704
+和https://lwn.net/Articles/330589
+
+KSM最初目的是爲了與KVM(即著名的內核共享內存)一起使用而開發的,通過共享虛擬機
+之間的公共數據,將更多虛擬機放入物理內存。但它對於任何會生成多個相同數據實例的
+應用程序都是很有用的。
+
+KSM的守護進程ksmd會定期掃描那些已註冊的用戶內存區域,查找內容相同的頁面,這些
+頁面可以被單個寫保護頁面替換(如果進程以後想要更新其內容,將自動複製)。使用:
+引用:`sysfs intraface <ksm_sysfs>` 接口來配置KSM守護程序在單個過程中所掃描的頁
+數以及兩個過程之間的間隔時間。
+
+KSM只合並匿名(私有)頁面,從不合並頁緩存(文件)頁面。KSM的合併頁面最初只能被
+鎖定在內核內存中,但現在可以就像其他用戶頁面一樣被換出(但當它們被交換回來時共
+享會被破壞: ksmd必須重新發現它們的身份並再次合併)。
+
+以madvise控制KSM
+================
+
+KSM僅在特定的地址空間區域時運行,即應用程序通過使用如下所示的madvise(2)系統調
+用來請求某塊地址成爲可能的合併候選者的地址空間::
+
+ int madvise(addr, length, MADV_MERGEABLE)
+
+應用程序當然也可以通過調用::
+
+ int madvise(addr, length, MADV_UNMERGEABLE)
+
+來取消該請求,並恢復爲非共享頁面:此時KSM將去除合併在該範圍內的任何合併頁。注意:
+這個去除合併的調用可能突然需要的內存量超過實際可用的內存量-那麼可能會出現EAGAIN
+失敗,但更可能會喚醒OOM killer。
+
+如果KSM未被配置到正在運行的內核中,則madvise MADV_MERGEABLE 和 MADV_UNMERGEABLE
+的調用只會以EINVAL 失敗。如果正在運行的內核是用CONFIG_KSM=y方式構建的,那麼這些
+調用通常會成功:即使KSM守護程序當前沒有運行,MADV_MERGEABLE 仍然會在KSM守護程序
+啓動時註冊範圍,即使該範圍不能包含KSM實際可以合併的任何頁面,即使MADV_UNMERGEABLE
+應用於從未標記爲MADV_MERGEABLE的範圍。
+
+如果一塊內存區域必須被拆分爲至少一個新的MADV_MERGEABLE區域或MADV_UNMERGEABLE區域,
+當該進程將超過 ``vm.max_map_count`` 的設定,則madvise可能返回ENOMEM。(請參閱文檔
+Documentation/admin-guide/sysctl/vm.rst)。
+
+與其他madvise調用一樣,它們在用戶地址空間的映射區域上使用:如果指定的範圍包含未
+映射的間隙(儘管在中間的映射區域工作),它們將報告ENOMEM,如果沒有足夠的內存用於
+內部結構,則可能會因EAGAIN而失敗。
+
+KSM守護進程sysfs接口
+====================
+
+KSM守護進程可以由``/sys/kernel/mm/ksm/`` 中的sysfs文件控制,所有人都可以讀取,但
+只能由root用戶寫入。各接口解釋如下:
+
+
+pages_to_scan
+ ksmd進程進入睡眠前要掃描的頁數。
+ 例如, ``echo 100 > /sys/kernel/mm/ksm/pages_to_scan``
+
+ 默認值:100(該值被選擇用於演示目的)
+
+sleep_millisecs
+ ksmd在下次掃描前應休眠多少毫秒
+ 例如, ``echo 20 > /sys/kernel/mm/ksm/sleep_millisecs``
+
+ 默認值:20(該值被選擇用於演示目的)
+
+merge_across_nodes
+ 指定是否可以合併來自不同NUMA節點的頁面。當設置爲0時,ksm僅合併在物理上位
+ 於同一NUMA節點的內存區域中的頁面。這降低了訪問共享頁面的延遲。在有明顯的
+ NUMA距離上,具有更多節點的系統可能受益於設置該值爲0時的更低延遲。而對於
+ 需要對內存使用量最小化的較小系統來說,設置該值爲1(默認設置)則可能會受
+ 益於更大共享頁面。在決定使用哪種設置之前,您可能希望比較系統在每種設置下
+ 的性能。 ``merge_across_nodes`` 僅當系統中沒有ksm共享頁面時,才能被更改設
+ 置:首先將接口`run` 設置爲2從而對頁進行去合併,然後在修改
+ ``merge_across_nodes`` 後再將‘run’又設置爲1,以根據新設置來重新合併。
+
+ 默認值:1(如早期的發佈版本一樣合併跨站點)
+
+run
+ * 設置爲0可停止ksmd運行,但保留合併頁面,
+ * 設置爲1可運行ksmd,例如, ``echo 1 > /sys/kernel/mm/ksm/run`` ,
+ * 設置爲2可停止ksmd運行,並且對所有目前已合併的頁進行去合併,但保留可合併
+ 區域以供下次運行。
+
+ 默認值:0(必須設置爲1才能激活KSM,除非禁用了CONFIG_SYSFS)
+
+use_zero_pages
+ 指定是否應當特殊處理空頁(即那些僅含zero的已分配頁)。當該值設置爲1時,
+ 空頁與內核零頁合併,而不是像通常情況下那樣空頁自身彼此合併。這可以根據
+ 工作負載的不同,在具有着色零頁的架構上可以提高性能。啓用此設置時應小心,
+ 因爲它可能會降低某些工作負載的KSM性能,比如,當待合併的候選頁面的校驗和
+ 與空頁面的校驗和恰好匹配的時候。此設置可隨時更改,僅對那些更改後再合併
+ 的頁面有效。
+
+ 默認值:0(如同早期版本的KSM正常表現)
+
+max_page_sharing
+ 單個KSM頁面允許的最大共享站點數。這將強制執行重複數據消除限制,以避免涉
+ 及遍歷共享KSM頁面的虛擬映射的虛擬內存操作的高延遲。最小值爲2,因爲新創
+ 建的KSM頁面將至少有兩個共享者。該值越高,KSM合併內存的速度越快,去重
+ 因子也越高,但是對於任何給定的KSM頁面,虛擬映射的最壞情況遍歷的速度也會
+ 越慢。減慢了這種遍歷速度就意味着在交換、壓縮、NUMA平衡和頁面遷移期間,
+ 某些虛擬內存操作將有更高的延遲,從而降低這些虛擬內存操作調用者的響應能力。
+ 其他任務如果不涉及執行虛擬映射遍歷的VM操作,其任務調度延遲不受此參數的影
+ 響,因爲這些遍歷本身是調度友好的。
+
+stable_node_chains_prune_millisecs
+ 指定KSM檢查特定頁面的元數據的頻率(即那些達到過時信息數據去重限制標準的
+ 頁面)單位是毫秒。較小的毫秒值將以更低的延遲來釋放KSM元數據,但它們將使
+ ksmd在掃描期間使用更多CPU。如果還沒有一個KSM頁面達到 ``max_page_sharing``
+ 標準,那就沒有什麼用。
+
+KSM與MADV_MERGEABLE的工作有效性體現於 ``/sys/kernel/mm/ksm/`` 路徑下的接口:
+
+pages_shared
+ 表示多少共享頁正在被使用
+pages_sharing
+ 表示還有多少站點正在共享這些共享頁,即節省了多少
+pages_unshared
+ 表示有多少頁是唯一的,但被反覆檢查以進行合併
+pages_volatile
+ 表示有多少頁因變化太快而無法放在tree中
+full_scans
+ 表示所有可合併區域已掃描多少次
+stable_node_chains
+ 達到 ``max_page_sharing`` 限制的KSM頁數
+stable_node_dups
+ 重複的KSM頁數
+
+比值 ``pages_sharing/pages_shared`` 的最大值受限制於 ``max_page_sharing``
+的設定。要想增加該比值,則相應地要增加 ``max_page_sharing`` 的值。
+
+監測KSM的收益
+=============
+
+KSM可以通過合併相同的頁面來節省內存,但也會消耗額外的內存,因爲它需要生成一些rmap_items
+來保存每個掃描頁面的簡要rmap信息。其中有些頁面可能會被合併,但有些頁面在被檢查幾次
+後可能無法被合併,這些都是無益的內存消耗。
+
+1) 如何確定KSM在全系統範圍內是節省內存還是消耗內存?這裏有一個簡單的近似計算方法供參考::
+
+ general_profit =~ pages_sharing * sizeof(page) - (all_rmap_items) *
+ sizeof(rmap_item);
+
+ 其中all_rmap_items可以通過對 ``pages_sharing`` 、 ``pages_shared`` 、 ``pages_unshared``
+ 和 ``pages_volatile`` 的求和而輕鬆獲得。
+
+2) 單一進程中KSM的收益也可以通過以下近似的計算得到::
+
+ process_profit =~ ksm_merging_pages * sizeof(page) -
+ ksm_rmap_items * sizeof(rmap_item).
+
+ 其中ksm_merging_pages顯示在 ``/proc/<pid>/`` 目錄下,而ksm_rmap_items
+ 顯示在 ``/proc/<pid>/ksm_stat`` 。
+
+從應用的角度來看, ``ksm_rmap_items`` 和 ``ksm_merging_pages`` 的高比例意
+味着不好的madvise-applied策略,所以開發者或管理員必須重新考慮如何改變madvis策
+略。舉個例子供參考,一個頁面的大小通常是4K,而rmap_item的大小在32位CPU架構上分
+別是32B,在64位CPU架構上是64B。所以如果 ``ksm_rmap_items/ksm_merging_pages``
+的比例在64位CPU上超過64,或者在32位CPU上超過128,那麼應用程序的madvise策略應
+該被放棄,因爲ksm收益大約爲零或負值。
+
+監控KSM事件
+===========
+
+在/proc/vmstat中有一些計數器,可以用來監控KSM事件。KSM可能有助於節省內存,這是
+一種權衡,因爲它可能會在KSM COW或複製中的交換上遭受延遲。這些事件可以幫助用戶評估
+是否或如何使用KSM。例如,如果cow_ksm增加得太快,用戶可以減少madvise(, , MADV_MERGEABLE)
+的範圍。
+
+cow_ksm
+ 在每次KSM頁面觸發寫時拷貝(COW)時都會被遞增,當用戶試圖寫入KSM頁面時,
+ 我們必須做一個拷貝。
+
+ksm_swpin_copy
+ 在換入時,每次KSM頁被複制時都會被遞增。請注意,KSM頁在換入時可能會被複
+ 制,因爲do_swap_page()不能做所有的鎖,而需要重組一個跨anon_vma的KSM頁。
+
+--
+Izik Eidus,
+Hugh Dickins, 2009年11月17日。
+
diff --git a/Documentation/translations/zh_TW/admin-guide/reporting-issues.rst b/Documentation/translations/zh_TW/admin-guide/reporting-issues.rst
new file mode 100644
index 000000000000..bc132b25f2ae
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/reporting-issues.rst
@@ -0,0 +1,1370 @@
+.. SPDX-License-Identifier: (GPL-2.0+ OR CC-BY-4.0)
+.. See the bottom of this file for additional redistribution information.
+
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/admin-guide/reporting-issues.rst
+
+:譯者:
+
+ 吳想成 Wu XiangCheng <bobwxc@email.cn>
+ 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+
+報告問題
++++++++++
+
+
+簡明指南(亦即 太長不看)
+==========================
+
+您面臨的是否爲同系列穩定版或長期支持內核的普通內核的迴歸?是否仍然受支持?
+請搜索 `LKML內核郵件列表 <https://lore.kernel.org/lkml/>`_ 和
+`Linux穩定版郵件列表 <https://lore.kernel.org/stable/>`_ 存檔中匹配的報告並
+加入討論。如果找不到匹配的報告,請安裝該系列的最新版本。如果它仍然出現問題,
+請報告給穩定版郵件列表(stable@vger.kernel.org)並抄送回歸郵件列表
+(regressions@lists.linux.dev);理想情況下,還可以抄送維護者和相關子系統的
+郵件列表。
+
+在所有其他情況下,請儘可能猜測是哪個內核部分導致了問題。查看MAINTAINERS文件,
+瞭解開發人員希望如何得知問題,大多數情況下,報告問題都是通過電子郵件和抄送
+相關郵件列表進行的。檢查報告目的地的存檔中是否已有匹配的報告;也請搜索
+`LKML <https://lore.kernel.org/lkml/>`_ 和網絡。如果找不到可加入的討論,請
+安裝 `最新的主線內核 <https://kernel.org/>`_ 。如果仍存在問題,請發送報告。
+
+問題已經解決了,但是您希望看到它在一個仍然支持的穩定版或長期支持系列中得到
+解決?請安裝其最新版本。如果它出現了問題,那麼在主線中搜索修復它的更改,並
+檢查是否正在回傳(backporting)或者已放棄;如果兩者都沒有,那麼可詢問處理
+更改的人員。
+
+**通用提醒** :當安裝和測試上述內核時,請確保它是普通的(即:沒有補丁,也沒
+有使用附加模塊)。還要確保它是在一個正常的環境中構建和運行,並且在問題發生
+之前沒有被污染(tainted)。
+
+當你同時面臨Linux內核的多個問題時,請分別報告。在編寫報告時,要涵蓋與問題
+相關的所有信息,如使用的內核和發行版。如果碰見迴歸,請把報告抄送回歸郵件列表
+(regressions@lists.linux.dev)。也請試試用二分法找出源頭;如果成功找到,請
+在報告中寫上它的提交ID並抄送sign-off-by鏈中的所有人。
+
+一旦報告發出,請回答任何出現的問題,並儘可能地提供幫助。這包括通過不時重新
+測試新版本併發送狀態更新來推動進展。
+
+
+如何向內核維護人員報告問題的逐步指南
+=====================================
+
+上面的簡明指南概述瞭如何向Linux內核開發人員報告問題。對於已經熟悉向自由和開
+源軟件(FLOSS)項目報告問題的人來說,這可能是他們所需要的全部內容。對於其他
+人,本部分更爲詳細,並一步一步地描述。爲了便於閱讀,它仍然儘量簡潔,並省略
+了許多細節;這些在逐步指南後的參考章節中進行了描述,該章節更詳細地解釋了每
+個步驟。
+
+注意:本節涉及的方面比簡明指南多,順序也稍有不同。這符合你的利益,以確保您
+儘早意識到看起來像Linux內核毛病的問題可能實際上是由其他原因引起的。這些步驟
+可以確保你最終不會覺得在這一過程中投入的時間是浪費:
+
+ * 您是否面臨硬件或軟件供應商提供的Linux內核的問題?那麼基本上您最好停止閱讀
+ 本文檔,轉而向您的供應商報告問題,除非您願意自己安裝最新的Linux版本。尋找
+ 和解決問題往往需要後者。
+
+ * 使用您喜愛的網絡搜索引擎對現有報告進行粗略搜索;此外,請檢查
+ `Linux內核郵件列表(LKML) <https://lore.kernel.org/lkml/>`_ 的存檔。如果
+ 找到匹配的報告,請加入討論而不是發送新報告。
+
+ * 看看你正在處理的問題是否爲迴歸問題、安全問題或非常嚴重的問題:這些都是需
+ 要在接下來的一些步驟中特別處理的“高優先級問題”。
+
+ * 確保不是內核環境導致了您面臨的問題。
+
+ * 創建一個新的備份,並將系統修復和恢復工具放在手邊。
+
+ * 確保您的系統不會通過動態構建額外的內核模塊來增強其內核,像DKMS這樣的解決
+ 方案可能在您不知情的情況下就在本地進行了這樣的工作。
+
+ * 當問題發生時,檢查您的內核是否被“污染”,因爲使內核設置這個標誌的事件可能
+ 會導致您面臨的問題。
+
+ * 粗略地寫下如何重現這個問題。如果您同時處理多個問題,請爲每個問題單獨寫注
+ 釋,並確保它們在新啓動的系統上獨立出現。這是必要的,因爲每個問題都需要分
+ 別報告給內核開發人員,除非它們嚴重糾纏在一起。
+
+ * 如果您正面臨穩定版或長期支持版本線的迴歸(例如從5.10.4更新到5.10.5時出現
+ 故障),請查看後文“報告穩定版和長期支持內核線的迴歸”小節。
+
+ * 定位可能引起問題的驅動程序或內核子系統。找出其開發人員期望的報告的方式和
+ 位置。注意:大多數情況下不會是 bugzilla.kernel.org,因爲問題通常需要通
+ 過郵件發送給維護人員和公共郵件列表。
+
+ * 在缺陷追蹤器或問題相關郵件列表的存檔中徹底搜索可能與您的問題匹配的報告。
+ 如果你發現了一些相關討論,請加入討論而不是發送新的報告。
+
+在完成這些準備之後,你將進入主要部分:
+
+ * 除非您已經在運行最新的“主線”Linux內核,否則最好在報告流程前安裝它。在某些
+ 情況下,使用最新的“穩定版”Linux進行測試和報告也是可以接受的替代方案;在
+ 合併窗口期間,這實際上可能是最好的方法,但在開發階段最好還是暫停幾天。無論
+ 你選擇什麼版本,最好使用“普通”構建。忽略這些建議會大大增加您的報告被拒絕
+ 或忽略的風險。
+
+ * 確保您剛剛安裝的內核在運行時不會“污染”自己。
+
+ * 在您剛剛安裝的內核中復現這個問題。如果它沒有出現,請查看下方只發生在
+ 穩定版和長期支持內核的問題的說明。
+
+ * 優化你的筆記:試着找到並寫出最直接的復現問題的方法。確保最終結果包含所有
+ 重要的細節,同時讓第一次聽說的人容易閱讀和理解。如果您在此過程中學到了一
+ 些東西,請考慮再次搜索關於該問題的現有報告。
+
+ * 如果失敗涉及“panic”、“Oops”、“warning”或“BUG”,請考慮解碼內核日誌以查找觸
+ 發錯誤的代碼行。
+
+ * 如果您的問題是迴歸問題,請儘可能縮小引入問題時的範圍。
+
+ * 通過詳細描述問題來開始編寫報告。記得包括以下條目:您爲復現而安裝的最新內
+ 核版本、使用的Linux發行版以及關於如何復現該問題的說明。如果可能,將內核
+ 構建配置(.config)和 ``dmesg`` 的輸出放在網上的某個地方,並鏈接到它。包
+ 含或上傳所有其他可能相關的信息,如Oops的輸出/截圖或來自 ``lspci`` 的輸出
+ 。一旦你寫完了這個主要部分,請在上方插入一個正常長度的段落快速概述問題和
+ 影響。再在此之上添加一個簡單描述問題的句子,以得到人們的閱讀。現在給出一
+ 個更短的描述性標題或主題。然後就可以像MAINTAINERS文件告訴你的那樣發送或
+ 提交報告了,除非你在處理一個“高優先級問題”:它們需要按照下面“高優先級問
+ 題的特殊處理”所述特別關照。
+
+ * 等待別人的反應,繼續推進事情,直到你能夠接受這樣或那樣的結果。因此,請公
+ 開和及時地回應任何詢問。測試提出的修復。積極地測試:至少重新測試每個新主
+ 線版本的首個候選版本(RC),並報告你的結果。如果出現拖延,就友好地提醒一
+ 下。如果你沒有得到任何幫助或者未能滿意,請試着自己幫助自己。
+
+
+報告穩定版和長期支持內核線的迴歸
+----------------------------------
+
+如果您發現了穩定版或長期支持內核版本線中的迴歸問題並按上述流程跳到這裏,那麼
+請閱讀本小節。即例如您在從5.10.4更新到5.10.5時出現了問題(從5.9.15到5.10.5則
+不是)。開發人員希望儘快修復此類迴歸,因此有一個簡化流程來報告它們:
+
+ * 檢查內核開發人員是否仍然維護你關心的Linux內核版本線:去 `kernel.org 的首頁
+ <https://kernel.org/>`_ ,確保此特定版本線的最新版沒有“[EOL]”標記。
+
+ * 檢查 `Linux穩定版郵件列表 <https://lore.kernel.org/stable/>`_ 中的現有報告。
+
+ * 從特定的版本線安裝最新版本作爲純淨內核。確保這個內核沒有被污染,並且仍然
+ 存在問題,因爲問題可能已經在那裏被修復了。如果您第一次發現供應商內核的問題,
+ 請檢查已知最新版本的普通構建是否可以正常運行。
+
+ * 向Linux穩定版郵件列表發送一個簡短的問題報告(stable@vger.kernel.org)並抄送
+ Linux迴歸郵件列表(regressions@lists.linux.dev);如果你懷疑是由某子系統
+ 引起的,請抄送其維護人員和子系統郵件列表。大致描述問題,並解釋如何復現。
+ 講清楚首個出現問題的版本和最後一個工作正常的版本。然後等待進一步的指示。
+
+下面的參考章節部分詳細解釋了這些步驟中的每一步。
+
+
+報告只發生在較舊內核版本線的問題
+----------------------------------
+
+若您嘗試了上述的最新主線內核,但未能在那裏復現問題,那麼本小節適用於您;以下
+流程有助於使問題在仍然支持的穩定版或長期支持版本線,或者定期基於最新穩定版或
+長期支持內核的供應商內核中得到修復。如果是這種情況,請執行以下步驟:
+
+ * 請做好準備,接下來的幾個步驟可能無法在舊版本中解決問題:修復可能太大或太
+ 冒險,無法移植到那裏。
+
+ * 執行前節“報告穩定版和長期支持內核線的迴歸”中的前三個步驟。
+
+ * 在Linux內核版本控制系統中搜索修復主線問題的更改,因爲它的提交消息可能會
+ 告訴你修復是否已經計劃好了支持。如果你沒有找到,搜索適當的郵件列表,尋找
+ 討論此類問題或同行評議可能修復的帖子;然後檢查討論是否認爲修復不適合支持。
+ 如果支持根本不被考慮,加入最新的討論,詢問是否有可能。
+
+ * 前面的步驟之一應該會給出一個解決方案。如果仍未能成功,請向可能引起問題的
+ 子系統的維護人員詢問建議;抄送特定子系統的郵件列表以及穩定版郵件列表
+
+下面的參考章節部分詳細解釋了這些步驟中的每一步。
+
+
+參考章節:向內核維護者報告問題
+===============================
+
+上面的詳細指南簡要地列出了所有主要步驟,這對大多數人來說應該足夠了。但有時,
+即使是有經驗的用戶也可能想知道如何實際執行這些步驟之一。這就是本節的目的,
+因爲它將提供關於上述每個步驟的更多細節。請將此作爲參考文檔:可以從頭到尾
+閱讀它。但它主要是爲了瀏覽和查找如何實際執行這些步驟的詳細信息。
+
+在深入挖掘細節之前,我想先給你一些一般性建議:
+
+ * Linux內核開發人員很清楚這個過程很複雜,比其他的FLOSS項目要求更多。我們很
+ 希望讓它更簡單。但這需要在不同的地方以及一些基礎設施上付諸努力,這些基礎
+ 設施需要持續的維護;尚未有人站出來做這些工作,所以目前情況就是這樣。
+
+ * 與某些供應商簽訂的保證或支持合同並不能使您有權要求上游Linux內核社區的開
+ 發人員進行修復:這樣的合同完全在Linux內核、其開發社區和本文檔的範圍之外。
+ 這就是爲什麼在這種情況下,你不能要求任何契約保證,即使開發人員處理的問
+ 題對供應商有效。如果您想主張您的權利,使用供應商的支持渠道代替。當這樣做
+ 的時候,你可能想提出你希望看到這個問題在上游Linux內核中修復;可以這是確
+ 保最終修復將被納入所有Linux發行版的唯一方法來鼓勵他們。
+
+ * 如果您從未向FLOSS項目報告過任何問題,那麼您應該考慮閱讀 `如何有效地報告
+ 缺陷 <https://www.chiark.greenend.org.uk/~sgtatham/bugs.html>`_ , `如何
+ 以明智的方式提問 <http://www.catb.org/esr/faqs/smart-questions.html>`_ ,
+ 和 `如何提出好問題 <https://jvns.ca/blog/good-questions/>`_ 。
+
+解決這些問題之後,可以在下面找到如何正確地向Linux內核報告問題的詳細信息。
+
+
+確保您使用的是上游Linux內核
+----------------------------
+
+ *您是否面臨硬件或軟件供應商提供的Linux內核的問題?那麼基本上您最好停止閱
+ 讀本文檔,轉而向您的供應商報告問題,除非您願意自己安裝最新的Linux版本。
+ 尋找和解決問題往往需要後者。*
+
+與大多數程序員一樣,Linux內核開發人員不喜歡花時間處理他們維護的源代碼中根本
+不會發生的問題的報告。這隻會浪費每個人的時間,尤其是你的時間。不幸的是,當
+涉及到內核時,這樣的情況很容易發生,並且常常導致雙方氣餒。這是因爲幾乎所有預
+裝在設備(臺式機、筆記本電腦、智能手機、路由器等)上的Linux內核,以及大多數
+由Linux發行商提供的內核,都與由kernel.org發行的官方Linux內核相距甚遠:從Linux
+開發的角度來看,這些供應商提供的內核通常是古老的或者經過了大量修改,通常兩點
+兼具。
+
+大多數供應商內核都不適合用來向Linux內核開發人員報告問題:您在其中遇到的問題
+可能已經由Linux內核開發人員在數月或數年前修復;此外,供應商的修改和增強可能
+會導致您面臨的問題,即使它們看起來很小或者完全不相關。這就是爲什麼您應該向
+供應商報告這些內核的問題。它的開發者應該查看報告,如果它是一個上游問題,直接
+於上游修復或將報告轉發到那裏。在實踐中,這有時行不通。因此,您可能需要考慮
+通過自己安裝最新的Linux內核內核來繞過供應商。如果如果您選擇此方法,那麼本指
+南後面的步驟將解釋如何在排除了其他可能導致您的問題的原因後執行此操作。
+
+注意前段使用的詞語是“大多數”,因爲有時候開發人員實際上願意處理供應商內核出現
+的問題報告。他們是否這麼做很大程度上取決於開發人員和相關問題。如果發行版只
+根據最近的Linux版本對內核進行了較小修改,那麼機會就比較大;例如對於Debian
+GNU/Linux Sid或Fedora Rawhide所提供的主線內核。一些開發人員還將接受基於最新
+穩定內核的發行版內核問題報告,只要它改動不大;例如Arch Linux、常規Fedora版本
+和openSUSE Turboweed。但是請記住,您最好使用主線Linux,並避免在此流程中使用
+穩定版內核,如“安裝一個新的內核進行測試”一節中所詳述。
+
+當然,您可以忽略所有這些建議,並向上遊Linux開發人員報告舊的或經過大量修改的
+供應商內核的問題。但是注意,這樣的報告經常被拒絕或忽視,所以自行小心考慮一下。
+不過這還是比根本不報告問題要好:有時候這樣的報告會直接或間接地幫助解決之後的
+問題。
+
+
+搜索現有報告(第一部分)
+-------------------------
+
+ *使用您喜愛的網絡搜索引擎對現有報告進行粗略搜索;此外,請檢查Linux內核
+ 郵件列表(LKML)的存檔。如果找到匹配的報告,請加入討論而不是發送新報告。*
+
+報告一個別人已經提出的問題,對每個人來說都是浪費時間,尤其是作爲報告人的你。
+所以徹底檢查是否有人已經報告了這個問題,這對你自己是有利的。在流程中的這一步,
+可以只執行一個粗略的搜索:一旦您知道您的問題需要報告到哪裏,稍後的步驟將告訴
+您如何詳細搜索。儘管如此,不要倉促完成這一步,它可以節省您的時間和減少麻煩。
+
+只需先用你最喜歡的搜索引擎在互聯網上搜索。然後再搜索Linux內核郵件列表(LKML)
+存檔。
+
+如果搜索結果實在太多,可以考慮讓你的搜索引擎將搜索時間範圍限制在過去的一個
+月或一年。而且無論你在哪裏搜索,一定要用恰當的搜索關鍵詞;也要變化幾次關鍵
+詞。同時,試着從別人的角度看問題:這將幫助你想出其他的關鍵詞。另外,一定不
+要同時使用過多的關鍵詞。記住搜索時要同時嘗試包含和不包含內核驅動程序的名稱
+或受影響的硬件組件的名稱等信息。但其確切的品牌名稱(比如說“華碩紅魔 Radeon
+RX 5700 XT Gaming OC”)往往幫助不大,因爲它太具體了。相反,嘗試搜索術語,如
+型號(Radeon 5700 或 Radeon 5000)和核心代號(“Navi”或“Navi10”),以及包含
+和不包含其製造商(“AMD”)。
+
+如果你發現了關於你的問題的現有報告,請加入討論,因爲你可能會提供有價值的額
+外信息。這一點很重要,即使是在修復程序已經準備好或處於最後階段,因爲開發人
+員可能會尋找能夠提供額外信息或測試建議修復程序的人。跳到“發佈報告後的責任”
+一節,瞭解有關如何正確參與的細節。
+
+注意,搜索 `bugzilla.kernel.org <https://bugzilla.kernel.org/>`_ 網站可能
+也是一個好主意,因爲這可能會提供有價值的見解或找到匹配的報告。如果您發現後者,
+請記住:大多數子系統都希望在不同的位置報告,如下面“你需要將問題報告到何處”
+一節中所述。因此本應處理這個問題的開發人員甚至可能不知道bugzilla的工單。所以
+請檢查工單中的問題是否已經按照本文檔所述得到報告,如果沒有,請考慮這樣做。
+
+高優先級的問題?
+-----------------
+
+ *看看你正在處理的問題是否是迴歸問題、安全問題或非常嚴重的問題:這些都是
+ 需要在接下來的一些步驟中特別處理的“高優先級問題”。*
+
+Linus Torvalds和主要的Linux內核開發人員希望看到一些問題儘快得到解決,因此在
+報告過程中有一些“高優先級問題”的處理略有不同。有三種情況符合條件:迴歸、安全
+問題和非常嚴重的問題。
+
+如果某個應用程序或實際用例在原先的Linux內核上運行良好,但在使用類似配置編譯的
+較新版本上效果更差、或者根本不能用,那麼你就需要處理迴歸問題。
+Documentation/admin-guide/reporting-regressions.rst 對此進行了更詳細的解釋。
+它還提供了很多你可能想知道的關於迴歸的其他信息;例如,它解釋瞭如何將您的問題
+添加到迴歸跟蹤列表中,以確保它不會被忽略。
+
+什麼是安全問題留給您自己判斷。在繼續之前,請考慮閱讀
+Documentation/translations/zh_CN/admin-guide/security-bugs.rst ,
+因爲它提供瞭如何最恰當地處理安全問題的額外細節。
+
+當發生了完全無法接受的糟糕事情時,此問題就是一個“非常嚴重的問題”。例如,
+Linux內核破壞了它處理的數據或損壞了它運行的硬件。當內核突然顯示錯誤消息
+(“kernel panic”)並停止工作,或者根本沒有任何停止信息時,您也在處理一個嚴重
+的問題。注意:不要混淆“panic”(內核停止自身的致命錯誤)和“Oops”(可恢復錯誤),
+因爲顯示後者之後內核仍然在運行。
+
+
+確保環境健康
+--------------
+
+ *確保不是內核所處環境導致了你所面臨的問題。*
+
+看起來很像內核問題的問題有時是由構建或運行時環境引起的。很難完全排除這種問
+題,但你應該儘量減少這種問題:
+
+ * 構建內核時,請使用經過驗證的工具,因爲編譯器或二進制文件中的錯誤可能會導
+ 致內核出現錯誤行爲。
+
+ * 確保您的計算機組件在其設計規範內運行;這對處理器、內存和主板尤爲重要。因
+ 此,當面臨潛在的內核問題時,停止低電壓或超頻。
+
+ * 儘量確保不是硬件故障導致了你的問題。例如,內存損壞會導致大量的問題,這些
+ 問題會表現爲看起來像內核問題。
+
+ * 如果你正在處理一個文件系統問題,你可能需要用 ``fsck`` 檢查一下文件系統,
+ 因爲它可能會以某種方式被損壞,從而導致無法預期的內核行爲。
+
+ * 在處理迴歸問題時,要確保沒有在更新內核的同時發生了其他變化。例如,這個問
+ 題可能是由同時更新的其他軟件引起的。也有可能是在你第一次重啓進入新內核時,
+ 某個硬件巧合地壞了。更新系統 BIOS 或改變 BIOS 設置中的某些內容也會導致
+ 一些看起來很像內核迴歸的問題。
+
+
+爲緊急情況做好準備
+-------------------
+
+ *創建一個全新的備份,並將系統修復和還原工具放在手邊*
+
+我得提醒您,您正在和計算機打交道,計算機有時會出現意想不到的事情,尤其是當
+您折騰其操作系統的內核等關鍵部件時。而這就是你在這個過程中要做的事情。因此,
+一定要創建一個全新的備份;還要確保你手頭有修復或重裝操作系統的所有工具,
+以及恢復備份所需的一切。
+
+
+確保你的內核不會被增強
+------------------------
+
+ *確保您的系統不會通過動態構建額外的內核模塊來增強其內核,像DKMS這樣的解
+ 決方案可能在您不知情的情況下就在本地進行了這樣的工作。*
+
+如果內核以任何方式得到增強,那麼問題報告被忽略或拒絕的風險就會急劇增加。這就
+是爲什麼您應該刪除或禁用像akmods和DKMS這樣的機制:這些機制會自動構建額外內核
+模塊,例如當您安裝新的Linux內核或第一次引導它時。也要記得同時刪除他們可能安裝
+的任何模塊。然後重新啓動再繼續。
+
+注意,你可能不知道你的系統正在使用這些解決方案之一:當你安裝 Nvidia 專有圖
+形驅動程序、VirtualBox 或其他需要 Linux 內核以外的模塊支持的軟件時,它們通
+常會靜默設置。這就是爲什麼你可能需要卸載這些軟件的軟件包,以擺脫任何第三方
+內核模塊。
+
+
+檢查“污染”標誌
+----------------
+
+ *當問題發生時,檢查您的內核是否被“污染”,因爲使內核設置這個標誌的事件可
+ 能會導致您面臨的問題。*
+
+當某些可能會導致看起來完全不相關的後續錯誤的事情發生時,內核會用“污染
+(taint)”標誌標記自己。如果您的內核受到污染,那麼您面臨的可能是這樣的錯誤。
+因此在投入更多時間到這個過程中之前,儘早排除此情況可能對你有好處。這是這個
+步驟出現在這裏的唯一原因,因爲這個過程稍後會告訴您安裝最新的主線內核;然後
+您將需要再次檢查污染標誌,因爲當它出問題的時候內核報告會關注它。
+
+在正在運行的系統上檢查內核是否污染非常容易:如果 ``cat /proc/sys/kernel/tainted``
+返回“0”,那麼內核沒有被污染,一切正常。在某些情況下無法檢查該文件;這就是
+爲什麼當內核報告內部問題(“kernel bug”)、可恢復錯誤(“kernel Oops”)或停止
+操作前不可恢復的錯誤(“kernel panic”)時,它也會提到污染狀態。當其中一個錯
+誤發生時,查看打印的錯誤消息的頂部,搜索以“CPU:”開頭的行。如果發現問題時內
+核未被污染,那麼它應該以“Not infected”結束;如果你看到“Tainted:”且後跟一些
+空格和字母,那就被污染了。
+
+如果你的內核被污染了,請閱讀 Documentation/translations/zh_CN/admin-guide/tainted-kernels.rst
+以找出原因。設法消除污染因素。通常是由以下三種因素之一引起的:
+
+ 1. 發生了一個可恢復的錯誤(“kernel Oops”),內核污染了自己,因爲內核知道在
+ 此之後它可能會出現奇怪的行爲錯亂。在這種情況下,檢查您的內核或系統日誌,
+ 並尋找以下列文字開頭的部分::
+
+ Oops: 0000 [#1] SMP
+
+ 如方括號中的“#1”所示,這是自啓動以來的第一次Oops。每個Oops和此後發生的
+ 任何其他問題都可能是首個Oops的後續問題,即使這兩個問題看起來完全不相關。
+ 通過消除首個Oops的原因並在之後復現該問題,可以排除這種情況。有時僅僅
+ 重新啓動就足夠了,有時更改配置後重新啓動可以消除Oops。但是在這個流程中
+ 不要花費太多時間在這一點上,因爲引起Oops的原因可能已經在您稍後將按流程
+ 安裝的新Linux內核版本中修復了。
+
+ 2. 您的系統使用的軟件安裝了自己的內核模塊,例如Nvidia的專有圖形驅動程序或
+ VirtualBox。當內核從外部源(即使它們是開源的)加載此類模塊時,它會污染
+ 自己:它們有時會在不相關的內核區域導致錯誤,從而可能導致您面臨的問題。
+ 因此,當您想要向Linux內核開發人員報告問題時,您必須阻止這些模塊加載。
+ 大多數情況下最簡單的方法是:臨時卸載這些軟件,包括它們可能已經安裝的任
+ 何模塊。之後重新啓動。
+
+ 3. 當內核加載駐留在Linux內核源代碼staging樹中的模塊時,它也會污染自身。這
+ 是一個特殊的區域,代碼(主要是驅動程序)還沒有達到正常Linux內核的質量
+ 標準。當您報告此種模塊的問題時,內核受到污染顯然是沒有問題的;只需確保
+ 問題模塊是造成污染的唯一原因。如果問題發生在一個不相關的區域,重新啓動
+ 並通過指定 ``foo.blacklist=1`` 作爲內核參數臨時阻止該模塊被加載(用有
+ 問題的模塊名替換“foo”)。
+
+
+記錄如何重現問題
+------------------
+
+ *粗略地寫下如何重現這個問題。如果您同時處理多個問題,請爲每個問題單獨寫
+ 註釋,並確保它們在新啓動的系統上獨立出現。這是必要的,因爲每個問題都需
+ 要分別報告給內核開發人員,除非它們嚴重糾纏在一起。*
+
+如果你同時處理多個問題,必須分別報告每個問題,因爲它們可能由不同的開發人員
+處理。在一份報告中描述多種問題,也會讓其他人難以將其分開。因此只有在問題嚴
+重糾纏的情況下,才能將問題合併在一份報告中。
+
+此外,在報告過程中,你必須測試該問題是否發生在其他內核版本上。因此,如果您
+知道如何在一個新啓動的系統上快速重現問題,將使您的工作更加輕鬆。
+
+注意:報告只發生過一次的問題往往是沒有結果的,因爲它們可能是由於宇宙輻射導
+致的位翻轉。所以你應該嘗試通過重現問題來排除這種情況,然後再繼續。如果你有
+足夠的經驗來區分由於硬件故障引起的一次性錯誤和難以重現的罕見內核問題,可以
+忽略這個建議。
+
+
+穩定版或長期支持內核的迴歸?
+-----------------------------
+
+ *如果您正面臨穩定版或長期支持版本線的迴歸(例如從5.10.4更新到5.10.5時出現
+ 故障),請查看後文“報告穩定版和長期支持內核線的迴歸”小節。*
+
+穩定版和長期支持內核版本線中的迴歸是Linux開發人員非常希望解決的問題,這樣的
+問題甚至比主線開發分支中的迴歸更不應出現,因爲它們會很快影響到很多人。開發人員
+希望儘快瞭解此類問題,因此有一個簡化流程來報告這些問題。注意,使用更新內核版
+本線的迴歸(比如從5.9.15切換到5.10.5時出現故障)不符合條件。
+
+
+你需要將問題報告到何處
+------------------------
+
+ *定位可能引起問題的驅動程序或內核子系統。找出其開發人員期望的報告的方式
+ 和位置。注意:大多數情況下不會是bugzilla.kernel.org,因爲問題通常需要通
+ 過郵件發送給維護人員和公共郵件列表。*
+
+將報告發送給合適的人是至關重要的,因爲Linux內核是一個大項目,大多數開發人員
+只熟悉其中的一小部分。例如,相當多的程序員只關心一個驅動程序,比如一個WiFi
+芯片驅動程序;它的開發人員可能對疏遠的或不相關的“子系統”(如TCP堆棧、
+PCIe/PCI子系統、內存管理或文件系統)的內部知識瞭解很少或完全不瞭解。
+
+問題在於:Linux內核缺少一個,可以簡單地將問題歸檔並讓需要了解它的開發人員了
+解它的,中心化缺陷跟蹤器。這就是爲什麼你必須找到正確的途徑來自己報告問題。
+您可以在腳本的幫助下做到這一點(見下文),但它主要針對的是內核開發人員和專
+家。對於其他人來說,MAINTAINERS(維護人員)文件是更好的選擇。
+
+如何閱讀MAINTAINERS維護者文件
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+爲了說明如何使用 :ref:`MAINTAINERS <maintainers>` 文件,讓我們假設您的筆記
+本電腦中的WiFi在更新內核後突然出現了錯誤行爲。這種情況下可能是WiFi驅動的問
+題。顯然,它也可能由於驅動基於的某些代碼,但除非你懷疑有這樣的東西會附着在
+驅動程序上。如果真的是其他的問題,驅動程序的開發人員會讓合適的人蔘與進來。
+
+遺憾的是,沒有通用且簡單的辦法來檢查哪個代碼驅動了特定硬件組件。
+
+在WiFi驅動出現問題的情況下,你可能想查看 ``lspci -k`` 的輸出,因爲它列出了
+PCI/PCIe總線上的設備和驅動它的內核模塊::
+
+ [user@something ~]$ lspci -k
+ [...]
+ 3a:00.0 Network controller: Qualcomm Atheros QCA6174 802.11ac Wireless Network Adapter (rev 32)
+ Subsystem: Bigfoot Networks, Inc. Device 1535
+ Kernel driver in use: ath10k_pci
+ Kernel modules: ath10k_pci
+ [...]
+
+但如果你的WiFi芯片通過USB或其他內部總線連接,這種方法就行不通了。在這種情況
+下,您可能需要檢查您的WiFi管理器或 ``ip link`` 的輸出。尋找有問題的網絡接口
+的名稱,它可能類似於“wlp58s0”。此名稱可以用來找到驅動它的模塊::
+
+ [user@something ~]$ realpath --relative-to=/sys/module//sys/class/net/wlp58s0/device/driver/module
+ ath10k_pci
+
+如果這些技巧不能進一步幫助您,請嘗試在網上搜索如何縮小相關驅動程序或子系統
+的範圍。如果你不確定是哪一個:試着猜一下,即使你猜得不好,也會有人會幫助你
+的。
+
+一旦您知道了相應的驅動程序或子系統,您就希望在MAINTAINERS文件中搜索它。如果
+是“ath10k_pci”,您不會找到任何東西,因爲名稱太具體了。有時你需要在網上尋找
+幫助;但在此之前,請嘗試使用一個稍短或修改過的名稱來搜索MAINTAINERS文件,因
+爲這樣你可能會發現類似這樣的東西::
+
+ QUALCOMM ATHEROS ATH10K WIRELESS DRIVER
+ Mail: A. Some Human <shuman@example.com>
+ Mailing list: ath10k@lists.infradead.org
+ Status: Supported
+ Web-page: https://wireless.wiki.kernel.org/en/users/Drivers/ath10k
+ SCM: git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
+ Files: drivers/net/wireless/ath/ath10k/
+
+注意:如果您閱讀在Linux源代碼樹的根目錄中找到的原始維護者文件,則行描述將是
+縮寫。例如,“Mail:(郵件)”將是“M:”,“Mailing list:(郵件列表)”將是“L”,
+“Status:(狀態)”將是“S:”。此文件頂部有一段解釋了這些和其他縮寫。
+
+首先查看“Status”狀態行。理想情況下,它應該得到“Supported(支持)”或
+“Maintained(維護)”。如果狀態爲“Obsolete(過時的)”,那麼你在使用一些過時的
+方法,需要轉換到新的解決方案上。有時候,只有在感到有動力時,纔會有人爲代碼
+提供“Odd Fixes”。如果碰見“Orphan”,你就完全不走運了,因爲再也沒有人關心代碼
+了,只剩下這些選項:準備好與問題共存,自己修復它,或者找一個願意修復它的程序員。
+
+檢查狀態後,尋找以“bug:”開頭的一行:它將告訴你在哪裏可以找到子系統特定的缺
+陷跟蹤器來提交你的問題。上面的例子沒有此行。大多數部分都是這樣,因爲 Linux
+內核的開發完全是由郵件驅動的。很少有子系統使用缺陷跟蹤器,且其中只有一部分
+依賴於 bugzilla.kernel.org。
+
+在這種以及其他很多情況下,你必須尋找以“Mail:”開頭的行。這些行提到了特定代碼
+的維護者的名字和電子郵件地址。也可以查找以“Mailing list:”開頭的行,它告訴你
+開發代碼的公共郵件列表。你的報告之後需要通過郵件發到這些地址。另外,對於所有
+通過電子郵件發送的問題報告,一定要抄送 Linux Kernel Mailing List(LKML)
+<linux-kernel@vger.kernel.org>。在以後通過郵件發送問題報告時,不要遺漏任何
+一個郵件列表!維護者都是大忙人,可能會把一些工作留給子系統特定列表上的其他開
+發者;而 LKML 很重要,因爲需要一個可以找到所有問題報告的地方。
+
+
+藉助腳本找到維護者
+~~~~~~~~~~~~~~~~~~~~
+
+對於手頭有Linux源碼的人來說,有第二個可以找到合適的報告地點的選擇:腳本
+“scripts/get_maintainer.pl”,它嘗試找到所有要聯繫的人。它會查詢MAINTAINERS
+文件,並需要用相關源代碼的路徑來調用。對於編譯成模塊的驅動程序,經常可以用
+這樣的命令找到::
+
+ $ modinfo ath10k_pci | grep filename | sed 's!/lib/modules/.*/kernel/!!; s!filename:!!; s!\.ko\(\|\.xz\)!!'
+ drivers/net/wireless/ath/ath10k/ath10k_pci.ko
+
+將其中的部分內容傳遞給腳本::
+
+ $ ./scripts/get_maintainer.pl -f drivers/net/wireless/ath/ath10k*
+ Some Human <shuman@example.com> (supporter:QUALCOMM ATHEROS ATH10K WIRELESS DRIVER)
+ Another S. Human <asomehuman@example.com> (maintainer:NETWORKING DRIVERS)
+ ath10k@lists.infradead.org (open list:QUALCOMM ATHEROS ATH10K WIRELESS DRIVER)
+ linux-wireless@vger.kernel.org (open list:NETWORKING DRIVERS (WIRELESS))
+ netdev@vger.kernel.org (open list:NETWORKING DRIVERS)
+ linux-kernel@vger.kernel.org (open list)
+
+不要把你的報告發給所有的人。發送給維護者,腳本稱之爲“supporter:”;另外抄送
+代碼最相關的郵件列表,以及 Linux 內核郵件列表(LKML)。在此例中,你需要將報
+告發送給 “Some Human <shuman@example.com>” ,並抄送
+“ath10k@lists.infradead.org”和“linux-kernel@vger.kernel.org”。
+
+注意:如果你用 git 克隆了 Linux 源代碼,你可能需要用--git 再次調用
+get_maintainer.pl。腳本會查看提交歷史,以找到最近哪些人蔘與了相關代碼的編寫,
+因爲他們可能會提供幫助。但要小心使用這些結果,因爲它很容易讓你誤入歧途。
+例如,這種情況常常會發生在很少被修改的地方(比如老舊的或未維護的驅動程序):
+有時這樣的代碼會在樹級清理期間被根本不關心此驅動程序的開發者修改。
+
+
+搜索現有報告(第二部分)
+--------------------------
+
+ *在缺陷追蹤器或問題相關郵件列表的存檔中徹底搜索可能與您的問題匹配的報告。
+ 如果找到匹配的報告,請加入討論而不是發送新報告。*
+
+如前所述:報告一個別人已經提出的問題,對每個人來說都是浪費時間,尤其是作爲報告
+人的你。這就是爲什麼你應該再次搜索現有的報告。現在你已經知道問題需要報告到哪裏。
+如果是郵件列表,那麼一般在 `lore.kernel.org <https://lore.kernel.org/>`_ 可以
+找到相應存檔。
+
+但有些列表運行在其他地方。例如前面步驟中當例子的ath10k WiFi驅動程序就是這種
+情況。但是你通常可以在網上很容易地找到這些列表的檔案。例如搜索“archive
+ath10k@lists.infradead.org”,將引導您到ath10k郵件列表的信息頁,該頁面頂部鏈接
+到其 `列表存檔 <https://lists.infradead.org/pipermail/ath10k/>`_ 。遺憾的是,
+這個列表和其他一些列表缺乏搜索其存檔的功能。在這種情況下可以使用常規的互聯網
+搜索引擎,並添加類似“site:lists.infadead.org/pipermail/ath10k/”這
+樣的搜索條件,這會把結果限制在該鏈接中的檔案。
+
+也請進一步搜索網絡、LKML和bugzilla.kernel.org網站。如果你的報告需要發送到缺陷
+跟蹤器中,那麼您可能還需要檢查子系統的郵件列表存檔,因爲可能有人只在那裏報告了它。
+
+有關如何搜索以及在找到匹配報告時如何操作的詳細信息,請參閱上面的“搜索現有報告
+(第一部分)”。
+
+不要急着完成報告過程的這一步:花30到60分鐘甚至更多的時間可以爲你和其他人節省 /
+減少相當多的時間和麻煩。
+
+
+安裝一個新的內核進行測試
+--------------------------
+
+ *除非您已經在運行最新的“主線”Linux內核,否則最好在報告流程前安裝它。在
+ 某些情況下,使用最新的“穩定版”Linux進行測試和報告也是可以接受的替代方案;
+ 在合併窗口期間,這實際上可能是最好的方法,但在開發階段最好還是暫停幾天。
+ 無論你選擇什麼版本,最好使用“普通”構建。忽略這些建議會大大增加您的報告
+ 被拒絕或忽略的風險。*
+
+正如第一步的詳細解釋中所提到的:與大多數程序員一樣,與大多數程序員一樣,Linux
+內核開發人員不喜歡花時間處理他們維護的源代碼中根本不會發生的問題的報告。這隻
+會浪費每個人的時間,尤其是你的時間。這就是爲什麼在報告問題之前,您必須先確認
+問題仍然存在於最新的上游代碼中,這符合每個人的利益。您可以忽略此建議,但如前
+所述:這樣做會極大地增加問題報告被拒絕或被忽略的風險。
+
+內核“最新上游”的範圍通常指:
+
+ * 安裝一個主線內核;最新的穩定版內核也可以是一個選擇,但大多數時候都最好避免。
+ 長期支持內核(有時稱爲“LTS內核”)不適合此流程。下一小節將更詳細地解釋所有
+ 這些。
+
+ * 下一小節描述獲取和安裝這樣一個內核的方法。它還指出了使用預編譯內核是可以的,
+ 但普通的內核更好,這意味着:它是直接使用從 `kernel.org <https://kernel.org/>`_
+ 獲得的Linux源代碼構建並且沒有任何方式修改或增強。
+
+
+選擇適合測試的版本
+~~~~~~~~~~~~~~~~~~~~
+
+前往 `kernel.org <https://kernel.org/>`_ 來決定使用哪個版本。忽略那個寫着
+“Latest release最新版本”的巨大黃色按鈕,往下看有一個表格。在表格的頂部,你會
+看到一行以“mainline”開頭的字樣,大多數情況下它會指向一個版本號類似“5.8-rc2”
+的預發佈版本。如果是這樣的話,你將需要使用這個主線內核進行測試。不要讓“rc”
+嚇到你,這些“開發版內核”實際上非常可靠——而且你已經按照上面的指示做了備份,
+不是嗎?
+
+大概每九到十週,“mainline”可能會給你指出一個版本號類似“5.7”的正式版本。如果
+碰見這種情況,請考慮暫停報告過程,直到下一個版本的第一個預發佈(5.8-rc1)出
+現在 `kernel.org <https://kernel.org/>`_ 上。這是因爲 Linux 的開發週期正在
+兩週的“合併窗口”內。大部分的改動和所有干擾性的改動都會在這段時間內被合併到
+下一個版本中。在此期間使用主線是比較危險的。內核開發者通常也很忙,可能沒有
+多餘的時間來處理問題報告。這也是很有可能在合併窗口中應用了許多修改來修復你
+所面臨的問題;這就是爲什麼你很快就得用一個新的內核版本重新測試,就像下面“發
+布報告後的責任”一節中所述的那樣。
+
+這就是爲什麼要等到合併窗口結束後纔去做。但是如果你處理的是一些不應該等待的
+東西,則無需這樣做。在這種情況下,可以考慮通過 git 獲取最新的主線內核(見下
+文),或者使用 kernel.org 上提供的最新穩定版本。如果 mainline 因爲某些原因
+不無法正常工作,那麼使用它也是可以接受的。總的來說:用它來重現問題也比完全
+不報告問題要好。
+
+最好避免在合併窗口外使用最新的穩定版內核,因爲所有修復都必須首先應用於主線。
+這就是爲什麼檢查最新的主線內核是如此重要:你希望看到在舊版本線修復的任何問題
+需要先在主線修復,然後才能得到回傳,這可能需要幾天或幾周。另一個原因是:您
+希望的修復對於回傳來說可能太難或太冒險;因此再次報告問題不太可能改變任何事情。
+
+這些方面也部分表明了爲什麼長期支持內核(有時稱爲“LTS內核”)不適合報告流程:
+它們與當前代碼的距離太遠。因此,先去測試主線,然後再按流程走:如果主線沒有
+出現問題,流程將指導您如何在舊版本線中修復它。
+
+如何獲得新的 Linux 內核
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+你可以使用預編譯或自編譯的內核進行測試;如果你選擇後者,可以使用 git 獲取源
+代碼,或者下載其 tar 存檔包。
+
+**使用預編譯的內核** :這往往是最快速、最簡單、最安全的方法——尤其是在你不熟
+悉 Linux 內核的情況下。問題是:發行商或附加存儲庫提供的大多數版本都是從修改
+過的Linux源代碼構建的。因此它們不是普通的,通常不適合於測試和問題報告:這些
+更改可能會導致您面臨的問題或以某種方式影響問題。
+
+但是如果您使用的是流行的Linux發行版,那麼您就很幸運了:對於大部分的發行版,
+您可以在網上找到包含最新主線或穩定版本Linux內核包的存儲庫。使用這些是完全可
+以的,只要從存儲庫的描述中確認它們是普通的或者至少接近普通。此外,請確保軟件
+包包含kernel.org上提供的最新版本內核。如果這些軟件包的時間超過一週,那麼它們
+可能就不合適了,因爲新的主線和穩定版內核通常至少每週發佈一次。
+
+請注意,您以後可能需要手動構建自己的內核:有時這是調試或測試修復程序所必需的,
+如後文所述。還要注意,預編譯的內核可能缺少在出現panic、Oops、warning或BUG時
+解碼內核打印的消息所需的調試符號;如果您計劃解碼這些消息,最好自己編譯內核
+(有關詳細信息,請參閱本小節結尾和“解碼失敗信息”小節)。
+
+**使用git** :熟悉 git 的開發者和有經驗的 Linux 用戶通常最好直接從
+`kernel.org 上的官方開發倉庫
+<https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/>`_
+中獲取最新的 Linux 內核源代碼。這些很可能比最新的主線預發佈版本更新一些。不
+用擔心:它們和正式的預發佈版本一樣可靠,除非內核的開發週期目前正處於合併窗
+口中。不過即便如此,它們也是相當可靠的。
+
+**常規方法** :不熟悉 git 的人通常最好從 `kernel.org <https://kernel.org/>`_
+下載源碼的tar 存檔包。
+
+如何實際構建一個內核並不在這裏描述,因爲許多網站已經解釋了必要的步驟。如果
+你是新手,可以考慮按照那些建議使用 ``make localmodconfig`` 來做,它將嘗試獲
+取你當前內核的配置,然後根據你的系統進行一些調整。這樣做並不能使編譯出來的
+內核更好,但可以更快地編譯。
+
+注意:如果您正在處理來自內核的pannc、Oops、warning或BUG,請在配置內核時嘗試
+啓用 CONFIG_KALLSYMS 選項。此外,還可以啓用 CONFIG_DEBUG_KERNEL 和
+CONFIG_DEBUG_INFO;後者是相關選項,但只有啓用前者才能開啓。請注意,
+CONFIG_DEBUG_INFO 會需要更多儲存空間來構建內核。但這是值得的,因爲這些選項將
+允許您稍後精確定位觸發問題的確切代碼行。下面的“解碼失敗信息”一節對此進行了更
+詳細的解釋。
+
+但請記住:始終記錄遇到的問題,以防難以重現。發送未解碼的報告總比不報告要好。
+
+
+檢查“污染”標誌
+----------------
+
+ *確保您剛剛安裝的內核在運行時不會“污染”自己。*
+
+正如上面已經詳細介紹過的:當發生一些可能會導致一些看起來完全不相關的後續錯
+誤的事情時,內核會設置一個“污染”標誌。這就是爲什麼你需要檢查你剛剛安裝的內
+核是否有設置此標誌。如果有的話,幾乎在任何情況下你都需要在報告問題之前先消
+除它。詳細的操作方法請看上面的章節。
+
+
+用新內核重現問題
+------------------
+
+ *在您剛剛安裝的內核中復現這個問題。如果它沒有出現,請查看下方只發生在
+ 穩定版和長期支持內核的問題的說明。*
+
+檢查這個問題是否發生在你剛剛安裝的新 Linux 內核版本上。如果新內核已經修復了,
+可以考慮使用此版本線,放棄報告問題。但是請記住,只要它沒有在 `kernel.org
+<https://kernel.org/>`_ 的穩定版和長期版(以及由這些版本衍生出來的廠商內核)
+中得到修復,其他用戶可能仍然會受到它的困擾。如果你喜歡使用其中的一個,或
+者只是想幫助它們的用戶,請前往下面的“報告只發生在較舊內核版本線的問題”一節。
+
+
+優化復現問題的描述
+--------------------
+
+ *優化你的筆記:試着找到並寫出最直接的復現問題的方法。確保最終結果包含所
+ 有重要的細節,同時讓第一次聽說的人容易閱讀和理解。如果您在此過程中學到
+ 了一些東西,請考慮再次搜索關於該問題的現有報告。*
+
+過於複雜的報告會讓別人很難理解。因此請儘量找到一個可以直接描述、易於以書面
+形式理解的再現方法。包含所有重要的細節,但同時也要儘量保持簡短。
+
+在這在前面的步驟中,你很可能已經瞭解了一些關於你所面臨的問題的點。利用這些
+知識,再次搜索可以轉而加入的現有報告。
+
+
+解碼失敗信息
+-------------
+
+ *如果失敗涉及“panic”、“Oops”、“warning”或“BUG”,請考慮解碼內核日誌以查找
+ 觸發錯誤的代碼行。*
+
+當內核檢測到內部問題時,它會記錄一些有關已執行代碼的信息。這使得在源代碼中精
+確定位觸發問題的行並顯示如何調用它成爲可能。但只有在配置內核時啓用了
+CONFIG_DEBUG_INFO 和 CONFIG_KALLSYMS選項時,這種方法才起效。如果已啓用此選項,
+請考慮解碼內核日誌中的信息。這將使我們更容易理解是什麼導致了“panic”、“Oops”、
+“warning”或“BUG”,從而增加了有人提供修復的幾率。
+
+解碼可以通過Linux源代碼樹中的腳本來完成。如果您運行的內核是之前自己編譯的,
+這樣這樣調用它::
+
+ [user@something ~]$ sudo dmesg | ./linux-5.10.5/scripts/decode_stacktrace.sh ./linux-5.10.5/vmlinux
+ /usr/lib/debug/lib/modules/5.10.10-4.1.x86_64/vmlinux /usr/src/kernels/5.10.10-4.1.x86_64/
+
+如果您運行的是打包好的普通內核,則可能需要安裝帶有調試符號的相應包。然後按以下
+方式調用腳本(如果發行版未打包,則可能需要從Linux源代碼獲取)::
+
+ [user@something ~]$ sudo dmesg | ./linux-5.10.5/scripts/decode_stacktrace.sh \
+ /usr/lib/debug/lib/modules/5.10.10-4.1.x86_64/vmlinux /usr/src/kernels/5.10.10-4.1.x86_64/
+
+腳本將解碼如下的日誌行,這些日誌行顯示內核在發生錯誤時正在執行的代碼的地址::
+
+ [ 68.387301] RIP: 0010:test_module_init+0x5/0xffa [test_module]
+
+解碼之後,這些行將變成這樣::
+
+ [ 68.387301] RIP: 0010:test_module_init (/home/username/linux-5.10.5/test-module/test-module.c:16) test_module
+
+在本例中,執行的代碼是從文件“~/linux-5.10.5/test-module/test-module.c”構建的,
+錯誤出現在第16行的指令中。
+
+該腳本也會如此解碼以“Call trace”開頭的部分中提到的地址,該部分顯示出現問題的
+函數的路徑。此外,腳本還會顯示內核正在執行的代碼部分的彙編輸出。
+
+注意,如果你沒法做到這一點,只需跳過這一步,並在報告中說明原因。如果你幸運的
+話,可能無需解碼。如果需要的話,也許有人會幫你做這件事情。還要注意,這只是解
+碼內核堆棧跟蹤的幾種方法之一。有時需要採取不同的步驟來檢索相關的詳細信息。
+別擔心,如果您碰到的情況需要這樣做,開發人員會告訴您該怎麼做。
+
+
+對迴歸的特別關照
+-----------------
+
+ *如果您的問題是迴歸問題,請儘可能縮小引入問題時的範圍。*
+
+Linux 首席開發者 Linus Torvalds 認爲 Linux 內核永遠不應惡化,這就是爲什麼他
+認爲迴歸是不可接受的,並希望看到它們被迅速修復。這就是爲什麼引入了迴歸的改
+動導致的問題若無法通過其他方式快速解決,通常會被迅速撤銷。因此,報告迴歸有
+點像“王炸”,會迅速得到修復。但要做到這一點,需要知道導致迴歸的變化。通常情
+況下,要由報告者來追查罪魁禍首,因爲維護者往往沒有時間或手頭設置不便來自行
+重現它。
+
+有一個叫做“二分”的過程可以來尋找變化,這在
+Documentation/translations/zh_CN/admin-guide/bug-bisect.rst 文檔中進行了詳細
+的描述,這個過程通常需要你構建十到二十個內核鏡像,每次都嘗試在構建下一個鏡像
+之前重現問題。是的,這需要花費一些時間,但不用擔心,它比大多數人想象的要快得多。
+多虧了“binary search二分搜索”,這將引導你在源代碼管理系統中找到導致迴歸的提交。
+一旦你找到它,就在網上搜索其主題、提交ID和縮短的提交ID(提交ID的前12個字符)。
+如果有的話,這將引導您找到關於它的現有報告。
+
+需要注意的是,二分法需要一點竅門,不是每個人都懂得訣竅,也需要相當多的努力,
+不是每個人都願意投入。儘管如此,還是強烈建議自己進行一次二分。如果你真的
+不能或者不想走這條路,至少要找出是哪個主線內核引入的迴歸。比如說從 5.5.15
+切換到 5.8.4 的時候出現了一些問題,那麼至少可以嘗試一下相近的所有的主線版本
+(5.6、5.7 和 5.8)來檢查它是什麼時候出現的。除非你想在一個穩定版或長期支持
+內核中找到一個迴歸,否則要避免測試那些編號有三段的版本(5.6.12、5.7.8),因
+爲那會使結果難以解釋,可能會讓你的測試變得無用。一旦你找到了引入迴歸的主要
+版本,就可以放心地繼續報告了。但請記住:在不知道罪魁禍首的情況下,開發人員
+是否能夠提供幫助取決於手頭的問題。有時他們可能會從報告中確認是什麼出現了問
+題,並能修復它;有時他們可能無法提供幫助,除非你進行二分。
+
+當處理迴歸問題時,請確保你所面臨的問題真的是由內核引起的,而不是由其他東西
+引起的,如上文所述。
+
+在整個過程中,請記住:只有當舊內核和新內核的配置相似時,問題纔算迴歸。這可以
+通過 ``make olddefconfig`` 來實現,詳細解釋參見
+Documentation/admin-guide/reporting-regressions.rst ;它還提供了大量其他您
+可能希望瞭解的有關回歸的信息。
+
+
+撰寫併發送報告
+---------------
+
+ *通過詳細描述問題來開始編寫報告。記得包括以下條目:您爲復現而安裝的最新
+ 內核版本、使用的Linux發行版以及關於如何復現該問題的說明。如果可能,將內
+ 核構建配置(.config)和 ``dmesg`` 的輸出放在網上的某個地方,並鏈接到它。
+ 包含或上傳所有其他可能相關的信息,如Oops的輸出/截圖或來自 ``lspci``
+ 的輸出。一旦你寫完了這個主要部分,請在上方插入一個正常長度的段落快速概
+ 述問題和影響。再在此之上添加一個簡單描述問題的句子,以得到人們的閱讀。
+ 現在給出一個更短的描述性標題或主題。然後就可以像MAINTAINERS文件告訴你的
+ 那樣發送或提交報告了,除非你在處理一個“高優先級問題”:它們需要按照下面
+ “高優先級問題的特殊處理”所述特別關照。*
+
+現在你已經準備好了一切,是時候寫你的報告了。上文前言中鏈接的三篇文檔對如何
+寫報告做了部分解釋。這就是爲什麼本文將只提到一些基本的內容以及 Linux 內核特
+有的東西。
+
+有一點是符合這兩類的:你的報告中最關鍵的部分是標題/主題、第一句話和第一段。
+開發者經常會收到許多郵件。因此,他們往往只是花幾秒鐘的時間瀏覽一下郵件,然
+後再決定繼續下一封或仔細查看。因此,你報告的開頭越好,有人研究並幫助你的機
+會就越大。這就是爲什麼你應該暫時忽略他們,先寫出詳細的報告。;-)
+
+每份報告都應提及的事項
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+詳細描述你的問題是如何發生在你安裝的新純淨內核上的。試着包含你之前寫的和優
+化過的分步說明,概述你和其他人如何重現這個問題;在極少數無法重現的情況下,
+儘量描述你做了什麼來觸發它。
+
+還應包括其他人爲了解該問題及其環境而可能需要的所有相關信息。實際需要的東西
+在很大程度上取決於具體問題,但有些事項你總是應該包括在內:
+
+ * ``cat /proc/version`` 的輸出,其中包含 Linux 內核版本號和構建時的編譯器。
+
+ * 機器正在運行的 Linux 發行版( ``hostnamectl | grep “Operating System“`` )
+
+ * CPU 和操作系統的架構( ``uname -mi`` )
+
+ * 如果您正在處理迴歸,並進行了二分,請提及導致迴歸的變更的主題和提交ID。
+
+許多情況下,讓讀你報告的人多瞭解兩件事也是明智之舉:
+
+ * 用於構建 Linux 內核的配置(“.config”文件)
+
+ * 內核的信息,你從 ``dmesg`` 得到的信息寫到一個文件裏。確保它以像“Linux
+ version 5.8-1 (foobar@example.com) (gcc (GCC) 10.2.1, GNU ld version
+ 2.34) #1 SMP Mon Aug 3 14:54:37 UTC 2020”這樣的行開始,如果沒有,那麼第
+ 一次啓動階段的重要信息已經被丟棄了。在這種情況下,可以考慮使用
+ ``journalctl -b 0 -k`` ;或者你也可以重啓,重現這個問題,然後調用
+ ``dmesg`` 。
+
+這兩個文件很大,所以直接把它們放到你的報告中是個壞主意。如果你是在缺陷跟蹤
+器中提交問題,那麼將它們附加到工單中。如果你通過郵件報告問題,不要用附件附
+上它們,因爲那會使郵件變得太大,可以按下列之一做:
+
+ * 將文件上傳到某個公開的地方(你的網站,公共文件粘貼服務,在
+ `bugzilla.kernel.org <https://bugzilla.kernel.org/>`_ 上創建的工單……),
+ 並在你的報告中放上鍊接。理想情況下請使用允許這些文件保存很多年的地方,因
+ 爲它們可能在很多年後對別人有用;例如 5 年或 10 年後,一個開發者正在修改
+ 一些代碼,而這些代碼正是爲了修復你的問題。
+
+ * 把文件放在一邊,然後說明你會在他人回覆時再單獨發送。只要記得報告發出去後,
+ 真正做到這一點就可以了。;-)
+
+提供這些東西可能是明智的
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+根據問題的不同,你可能需要提供更多的背景數據。這裏有一些關於提供什麼比較好
+的建議:
+
+ * 如果你處理的是內核的“warning”、“OOPS”或“panic”,請包含它。如果你不能複製
+ 粘貼它,試着用netconsole網絡終端遠程跟蹤或者至少拍一張屏幕的照片。
+
+ * 如果問題可能與你的電腦硬件有關,請說明你使用的是什麼系統。例如,如果你的
+ 顯卡有問題,請提及它的製造商,顯卡的型號,以及使用的芯片。如果是筆記本電
+ 腦,請提及它的型號名稱,但儘量確保意義明確。例如“戴爾 XPS 13”就不很明確,
+ 因爲它可能是 2012 年的那款,那款除了看起來和現在銷售的沒有什麼不同之外,
+ 兩者沒有任何共同之處。因此,在這種情況下,要加上準確的型號,例如 2019
+ 年內推出的 XPS 13 型號爲“9380”或“7390”。像“聯想 Thinkpad T590”這樣的名字
+ 也有些含糊不清:這款筆記本有帶獨立顯卡和不帶的子型號,所以要儘量找到準確
+ 的型號名稱或註明主要部件。
+
+ * 說明正在使用的相關軟件。如果你在加載模塊時遇到了問題,你要說明正在使用的
+ kmod、systemd 和 udev 的版本。如果其中一個 DRM 驅動出現問題,你要說明
+ libdrm 和 Mesa 的版本;還要說明你的 Wayland 合成器或 X-Server 及其驅動。
+ 如果你有文件系統問題,請註明相應的文件系統實用程序的版本(e2fsprogs,
+ btrfs-progs, xfsprogs……)。
+
+ * 從內核中收集可能有用的額外信息。例如, ``lspci -nn`` 的輸出可以幫助別人
+ 識別你使用的硬件。如果你的硬件有問題,你甚至可以給出 ``sudo lspci -vvv``
+ 的結果,因爲它提供了組件是如何配置的信息。對於一些問題,可能最好包含
+ ``/proc/cpuinfo`` , ``/proc/ioports`` , ``/proc/iomem`` ,
+ ``/proc/modules`` 或 ``/proc/scsi/scsi`` 等文件的內容。一些子系統還提
+ 供了收集相關信息的工具。 ``alsa-info.sh`` `就是這樣一個工具,它是音頻/聲
+ 音子系統開發者提供的 <https://www.alsa-project.org/wiki/AlsaInfo>`_ 。
+
+這些例子應該會給你一些知識點,讓你知道附上什麼數據可能是明智的,但你自己也
+要想一想,哪些數據對別人會有幫助。不要太擔心忘記一些東西,因爲開發人員會要
+求提供他們需要的額外細節。但從一開始就把所有重要的東西都提供出來,會增加別
+人仔細查看的機會。
+
+
+重要部分:報告的開頭
+~~~~~~~~~~~~~~~~~~~~~~
+
+現在你已經準備好了報告的詳細部分,讓我們進入最重要的部分:開頭幾句。現在到
+報告的最前面,在你剛纔寫的部分之前加上類似“The detailed description:”(詳細
+描述)這樣的內容,並在最前面插入兩個新行。現在寫一個正常長度的段落,大致概
+述這個問題。去掉所有枯燥的細節,把重點放在讀者需要知道的關鍵部分,以讓人了
+解這是怎麼回事;如果你認爲這個缺陷影響了很多用戶,就提一下這點來吸引大家關
+注。
+
+做好這一點後,在頂部再插入兩行,寫一句話的摘要,快速解釋報告的內容。之後你
+要更加抽象,爲報告寫一個更短的主題/標題。
+
+現在你已經寫好了這部分,請花點時間來優化它,因爲它是你的報告中最重要的部分:
+很多人會先讀這部分,然後纔會決定是否值得花時間閱讀其他部分。
+
+現在就像 :ref:`MAINTAINERS <maintainers>` 維護者文件告訴你的那樣發送或提交
+報告,除非它是前面概述的那些“高優先級問題”之一:在這種情況下,請先閱讀下一
+小節,然後再發送報告。
+
+高優先級問題的特殊處理
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+高優先級問題的報告需要特殊處理。
+
+**非常嚴重的缺陷** :確保在主題或工單標題以及第一段中明顯標出 severeness
+(非常嚴重的)。
+
+**迴歸** :報告的主題應以“[REGRESSION]”開頭。
+
+如果您成功用二分法定位了問題,請使用引入迴歸之更改的標題作爲主題的第二部分。
+請在報告中寫明“罪魁禍首”的提交ID。如果未能成功二分,請在報告中講明最後一個
+正常工作的版本(例如5.7)和最先發生問題的版本(例如5.8-rc1)。
+
+通過郵件發送報告時,請抄送Linux迴歸郵件列表(regressions@lists.linux.dev)。
+如果報告需要提交到某個web追蹤器,請繼續提交;並在提交後,通過郵件將報告轉發
+至迴歸列表;抄送相關子系統的維護人員和郵件列表。請確保報告是內聯轉發的,不要
+把它作爲附件。另外請在頂部添加一個簡短的說明,在那裏寫上工單的網址。
+
+在郵寄或轉發報告時,如果成功二分,需要將“罪魁禍首”的作者添加到收件人中;同時
+抄送signed-off-by鏈中的每個人,您可以在提交消息的末尾找到。
+
+**安全問題** :對於這種問題,你將必須評估:如果細節被公開披露,是否會對其他
+用戶產生短期風險。如果不會,只需按照所述繼續報告問題。如果有此風險,你需要
+稍微調整一下報告流程。
+
+ * 如果 MAINTAINERS 文件指示您通過郵件報告問題,請不要抄送任何公共郵件列表。
+
+ * 如果你應該在缺陷跟蹤器中提交問題,請確保將工單標記爲“私有”或“安全問題”。
+ 如果缺陷跟蹤器沒有提供保持報告私密性的方法,那就別想了,把你的報告以私人
+ 郵件的形式發送給維護者吧。
+
+在這兩種情況下,都一定要將報告發到 MAINTAINERS 文件中“安全聯絡”部分列出的
+地址。理想的情況是在發送報告的時候直接抄送他們。如果您在缺陷跟蹤器中提交了
+報告,請將報告的文本轉發到這些地址;但請在報告的頂部加上註釋,表明您提交了
+報告,並附上工單鏈接。
+
+更多信息請參見 Documentation/translations/zh_CN/admin-guide/security-bugs.rst 。
+
+
+發佈報告後的責任
+------------------
+
+ *等待別人的反應,繼續推進事情,直到你能夠接受這樣或那樣的結果。因此,請
+ 公開和及時地回應任何詢問。測試提出的修復。積極地測試:至少重新測試每個
+ 新主線版本的首個候選版本(RC),並報告你的結果。如果出現拖延,就友好地
+ 提醒一下。如果你沒有得到任何幫助或者未能滿意,請試着自己幫助自己。*
+
+如果你的報告非常優秀,而且你真的很幸運,那麼某個開發者可能會立即發現導致問
+題的原因;然後他們可能會寫一個補丁來修復、測試它,並直接發送給主線集成,同
+時標記它以便以後回溯到需要它的穩定版和長期支持內核。那麼你需要做的就是回覆
+一句“Thank you very much”(非常感謝),然後在發佈後換上修復好的版本。
+
+但這種理想狀況很少發生。這就是爲什麼你把報告拿出來之後工作纔開始。你要做的
+事情要視情況而定,但通常會是下面列出的事情。但在深入研究細節之前,這裏有幾
+件重要的事情,你需要記住這部分的過程。
+
+
+關於進一步互動的一般建議
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**總是公開回復** :當你在缺陷跟蹤器中提交問題時,一定要在那裏回覆,不要私下
+聯繫任何開發者。對於郵件報告,在回覆您收到的任何郵件時,總是使用“全部回覆”
+功能。這包括帶有任何你可能想要添加到你的報告中的額外數據的郵件:進入郵件應
+用程序“已發送”文件夾,並在郵件上使用“全部回覆”來回復報告。這種方法可以確保
+公共郵件列表和其他所有參與者都能及時瞭解情況;它還能保持郵件線程的完整性,
+這對於郵件列表將所有相關郵件歸爲一類是非常重要的。
+
+只有兩種情況不適合在缺陷跟蹤器或“全部回覆”中發表評論:
+
+ * 有人讓你私下發東西。
+
+ * 你被告知要發送一些東西,但注意到其中包含需要保密的敏感信息。在這種情況下,
+ 可以私下發送給要求發送的開發者。但要在工單或郵件中註明你是這麼做的,這
+ 樣其他人就知道你尊重了這個要求。
+
+**在請求解釋或幫助之前先研究一下** :在這部分過程中,有人可能會告訴你用尚未
+掌握的技能做一些事情。例如你可能會被要求使用一些你從未聽說過的測試工具;或
+者你可能會被要求在 Linux 內核源代碼上應用一個補丁來測試它是否有幫助。在某些
+情況下,發個回覆詢問如何做就可以了。但在走這條路之前,儘量通過在互聯網上搜
+索自行找到答案;或者考慮在其他地方詢問建議。比如詢問朋友,或者到你平時常去
+的聊天室或論壇發帖諮詢。
+
+**要有耐心** :如果你真的很幸運,你可能會在幾個小時內收到對你的報告的答覆。
+但大多數情況下會花費更多的時間,因爲維護者分散在全球各地,因此可能在不同的
+時區——在那裏他們已經享受着遠離鍵盤的夜晚。
+
+一般來說,內核開發者需要一到五個工作日來回復報告。有時會花費更長的時間,因
+爲他們可能正忙於合併窗口、其他工作、參加開發者會議,或者只是在享受一個漫長
+的暑假。
+
+“高優先級的問題”(見上面的解釋)例外:維護者應該儘快解決這些問題;這就是爲
+什麼你應該最多等待一個星期(如果是緊急的事情,則只需兩天),然後再發送友好
+的提醒。
+
+有時維護者可能沒有及時回覆;有時候可能會出現分歧,例如一個問題是否符合迴歸
+的條件。在這種情況下,在郵件列表上提出你的顧慮,並請求其他人公開或私下回復
+如何繼續推進。如果失敗了,可能應該讓更高級別的維護者介入。如果是 WiFi 驅動,
+那就是無線維護者;如果沒有更高級別的維護者,或者其他一切努力都失敗了,那
+這可能是一種罕見的、可以讓 Linus Torvalds 參與進來的情況。
+
+**主動測試** :每當一個新的主線內核版本的第一個預發佈版本(rc1)發佈的時候,
+去檢查一下這個問題是否得到了解決,或者是否有什麼重要的變化。在工單中或在
+回覆報告的郵件中提及結果(確保所有參與討論的人都被抄送)。這將表明你的承諾
+和你願意幫忙。如果問題持續存在,它也會提醒開發者確保他們不會忘記它。其他一
+些不定期的重新測試(例如用rc3、rc5 和最終版本)也是一個好主意,但只有在相關
+的東西發生變化或者你正在寫什麼東西的時候才報告你的結果。
+
+這些些常規的事情就不說了,我們來談談報告後如何幫助解決問題的細節。
+
+查詢和測試請求
+~~~~~~~~~~~~~~~
+
+如果你的報告得到了回覆則需履行以下責任:
+
+**檢查與你打交道的人** :大多數情況下,會是維護者或特定代碼區域的開發人員對
+你的報告做出回應。但由於問題通常是公開報告的,所以回覆的可能是任何人——包括
+那些想要幫忙的人,但最後可能會用他們的問題或請求引導你完全偏離軌道。這很少
+發生,但這是快速上網搜搜看你正在與誰互動是明智之舉的許多原因之一。通過這樣
+做,你也可以知道你的報告是否被正確的人聽到,因爲如果討論沒有導致滿意的問題
+解決方案而淡出,之後可能需要提醒維護者(見下文)。
+
+**查詢數據** :通常你會被要求測試一些東西或提供更多細節。儘快提供所要求的信
+息,因爲你已經得到了可能會幫助你的人的注意,你等待的時間越長就有越可能失去
+關注;如果你不在數個工作日內提供信息,甚至可能出現這種結果。
+
+**測試請求** :當你被要求測試一個診斷補丁或可能的修復時,也要儘量及時測試。
+但要做得恰當,一定不要急於求成:混淆事情很容易發生,這會給所有人帶來許多困
+惑。例如一個常見的錯誤是以爲應用了一個帶修復的建議補丁,但事實上並沒有。即
+使是有經驗的測試人員也會偶爾發生這樣的事情,但當有修復的內核和沒有修復的內
+核表現得一樣時,他們大多時候會注意到。
+
+當沒有任何實質性進展時該怎麼辦
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+有些報告不會得到負有相關責任的 Linux 內核開發者的任何反應;或者圍繞這個問題
+的討論有所發展,但漸漸淡出,沒有任何實質內容產出。
+
+在這種情況下,要等兩個星期(最好是三個星期)後再發出友好的提醒:也許當你的
+報告到達時,維護者剛剛離開鍵盤一段時間,或者有更重要的事情要處理。在寫提醒
+信的時候,要善意地問一下,是否還需要你這邊提供什麼來讓事情推進下去。如果報
+告是通過郵件發出來的,那就在郵件的第一行回覆你的初始郵件(見上文),其中包
+括下方的原始報告的完整引用:這是少數幾種情況下,這樣的“TOFU”(Text Over,
+Fullquote Under文字在上,完整引用在下)是正確的做法,因爲這樣所有的收件人都
+會以適當的順序立即讓細節到手頭上來。
+
+在提醒之後,再等三週的回覆。如果你仍然沒有得到適當的反饋,你首先應該重新考
+慮你的方法。你是否可能嘗試接觸了錯誤的人?是不是報告也許令人反感或者太混亂,
+以至於人們決定完全遠離它?排除這些因素的最好方法是:把報告給一兩個熟悉
+FLOSS 問題報告的人看,詢問他們的意見。同時徵求他們關於如何繼續推進的建議。
+這可能意味着:準備一份更好的報告,讓這些人在你發出去之前對它進行審查。這樣
+的方法完全可以;只需說明這是關於這個問題的第二份改進的報告,並附上第一份報
+告的鏈接。
+
+如果報告是恰當的,你可以發送第二封提醒信;在其中詢問爲什麼報告沒有得到任何
+回覆。第二封提醒郵件的好時機是在新 Linux 內核版本的首個預發佈版本('rc1')
+發佈後不久,因爲無論如何你都應該在那個時候重新測試並提供狀態更新(見上文)。
+
+如果第二次提醒的結果又在一週內沒有任何反應,可以嘗試聯繫上級維護者詢問意見:
+即使再忙的維護者在這時候也至少應該發過某種確認。
+
+記住要做好失望的準備:理想狀況下維護者最好對每一個問題報告做出回應,但他們
+只有義務解決之前列出的“高優先級問題”。所以,如果你得到的回覆是“謝謝你的報告,
+我目前有更重要的問題要處理,在可預見的未來沒有時間去研究這個問題”,那請不
+要太沮喪。
+
+也有可能在缺陷跟蹤器或列表中進行了一些討論之後,什麼都沒有發生,提醒也無助
+於激勵大家進行修復。這種情況可能是毀滅性的,但在 Linux 內核開發中確實會發生。
+這些和其他得不到幫助的原因在本文結尾處的“爲什麼有些問題在被報告後沒有得到
+任何回應或者仍然沒有修復”中進行了解釋。
+
+如果你沒有得到任何幫助或問題最終沒有得到解決,不要沮喪:Linux 內核是 FLOSS,
+因此你仍然可以自己幫助自己。例如,你可以試着找到其他受影響的人,和他們一
+起合作來解決這個問題。這樣的團隊可以一起準備一份新的報告,提到團隊有多少人,
+爲什麼你們認爲這是應該得到解決的事情。也許你們還可以一起縮小確切原因或引
+入迴歸的變化,這往往會使修復更容易。而且如果運氣好的話,團隊中可能會有懂點
+編程的人,也許能寫出一個修復方案。
+
+
+
+“報告穩定版和長期支持內核線的迴歸”的參考
+------------------------------------------
+
+本小節提供了在穩定版和長期支持內核線中面對迴歸時需要執行的步驟的詳細信息。
+
+確保特定版本線仍然受支持
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ *檢查內核開發人員是否仍然維護你關心的Linux內核版本線:去 kernel.org 的
+ 首頁,確保此特定版本線的最新版沒有“[EOL]”標記。*
+
+大多數內核版本線只支持三個月左右,因爲延長維護時間會帶來相當多的工作。因此,
+每年只會選擇一個版本來支持至少兩年(通常是六年)。這就是爲什麼你需要檢查
+內核開發者是否還支持你關心的版本線。
+
+注意,如果 `kernel.org <https://kernel.org/>`_ 在首頁上列出了兩個“穩定”版本,
+你應該考慮切換到較新的版本,而忘掉較舊的版本:對它的支持可能很快就會結束。
+然後,它將被標記爲“生命週期結束”(EOL)。達到這個程度的版本線仍然會在
+`kernel.org <https://kernel.org/>`_ 首頁上被顯示一兩週,但不適合用於測試和
+報告。
+
+搜索穩定版郵件列表
+~~~~~~~~~~~~~~~~~~~
+
+ *檢查Linux穩定版郵件列表中的現有報告。*
+
+也許你所面臨的問題已經被發現,並且已經或即將被修復。因此,請在 `Linux 穩定
+版郵件列表的檔案 <https://lore.kernel.org/stable/>`_ 中搜索類似問題的報告。
+如果你找到任何匹配的問題,可以考慮加入討論,除非修復工作已經完成並計劃很快
+得到應用。
+
+用最新版本復現問題
+~~~~~~~~~~~~~~~~~~~
+
+ *從特定的版本線安裝最新版本作爲純淨內核。確保這個內核沒有被污染,並且仍
+ 然存在問題,因爲問題可能已經在那裏被修復了。*
+
+在投入更多時間到這個過程中之前,你要檢查這個問題是否在你關注的版本線的最新
+版本中已經得到了修復。這個內核需要是純淨的,在問題發生之前不應該被污染,正
+如上面已經在測試主線的過程中詳細介紹過的一樣。
+
+您是否是第一次注意到供應商內核的迴歸?供應商的更改可能會發生變化。你需要重新
+檢查排除來這個問題。當您從5.10.4-vendor.42更新到5.10.5-vendor.43時,記錄損壞
+的信息。然後在測試了前一段中所述的最新5.10版本之後,檢查Linux 5.10.4的普通版本
+是否也可以正常工作。如果問題在那裏出現,那就不符合上游迴歸的條件,您需要切換
+回主逐步指南來報告問題。
+
+報告迴歸
+~~~~~~~~~~
+
+ *向Linux穩定版郵件列表發送一個簡短的問題報告(stable@vger.kernel.org)並
+ 抄送Linux迴歸郵件列表(regressions@lists.linux.dev);如果你懷疑是由某
+ 子系統引起的,請抄送其維護人員和子系統郵件列表。大致描述問題,並解釋如
+ 何復現。講清楚首個出現問題的版本和最後一個工作正常的版本。然後等待進一
+ 步的指示。*
+
+當報告在穩定版或長期支持內核線內發生的迴歸(例如在從5.10.4更新到5.10.5時),
+一份簡短的報告足以快速報告問題。因此只需向穩定版和迴歸郵件列表發送粗略的描述;
+不過如果你懷疑某子系統導致此問題的話,請一併抄送其維護人員和子系統郵件列表,
+這會加快進程。
+
+請注意,如果您能夠指明引入問題的確切版本,這將對開發人員有很大幫助。因此
+如果有時間的話,請嘗試使用普通內核找到該版本。讓我們假設發行版發佈Linux內核
+5.10.5到5.10.8的更新時發生了故障。那麼按照上面的指示,去檢查該版本線中的最新
+內核,比如5.10.9。如果問題出現,請嘗試普通5.10.5,以確保供應商應用的補丁不會
+干擾。如果問題沒有出現,那麼嘗試5.10.7,然後直到5.10.8或5.10.6(取決於結果)
+找到第一個引入問題的版本。在報告中寫明這一點,並指出5.10.9仍然存在故障。
+
+前一段基本粗略地概述了“二分”方法。一旦報告出來,您可能會被要求做一個正確的
+報告,因爲它允許精確地定位導致問題的確切更改(然後很容易被恢復以快速修復問題)。
+因此如果時間允許,考慮立即進行適當的二分。有關如何詳細信息,請參閱“對迴歸的
+特別關照”部分和文檔 Documentation/translations/zh_CN/admin-guide/bug-bisect.rst 。
+如果成功二分的話,請將“罪魁禍首”的作者添加到收件人中;同時抄送所有在
+signed-off-by鏈中的人,您可以在提交消息的末尾找到。
+
+
+“報告僅在舊內核版本線中發生的問題”的參考
+----------------------------------------
+
+本節詳細介紹瞭如果無法用主線內核重現問題,但希望在舊版本線(又稱穩定版內核和
+長期支持內核)中修復問題時需要採取的步驟。
+
+有些修復太複雜
+~~~~~~~~~~~~~~~
+
+ *請做好準備,接下來的幾個步驟可能無法在舊版本中解決問題:修復可能太大或
+ 太冒險,無法移植到那裏。*
+
+即使是微小的、看似明顯的代碼變化,有時也會帶來新的、完全意想不到的問題。穩
+定版和長期支持內核的維護者非常清楚這一點,因此他們只對這些內核進行符合
+Documentation/translations/zh_CN/process/stable-kernel-rules.rst 中所列出的
+規則的修改。
+
+複雜或有風險的修改不符合條件,因此只能應用於主線。其他的修復很容易被回溯到
+最新的穩定版和長期支持內核,但是風險太大,無法集成到舊版內核中。所以要注意
+你所希望的修復可能是那些不會被回溯到你所關心的版本線的修復之一。在這種情況
+下,你將別無選擇,要麼忍受這個問題,要麼切換到一個較新的 Linux 版本,除非你
+想自己把修復補丁應用到你的內核中。
+
+通用準備
+~~~~~~~~~~
+
+ *執行上面“報告僅在舊內核版本線中發生的問題”一節中的前三個步驟。*
+
+您需要執行本指南另一節中已經描述的幾個步驟。這些步驟將讓您:
+
+ * 檢查內核開發人員是否仍然維護您關心的Linux內核版本行。
+
+ * 在Linux穩定郵件列表中搜索退出的報告。
+
+ * 檢查最新版本。
+
+
+檢查代碼歷史和搜索現有的討論
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ *在Linux內核版本控制系統中搜索修復主線問題的更改,因爲它的提交消息可能
+ 會告訴你修復是否已經計劃好了支持。如果你沒有找到,搜索適當的郵件列表,
+ 尋找討論此類問題或同行評議可能修復的帖子;然後檢查討論是否認爲修復不適
+ 合支持。如果支持根本不被考慮,加入最新的討論,詢問是否有可能。*
+
+在許多情況下,你所處理的問題會發生在主線上,但已在主線上得到了解決。修正它
+的提交也需要被回溯才能解決這個問題。這就是爲什麼你要搜索它或任何相關討論。
+
+ * 首先嚐試在存放 Linux 內核源代碼的 Git 倉庫中找到修復。你可以通過
+ `kernel.org 上的網頁
+ <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/>`_
+ 或 `GitHub 上的鏡像 <https://github.com/torvalds/linux>`_ 來實現;如果你
+ 有一個本地克隆,你也可以在命令行用 ``git log --grep=<pattern>`` 來搜索。
+
+ 如果你找到了修復,請查看提交消息的尾部是否包含了類似這樣的“穩定版標籤”:
+
+ Cc: <stable@vger.kernel.org> # 5.4+
+
+ 像上面這行,開發者標記了安全修復可以回傳到 5.4 及以後的版本。大多數情況
+ 下,它會在兩週內被應用到那裏,但有時需要更長的時間。
+
+ * 如果提交沒有告訴你任何東西,或者你找不到修復,請再找找關於這個問題的討論。
+ 用你最喜歡的搜索引擎搜索網絡,以及 `Linux kernel developers mailing
+ list 內核開發者郵件列表 <https://lore.kernel.org/lkml/>`_ 的檔案。也可以
+ 閱讀上面的 `定位導致問題的內核區域` 一節,然後按照說明找到導致問題的子系
+ 統:它的缺陷跟蹤器或郵件列表存檔中可能有你要找的答案。
+
+ * 如果你看到了一個計劃的修復,請按上所述在版本控制系統中搜索它,因爲提交可
+ 能會告訴你是否可以進行回溯。
+
+ * 檢查討論中是否有任何跡象表明,該修復程序可能風險太大,無法回溯到你關心
+ 的版本線。如果是這樣的話,你必須忍受這個問題,或者切換到應用了修復的內
+ 核版本線。
+
+ * 如果修復的問題未包含穩定版標籤,並且沒有討論過回溯問題,請加入討論:如
+ 果合適的話,請提及你所面對的問題的版本,以及你希望看到它被修復。
+
+
+請求建議
+~~~~~~~~~
+
+ *前面的步驟之一應該會給出一個解決方案。如果仍未能成功,請向可能引起問題
+ 的子系統的維護人員詢問建議;抄送特定子系統的郵件列表以及穩定版郵件列表。*
+
+如果前面的三個步驟都沒有讓你更接近解決方案,那麼只剩下一個選擇:請求建議。
+在你發給可能是問題根源的子系統的維護者的郵件中這樣做;抄送子系統的郵件列表
+以及穩定版郵件列表(stable@vger.kernel.org)。
+
+
+爲什麼有些問題在報告後沒有任何回應或仍未解決?
+===============================================
+
+當向 Linux 開發者報告問題時,要注意只有“高優先級的問題”(迴歸、安全問題、嚴
+重問題)才一定會得到解決。如果維護者或其他人都失敗了,Linus Torvalds 他自己
+會確保這一點。他們和其他內核開發者也會解決很多其他問題。但是要知道,有時他
+們也會不能或不願幫忙;有時甚至沒有人發報告給他們。
+
+最好的解釋就是那些內核開發者常常是在業餘時間爲 Linux 內核做出貢獻。內核中的
+不少驅動程序都是由這樣的程序員編寫的,往往只是因爲他們想讓自己的硬件可以在
+自己喜歡的操作系統上使用。
+
+這些程序員大多數時候會很樂意修復別人報告的問題。但是沒有人可以強迫他們這樣
+做,因爲他們是自願貢獻的。
+
+還有一些情況下,這些開發者真的很想解決一個問題,但卻不能解決:有時他們缺乏
+硬件編程文檔來解決問題。這種情況往往由於公開的文檔太簡陋,或者驅動程序是通
+過逆向工程編寫的。
+
+業餘開發者遲早也會不再關心某驅動。也許他們的測試硬件壞了,被更高級的玩意取
+代了,或者是太老了以至於只能在計算機博物館裏找到。有時開發者根本就不關心他
+們的代碼和 Linux 了,因爲在他們的生活中一些不同的東西變得更重要了。在某些情
+況下,沒有人願意接手維護者的工作——也沒有人可以被強迫,因爲對 Linux 內核的貢
+獻是自願的。然而被遺棄的驅動程序仍然存在於內核中:它們對人們仍然有用,刪除
+它們可能導致迴歸。
+
+對於那些爲 Linux 內核工作而獲得報酬的開發者來說,情況並沒有什麼不同。這些人
+現在貢獻了大部分的變更。但是他們的僱主遲早也會停止關注他們的代碼或者讓程序
+員專注於其他事情。例如,硬件廠商主要通過銷售新硬件來賺錢;因此,他們中的不
+少人並沒有投入太多時間和精力來維護他們多年前就停止銷售的東西的 Linux 內核驅
+動。企業級 Linux 發行商往往持續維護的時間比較長,但在新版本中往往會把對老舊
+和稀有硬件的支持放在一邊,以限制範圍。一旦公司拋棄了一些代碼,往往由業餘貢
+獻者接手,但正如上面提到的:他們遲早也會放下代碼。
+
+優先級是一些問題沒有被修復的另一個原因,因爲維護者相當多的時候是被迫設置這
+些優先級的,因爲在 Linux 上工作的時間是有限的。對於業餘時間或者僱主給予他們
+的開發人員用於上游內核維護工作的時間也是如此。有時維護人員也會被報告淹沒,
+即使一個驅動程序幾乎完美地工作。爲了不被完全纏住,程序員可能別無選擇,只能
+對問題報告進行優先級排序而拒絕其中的一些報告。
+
+不過這些都不用太過擔心,很多驅動都有積極的維護者,他們對儘可能多的解決問題
+相當感興趣。
+
+
+結束語
+=======
+
+與其他免費/自由&開源軟件(Free/Libre & Open Source Software,FLOSS)相比,
+向 Linux 內核開發者報告問題是很難的:這個文檔的長度和複雜性以及字裏行間的內
+涵都說明了這一點。但目前就是這樣了。這篇文字的主要作者希望通過記錄現狀來爲
+以後改善這種狀況打下一些基礎。
+
+
+..
+ end-of-content
+..
+ This English version of this document is maintained by Thorsten Leemhuis
+ <linux@leemhuis.info>. If you spot a typo or small mistake, feel free to
+ let him know directly and he'll fix it. For translation problems, please
+ contact with translators. You are free to do the same in a mostly informal
+ way if you want to contribute changes to the text, but for copyright
+ reasons please CC linux-doc@vger.kernel.org and "sign-off" your
+ contribution as Documentation/process/submitting-patches.rst outlines in
+ the section "Sign your work - the Developer's Certificate of Origin".
+..
+ This text is available under GPL-2.0+ or CC-BY-4.0, as stated at the top
+ of the file. If you want to distribute this text under CC-BY-4.0 only,
+ please use "The Linux kernel developers" for author attribution and link
+ this as source:
+ https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/Documentation/admin-guide/reporting-issues.rst
+..
+ Note: Only the content of this RST file as found in the Linux kernel sources
+ is available under CC-BY-4.0, as versions of this text that were processed
+ (for example by the kernel's build system) might contain content taken from
+ files which use a more restrictive license.
+
diff --git a/Documentation/translations/zh_TW/admin-guide/reporting-regressions.rst b/Documentation/translations/zh_TW/admin-guide/reporting-regressions.rst
new file mode 100644
index 000000000000..d7dcb2a26564
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/reporting-regressions.rst
@@ -0,0 +1,371 @@
+.. SPDX-License-Identifier: (GPL-2.0+ OR CC-BY-4.0)
+.. 【重分發信息參見本文件結尾】
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/admin-guide/reporting-regressions.rst
+
+:譯者:
+
+ 吳想成 Wu XiangCheng <bobwxc@email.cn>
+
+
+============
+報告迴歸問題
+============
+
+“*我們拒絕出現迴歸*”是Linux內核開發的首要規則;Linux的發起者和領軍開發者Linus
+Torvalds立下了此規則並確保它被落實。
+
+本文檔描述了這條規則對用戶的意義,以及Linux內核開發模型如何確保解決所有被報告
+的迴歸;關於內核開發者如何處理的方面參見 Documentation/process/handling-regressions.rst 。
+
+
+本文重點(亦即“太長不看”)
+==========================
+
+#. 如果某程序在原先的Linux內核上運行良好,但在較新版本上效果更差、或者根本不
+ 能用,那麼你就碰見迴歸問題了。注意,新內核需要使用類似配置編譯;更多相關細
+ 節參見下方。
+
+#. 按照 Documentation/translations/zh_CN/admin-guide/reporting-issues.rst 中
+ 所說的報告你的問題,該文檔已經包含了所有關於迴歸的重要方面,爲了方便起見也
+ 複製到了下面。兩個重點:在報告主題中使用“[REGRESSION]”開頭並抄送或轉發到
+ `迴歸郵件列表 <https://lore.kernel.org/regressions/>`_
+ (regressions@lists.linux.dev)。
+
+#. 可選但是建議:在發送或轉發報告時,指明該回歸發生的起點,以便Linux內核迴歸
+ 追蹤機器人“regzbot”可以追蹤此問題::
+
+ #regzbot introduced v5.13..v5.14-rc1
+
+
+與用戶相關的所有Linux內核迴歸細節
+=================================
+
+
+基本重點
+--------
+
+
+什麼是“迴歸”以及什麼是“無迴歸規則”?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+如果某程序/實例在原先的Linux內核上運行良好,但在較新版本上效果更差、或者根本
+不能用,那麼你就碰見迴歸問題了。“無迴歸規則”不允許出現這種情況。如果偶然發
+生了,導致問題的開發者應當迅速修復問題。
+
+也就是說,若Linux 5.13中的WiFi驅動程序運行良好,但是在5.14版本上卻不能用、速
+度明顯變慢或出現錯誤,那就出現了迴歸。如果某正常工作的應用程序突然在新內核上
+出現不穩定,這也是迴歸;這些問題可能是由於procfs、sysfs或Linux提供給用戶空間
+軟件的許多其他接口之一的變化。但請記住,前述例子中的5.14需要使用類似於5.13的
+配置構建。這可以用 ``make olddefconfig`` 實現,詳細解釋見下。
+
+注意本節第一句話中的“實例”:即使開發者需要遵循“無迴歸”規則,但仍可自由地改
+變內核的任何方面,甚至是導出到用戶空間的API或ABI,只要別破壞現有的應用程序或
+用例。
+
+還需注意,“無迴歸”規則只限制內核提供給用戶空間的接口。它不適用於內核內部接
+口,比如一些外部開發的驅動程序用來插入鉤子到內核的模塊API。
+
+如何報告迴歸?
+~~~~~~~~~~~~~~
+
+只需按照 Documentation/translations/zh_CN/admin-guide/reporting-issues.rst 中
+所說的報告你的問題,該文檔已經包含了要點。下面幾點概述了一下只在迴歸中重要的
+方面:
+
+ * 在檢查可加入討論的現有報告時,別忘了搜索 `Linux迴歸郵件列表
+ <https://lore.kernel.org/regressions/>`_ 和 `regzbot網頁界面
+ <https://linux-regtracking.leemhuis.info/regzbot/>`_ 。
+
+ * 在報告主題的開頭加上“[REGRESSION]”。
+
+ * 在你的報告中明確最後一個正常工作的內核版本和首個出問題的版本。如若可能,
+ 用二分法嘗試找出導致迴歸的變更,更多細節見下。
+
+ * 記得把報告發到Linux迴歸郵件列表(regressions@lists.linux.dev)。
+
+ * 如果通過郵件報告迴歸,請抄送回歸列表。
+
+ * 如果你使用某些缺陷追蹤器報告迴歸,請通過郵件轉發已提交的報告到迴歸列表,
+ 並抄送維護者以及出問題的相關子系統的郵件列表。
+
+ 如果是穩定版或長期支持版系列(如v5.15.3…v5.15.5)的迴歸,請記得抄送
+ `Linux穩定版郵件列表 <https://lore.kernel.org/stable/>`_ (stable@vger.kernel.org)。
+
+ 如果你成功地執行了二分,請抄送肇事提交的信息中所有簽了“Signed-off-by:”的人。
+
+在抄送你的報告到列表時,也請記得通知前述的Linux內核迴歸追蹤機器人。只需在郵件
+中包含如下片段::
+
+ #regzbot introduced: v5.13..v5.14-rc1
+
+Regzbot會就將你的郵件視爲在某個特定版本區間的迴歸報告。上例中即linux v5.13仍
+然正常,而Linux 5.14-rc1是首個您遇到問題的版本。如果你執行了二分以查找導致回
+歸的提交,請使用指定肇事提交的id代替::
+
+ #regzbot introduced: 1f2e3d4c5d
+
+添加這樣的“regzbot命令”對你是有好處的,它會確保報告不會被忽略。如果你省略了
+它,Linux內核的迴歸跟蹤者會把你的迴歸告訴regzbot,只要你發送了一個副本到迴歸
+郵件列表。但是迴歸跟蹤者只有一個人,有時不得不休息或甚至偶爾享受可以遠離電腦
+的時光(聽起來很瘋狂)。因此,依賴此人手動將回歸添加到 `已追蹤且尚未解決的
+Linux內核迴歸列表 <https://linux-regtracking.leemhuis.info/regzbot/>`_ 和
+regzbot發送的每週迴歸報告,可能會出現延遲。 這樣的延誤會導致Linus Torvalds
+在決定“繼續開發還是發佈新版本?”時忽略嚴重的迴歸。
+
+真的修復了所有的迴歸嗎?
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+幾乎所有都是,只要引起問題的變更(肇事提交)被可靠定位。也有些迴歸可以不用這
+樣,但通常是必須的。
+
+誰需要找出迴歸的根本原因?
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+受影響代碼區域的開發者應該自行嘗試定位問題所在。但僅靠他們的努力往往是不可
+能做到的,很多問題只發生在開發者的無法接觸的其他特定外部環境中——例如特定的
+硬件平臺、固件、Linux發行版、系統的配置或應用程序。這就是爲什麼最終往往是報
+告者定位肇事提交;有時用戶甚至需要再運行額外測試以查明確切的根本原因。開發
+者應該提供建議和可能的幫助,以使普通用戶更容易完成該流程。
+
+如何找到罪魁禍首?
+~~~~~~~~~~~~~~~~~~
+
+如 Documentation/translations/zh_CN/admin-guide/reporting-issues.rst (簡要)
+和 Documentation/translations/zh_CN/admin-guide/bug-bisect.rst (詳細)中所
+述,執行二分。聽起來工作量很大,但大部分情況下很快就能找到罪魁禍首。如果這很
+困難或可靠地重現問題很耗時,請考慮與其他受影響的用戶合作,一起縮小搜索範圍。
+
+當出現迴歸時我可以向誰尋求建議?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+發送郵件到迴歸郵件列表(regressions@lists.linux.dev)同時抄送Linux內核的迴歸
+跟蹤者(regressions@leemhuis.info);如果問題需要保密處理,可以省略列表。
+
+
+關於迴歸的更多細節
+------------------
+
+
+“無迴歸規則”的目標是什麼?
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+用戶應該放心升級內核版本,而不必擔心有程序可能崩潰。這符合內核開發者的利益,
+可以使更新有吸引力:他們不希望用戶停留在停止維護或超過一年半的穩定/長期Linux
+版本系列上。這也符合所有人的利益,因爲 `那些系列可能含有已知的缺陷、安全問題
+或其他後續版本已經修復的問題
+<http://www.kroah.com/log/blog/2018/08/24/what-stable-kernel-should-i-use/>`_ 。
+此外,內核開發者希望使用戶測試最新的預發行版或常規發行版變得簡單而有吸引力。
+這同樣符合所有人的利益,如果新版本出來後很快就有相關報告,會使追蹤和修復問題
+更容易。
+
+實際中“無迴歸”規則真的可行嗎?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+這不是句玩笑話,請見Linux創建者和主要開發人員Linus Torvalds在郵件列表中的許
+多發言,其中一些在 Documentation/process/handling-regressions.rst 中被引用。
+
+此規則的例外情況極爲罕見;之前當開發者認爲某個特定的情況有必要援引例外時,
+基本都被證明錯了。
+
+誰來確保“無迴歸”被落實?
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+照看和支撐樹的子系統維護者應該關心這一點——例如,Linus Torvalds之於主線,
+Greg Kroah-Hartman等人之於各種穩定/長期系列。
+
+他們都得到了別人的幫助,以確保迴歸報告不會被遺漏。其中之一是Thorsten
+Leemhuis,他目前擔任Linux內核的“迴歸跟蹤者”;爲了做好這項工作,他使用了
+regzbot——Linux內核迴歸跟蹤機器人。所以這就是爲什麼要抄送或轉發你的報告到
+迴歸郵件列表來通知這些人,已經最好在你的郵件中包含“regzbot命令”來立即追蹤它。
+
+迴歸通常多久能修復?
+~~~~~~~~~~~~~~~~~~~~
+
+開發者應該儘快修復任何被報告的迴歸,以提供及時爲受影響的用戶提供解決方案,並
+防止更多用戶遇到問題;然而,開發人員需要花足夠的時間和注意力確保迴歸修復不會
+造成額外的損害。
+
+因此,答案取決於各種因素,如迴歸的影響、存在時長或出現於哪個Linux版本系列。
+但最終,大多數的迴歸應該在兩週內修復。
+
+當問題可以通過升級某些軟件解決時,是迴歸嗎?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+基本都是。如果開發人員告訴您其他情況,請諮詢上述迴歸跟蹤者。
+
+當新內核變慢或能耗增加,是迴歸嗎?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+是的,但有一些差別。在微型基準測試中變慢5%不太可能被視爲迴歸,除非它也會對
+廣泛基準測試的結果產生超過1%的影響。如果有疑問,請尋求建議。
+
+當更新Linux時外部內核模塊崩潰了,是迴歸嗎?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+不,因爲“無迴歸”規則僅限於Linux內核提供給用戶空間的接口和服務。因此,它不包括
+構建或運行外部開發的內核模塊,因爲它們在內核空間中運行與掛進內核使用的內部接
+口偶爾會變化。
+
+如何處理安全修復引起的迴歸?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+在極爲罕見的情況下,安全問題無法在不引起迴歸的情況下修復;這些修復都被放棄了,
+因爲它們終究會引起問題。幸運的是這種兩難境地基本都可以避免,受影響區域的主要
+開發者以及Linus Torvalds本人通常都會努力在不引入迴歸的情況下解決安全問題。
+
+如果你仍然面臨此種情況,請查看郵件列表檔案是否有人盡力避免過迴歸。如果沒有,
+請報告它;如有疑問,請如上所述尋求建議。
+
+當修復迴歸時不可避免會引入另一個,如何處理?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+很遺憾這種事確實會出現,但幸運的是並不經常出現;如果發生了,受影響代碼區的資
+深開發者應當調查該問題以找到避免迴歸的解決方法,至少避免它們的影響。如果你遇
+到這樣的情況,如上所述:檢查之前的討論是否有人已經盡了最大努力,如有疑問請尋
+求建議。
+
+小提示:如果人們在每個開發週期中定期給出主線預發佈(即v5.15-rc1或-rc3)以供
+測試,則可以避免這種情況。爲了更好地解釋,可以設想一個在Linux v5.14和v5.15-rc1
+之間集成的更改,該更改導致了迴歸,但同時是應用於5.15-rc1的其他改進的強依賴。
+如果有人在5.15發佈之前就發現並報告了這個問題,那麼所有更改都可以直接撤銷,從
+而解決迴歸問題。而就在幾天或幾周後,此解決方案變成了不可能,因爲一些軟件可能
+已經開始依賴於後續更改之一:撤銷所有更改將導致上述用戶軟件出現迴歸,這是不可
+接受的。
+
+若我所依賴的功能在數月前被移除了,是迴歸嗎?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+是的,但如前節所述,通常很難修復此類迴歸。因此需要逐案處理。這也是定期測試主
+線預發佈對所有人有好處的另一個原因。
+
+如果我似乎是唯一受影響的人,是否仍適用“無迴歸”規則?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+適用,但僅限於實際使用:Linux開發人員希望能夠自由地取消那些只能在閣樓和博物
+館中找到的硬件的支持。
+
+請注意,有時爲了取得進展,不得不出現迴歸——後者也是防止Linux停滯不前所必需
+的。因此如果迴歸所影響的用戶很少,那麼爲了他們和其他人更大的利益,還是讓事情
+過去吧。尤其是存在某種規避迴歸的簡單方法,例如更新一些軟件或者使用專門爲此目
+的創建的內核參數。
+
+迴歸規則是否也適用於staging樹中的代碼?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+不,參見 `適用於所有staging代碼配置選項的幫助文本
+<https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/staging/Kconfig>`_ ,
+其早已聲明::
+
+ 請注意:這些驅動正在積極開發中,可能無法正常工作,並可能包含會在不久的
+ 將來發生變化的用戶接口。
+
+雖然staging開發人員通常堅持“無迴歸”的原則,但有時爲了取得進展也會違背它。這就
+是爲什麼當staging樹的WiFi驅動被基本推倒重來時,有些用戶不得不處理迴歸(通常可
+以忽略)。
+
+爲什麼較新版本必須“使用相似配置編譯”?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+因爲Linux內核開發人員有時會集成已知的會導致迴歸的變更,但使它們成爲可選的,並
+在內核的默認配置下禁用它們。這一技巧允許進步,否則“無迴歸”規則將導致停滯。
+
+例如,試想一個新的可以阻止惡意軟件濫用某個內核的接口的安全特性,同時又需要滿足
+另一個很罕見的應用程序。上述的方法可使兩方都滿意:使用這些應用程序的人可以關閉
+新的安全功能,而其他不會遇到麻煩的人可以啓用它。
+
+如何創建與舊內核相似的配置?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+用一個已知良好的內核啓動機器,並用 ``make olddefconfig`` 配置新版的Linux。這
+會讓內核的構建腳本從正在運行的內核中摘錄配置文件(“.config”文件),作爲即將編
+譯的新版本的基礎配置;同時將所有新的配置選項設爲默認值,以禁用可能導致迴歸的
+新功能。
+
+如何報告在預編譯的普通內核中發現的迴歸?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+您需要確保新的內核是用與舊版相似的配置編譯(見上文),因爲那些構建它們的人可
+能啓用了一些已知的與新內核不兼容的特性。如有疑問,請向內核的提供者報告問題並
+尋求建議。
+
+
+用“regzbot”追蹤迴歸的更多信息
+-----------------------------
+
+什麼是迴歸追蹤?爲啥我需要關心它?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+像“無迴歸”這樣的規則需要有人來確保它們被遵守,否則會被有意/無意打破。歷史證
+明瞭這一點對於Linux內核開發也適用。這就是爲什麼Linux內核的迴歸跟蹤者Thorsten
+Leemhuis,,和另一些人盡力關注所有的迴歸直到他們解決。他們從未爲此獲得報酬,
+因此這項工作是在盡最大努力的基礎上完成的。
+
+爲什麼/如何使用機器人追蹤Linux內核迴歸?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+由於Linux內核開發過程的分佈式和鬆散結構,完全手動跟蹤迴歸已經被證明是相當困難
+的。因此Linux內核的迴歸跟蹤者開發了regzbot來促進這項工作,其長期目標是儘可能爲
+所有相關人員自動化迴歸跟蹤。
+
+Regzbot通過監視跟蹤的迴歸報告的回覆來工作。此外,它還查找用“Link:”標籤引用這
+些報告的補丁;對這些補丁的回覆也會被跟蹤。結合這些數據,可以很好地瞭解當前修
+復過程的狀態。
+
+如何查看regzbot當前追蹤的迴歸?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+參見 `regzbot在線 <https://linux-regtracking.leemhuis.info/regzbot/>`_ 。
+
+何種問題可以由regzbot追蹤?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+該機器人只爲了跟蹤迴歸,因此請不要讓regzbot涉及常規問題。但是對於Linux內核的
+迴歸跟蹤者來說,讓regzbot跟蹤嚴重問題也可以,如有關掛起、損壞數據或內部錯誤
+(Panic、Oops、BUG()、warning…)的報告。
+
+如何修改被追蹤迴歸的相關信息?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+在直接或間接回復報告郵件時使用“regzbot命令”即可。最簡單的方法是:在“已發送”文
+件夾或郵件列表存檔中找到報告,然後使用郵件客戶端的“全部回覆”功能對其進行回覆。
+在該郵件中的獨立段落中可使用以下命令之一(即使用空行將這些命令中的一個或多個與
+其餘郵件文本分隔開)。
+
+ * 更新迴歸引入起點,例如在執行二分之後::
+
+ #regzbot introduced: 1f2e3d4c5d
+
+ * 設置或更新標題::
+
+ #regzbot title: foo
+
+ * 監視討論或bugzilla.kernel.org上有關討論或修復的工單::
+
+ #regzbot monitor: https://lore.kernel.org/r/30th.anniversary.repost@klaava.Helsinki.FI/
+ #regzbot monitor: https://bugzilla.kernel.org/show_bug.cgi?id=123456789
+
+ * 標記一個有更多相關細節的地方,例如有關但主題不同的郵件列表帖子或缺陷追蹤器中的工單::
+
+ #regzbot link: https://bugzilla.kernel.org/show_bug.cgi?id=123456789
+
+ * 標記迴歸已失效::
+
+ #regzbot invalid: wasn't a regression, problem has always existed
+
+Regzbot還支持其他一些主要由開發人員或迴歸追蹤人員使用的命令。命令的更多細節請
+參考 `入門指南 <https://gitlab.com/knurd42/regzbot/-/blob/main/docs/getting_started.md>`_
+和 `參考手冊 <https://gitlab.com/knurd42/regzbot/-/blob/main/docs/reference.md>`_ 。
+
+..
+ 正文結束
+..
+ 如本文件開頭所述,本文以GPL-2.0+或CC-BY-4.0許可發行。如您想僅在CC-BY-4.0許
+ 可下重分發本文,請用“Linux內核開發者”作爲作者,並用如下鏈接作爲來源:
+ https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/Documentation/translations/zh_CN/admin-guide/reporting-regressions.rst
+..
+ 注意:本RST文件內容只有在來自Linux內核源代碼時是使用CC-BY-4.0許可的,因爲經
+ 過處理的版本(如經內核的構建系統)可能包含來自使用更嚴格許可證的文件的內容。
+
diff --git a/Documentation/translations/zh_TW/admin-guide/security-bugs.rst b/Documentation/translations/zh_TW/admin-guide/security-bugs.rst
new file mode 100644
index 000000000000..cfe1e58e116b
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/security-bugs.rst
@@ -0,0 +1,78 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :doc:`../../../process/security-bugs`
+
+:譯者:
+
+ 吳想成 Wu XiangCheng <bobwxc@email.cn>
+ 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+安全缺陷
+=========
+
+Linux內核開發人員非常重視安全性。因此我們想知道何時發現了安全漏洞,以便儘快
+修復和披露。請向Linux內核安全團隊報告安全漏洞。
+
+聯絡
+-----
+
+可以通過電子郵件<security@kernel.org>聯繫Linux內核安全團隊。這是一個安全人員
+的私有列表,他們將幫助驗證錯誤報告並開發和發佈修復程序。如果您已經有了一個
+修復,請將其包含在您的報告中,這樣可以大大加快進程。安全團隊可能會從區域維護
+人員那裏獲得額外的幫助,以理解和修復安全漏洞。
+
+與任何缺陷一樣,提供的信息越多,診斷和修復就越容易。如果您不清楚哪些信息有用,
+請查看“Documentation/translations/zh_CN/admin-guide/reporting-issues.rst”中
+概述的步驟。任何利用漏洞的攻擊代碼都非常有用,未經報告者同意不會對外發布,除
+非已經公開。
+
+請儘可能發送無附件的純文本電子郵件。如果所有的細節都藏在附件裏,那麼就很難對
+一個複雜的問題進行上下文引用的討論。把它想象成一個
+:doc:`常規的補丁提交 <../process/submitting-patches>` (即使你還沒有補丁):
+描述問題和影響,列出復現步驟,然後給出一個建議的解決方案,所有這些都是純文本的。
+
+披露和限制信息
+---------------
+
+安全列表不是公開渠道。爲此,請參見下面的協作。
+
+一旦開發出了健壯的補丁,發佈過程就開始了。對公開的缺陷的修復會立即發佈。
+
+儘管我們傾向於在未公開缺陷的修復可用時即發佈補丁,但應報告者或受影響方的請求,
+這可能會被推遲到發佈過程開始後的7日內,如果根據缺陷的嚴重性需要更多的時間,
+則可額外延長到14天。推遲發佈修復的唯一有效原因是爲了適應QA的邏輯和需要發佈
+協調的大規模部署。
+
+雖然可能與受信任的個人共享受限信息以開發修復,但未經報告者許可,此類信息不會
+與修復程序一起發佈或發佈在任何其他披露渠道上。這包括但不限於原始錯誤報告和
+後續討論(如有)、漏洞、CVE信息或報告者的身份。
+
+換句話說,我們唯一感興趣的是修復缺陷。提交給安全列表的所有其他資料以及對報告
+的任何後續討論,即使在解除限制之後,也將永久保密。
+
+協調
+------
+
+對敏感缺陷(例如那些可能導致權限提升的缺陷)的修復可能需要與私有郵件列表
+<linux-distros@vs.openwall.org>進行協調,以便分發供應商做好準備,在公開披露
+上游補丁時發佈一個已修復的內核。發行版將需要一些時間來測試建議的補丁,通常
+會要求至少幾天的限制,而供應商更新發布更傾向於週二至週四。若合適,安全團隊
+可以協助這種協調,或者報告者可以從一開始就包括linux發行版。在這種情況下,請
+記住在電子郵件主題行前面加上“[vs]”,如linux發行版wiki中所述:
+<http://oss-security.openwall.org/wiki/mailing-lists/distros#how-to-use-the-lists>。
+
+CVE分配
+--------
+
+安全團隊通常不分配CVE,我們也不需要它們來進行報告或修復,因爲這會使過程不必
+要的複雜化,並可能耽誤缺陷處理。如果報告者希望在公開披露之前分配一個CVE編號,
+他們需要聯繫上述的私有linux-distros列表。當在提供補丁之前已有這樣的CVE編號時,
+如報告者願意,最好在提交消息中提及它。
+
+保密協議
+---------
+
+Linux內核安全團隊不是一個正式的機構實體,因此無法簽訂任何保密協議。
+
diff --git a/Documentation/translations/zh_TW/admin-guide/sysrq.rst b/Documentation/translations/zh_TW/admin-guide/sysrq.rst
new file mode 100644
index 000000000000..4a08db00a495
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/sysrq.rst
@@ -0,0 +1,281 @@
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/admin-guide/sysrq.rst
+
+:翻譯:
+
+ 黃軍華 Junhua Huang <huang.junhua@zte.com.cn>
+
+:校譯:
+
+ 司延騰 Yanteng Si <siyanteng@loongson.cn>
+
+.. _tw_admin-guide_sysrq:
+
+Linux 魔法系統請求鍵駭客
+========================
+
+針對 sysrq.c 的文檔說明
+
+什麼是魔法 SysRq 鍵?
+~~~~~~~~~~~~~~~~~~~~~
+
+它是一個你可以輸入的具有魔法般的組合鍵。
+無論內核在做什麼,內核都會響應 SysRq 鍵的輸入,除非內核完全卡死。
+
+如何使能魔法 SysRq 鍵?
+~~~~~~~~~~~~~~~~~~~~~~~
+
+在配置內核時,我們需要設置 'Magic SysRq key (CONFIG_MAGIC_SYSRQ)' 爲 'Y'。
+當運行一個編譯進 sysrq 功能的內核時,/proc/sys/kernel/sysrq 控制着被
+SysRq 鍵調用的功能許可。這個文件的默認值由 CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE
+配置符號設定,文件本身默認設置爲 1。以下是 /proc/sys/kernel/sysrq 中可能的
+值列表:
+
+ - 0 - 完全不使能 SysRq 鍵
+ - 1 - 使能 SysRq 鍵的全部功能
+ - >1 - 對於允許的 SysRq 鍵功能的比特掩碼(參見下面更詳細的功能描述)::
+
+ 2 = 0x2 - 使能對控制檯日誌記錄級別的控制
+ 4 = 0x4 - 使能對鍵盤的控制 (SAK, unraw)
+ 8 = 0x8 - 使能對進程的調試導出等
+ 16 = 0x10 - 使能同步命令
+ 32 = 0x20 - 使能重新掛載只讀
+ 64 = 0x40 - 使能對進程的信號操作 (term, kill, oom-kill)
+ 128 = 0x80 - 允許重啓、斷電
+ 256 = 0x100 - 允許讓所有實時任務變普通任務
+
+你可以通過如下命令把值設置到這個文件中::
+
+ echo "number" >/proc/sys/kernel/sysrq
+
+這裏被寫入的 number 可以是 10 進制數,或者是帶着 0x 前綴的 16 進制數。
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE 必須是以 16 進制數寫入。
+
+注意,``/proc/sys/kernel/sysrq`` 的值隻影響通過鍵盤觸發 SySRq 的調用,對於
+通過 ``/proc/sysrq-trigger`` 的任何操作調用都是允許的
+(通過具有系統權限的用戶)。
+
+如何使用魔法 SysRq 鍵?
+~~~~~~~~~~~~~~~~~~~~~~~
+
+在 x86 架構上
+ 你可以按下鍵盤組合鍵 :kbd:`ALT-SysRq-<command key>`。
+
+ .. note::
+ 一些鍵盤可能沒有標識 'SySRq' 鍵。'SySRq' 鍵也被當做 'Print Screen'鍵。
+ 同時有些鍵盤無法處理同時按下這麼多鍵,因此你可以先按下鍵盤 :kbd:`Alt` 鍵,
+ 然後按下鍵盤 :kbd:`SysRq` 鍵,再釋放鍵盤 :kbd:`SysRq` 鍵,之後按下鍵盤上命令鍵
+ :kbd:`<command key>`,最後釋放所有鍵。
+
+在 SPARC 架構上
+ 你可以按下鍵盤組合鍵 :kbd:`ALT-STOP-<command key>` 。
+
+在串行控制檯(只針對 PC 類型的標準串口)
+ 你可以發一個 ``BREAK`` ,然後在 5 秒內發送一個命令鍵,
+ 發送 ``BREAK`` 兩次將被翻譯爲一個正常的 BREAK 操作。
+
+在 PowerPC 架構上
+ 按下鍵盤組合鍵 :kbd:`ALT - Print Screen` (或者 :kbd:`F13`) - :kbd:`<命令鍵>` 。
+ :kbd:`Print Screen` (或者 :kbd:`F13`) - :kbd:`<命令鍵>` 或許也能實現。
+
+在其他架構上
+ 如果你知道其他架構的組合鍵,請告訴我,我可以把它們添加到這部分。
+
+在所有架構上
+ 寫一個字符到 /proc/sysrq-trigger 文件,例如::
+
+ echo t > /proc/sysrq-trigger
+
+這個命令鍵 :kbd:`<command key>` 是區分大小寫的。
+
+什麼是命令鍵?
+~~~~~~~~~~~~~~
+
+=========== ================================================================
+命令鍵 功能
+=========== ================================================================
+``b`` 將立即重啓系統,不會同步或者卸載磁盤。
+
+``c`` 將執行系統 crash,如果配置了系統 crashdump,將執行 crashdump。
+
+``d`` 顯示所有持有的鎖。
+
+``e`` 發送 SIGTERM 信號給所有進程,除了 init 進程。
+
+``f`` 將調用 oom killer 殺掉一個過度佔用內存的進程,如果什麼任務都沒殺,
+ 也不會 panic。
+
+``g`` kgdb 使用(內核調試器)。
+
+``h`` 將會顯示幫助。(實際上除了這裏列舉的鍵,其他的都將顯示幫助,
+ 但是 ``h`` 容易記住):-)
+
+``i`` 發送 SIGKILL 給所有進程,除了 init 進程。
+
+``j`` 強制性的 “解凍它” - 用於被 FIFREEZE ioctl 操作凍住的文件系統。
+
+``k`` 安全訪問祕鑰(SAK)殺掉在當前虛擬控制檯的所有程序,注意:參考
+ 下面 SAK 節重要論述。
+
+``l`` 顯示所有活動 cpu 的棧回溯。
+
+``m`` 將導出當前內存信息到你的控制檯。
+
+``n`` 用於使所有實時任務變成普通任務。
+
+``o`` 將關閉系統(如果配置和支持的話)。
+
+``p`` 將導出當前寄存器和標誌位到控制檯。
+
+``q`` 將導出每個 cpu 上所有已裝備的高精度定時器(不是完整的
+ time_list 文件顯示的 timers)和所有時鐘事件設備的詳細信息。
+
+``r`` 關閉鍵盤的原始模式,設置爲轉換模式。
+
+``s`` 將嘗試同步所有的已掛載文件系統。
+
+``t`` 將導出當前所有任務列表和它們的信息到控制檯。
+
+``u`` 將嘗試重新掛載已掛載文件系統爲只讀。
+
+``v`` 強制恢復幀緩存控制檯。
+``v`` 觸發 ETM 緩存導出 [ARM 架構特有]
+
+``w`` 導出處於不可中斷狀態(阻塞)的任務。
+
+``x`` 在 ppc/powerpc 架構上用於 xmon 接口。
+ 在 sparc64 架構上用於顯示全局的 PMU(性能監控單元)寄存器。
+ 在 MIPS 架構上導出所有的 tlb 條目。
+
+``y`` 顯示全局 cpu 寄存器 [SPARC-64 架構特有]
+
+``z`` 導出 ftrace 緩存信息
+
+``0``-``9`` 設置控制檯日誌級別,該級別控制什麼樣的內核信息將被打印到你的
+ 控制檯。(比如 ``0`` ,將使得只有緊急信息,像 PANICs or OOPSes
+ 才能到你的控制檯。)
+=========== ================================================================
+
+好了,我能用他們做什麼呢?
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+嗯,當你的 X 服務端或者 svgalib 程序崩潰,unraw(r) 非原始模式命令鍵是非常
+方便的。
+
+sak(k)(安全訪問祕鑰)在你嘗試登陸的同時,又想確保當前控制檯沒有可以獲取你的
+密碼的特洛伊木馬程序運行時是有用的。它會殺掉給定控制檯的所有程序,這樣你
+就可以確認當前的登陸提示程序是實際來自 init 進程的程序,而不是某些特洛伊
+木馬程序。
+
+.. important::
+
+ 在其實際的形式中,在兼容 C2 安全標準的系統上,它不是一個真正的 SAK,
+ 它也不應該誤認爲此。
+
+似乎其他人發現其可以作爲(系統終端聯機鍵)當你想退出一個程序,
+同時不會讓你切換控制檯的方法。(比如,X 服務端或者 svgalib 程序)
+
+``reboot(b)`` 是個好方法,當你不能關閉機器時,它等同於按下"復位"按鈕。
+
+``crash(c)`` 可以用於手動觸發一個 crashdump,當系統卡住時。
+注意當 crashdump 機制不可用時,這個只是觸發一個內核 crash。
+
+``sync(s)`` 在拔掉可移動介質之前,或者在使用不提供優雅關機的
+救援 shell 之後很方便 -- 它將確保你的數據被安全地寫入磁盤。注意,在你看到
+屏幕上出現 "OK" 和 "Done" 之前,同步還沒有發生。
+
+``umount(u)`` 可以用來標記文件系統正常卸載,從正在運行的系統角度來看,它們將
+被重新掛載爲只讀。這個重新掛載動作直到你看到 "OK" 和 "Done" 信息出現在屏幕上
+纔算完成。
+
+日誌級別 ``0`` - ``9`` 用於當你的控制檯被大量的內核信息衝擊,你不想看見的時候。
+選擇 ``0`` 將禁止除了最緊急的內核信息外的所有的內核信息輸出到控制檯。(但是如果
+syslogd/klogd 進程是運行的,它們仍將被記錄。)
+
+``term(e)`` 和 ``kill(i)`` 用於當你有些有點失控的進程,你無法通過其他方式殺掉
+它們的時候,特別是它正在創建其他進程。
+
+"just thaw ``it(j)`` " 用於當你的系統由於一個 FIFREEZE ioctl 調用而產生的文件
+系統凍結,而導致的不響應時。
+
+有的時候 SysRq 鍵在使用它之後,看起來像是“卡住”了,我能做些什麼?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+這也會發生在我這,我發現輕敲鍵盤兩側的 shift、alt 和 control 鍵,然後再次敲擊
+一個無效的 SysRq 鍵序列可以解決問題。(比如,像鍵盤組合鍵 :kbd:`alt-sysrq-z` )
+切換到另一個虛擬控制檯(鍵盤操作 :kbd:`ALT+Fn` ),然後再切回來應該也有幫助。
+
+我敲擊了 SysRq 鍵,但像是什麼都沒發生,發生了什麼錯誤?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+有一些鍵盤對於 SysRq 鍵設置了不同的鍵值,而不是提前定義的 99
+(查看在 ``include/uapi/linux/input-event-codes.h`` 文件中 ``KEY_SYSRQ`` 的定義)
+或者就根本沒有 SysRq 鍵。在這些場景下,執行 ``showkey -s`` 命令來找到一個合適
+的掃描碼序列,然後使用 ``setkeycodes <sequence> 99`` 命令映射這個序列值到通用
+的 SysRq 鍵編碼上(比如 ``setkeycodes e05b 99`` )。最好將這個命令放在啓動腳本
+中。
+哦,順便說一句,你十秒鐘不輸入任何東西就將退出 “showkey”。
+
+我想添加一個 SysRq 鍵事件到一個模塊中,如何去做呢?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+爲了註冊一個基礎函數到這個表中,首先你必須包含 ``include/linux/sysrq.h`` 頭
+文件,這個頭文件定義了你所需要的所有東西。然後你必須創建一個 ``sysrq_key_op``
+結構體,然後初始化它,使用如下內容,A) 你將使用的這個鍵的處理函數, B) 一個
+help_msg 字符串,在 SysRq 鍵打印幫助信息時將打印出來,C) 一個 action_msg 字
+符串,就在你的處理函數調用前打印出來。你的處理函數必須符合在 'sysrq.h' 文件中
+的函數原型。
+
+在 ``sysrq_key_op`` 結構體被創建後,你可以調用內核函數
+``register_sysrq_key(int key, const struct sysrq_key_op *op_p);``,
+該函數在表中的 'key' 對應位置內容是空的情況下,將通過 ``op_p`` 指針註冊這個操作
+函數到表中 'key' 對應位置上。在模塊卸載的時候,你必須調用
+``unregister_sysrq_key(int key, const struct sysrq_key_op *op_p)`` 函數,該函數
+只有在當前該鍵對應的處理函數被註冊到了 'key' 對應位置時,纔會移除 'op_p' 指針
+對應的鍵值操作函數。這是爲了防止在你註冊之後,該位置被改寫的情況。
+
+魔法 SysRq 鍵系統的工作原理是將鍵對應操作函數註冊到鍵的操作查找表,
+該表定義在 'drivers/tty/sysrq.c' 文件中。
+該鍵表有許多在編譯時候就註冊進去的操作函數,但是是可變的。
+並且有兩個函數作爲操作該表的接口被導出::
+
+ register_sysrq_key 和 unregister_sysrq_key.
+
+當然,永遠不要在表中留下無效指針,即,當你的模塊存在調用 register_sysrq_key()
+函數,它一定要調用 unregister_sysrq_key() 來清除它使用過的 SysRq 鍵表條目。
+表中的空指針是安全的。:)
+
+如果對於某種原因,在 handle_sysrq 調用的處理函數中,你認爲有必要調用
+handle_sysrq 函數時,你必須意識到當前你處於一個鎖中(你同時也處於一箇中斷處理
+函數中,這意味着不能睡眠)。所以這時你必須使用 ``__handle_sysrq_nolock`` 替代。
+
+當我敲擊一個 SysRq 組合鍵時,只有標題打印出現在控制檯?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+SysRq 鍵的輸出和所有其他控制檯輸出一樣,受制於控制檯日誌級別控制。
+這意味着,如果內核以發行版內核中常見的 "quiet" 方式啓動,則輸出可能不會出現在實際
+的控制檯上,即使它會出現在 dmesg 緩存中,也可以通過 dmesg 命令和 ``/proc/kmsg``
+文件的消費訪問到。作爲一個特例,來自 sysrq 命令的標題行將被傳遞給所有控制檯
+使用者,就好像當前日誌級別是最大的一樣。如果只發出標題頭,則幾乎可以肯定內核日誌
+級別太低。如果你需要控制檯上的輸出,那麼你將需要臨時提高控制檯日誌級別,通過使用
+鍵盤組合鍵 :kbd:`alt-sysrq-8` 或者::
+
+ echo 8 > /proc/sysrq-trigger
+
+在觸發了你感興趣的 SysRq 鍵命令後,記得恢復日誌級別到正常情況。
+
+我有很多問題時,可以請教誰?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+請教在內核郵件列表上的人,郵箱:
+ linux-kernel@vger.kernel.org
+
+致謝
+~~~~
+
+- Mydraal <vulpyne@vulpyne.net> 撰寫了該文件
+- Adam Sulmicki <adam@cfar.umd.edu> 進行了更新
+- Jeremy M. Dolan <jmd@turbogeek.org> 在 2001/01/28 10:15:59 進行了更新
+- Crutcher Dunnavant <crutcher+kernel@datastacks.com> 添加鍵註冊部分
+
diff --git a/Documentation/translations/zh_TW/admin-guide/tainted-kernels.rst b/Documentation/translations/zh_TW/admin-guide/tainted-kernels.rst
new file mode 100644
index 000000000000..0d8046576d04
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/tainted-kernels.rst
@@ -0,0 +1,161 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :doc:`../../../admin-guide/tainted-kernels`
+
+:譯者:
+
+ 吳想成 Wu XiangCheng <bobwxc@email.cn>
+ 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+受污染的內核
+-------------
+
+當發生一些在稍後調查問題時可能相關的事件時,內核會將自己標記爲“受污染
+(tainted)”的。不用太過擔心,大多數情況下運行受污染的內核沒有問題;這些信息
+主要在有人想調查某個問題時纔有意義的,因爲問題的真正原因可能是導致內核受污染
+的事件。這就是爲什麼來自受污染內核的缺陷報告常常被開發人員忽略,因此請嘗試用
+未受污染的內核重現問題。
+
+請注意,即使在您消除導致污染的原因(亦即卸載專有內核模塊)之後,內核仍將保持
+污染狀態,以表示內核仍然不可信。這也是爲什麼內核在注意到內部問題(“kernel
+bug”)、可恢復錯誤(“kernel oops”)或不可恢復錯誤(“kernel panic”)時會打印
+受污染狀態,並將有關此的調試信息寫入日誌 ``dmesg`` 輸出。也可以通過
+``/proc/`` 中的文件在運行時檢查受污染的狀態。
+
+
+BUG、Oops或Panics消息中的污染標誌
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+在頂部以“CPU:”開頭的一行中可以找到受污染的狀態;內核是否受到污染和原因會顯示
+在進程ID(“PID:”)和觸發事件命令的縮寫名稱(“Comm:”)之後::
+
+ BUG: unable to handle kernel NULL pointer dereference at 0000000000000000
+ Oops: 0002 [#1] SMP PTI
+ CPU: 0 PID: 4424 Comm: insmod Tainted: P W O 4.20.0-0.rc6.fc30 #1
+ Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011
+ RIP: 0010:my_oops_init+0x13/0x1000 [kpanic]
+ [...]
+
+如果內核在事件發生時沒有被污染,您將在那裏看到“Not-tainted:”;如果被污染,那
+麼它將是“Tainted:”以及字母或空格。在上面的例子中,它看起來是這樣的::
+
+ Tainted: P W O
+
+下表解釋了這些字符的含義。在本例中,由於加載了專有模塊( ``P`` ),出現了
+警告( ``W`` ),並且加載了外部構建的模塊( ``O`` ),所以內核早些時候受到
+了污染。要解碼其他字符,請使用下表。
+
+
+解碼運行時的污染狀態
+~~~~~~~~~~~~~~~~~~~~~
+
+在運行時,您可以通過讀取 ``cat /proc/sys/kernel/tainted`` 來查詢受污染狀態。
+如果返回 ``0`` ,則內核沒有受到污染;任何其他數字都表示受到污染的原因。解碼
+這個數字的最簡單方法是使用腳本 ``tools/debugging/kernel-chktaint`` ,您的
+發行版可能會將其作爲名爲 ``linux-tools`` 或 ``kernel-tools`` 的包的一部分提
+供;如果沒有,您可以從
+`git.kernel.org <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/tools/debugging/kernel-chktaint>`_
+網站下載此腳本並用 ``sh kernel-chktaint`` 執行,它會在上面引用的日誌中有類似
+語句的機器上打印這樣的內容::
+
+ Kernel is Tainted for following reasons:
+ * Proprietary module was loaded (#0)
+ * Kernel issued warning (#9)
+ * Externally-built ('out-of-tree') module was loaded (#12)
+ See Documentation/admin-guide/tainted-kernels.rst in the Linux kernel or
+ https://www.kernel.org/doc/html/latest/admin-guide/tainted-kernels.html for
+ a more details explanation of the various taint flags.
+ Raw taint value as int/string: 4609/'P W O '
+
+你也可以試着自己解碼這個數字。如果內核被污染的原因只有一個,那麼這很簡單,
+在本例中您可以通過下表找到數字。如果你需要解碼有多個原因的數字,因爲它是一
+個位域(bitfield),其中每個位表示一個特定類型的污染的存在或不存在,最好讓
+前面提到的腳本來處理。但是如果您需要快速看一下,可以使用這個shell命令來檢查
+設置了哪些位::
+
+ $ for i in $(seq 18); do echo $(($i-1)) $(($(cat /proc/sys/kernel/tainted)>>($i-1)&1));done
+
+污染狀態代碼表
+~~~~~~~~~~~~~~~
+
+=== ===== ====== ========================================================
+ 位 日誌 數字 內核被污染的原因
+=== ===== ====== ========================================================
+ 0 G/P 1 已加載專用模塊
+ 1 _/F 2 模塊被強制加載
+ 2 _/S 4 內核運行在不合規範的系統上
+ 3 _/R 8 模塊被強制卸載
+ 4 _/M 16 處理器報告了機器檢測異常(MCE)
+ 5 _/B 32 引用了錯誤的頁或某些意外的頁標誌
+ 6 _/U 64 用戶空間應用程序請求的污染
+ 7 _/D 128 內核最近死機了,即曾出現OOPS或BUG
+ 8 _/A 256 ACPI表被用戶覆蓋
+ 9 _/W 512 內核發出警告
+ 10 _/C 1024 已加載staging驅動程序
+ 11 _/I 2048 已應用平臺固件缺陷的解決方案
+ 12 _/O 4096 已加載外部構建(“樹外”)模塊
+ 13 _/E 8192 已加載未簽名的模塊
+ 14 _/L 16384 發生軟鎖定
+ 15 _/K 32768 內核已實時打補丁
+ 16 _/X 65536 備用污染,爲發行版定義並使用
+ 17 _/T 131072 內核是用結構隨機化插件構建的
+=== ===== ====== ========================================================
+
+注:字符 ``_`` 表示空白,以便於閱讀表。
+
+污染的更詳細解釋
+~~~~~~~~~~~~~~~~~
+
+ 0) ``G`` 加載的所有模塊都有GPL或兼容許可證, ``P`` 加載了任何專有模塊。
+ 沒有MODULE_LICENSE(模塊許可證)或MODULE_LICENSE未被insmod認可爲GPL
+ 兼容的模塊被認爲是專有的。
+
+
+ 1) ``F`` 任何模塊被 ``insmod -f`` 強制加載, ``' '`` 所有模塊正常加載。
+
+ 2) ``S`` 內核運行在不合規範的處理器或系統上:硬件已運行在不受支持的配置中,
+ 因此無法保證正確執行。內核將被污染,例如:
+
+ - 在x86上:PAE是通過intel CPU(如Pentium M)上的forcepae強制執行的,這些
+ CPU不報告PAE,但可能有功能實現,SMP內核在非官方支持的SMP Athlon CPU上
+ 運行,MSR被暴露到用戶空間中。
+ - 在arm上:在某些CPU(如Keystone 2)上運行的內核,沒有啓用某些內核特性。
+ - 在arm64上:CPU之間存在不匹配的硬件特性,引導加載程序以不同的模式引導CPU。
+ - 某些驅動程序正在被用在不受支持的體系結構上(例如x86_64以外的其他系統
+ 上的scsi/snic,非x86/x86_64/itanium上的scsi/ips,已經損壞了arm64上
+ irqchip/irq-gic的固件設置…)。
+
+ 3) ``R`` 模塊被 ``rmmod -f`` 強制卸載, ``' '`` 所有模塊都正常卸載。
+
+ 4) ``M`` 任何處理器報告了機器檢測異常, ``' '`` 未發生機器檢測異常。
+
+ 5) ``B`` 頁面釋放函數發現錯誤的頁面引用或某些意外的頁面標誌。這表示硬件問題
+ 或內核錯誤;日誌中應該有其他信息指示發生此污染的原因。
+
+ 6) ``U`` 用戶或用戶應用程序特意請求設置受污染標誌,否則應爲 ``' '`` 。
+
+ 7) ``D`` 內核最近死機了,即出現了OOPS或BUG。
+
+ 8) ``A`` ACPI表被重寫。
+
+ 9) ``W`` 內核之前已發出過警告(儘管有些警告可能會設置更具體的污染標誌)。
+
+ 10) ``C`` 已加載staging驅動程序。
+
+ 11) ``I`` 內核正在處理平臺固件(BIOS或類似軟件)中的嚴重錯誤。
+
+ 12) ``O`` 已加載外部構建(“樹外”)模塊。
+
+ 13) ``E`` 在支持模塊簽名的內核中加載了未簽名的模塊。
+
+ 14) ``L`` 系統上先前發生過軟鎖定。
+
+ 15) ``K`` 內核已經實時打了補丁。
+
+ 16) ``X`` 備用污染,由Linux發行版定義和使用。
+
+ 17) ``T`` 內核構建時使用了randstruct插件,它可以有意生成非常不尋常的內核結構
+ 佈局(甚至是性能病態的佈局),這在調試時非常有用。於構建時設置。
+
diff --git a/Documentation/translations/zh_TW/admin-guide/unicode.rst b/Documentation/translations/zh_TW/admin-guide/unicode.rst
new file mode 100644
index 000000000000..f43edb2b5ed0
--- /dev/null
+++ b/Documentation/translations/zh_TW/admin-guide/unicode.rst
@@ -0,0 +1,174 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/admin-guide/unicode.rst
+
+:譯者:
+
+ 吳想成 Wu XiangCheng <bobwxc@email.cn>
+ 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+Unicode(統一碼)支持
+======================
+
+ (英文版)上次更新:2005-01-17,版本號 1.4
+
+此文檔由H. Peter Anvin <unicode@lanana.org>管理,是Linux註冊名稱與編號管理局
+(Linux Assigned Names And Numbers Authority,LANANA)項目的一部分。
+現行版本請見:
+
+ http://www.lanana.org/docs/unicode/admin-guide/unicode.rst
+
+簡介
+-----
+
+Linux內核代碼已被重寫以使用Unicode來將字符映射到字體。下載一個Unicode到字體
+(Unicode-to-font)表,八位字符集與UTF-8模式都將改用此字體來顯示。
+
+這微妙地改變了八位字符表的語義。現在的四個字符表是:
+
+=============== =============================== ================
+映射代號 映射名稱 Escape代碼 (G0)
+=============== =============================== ================
+LAT1_MAP Latin-1 (ISO 8859-1) ESC ( B
+GRAF_MAP DEC VT100 pseudographics ESC ( 0
+IBMPC_MAP IBM code page 437 ESC ( U
+USER_MAP User defined ESC ( K
+=============== =============================== ================
+
+特別是 ESC ( U 不再是“直通字體”,因爲字體可能與IBM字符集完全不同。
+例如,即使加載了一個Latin-1字體,也允許使用塊圖形(block graphics)。
+
+請注意,儘管這些代碼與ISO 2022類似,但這些代碼及其用途都與ISO 2022不匹配;
+Linux有兩個八位代碼(G0和G1),而ISO 2022有四個七位代碼(G0-G3)。
+
+根據Unicode標準/ISO 10646,U+F000到U+F8FF被保留用於操作系統範圍內的分配
+(Unicode標準將其稱爲“團體區域(Corporate Zone)”,因爲這對於Linux是不準確
+的,所以我們稱之爲“Linux區域”)。選擇U+F000作爲起點,因爲它允許直接映射
+區域以2的大倍數開始(以防需要1024或2048個字符的字體)。這就留下U+E000到
+U+EFFF作爲最終用戶區。
+
+[v1.2]:Unicodes範圍從U+F000到U+F7FF已經被硬編碼爲直接映射到加載的字體,
+繞過了翻譯表。用戶定義的映射現在默認爲U+F000到U+F0FF,模擬前述行爲。實際上,
+此範圍可能較短;例如,vgacon只能處理256字符(U+F000..U+F0FF)或512字符
+(U+F000..U+F1FF)字體。
+
+Linux 區域中定義的實際字符
+---------------------------
+
+此外,還定義了Unicode 1.1.4中不存在的以下字符;這些字符由DEC VT圖形映射使用。
+[v1.2]此用法已過時,不應再使用;請參見下文。
+
+====== ======================================
+U+F800 DEC VT GRAPHICS HORIZONTAL LINE SCAN 1
+U+F801 DEC VT GRAPHICS HORIZONTAL LINE SCAN 3
+U+F803 DEC VT GRAPHICS HORIZONTAL LINE SCAN 7
+U+F804 DEC VT GRAPHICS HORIZONTAL LINE SCAN 9
+====== ======================================
+
+DEC VT220使用6x10字符矩陣,這些字符在DEC VT圖形字符集中形成一個平滑的過渡。
+我省略了掃描5行,因爲它也被用作塊圖形字符,因此被編碼爲U+2500 FORMS LIGHT
+HORIZONTAL。
+
+[v1.3]:這些字符已正式添加到Unicode 3.2.0中;它們在U+23BA、U+23BB、U+23BC、
+U+23BD處添加。Linux現在使用新值。
+
+[v1.2]:添加了以下字符來表示常見的鍵盤符號,這些符號不太可能被添加到Unicode
+中,因爲它們非常討厭地取決於特定供應商。當然,這是糟糕設計的一個好例子。
+
+====== ======================================
+U+F810 KEYBOARD SYMBOL FLYING FLAG
+U+F811 KEYBOARD SYMBOL PULLDOWN MENU
+U+F812 KEYBOARD SYMBOL OPEN APPLE
+U+F813 KEYBOARD SYMBOL SOLID APPLE
+====== ======================================
+
+克林貢(Klingon)語支持
+------------------------
+
+1996年,Linux是世界上第一個添加對人工語言克林貢支持的操作系統,克林貢是由
+Marc Okrand爲《星際迷航》電視連續劇創造的。這種編碼後來被徵募Unicode註冊表
+(ConScript Unicode Registry,CSUR)採用,並建議(但最終被拒絕)納入Unicode
+平面一。不過,它仍然是Linux區域中的Linux/CSUR私有分配。
+
+這種編碼已經得到克林貢語言研究所(Klingon Language Institute)的認可。
+有關更多信息,請聯繫他們:
+
+ http://www.kli.org/
+
+由於Linux CZ開頭部分的字符大多是dingbats/symbols/forms類型,而且這是一種
+語言,因此根據標準Unicode慣例,我將它放置在16單元的邊界上。
+
+.. note::
+
+ 這個範圍現在由徵募Unicode註冊表正式管理。規範性引用文件爲:
+
+ https://www.evertype.com/standards/csur/klingon.html
+
+克林貢語有一個26個字符的字母表,一個10位數的位置數字書寫系統,從左到右
+,從上到下書寫。
+
+克林貢字母的幾種字形已經被提出。但是由於這組符號看起來始終是一致的,只有實際
+的形狀不同,因此按照標準Unicode慣例,這些差異被認爲是字體變體。
+
+====== =======================================================
+U+F8D0 KLINGON LETTER A
+U+F8D1 KLINGON LETTER B
+U+F8D2 KLINGON LETTER CH
+U+F8D3 KLINGON LETTER D
+U+F8D4 KLINGON LETTER E
+U+F8D5 KLINGON LETTER GH
+U+F8D6 KLINGON LETTER H
+U+F8D7 KLINGON LETTER I
+U+F8D8 KLINGON LETTER J
+U+F8D9 KLINGON LETTER L
+U+F8DA KLINGON LETTER M
+U+F8DB KLINGON LETTER N
+U+F8DC KLINGON LETTER NG
+U+F8DD KLINGON LETTER O
+U+F8DE KLINGON LETTER P
+U+F8DF KLINGON LETTER Q
+ - Written <q> in standard Okrand Latin transliteration
+U+F8E0 KLINGON LETTER QH
+ - Written <Q> in standard Okrand Latin transliteration
+U+F8E1 KLINGON LETTER R
+U+F8E2 KLINGON LETTER S
+U+F8E3 KLINGON LETTER T
+U+F8E4 KLINGON LETTER TLH
+U+F8E5 KLINGON LETTER U
+U+F8E6 KLINGON LETTER V
+U+F8E7 KLINGON LETTER W
+U+F8E8 KLINGON LETTER Y
+U+F8E9 KLINGON LETTER GLOTTAL STOP
+
+U+F8F0 KLINGON DIGIT ZERO
+U+F8F1 KLINGON DIGIT ONE
+U+F8F2 KLINGON DIGIT TWO
+U+F8F3 KLINGON DIGIT THREE
+U+F8F4 KLINGON DIGIT FOUR
+U+F8F5 KLINGON DIGIT FIVE
+U+F8F6 KLINGON DIGIT SIX
+U+F8F7 KLINGON DIGIT SEVEN
+U+F8F8 KLINGON DIGIT EIGHT
+U+F8F9 KLINGON DIGIT NINE
+
+U+F8FD KLINGON COMMA
+U+F8FE KLINGON FULL STOP
+U+F8FF KLINGON SYMBOL FOR EMPIRE
+====== =======================================================
+
+其他虛構和人工字母
+-------------------
+
+自從分配了克林貢Linux Unicode塊之後,John Cowan <jcowan@reutershealth.com>
+和 Michael Everson <everson@evertype.com> 建立了一個虛構和人工字母的註冊表。
+徵募Unicode註冊表請訪問:
+
+ https://www.evertype.com/standards/csur/
+
+所使用的範圍位於最終用戶區域的低端,因此無法進行規範化分配,但建議希望對虛構
+字母進行編碼的人員使用這些代碼,以實現互操作性。對於克林貢語,CSUR採用了Linux
+編碼。CSUR的人正在推動將Tengwar和Cirth添加到Unicode平面一;將克林貢添加到
+Unicode平面一被拒絕,因此上述編碼仍然是官方的。
+
diff --git a/Documentation/translations/zh_TW/arch/arm/Booting b/Documentation/translations/zh_TW/arch/arm/Booting
new file mode 100644
index 000000000000..a5375f262de2
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/arm/Booting
@@ -0,0 +1,176 @@
+Chinese translated version of Documentation/arch/arm/booting.rst
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly. However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help. Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Maintainer: Russell King <linux@arm.linux.org.uk>
+Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
+---------------------------------------------------------------------
+Documentation/arch/arm/booting.rst 的中文翻譯
+
+如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
+交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻
+譯存在問題,請聯繫中文版維護者。
+
+英文版維護者: Russell King <linux@arm.linux.org.uk>
+中文版維護者: 傅煒 Fu Wei <tekkamanninja@gmail.com>
+中文版翻譯者: 傅煒 Fu Wei <tekkamanninja@gmail.com>
+中文版校譯者: 傅煒 Fu Wei <tekkamanninja@gmail.com>
+
+以下爲正文
+---------------------------------------------------------------------
+
+ 啓動 ARM Linux
+ ==============
+
+作者:Russell King
+日期:2002年5月18日
+
+以下文檔適用於 2.4.18-rmk6 及以上版本。
+
+爲了啓動 ARM Linux,你需要一個引導裝載程序(boot loader),
+它是一個在主內核啓動前運行的一個小程序。引導裝載程序需要初始化各種
+設備,並最終調用 Linux 內核,將信息傳遞給內核。
+
+從本質上講,引導裝載程序應提供(至少)以下功能:
+
+1、設置和初始化 RAM。
+2、初始化一個串口。
+3、檢測機器的類型(machine type)。
+4、設置內核標籤列表(tagged list)。
+5、調用內核映像。
+
+
+1、設置和初始化 RAM
+-------------------
+
+現有的引導加載程序: 強制
+新開發的引導加載程序: 強制
+
+引導裝載程序應該找到並初始化系統中所有內核用於保持系統變量數據的 RAM。
+這個操作的執行是設備依賴的。(它可能使用內部算法來自動定位和計算所有
+RAM,或可能使用對這個設備已知的 RAM 信息,還可能使用任何引導裝載程序
+設計者想到的匹配方法。)
+
+
+2、初始化一個串口
+-----------------------------
+
+現有的引導加載程序: 可選、建議
+新開發的引導加載程序: 可選、建議
+
+引導加載程序應該初始化並使能一個目標板上的串口。這允許內核串口驅動
+自動檢測哪個串口用於內核控制檯。(一般用於調試或與目標板通信。)
+
+作爲替代方案,引導加載程序也可以通過標籤列表傳遞相關的'console='
+選項給內核以指定某個串口,而串口數據格式的選項在以下文檔中描述:
+
+ Documentation/admin-guide/kernel-parameters.rst。
+
+
+3、檢測機器類型
+--------------------------
+
+現有的引導加載程序: 可選
+新開發的引導加載程序: 強制
+
+引導加載程序應該通過某些方式檢測自身所處的機器類型。這是一個硬件
+代碼或通過查看所連接的硬件用某些算法得到,這些超出了本文檔的範圍。
+引導加載程序最終必須能提供一個 MACH_TYPE_xxx 值給內核。
+(詳見 linux/arch/arm/tools/mach-types )。
+
+4、設置啓動數據
+------------------
+
+現有的引導加載程序: 可選、強烈建議
+新開發的引導加載程序: 強制
+
+引導加載程序必須提供標籤列表或者 dtb 映像以傳遞配置數據給內核。啓動
+數據的物理地址通過寄存器 r2 傳遞給內核。
+
+4a、設置內核標籤列表
+--------------------------------
+
+bootloader 必須創建和初始化內核標籤列表。一個有效的標籤列表以
+ATAG_CORE 標籤開始,並以 ATAG_NONE 標籤結束。ATAG_CORE 標籤可以是
+空的,也可以是非空。一個空 ATAG_CORE 標籤其 size 域設置爲
+‘2’(0x00000002)。ATAG_NONE 標籤的 size 域必須設置爲零。
+
+在列表中可以保存任意數量的標籤。對於一個重複的標籤是追加到之前標籤
+所攜帶的信息之後,還是會覆蓋原來的信息,是未定義的。某些標籤的行爲
+是前者,其他是後者。
+
+bootloader 必須傳遞一個系統內存的位置和最小值,以及根文件系統位置。
+因此,最小的標籤列表如下所示:
+
+ +-----------+
+基地址 -> | ATAG_CORE | |
+ +-----------+ |
+ | ATAG_MEM | | 地址增長方向
+ +-----------+ |
+ | ATAG_NONE | |
+ +-----------+ v
+
+標籤列表應該保存在系統的 RAM 中。
+
+標籤列表必須置於內核自解壓和 initrd'bootp' 程序都不會覆蓋的內存區。
+建議放在 RAM 的頭 16KiB 中。
+
+4b、設置設備樹
+-------------------------
+
+bootloader 必須以 64bit 地址對齊的形式加載一個設備樹映像(dtb)到系統
+RAM 中,並用啓動數據初始化它。dtb 格式在文檔
+https://www.devicetree.org/specifications/ 中。內核將會在
+dtb 物理地址處查找 dtb 魔數值(0xd00dfeed),以確定 dtb 是否已經代替
+標籤列表被傳遞進來。
+
+bootloader 必須傳遞一個系統內存的位置和最小值,以及根文件系統位置。
+dtb 必須置於內核自解壓不會覆蓋的內存區。建議將其放置於 RAM 的頭 16KiB
+中。但是不可將其放置於“0”物理地址處,因爲內核認爲:r2 中爲 0,意味着
+沒有標籤列表和 dtb 傳遞過來。
+
+5、調用內核映像
+---------------------------
+
+現有的引導加載程序: 強制
+新開發的引導加載程序: 強制
+
+調用內核映像 zImage 有兩個選擇。如果 zImge 保存在 flash 中,且是爲了
+在 flash 中直接運行而被正確鏈接的。這樣引導加載程序就可以在 flash 中
+直接調用 zImage。
+
+zImage 也可以被放在系統 RAM(任意位置)中被調用。注意:內核使用映像
+基地址的前 16KB RAM 空間來保存頁表。建議將映像置於 RAM 的 32KB 處。
+
+對於以上任意一種情況,都必須符合以下啓動狀態:
+
+- 停止所有 DMA 設備,這樣內存數據就不會因爲虛假網絡包或磁盤數據而被破壞。
+ 這可能可以節省你許多的調試時間。
+
+- CPU 寄存器配置
+ r0 = 0,
+ r1 = (在上面 3 中獲取的)機器類型碼。
+ r2 = 標籤列表在系統 RAM 中的物理地址,或
+ 設備樹塊(dtb)在系統 RAM 中的物理地址
+
+- CPU 模式
+ 所有形式的中斷必須被禁止 (IRQs 和 FIQs)
+ CPU 必須處於 SVC 模式。(對於 Angel 調試有特例存在)
+
+- 緩存,MMUs
+ MMU 必須關閉。
+ 指令緩存開啓或關閉都可以。
+ 數據緩存必須關閉。
+
+- 引導加載程序應該通過直接跳轉到內核映像的第一條指令來調用內核映像。
+
+ 對於支持 ARM 指令集的 CPU,跳入內核入口時必須處在 ARM 狀態,即使
+ 對於 Thumb-2 內核也是如此。
+
+ 對於僅支持 Thumb 指令集的 CPU,比如 Cortex-M 系列的 CPU,跳入
+ 內核入口時必須處於 Thumb 狀態。
+
diff --git a/Documentation/translations/zh_TW/arch/arm/kernel_user_helpers.txt b/Documentation/translations/zh_TW/arch/arm/kernel_user_helpers.txt
new file mode 100644
index 000000000000..4c0bff97af31
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/arm/kernel_user_helpers.txt
@@ -0,0 +1,285 @@
+Chinese translated version of Documentation/arch/arm/kernel_user_helpers.rst
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly. However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help. Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Maintainer: Nicolas Pitre <nicolas.pitre@linaro.org>
+ Dave Martin <dave.martin@linaro.org>
+Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
+---------------------------------------------------------------------
+Documentation/arch/arm/kernel_user_helpers.rst 的中文翻譯
+
+如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
+交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻
+譯存在問題,請聯繫中文版維護者。
+英文版維護者: Nicolas Pitre <nicolas.pitre@linaro.org>
+ Dave Martin <dave.martin@linaro.org>
+中文版維護者: 傅煒 Fu Wei <tekkamanninja@gmail.com>
+中文版翻譯者: 傅煒 Fu Wei <tekkamanninja@gmail.com>
+中文版校譯者: 宋冬生 Dongsheng Song <dongshneg.song@gmail.com>
+ 傅煒 Fu Wei <tekkamanninja@gmail.com>
+
+
+以下爲正文
+---------------------------------------------------------------------
+內核提供的用戶空間輔助代碼
+=========================
+
+在內核內存空間的固定地址處,有一個由內核提供並可從用戶空間訪問的代碼
+段。它用於向用戶空間提供因在許多 ARM CPU 中未實現的特性和/或指令而需
+內核提供幫助的某些操作。這些代碼直接在用戶模式下執行的想法是爲了獲得
+最佳效率,但那些與內核計數器聯繫過於緊密的部分,則被留給了用戶庫實現。
+事實上,此代碼甚至可能因不同的 CPU 而異,這取決於其可用的指令集或它
+是否爲 SMP 系統。換句話說,內核保留在不作出警告的情況下根據需要更改
+這些代碼的權利。只有本文檔描述的入口及其結果是保證穩定的。
+
+這與完全成熟的 VDSO 實現不同(但兩者並不衝突),儘管如此,VDSO 可阻止
+某些通過常量高效跳轉到那些代碼段的彙編技巧。且由於那些代碼段在返回用戶
+代碼前僅使用少量的代碼週期,則一個 VDSO 間接遠程調用將會在這些簡單的
+操作上增加一個可測量的開銷。
+
+在對那些擁有原生支持的新型處理器進行代碼優化時,僅在已爲其他操作使用
+了類似的新增指令,而導致二進制結果已與早期 ARM 處理器不兼容的情況下,
+用戶空間才應繞過這些輔助代碼,並在內聯函數中實現這些操作(無論是通過
+編譯器在代碼中直接放置,還是作爲庫函數調用實現的一部分)。也就是說,
+如果你編譯的代碼不會爲了其他目的使用新指令,則不要僅爲了避免使用這些
+內核輔助代碼,導致二進制程序無法在早期處理器上運行。
+
+新的輔助代碼可能隨着時間的推移而增加,所以新內核中的某些輔助代碼在舊
+內核中可能不存在。因此,程序必須在對任何輔助代碼調用假設是安全之前,
+檢測 __kuser_helper_version 的值(見下文)。理想情況下,這種檢測應該
+只在進程啓動時執行一次;如果內核版本不支持所需輔助代碼,則該進程可儘早
+中止執行。
+
+kuser_helper_version
+--------------------
+
+位置: 0xffff0ffc
+
+參考聲明:
+
+ extern int32_t __kuser_helper_version;
+
+定義:
+
+ 這個區域包含了當前運行內核實現的輔助代碼版本號。用戶空間可以通過讀
+ 取此版本號以確定特定的輔助代碼是否存在。
+
+使用範例:
+
+#define __kuser_helper_version (*(int32_t *)0xffff0ffc)
+
+void check_kuser_version(void)
+{
+ if (__kuser_helper_version < 2) {
+ fprintf(stderr, "can't do atomic operations, kernel too old\n");
+ abort();
+ }
+}
+
+注意:
+
+ 用戶空間可以假設這個域的值不會在任何單個進程的生存期內改變。也就
+ 是說,這個域可以僅在庫的初始化階段或進程啓動階段讀取一次。
+
+kuser_get_tls
+-------------
+
+位置: 0xffff0fe0
+
+參考原型:
+
+ void * __kuser_get_tls(void);
+
+輸入:
+
+ lr = 返回地址
+
+輸出:
+
+ r0 = TLS 值
+
+被篡改的寄存器:
+
+ 無
+
+定義:
+
+ 獲取之前通過 __ARM_NR_set_tls 系統調用設置的 TLS 值。
+
+使用範例:
+
+typedef void * (__kuser_get_tls_t)(void);
+#define __kuser_get_tls (*(__kuser_get_tls_t *)0xffff0fe0)
+
+void foo()
+{
+ void *tls = __kuser_get_tls();
+ printf("TLS = %p\n", tls);
+}
+
+注意:
+
+ - 僅在 __kuser_helper_version >= 1 時,此輔助代碼存在
+ (從內核版本 2.6.12 開始)。
+
+kuser_cmpxchg
+-------------
+
+位置: 0xffff0fc0
+
+參考原型:
+
+ int __kuser_cmpxchg(int32_t oldval, int32_t newval, volatile int32_t *ptr);
+
+輸入:
+
+ r0 = oldval
+ r1 = newval
+ r2 = ptr
+ lr = 返回地址
+
+輸出:
+
+ r0 = 成功代碼 (零或非零)
+ C flag = 如果 r0 == 0 則置 1,如果 r0 != 0 則清零。
+
+被篡改的寄存器:
+
+ r3, ip, flags
+
+定義:
+
+ 僅在 *ptr 爲 oldval 時原子保存 newval 於 *ptr 中。
+ 如果 *ptr 被改變,則返回值爲零,否則爲非零值。
+ 如果 *ptr 被改變,則 C flag 也會被置 1,以實現調用代碼中的彙編
+ 優化。
+
+使用範例:
+
+typedef int (__kuser_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
+#define __kuser_cmpxchg (*(__kuser_cmpxchg_t *)0xffff0fc0)
+
+int atomic_add(volatile int *ptr, int val)
+{
+ int old, new;
+
+ do {
+ old = *ptr;
+ new = old + val;
+ } while(__kuser_cmpxchg(old, new, ptr));
+
+ return new;
+}
+
+注意:
+
+ - 這個例程已根據需要包含了內存屏障。
+
+ - 僅在 __kuser_helper_version >= 2 時,此輔助代碼存在
+ (從內核版本 2.6.12 開始)。
+
+kuser_memory_barrier
+--------------------
+
+位置: 0xffff0fa0
+
+參考原型:
+
+ void __kuser_memory_barrier(void);
+
+輸入:
+
+ lr = 返回地址
+
+輸出:
+
+ 無
+
+被篡改的寄存器:
+
+ 無
+
+定義:
+
+ 應用於任何需要內存屏障以防止手動數據修改帶來的一致性問題,以及
+ __kuser_cmpxchg 中。
+
+使用範例:
+
+typedef void (__kuser_dmb_t)(void);
+#define __kuser_dmb (*(__kuser_dmb_t *)0xffff0fa0)
+
+注意:
+
+ - 僅在 __kuser_helper_version >= 3 時,此輔助代碼存在
+ (從內核版本 2.6.15 開始)。
+
+kuser_cmpxchg64
+---------------
+
+位置: 0xffff0f60
+
+參考原型:
+
+ int __kuser_cmpxchg64(const int64_t *oldval,
+ const int64_t *newval,
+ volatile int64_t *ptr);
+
+輸入:
+
+ r0 = 指向 oldval
+ r1 = 指向 newval
+ r2 = 指向目標值
+ lr = 返回地址
+
+輸出:
+
+ r0 = 成功代碼 (零或非零)
+ C flag = 如果 r0 == 0 則置 1,如果 r0 != 0 則清零。
+
+被篡改的寄存器:
+
+ r3, lr, flags
+
+定義:
+
+ 僅在 *ptr 等於 *oldval 指向的 64 位值時,原子保存 *newval
+ 指向的 64 位值於 *ptr 中。如果 *ptr 被改變,則返回值爲零,
+ 否則爲非零值。
+
+ 如果 *ptr 被改變,則 C flag 也會被置 1,以實現調用代碼中的彙編
+ 優化。
+
+使用範例:
+
+typedef int (__kuser_cmpxchg64_t)(const int64_t *oldval,
+ const int64_t *newval,
+ volatile int64_t *ptr);
+#define __kuser_cmpxchg64 (*(__kuser_cmpxchg64_t *)0xffff0f60)
+
+int64_t atomic_add64(volatile int64_t *ptr, int64_t val)
+{
+ int64_t old, new;
+
+ do {
+ old = *ptr;
+ new = old + val;
+ } while(__kuser_cmpxchg64(&old, &new, ptr));
+
+ return new;
+}
+
+注意:
+
+ - 這個例程已根據需要包含了內存屏障。
+
+ - 由於這個過程的代碼長度(此輔助代碼跨越 2 個常規的 kuser “槽”),
+ 因此 0xffff0f80 不被作爲有效的入口點。
+
+ - 僅在 __kuser_helper_version >= 5 時,此輔助代碼存在
+ (從內核版本 3.1 開始)。
+
diff --git a/Documentation/translations/zh_TW/arch/arm64/amu.rst b/Documentation/translations/zh_TW/arch/arm64/amu.rst
new file mode 100644
index 000000000000..3726c1671ab6
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/arm64/amu.rst
@@ -0,0 +1,104 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/arch/arm64/amu.rst <amu_index>`
+
+Translator: Bailu Lin <bailu.lin@vivo.com>
+ Hu Haowen <2023002089@link.tyut.edu.cn>
+
+==================================
+AArch64 Linux 中擴展的活動監控單元
+==================================
+
+作者: Ionela Voinescu <ionela.voinescu@arm.com>
+
+日期: 2019-09-10
+
+本文檔簡要描述了 AArch64 Linux 支持的活動監控單元的規範。
+
+
+架構總述
+--------
+
+活動監控是 ARMv8.4 CPU 架構引入的一個可選擴展特性。
+
+活動監控單元(在每個 CPU 中實現)爲系統管理提供了性能計數器。既可以通
+過系統寄存器的方式訪問計數器,同時也支持外部內存映射的方式訪問計數器。
+
+AMUv1 架構實現了一個由4個固定的64位事件計數器組成的計數器組。
+
+ - CPU 週期計數器:同 CPU 的頻率增長
+ - 常量計數器:同固定的系統時鐘頻率增長
+ - 淘汰指令計數器: 同每次架構指令執行增長
+ - 內存停頓週期計數器:計算由在時鐘域內的最後一級緩存中未命中而引起
+ 的指令調度停頓週期數
+
+當處於 WFI 或者 WFE 狀態時,計數器不會增長。
+
+AMU 架構提供了一個高達16位的事件計數器空間,未來新的 AMU 版本中可能
+用它來實現新增的事件計數器。
+
+另外,AMUv1 實現了一個多達16個64位輔助事件計數器的計數器組。
+
+冷復位時所有的計數器會清零。
+
+
+基本支持
+--------
+
+內核可以安全地運行在支持 AMU 和不支持 AMU 的 CPU 組合中。
+因此,當配置 CONFIG_ARM64_AMU_EXTN 後我們無條件使能後續
+(secondary or hotplugged) CPU 檢測和使用這個特性。
+
+當在 CPU 上檢測到該特性時,我們會標記爲特性可用但是不能保證計數器的功能,
+僅表明有擴展屬性。
+
+固件(代碼運行在高異常級別,例如 arm-tf )需支持以下功能:
+
+ - 提供低異常級別(EL2 和 EL1)訪問 AMU 寄存器的能力。
+ - 使能計數器。如果未使能,它的值應爲 0。
+ - 在從電源關閉狀態啓動 CPU 前或後保存或者恢復計數器。
+
+當使用使能了該特性的內核啓動但固件損壞時,訪問計數器寄存器可能會遭遇
+panic 或者死鎖。即使未發現這些症狀,計數器寄存器返回的數據結果並不一
+定能反映真實情況。通常,計數器會返回 0,表明他們未被使能。
+
+如果固件沒有提供適當的支持最好關閉 CONFIG_ARM64_AMU_EXTN。
+值得注意的是,出於安全原因,不要繞過 AMUSERRENR_EL0 設置而捕獲從
+EL0(用戶空間) 訪問 EL1(內核空間)。 因此,固件應該確保訪問 AMU寄存器
+不會困在 EL2或EL3。
+
+AMUv1 的固定計數器可以通過如下系統寄存器訪問:
+
+ - SYS_AMEVCNTR0_CORE_EL0
+ - SYS_AMEVCNTR0_CONST_EL0
+ - SYS_AMEVCNTR0_INST_RET_EL0
+ - SYS_AMEVCNTR0_MEM_STALL_EL0
+
+特定輔助計數器可以通過 SYS_AMEVCNTR1_EL0(n) 訪問,其中n介於0到15。
+
+詳細信息定義在目錄:arch/arm64/include/asm/sysreg.h。
+
+
+用戶空間訪問
+------------
+
+由於以下原因,當前禁止從用戶空間訪問 AMU 的寄存器:
+
+ - 安全因數:可能會暴露處於安全模式執行的代碼信息。
+ - 意願:AMU 是用於系統管理的。
+
+同樣,該功能對用戶空間不可見。
+
+
+虛擬化
+------
+
+由於以下原因,當前禁止從 KVM 客戶端的用戶空間(EL0)和內核空間(EL1)
+訪問 AMU 的寄存器:
+
+ - 安全因數:可能會暴露給其他客戶端或主機端執行的代碼信息。
+
+任何試圖訪問 AMU 寄存器的行爲都會觸發一個註冊在客戶端的未定義異常。
+
diff --git a/Documentation/translations/zh_TW/arch/arm64/booting.txt b/Documentation/translations/zh_TW/arch/arm64/booting.txt
new file mode 100644
index 000000000000..f1ac96370ace
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/arm64/booting.txt
@@ -0,0 +1,251 @@
+SPDX-License-Identifier: GPL-2.0
+
+Chinese translated version of Documentation/arch/arm64/booting.rst
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly. However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help. Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+M: Will Deacon <will.deacon@arm.com>
+zh_CN: Fu Wei <wefu@redhat.com>
+zh_TW: Hu Haowen <2023002089@link.tyut.edu.cn>
+C: 55f058e7574c3615dea4615573a19bdb258696c6
+---------------------------------------------------------------------
+Documentation/arch/arm64/booting.rst 的中文翻譯
+
+如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
+交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻
+譯存在問題,請聯繫中文版維護者。
+
+英文版維護者: Will Deacon <will.deacon@arm.com>
+中文版維護者: 傅煒 Fu Wei <wefu@redhat.com>
+中文版翻譯者: 傅煒 Fu Wei <wefu@redhat.com>
+中文版校譯者: 傅煒 Fu Wei <wefu@redhat.com>
+繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+本文翻譯提交時的 Git 檢出點爲: 55f058e7574c3615dea4615573a19bdb258696c6
+
+以下爲正文
+---------------------------------------------------------------------
+ 啓動 AArch64 Linux
+ ==================
+
+作者: Will Deacon <will.deacon@arm.com>
+日期: 2012 年 09 月 07 日
+
+本文檔基於 Russell King 的 ARM 啓動文檔,且適用於所有公開發布的
+AArch64 Linux 內核代碼。
+
+AArch64 異常模型由多個異常級(EL0 - EL3)組成,對於 EL0 和 EL1 異常級
+有對應的安全和非安全模式。EL2 是系統管理級,且僅存在於非安全模式下。
+EL3 是最高特權級,且僅存在於安全模式下。
+
+基於本文檔的目的,我們將簡單地使用‘引導裝載程序’(‘boot loader’)
+這個術語來定義在將控制權交給 Linux 內核前 CPU 上執行的所有軟件。
+這可能包含安全監控和系統管理代碼,或者它可能只是一些用於準備最小啓動
+環境的指令。
+
+基本上,引導裝載程序(至少)應實現以下操作:
+
+1、設置和初始化 RAM
+2、設置設備樹數據
+3、解壓內核映像
+4、調用內核映像
+
+
+1、設置和初始化 RAM
+-----------------
+
+必要性: 強制
+
+引導裝載程序應該找到並初始化系統中所有內核用於保持系統變量數據的 RAM。
+這個操作的執行方式因設備而異。(它可能使用內部算法來自動定位和計算所有
+RAM,或可能使用對這個設備已知的 RAM 信息,還可能是引導裝載程序設計者
+想到的任何合適的方法。)
+
+
+2、設置設備樹數據
+---------------
+
+必要性: 強制
+
+設備樹數據塊(dtb)必須 8 字節對齊,且大小不能超過 2MB。由於設備樹
+數據塊將在使能緩存的情況下以 2MB 粒度被映射,故其不能被置於必須以特定
+屬性映射的2M區域內。
+
+注: v4.2 之前的版本同時要求設備樹數據塊被置於從內核映像以下
+text_offset 字節處算起第一個 512MB 內。
+
+3、解壓內核映像
+-------------
+
+必要性: 可選
+
+AArch64 內核當前沒有提供自解壓代碼,因此如果使用了壓縮內核映像文件
+(比如 Image.gz),則需要通過引導裝載程序(使用 gzip 等)來進行解壓。
+若引導裝載程序沒有實現這個功能,就要使用非壓縮內核映像文件。
+
+
+4、調用內核映像
+-------------
+
+必要性: 強制
+
+已解壓的內核映像包含一個 64 字節的頭,內容如下:
+
+ u32 code0; /* 可執行代碼 */
+ u32 code1; /* 可執行代碼 */
+ u64 text_offset; /* 映像裝載偏移,小端模式 */
+ u64 image_size; /* 映像實際大小, 小端模式 */
+ u64 flags; /* 內核旗標, 小端模式 *
+ u64 res2 = 0; /* 保留 */
+ u64 res3 = 0; /* 保留 */
+ u64 res4 = 0; /* 保留 */
+ u32 magic = 0x644d5241; /* 魔數, 小端, "ARM\x64" */
+ u32 res5; /* 保留 (用於 PE COFF 偏移) */
+
+
+映像頭註釋:
+
+- 自 v3.17 起,除非另有說明,所有域都是小端模式。
+
+- code0/code1 負責跳轉到 stext.
+
+- 當通過 EFI 啓動時, 最初 code0/code1 被跳過。
+ res5 是到 PE 文件頭的偏移,而 PE 文件頭含有 EFI 的啓動入口點
+ (efi_stub_entry)。當 stub 代碼完成了它的使命,它會跳轉到 code0
+ 繼續正常的啓動流程。
+
+- v3.17 之前,未明確指定 text_offset 的字節序。此時,image_size 爲零,
+ 且 text_offset 依照內核字節序爲 0x80000。
+ 當 image_size 非零,text_offset 爲小端模式且是有效值,應被引導加載
+ 程序使用。當 image_size 爲零,text_offset 可假定爲 0x80000。
+
+- flags 域 (v3.17 引入) 爲 64 位小端模式,其編碼如下:
+ 位 0: 內核字節序。 1 表示大端模式,0 表示小端模式。
+ 位 1-2: 內核頁大小。
+ 0 - 未指定。
+ 1 - 4K
+ 2 - 16K
+ 3 - 64K
+ 位 3: 內核物理位置
+ 0 - 2MB 對齊基址應儘量靠近內存起始處,因爲
+ 其基址以下的內存無法通過線性映射訪問
+ 1 - 2MB 對齊基址可以在物理內存的任意位置
+ 位 4-63: 保留。
+
+- 當 image_size 爲零時,引導裝載程序應試圖在內核映像末尾之後儘可能
+ 多地保留空閒內存供內核直接使用。對內存空間的需求量因所選定的內核
+ 特性而異, 並無實際限制。
+
+內核映像必須被放置在任意一個可用系統內存 2MB 對齊基址的 text_offset
+字節處,並從該處被調用。2MB 對齊基址和內核映像起始地址之間的區域對於
+內核來說沒有特殊意義,且可能被用於其他目的。
+從映像起始地址算起,最少必須準備 image_size 字節的空閒內存供內核使用。
+注: v4.6 之前的版本無法使用內核映像物理偏移以下的內存,所以當時建議
+將映像儘量放置在靠近系統內存起始的地方。
+
+任何提供給內核的內存(甚至在映像起始地址之前),若未從內核中標記爲保留
+(如在設備樹(dtb)的 memreserve 區域),都將被認爲對內核是可用。
+
+在跳轉入內核前,必須符合以下狀態:
+
+- 停止所有 DMA 設備,這樣內存數據就不會因爲虛假網絡包或磁盤數據而
+ 被破壞。這可能可以節省你許多的調試時間。
+
+- 主 CPU 通用寄存器設置
+ x0 = 系統 RAM 中設備樹數據塊(dtb)的物理地址。
+ x1 = 0 (保留,將來可能使用)
+ x2 = 0 (保留,將來可能使用)
+ x3 = 0 (保留,將來可能使用)
+
+- CPU 模式
+ 所有形式的中斷必須在 PSTATE.DAIF 中被屏蔽(Debug、SError、IRQ
+ 和 FIQ)。
+ CPU 必須處於 EL2(推薦,可訪問虛擬化擴展)或非安全 EL1 模式下。
+
+- 高速緩存、MMU
+ MMU 必須關閉。
+ 指令緩存開啓或關閉皆可。
+ 已載入的內核映像的相應內存區必須被清理,以達到緩存一致性點(PoC)。
+ 當存在系統緩存或其他使能緩存的一致性主控器時,通常需使用虛擬地址
+ 維護其緩存,而非 set/way 操作。
+ 遵從通過虛擬地址操作維護構架緩存的系統緩存必須被配置,並可以被使能。
+ 而不通過虛擬地址操作維護構架緩存的系統緩存(不推薦),必須被配置且
+ 禁用。
+
+ *譯者注:對於 PoC 以及緩存相關內容,請參考 ARMv8 構架參考手冊
+ ARM DDI 0487A
+
+- 架構計時器
+ CNTFRQ 必須設定爲計時器的頻率,且 CNTVOFF 必須設定爲對所有 CPU
+ 都一致的值。如果在 EL1 模式下進入內核,則 CNTHCTL_EL2 中的
+ EL1PCTEN (bit 0) 必須置位。
+
+- 一致性
+ 通過內核啓動的所有 CPU 在內核入口地址上必須處於相同的一致性域中。
+ 這可能要根據具體實現來定義初始化過程,以使能每個CPU上對維護操作的
+ 接收。
+
+- 系統寄存器
+ 在進入內核映像的異常級中,所有構架中可寫的系統寄存器必須通過軟件
+ 在一個更高的異常級別下初始化,以防止在 未知 狀態下運行。
+
+ 對於擁有 GICv3 中斷控制器並以 v3 模式運行的系統:
+ - 如果 EL3 存在:
+ ICC_SRE_EL3.Enable (位 3) 必須初始化爲 0b1。
+ ICC_SRE_EL3.SRE (位 0) 必須初始化爲 0b1。
+ - 若內核運行在 EL1:
+ ICC_SRE_EL2.Enable (位 3) 必須初始化爲 0b1。
+ ICC_SRE_EL2.SRE (位 0) 必須初始化爲 0b1。
+ - 設備樹(DT)或 ACPI 表必須描述一個 GICv3 中斷控制器。
+
+ 對於擁有 GICv3 中斷控制器並以兼容(v2)模式運行的系統:
+ - 如果 EL3 存在:
+ ICC_SRE_EL3.SRE (位 0) 必須初始化爲 0b0。
+ - 若內核運行在 EL1:
+ ICC_SRE_EL2.SRE (位 0) 必須初始化爲 0b0。
+ - 設備樹(DT)或 ACPI 表必須描述一個 GICv2 中斷控制器。
+
+以上對於 CPU 模式、高速緩存、MMU、架構計時器、一致性、系統寄存器的
+必要條件描述適用於所有 CPU。所有 CPU 必須在同一異常級別跳入內核。
+
+引導裝載程序必須在每個 CPU 處於以下狀態時跳入內核入口:
+
+- 主 CPU 必須直接跳入內核映像的第一條指令。通過此 CPU 傳遞的設備樹
+ 數據塊必須在每個 CPU 節點中包含一個 ‘enable-method’ 屬性,所
+ 支持的 enable-method 請見下文。
+
+ 引導裝載程序必須生成這些設備樹屬性,並在跳入內核入口之前將其插入
+ 數據塊。
+
+- enable-method 爲 “spin-table” 的 CPU 必須在它們的 CPU
+ 節點中包含一個 ‘cpu-release-addr’ 屬性。這個屬性標識了一個
+ 64 位自然對齊且初始化爲零的內存位置。
+
+ 這些 CPU 必須在內存保留區(通過設備樹中的 /memreserve/ 域傳遞
+ 給內核)中自旋於內核之外,輪詢它們的 cpu-release-addr 位置(必須
+ 包含在保留區中)。可通過插入 wfe 指令來降低忙循環開銷,而主 CPU 將
+ 發出 sev 指令。當對 cpu-release-addr 所指位置的讀取操作返回非零值
+ 時,CPU 必須跳入此值所指向的地址。此值爲一個單獨的 64 位小端值,
+ 因此 CPU 須在跳轉前將所讀取的值轉換爲其本身的端模式。
+
+- enable-method 爲 “psci” 的 CPU 保持在內核外(比如,在
+ memory 節點中描述爲內核空間的內存區外,或在通過設備樹 /memreserve/
+ 域中描述爲內核保留區的空間中)。內核將會發起在 ARM 文檔(編號
+ ARM DEN 0022A:用於 ARM 上的電源狀態協調接口系統軟件)中描述的
+ CPU_ON 調用來將 CPU 帶入內核。
+
+ *譯者注: ARM DEN 0022A 已更新到 ARM DEN 0022C。
+
+ 設備樹必須包含一個 ‘psci’ 節點,請參考以下文檔:
+ Documentation/devicetree/bindings/arm/psci.yaml
+
+
+- 輔助 CPU 通用寄存器設置
+ x0 = 0 (保留,將來可能使用)
+ x1 = 0 (保留,將來可能使用)
+ x2 = 0 (保留,將來可能使用)
+ x3 = 0 (保留,將來可能使用)
+
diff --git a/Documentation/translations/zh_TW/arch/arm64/elf_hwcaps.rst b/Documentation/translations/zh_TW/arch/arm64/elf_hwcaps.rst
new file mode 100644
index 000000000000..cada25303e8d
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/arm64/elf_hwcaps.rst
@@ -0,0 +1,244 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/arch/arm64/elf_hwcaps.rst <elf_hwcaps_index>`
+
+Translator: Bailu Lin <bailu.lin@vivo.com>
+ Hu Haowen <2023002089@link.tyut.edu.cn>
+
+================
+ARM64 ELF hwcaps
+================
+
+這篇文檔描述了 arm64 ELF hwcaps 的用法和語義。
+
+
+1. 簡介
+-------
+
+有些硬件或軟件功能僅在某些 CPU 實現上和/或在具體某個內核配置上可用,但
+對於處於 EL0 的用戶空間代碼沒有可用的架構發現機制。內核通過在輔助向量表
+公開一組稱爲 hwcaps 的標誌而把這些功能暴露給用戶空間。
+
+用戶空間軟件可以通過獲取輔助向量的 AT_HWCAP 或 AT_HWCAP2 條目來測試功能,
+並測試是否設置了相關標誌,例如::
+
+ bool floating_point_is_present(void)
+ {
+ unsigned long hwcaps = getauxval(AT_HWCAP);
+ if (hwcaps & HWCAP_FP)
+ return true;
+
+ return false;
+ }
+
+如果軟件依賴於 hwcap 描述的功能,在嘗試使用該功能前則應檢查相關的 hwcap
+標誌以驗證該功能是否存在。
+
+不能通過其他方式探查這些功能。當一個功能不可用時,嘗試使用它可能導致不可
+預測的行爲,並且無法保證能確切的知道該功能不可用,例如 SIGILL。
+
+
+2. Hwcaps 的說明
+----------------
+
+大多數 hwcaps 旨在說明通過架構 ID 寄存器(處於 EL0 的用戶空間代碼無法訪問)
+描述的功能的存在。這些 hwcap 通過 ID 寄存器字段定義,並且應根據 ARM 體系
+結構參考手冊(ARM ARM)中定義的字段來解釋說明。
+
+這些 hwcaps 以下面的形式描述::
+
+ idreg.field == val 表示有某個功能。
+
+當 idreg.field 中有 val 時,hwcaps 表示 ARM ARM 定義的功能是有效的,但是
+並不是說要完全和 val 相等,也不是說 idreg.field 描述的其他功能就是缺失的。
+
+其他 hwcaps 可能表明無法僅由 ID 寄存器描述的功能的存在。這些 hwcaps 可能
+沒有被 ID 寄存器描述,需要參考其他文檔。
+
+
+3. AT_HWCAP 中揭示的 hwcaps
+---------------------------
+
+HWCAP_FP
+ ID_AA64PFR0_EL1.FP == 0b0000 表示有此功能。
+
+HWCAP_ASIMD
+ ID_AA64PFR0_EL1.AdvSIMD == 0b0000 表示有此功能。
+
+HWCAP_EVTSTRM
+ 通用計時器頻率配置爲大約100KHz以生成事件。
+
+HWCAP_AES
+ ID_AA64ISAR0_EL1.AES == 0b0001 表示有此功能。
+
+HWCAP_PMULL
+ ID_AA64ISAR0_EL1.AES == 0b0010 表示有此功能。
+
+HWCAP_SHA1
+ ID_AA64ISAR0_EL1.SHA1 == 0b0001 表示有此功能。
+
+HWCAP_SHA2
+ ID_AA64ISAR0_EL1.SHA2 == 0b0001 表示有此功能。
+
+HWCAP_CRC32
+ ID_AA64ISAR0_EL1.CRC32 == 0b0001 表示有此功能。
+
+HWCAP_ATOMICS
+ ID_AA64ISAR0_EL1.Atomic == 0b0010 表示有此功能。
+
+HWCAP_FPHP
+ ID_AA64PFR0_EL1.FP == 0b0001 表示有此功能。
+
+HWCAP_ASIMDHP
+ ID_AA64PFR0_EL1.AdvSIMD == 0b0001 表示有此功能。
+
+HWCAP_CPUID
+ 根據 Documentation/arch/arm64/cpu-feature-registers.rst 描述,EL0 可以訪問
+ 某些 ID 寄存器。
+
+ 這些 ID 寄存器可能表示功能的可用性。
+
+HWCAP_ASIMDRDM
+ ID_AA64ISAR0_EL1.RDM == 0b0001 表示有此功能。
+
+HWCAP_JSCVT
+ ID_AA64ISAR1_EL1.JSCVT == 0b0001 表示有此功能。
+
+HWCAP_FCMA
+ ID_AA64ISAR1_EL1.FCMA == 0b0001 表示有此功能。
+
+HWCAP_LRCPC
+ ID_AA64ISAR1_EL1.LRCPC == 0b0001 表示有此功能。
+
+HWCAP_DCPOP
+ ID_AA64ISAR1_EL1.DPB == 0b0001 表示有此功能。
+
+HWCAP_SHA3
+ ID_AA64ISAR0_EL1.SHA3 == 0b0001 表示有此功能。
+
+HWCAP_SM3
+ ID_AA64ISAR0_EL1.SM3 == 0b0001 表示有此功能。
+
+HWCAP_SM4
+ ID_AA64ISAR0_EL1.SM4 == 0b0001 表示有此功能。
+
+HWCAP_ASIMDDP
+ ID_AA64ISAR0_EL1.DP == 0b0001 表示有此功能。
+
+HWCAP_SHA512
+ ID_AA64ISAR0_EL1.SHA2 == 0b0010 表示有此功能。
+
+HWCAP_SVE
+ ID_AA64PFR0_EL1.SVE == 0b0001 表示有此功能。
+
+HWCAP_ASIMDFHM
+ ID_AA64ISAR0_EL1.FHM == 0b0001 表示有此功能。
+
+HWCAP_DIT
+ ID_AA64PFR0_EL1.DIT == 0b0001 表示有此功能。
+
+HWCAP_USCAT
+ ID_AA64MMFR2_EL1.AT == 0b0001 表示有此功能。
+
+HWCAP_ILRCPC
+ ID_AA64ISAR1_EL1.LRCPC == 0b0010 表示有此功能。
+
+HWCAP_FLAGM
+ ID_AA64ISAR0_EL1.TS == 0b0001 表示有此功能。
+
+HWCAP_SSBS
+ ID_AA64PFR1_EL1.SSBS == 0b0010 表示有此功能。
+
+HWCAP_SB
+ ID_AA64ISAR1_EL1.SB == 0b0001 表示有此功能。
+
+HWCAP_PACA
+ 如 Documentation/arch/arm64/pointer-authentication.rst 所描述,
+ ID_AA64ISAR1_EL1.APA == 0b0001 或 ID_AA64ISAR1_EL1.API == 0b0001
+ 表示有此功能。
+
+HWCAP_PACG
+ 如 Documentation/arch/arm64/pointer-authentication.rst 所描述,
+ ID_AA64ISAR1_EL1.GPA == 0b0001 或 ID_AA64ISAR1_EL1.GPI == 0b0001
+ 表示有此功能。
+
+HWCAP2_DCPODP
+
+ ID_AA64ISAR1_EL1.DPB == 0b0010 表示有此功能。
+
+HWCAP2_SVE2
+
+ ID_AA64ZFR0_EL1.SVEVer == 0b0001 表示有此功能。
+
+HWCAP2_SVEAES
+
+ ID_AA64ZFR0_EL1.AES == 0b0001 表示有此功能。
+
+HWCAP2_SVEPMULL
+
+ ID_AA64ZFR0_EL1.AES == 0b0010 表示有此功能。
+
+HWCAP2_SVEBITPERM
+
+ ID_AA64ZFR0_EL1.BitPerm == 0b0001 表示有此功能。
+
+HWCAP2_SVESHA3
+
+ ID_AA64ZFR0_EL1.SHA3 == 0b0001 表示有此功能。
+
+HWCAP2_SVESM4
+
+ ID_AA64ZFR0_EL1.SM4 == 0b0001 表示有此功能。
+
+HWCAP2_FLAGM2
+
+ ID_AA64ISAR0_EL1.TS == 0b0010 表示有此功能。
+
+HWCAP2_FRINT
+
+ ID_AA64ISAR1_EL1.FRINTTS == 0b0001 表示有此功能。
+
+HWCAP2_SVEI8MM
+
+ ID_AA64ZFR0_EL1.I8MM == 0b0001 表示有此功能。
+
+HWCAP2_SVEF32MM
+
+ ID_AA64ZFR0_EL1.F32MM == 0b0001 表示有此功能。
+
+HWCAP2_SVEF64MM
+
+ ID_AA64ZFR0_EL1.F64MM == 0b0001 表示有此功能。
+
+HWCAP2_SVEBF16
+
+ ID_AA64ZFR0_EL1.BF16 == 0b0001 表示有此功能。
+
+HWCAP2_I8MM
+
+ ID_AA64ISAR1_EL1.I8MM == 0b0001 表示有此功能。
+
+HWCAP2_BF16
+
+ ID_AA64ISAR1_EL1.BF16 == 0b0001 表示有此功能。
+
+HWCAP2_DGH
+
+ ID_AA64ISAR1_EL1.DGH == 0b0001 表示有此功能。
+
+HWCAP2_RNG
+
+ ID_AA64ISAR0_EL1.RNDR == 0b0001 表示有此功能。
+
+HWCAP2_BTI
+
+ ID_AA64PFR0_EL1.BT == 0b0001 表示有此功能。
+
+
+4. 未使用的 AT_HWCAP 位
+-----------------------
+
+爲了與用戶空間交互,內核保證 AT_HWCAP 的第62、63位將始終返回0。
+
diff --git a/Documentation/translations/zh_TW/arch/arm64/hugetlbpage.rst b/Documentation/translations/zh_TW/arch/arm64/hugetlbpage.rst
new file mode 100644
index 000000000000..b6849935e028
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/arm64/hugetlbpage.rst
@@ -0,0 +1,49 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/arch/arm64/hugetlbpage.rst <hugetlbpage_index>`
+
+Translator: Bailu Lin <bailu.lin@vivo.com>
+ Hu Haowen <2023002089@link.tyut.edu.cn>
+
+=====================
+ARM64中的 HugeTLBpage
+=====================
+
+大頁依靠有效利用 TLBs 來提高地址翻譯的性能。這取決於以下
+兩點 -
+
+ - 大頁的大小
+ - TLBs 支持的條目大小
+
+ARM64 接口支持2種大頁方式。
+
+1) pud/pmd 級別的塊映射
+-----------------------
+
+這是常規大頁,他們的 pmd 或 pud 頁面表條目指向一個內存塊。
+不管 TLB 中支持的條目大小如何,塊映射可以減少翻譯大頁地址
+所需遍歷的頁表深度。
+
+2) 使用連續位
+-------------
+
+架構中轉換頁表條目(D4.5.3, ARM DDI 0487C.a)中提供一個連續
+位告訴 MMU 這個條目是一個連續條目集的一員,它可以被緩存在單
+個 TLB 條目中。
+
+在 Linux 中連續位用來增加 pmd 和 pte(最後一級)級別映射的大
+小。受支持的連續頁表條目數量因頁面大小和頁表級別而異。
+
+
+支持以下大頁尺寸配置 -
+
+ ====== ======== ==== ======== ===
+ - CONT PTE PMD CONT PMD PUD
+ ====== ======== ==== ======== ===
+ 4K: 64K 2M 32M 1G
+ 16K: 2M 32M 1G
+ 64K: 2M 512M 16G
+ ====== ======== ==== ======== ===
+
diff --git a/Documentation/translations/zh_TW/arch/arm64/index.rst b/Documentation/translations/zh_TW/arch/arm64/index.rst
new file mode 100644
index 000000000000..86014346792e
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/arm64/index.rst
@@ -0,0 +1,23 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/arch/arm64/index.rst <arm64_index>`
+:Translator: Bailu Lin <bailu.lin@vivo.com>
+ Hu Haowen <2023002089@link.tyut.edu.cn>
+
+.. _tw_arm64_index:
+
+
+==========
+ARM64 架構
+==========
+
+.. toctree::
+ :maxdepth: 2
+
+ amu
+ hugetlbpage
+ perf
+ elf_hwcaps
+
diff --git a/Documentation/translations/zh_TW/arch/arm64/legacy_instructions.txt b/Documentation/translations/zh_TW/arch/arm64/legacy_instructions.txt
new file mode 100644
index 000000000000..5c664555a71a
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/arm64/legacy_instructions.txt
@@ -0,0 +1,77 @@
+SPDX-License-Identifier: GPL-2.0
+
+Chinese translated version of Documentation/arch/arm64/legacy_instructions.rst
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly. However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help. Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Maintainer: Punit Agrawal <punit.agrawal@arm.com>
+ Suzuki K. Poulose <suzuki.poulose@arm.com>
+Chinese maintainer: Fu Wei <wefu@redhat.com>
+Traditional Chinese maintainer: Hu Haowen <2023002089@link.tyut.edu.cn>
+---------------------------------------------------------------------
+Documentation/arch/arm64/legacy_instructions.rst 的中文翻譯
+
+如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
+交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻
+譯存在問題,請聯繫中文版維護者。
+
+本文翻譯提交時的 Git 檢出點爲: bc465aa9d045feb0e13b4a8f32cc33c1943f62d6
+
+英文版維護者: Punit Agrawal <punit.agrawal@arm.com>
+ Suzuki K. Poulose <suzuki.poulose@arm.com>
+中文版維護者: 傅煒 Fu Wei <wefu@redhat.com>
+中文版翻譯者: 傅煒 Fu Wei <wefu@redhat.com>
+中文版校譯者: 傅煒 Fu Wei <wefu@redhat.com>
+繁體中文版校譯者:胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+以下爲正文
+---------------------------------------------------------------------
+Linux 內核在 arm64 上的移植提供了一個基礎框架,以支持構架中正在被淘汰或已廢棄指令的模擬執行。
+這個基礎框架的代碼使用未定義指令鉤子(hooks)來支持模擬。如果指令存在,它也允許在硬件中啓用該指令。
+
+模擬模式可通過寫 sysctl 節點(/proc/sys/abi)來控制。
+不同的執行方式及 sysctl 節點的相應值,解釋如下:
+
+* Undef(未定義)
+ 值: 0
+ 產生未定義指令終止異常。它是那些構架中已廢棄的指令,如 SWP,的默認處理方式。
+
+* Emulate(模擬)
+ 值: 1
+ 使用軟件模擬方式。爲解決軟件遷移問題,這種模擬指令模式的使用是被跟蹤的,並會發出速率限制警告。
+ 它是那些構架中正在被淘汰的指令,如 CP15 barriers(隔離指令),的默認處理方式。
+
+* Hardware Execution(硬件執行)
+ 值: 2
+ 雖然標記爲正在被淘汰,但一些實現可能提供硬件執行這些指令的使能/禁用操作。
+ 使用硬件執行一般會有更好的性能,但將無法收集運行時對正被淘汰指令的使用統計數據。
+
+默認執行模式依賴於指令在構架中狀態。正在被淘汰的指令應該以模擬(Emulate)作爲默認模式,
+而已廢棄的指令必須默認使用未定義(Undef)模式
+
+注意:指令模擬可能無法應對所有情況。更多詳情請參考單獨的指令註釋。
+
+受支持的遺留指令
+-------------
+* SWP{B}
+節點: /proc/sys/abi/swp
+狀態: 已廢棄
+默認執行方式: Undef (0)
+
+* CP15 Barriers
+節點: /proc/sys/abi/cp15_barrier
+狀態: 正被淘汰,不推薦使用
+默認執行方式: Emulate (1)
+
+* SETEND
+節點: /proc/sys/abi/setend
+狀態: 正被淘汰,不推薦使用
+默認執行方式: Emulate (1)*
+注:爲了使能這個特性,系統中的所有 CPU 必須在 EL0 支持混合字節序。
+如果一個新的 CPU (不支持混合字節序) 在使能這個特性後被熱插入系統,
+在應用中可能會出現不可預期的結果。
+
diff --git a/Documentation/translations/zh_TW/arch/arm64/memory.txt b/Documentation/translations/zh_TW/arch/arm64/memory.txt
new file mode 100644
index 000000000000..6ee2239c293f
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/arm64/memory.txt
@@ -0,0 +1,119 @@
+SPDX-License-Identifier: GPL-2.0
+
+Chinese translated version of Documentation/arch/arm64/memory.rst
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly. However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help. Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Maintainer: Catalin Marinas <catalin.marinas@arm.com>
+Chinese maintainer: Fu Wei <wefu@redhat.com>
+Traditional Chinese maintainer: Hu Haowen <2023002089@link.tyut.edu.cn>
+---------------------------------------------------------------------
+Documentation/arch/arm64/memory.rst 的中文翻譯
+
+如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
+交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻
+譯存在問題,請聯繫中文版維護者。
+
+本文翻譯提交時的 Git 檢出點爲: bc465aa9d045feb0e13b4a8f32cc33c1943f62d6
+
+英文版維護者: Catalin Marinas <catalin.marinas@arm.com>
+中文版維護者: 傅煒 Fu Wei <wefu@redhat.com>
+中文版翻譯者: 傅煒 Fu Wei <wefu@redhat.com>
+中文版校譯者: 傅煒 Fu Wei <wefu@redhat.com>
+繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+以下爲正文
+---------------------------------------------------------------------
+ Linux 在 AArch64 中的內存佈局
+ ===========================
+
+作者: Catalin Marinas <catalin.marinas@arm.com>
+
+本文檔描述 AArch64 Linux 內核所使用的虛擬內存佈局。此構架可以實現
+頁大小爲 4KB 的 4 級轉換表和頁大小爲 64KB 的 3 級轉換表。
+
+AArch64 Linux 使用 3 級或 4 級轉換表,其頁大小配置爲 4KB,對於用戶和內核
+分別都有 39-bit (512GB) 或 48-bit (256TB) 的虛擬地址空間。
+對於頁大小爲 64KB的配置,僅使用 2 級轉換表,有 42-bit (4TB) 的虛擬地址空間,但內存佈局相同。
+
+用戶地址空間的 63:48 位爲 0,而內核地址空間的相應位爲 1。TTBRx 的
+選擇由虛擬地址的 63 位給出。swapper_pg_dir 僅包含內核(全局)映射,
+而用戶 pgd 僅包含用戶(非全局)映射。swapper_pg_dir 地址被寫入
+TTBR1 中,且從不寫入 TTBR0。
+
+
+AArch64 Linux 在頁大小爲 4KB,並使用 3 級轉換表時的內存佈局:
+
+起始地址 結束地址 大小 用途
+-----------------------------------------------------------------------
+0000000000000000 0000007fffffffff 512GB 用戶空間
+ffffff8000000000 ffffffffffffffff 512GB 內核空間
+
+
+AArch64 Linux 在頁大小爲 4KB,並使用 4 級轉換表時的內存佈局:
+
+起始地址 結束地址 大小 用途
+-----------------------------------------------------------------------
+0000000000000000 0000ffffffffffff 256TB 用戶空間
+ffff000000000000 ffffffffffffffff 256TB 內核空間
+
+
+AArch64 Linux 在頁大小爲 64KB,並使用 2 級轉換表時的內存佈局:
+
+起始地址 結束地址 大小 用途
+-----------------------------------------------------------------------
+0000000000000000 000003ffffffffff 4TB 用戶空間
+fffffc0000000000 ffffffffffffffff 4TB 內核空間
+
+
+AArch64 Linux 在頁大小爲 64KB,並使用 3 級轉換表時的內存佈局:
+
+起始地址 結束地址 大小 用途
+-----------------------------------------------------------------------
+0000000000000000 0000ffffffffffff 256TB 用戶空間
+ffff000000000000 ffffffffffffffff 256TB 內核空間
+
+
+更詳細的內核虛擬內存佈局,請參閱內核啓動信息。
+
+
+4KB 頁大小的轉換表查找:
+
++--------+--------+--------+--------+--------+--------+--------+--------+
+|63 56|55 48|47 40|39 32|31 24|23 16|15 8|7 0|
++--------+--------+--------+--------+--------+--------+--------+--------+
+ | | | | | |
+ | | | | | v
+ | | | | | [11:0] 頁內偏移
+ | | | | +-> [20:12] L3 索引
+ | | | +-----------> [29:21] L2 索引
+ | | +---------------------> [38:30] L1 索引
+ | +-------------------------------> [47:39] L0 索引
+ +-------------------------------------------------> [63] TTBR0/1
+
+
+64KB 頁大小的轉換表查找:
+
++--------+--------+--------+--------+--------+--------+--------+--------+
+|63 56|55 48|47 40|39 32|31 24|23 16|15 8|7 0|
++--------+--------+--------+--------+--------+--------+--------+--------+
+ | | | | |
+ | | | | v
+ | | | | [15:0] 頁內偏移
+ | | | +----------> [28:16] L3 索引
+ | | +--------------------------> [41:29] L2 索引
+ | +-------------------------------> [47:42] L1 索引
+ +-------------------------------------------------> [63] TTBR0/1
+
+
+當使用 KVM 時, 管理程序(hypervisor)在 EL2 中通過相對內核虛擬地址的
+一個固定偏移來映射內核頁(內核虛擬地址的高 24 位設爲零):
+
+起始地址 結束地址 大小 用途
+-----------------------------------------------------------------------
+0000004000000000 0000007fffffffff 256GB 在 HYP 中映射的內核對象
+
diff --git a/Documentation/translations/zh_TW/arch/arm64/perf.rst b/Documentation/translations/zh_TW/arch/arm64/perf.rst
new file mode 100644
index 000000000000..ce083ba63872
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/arm64/perf.rst
@@ -0,0 +1,88 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/arch/arm64/perf.rst <perf_index>`
+
+Translator: Bailu Lin <bailu.lin@vivo.com>
+ Hu Haowen <2023002089@link.tyut.edu.cn>
+
+=============
+Perf 事件屬性
+=============
+
+:作者: Andrew Murray <andrew.murray@arm.com>
+:日期: 2019-03-06
+
+exclude_user
+------------
+
+該屬性排除用戶空間。
+
+用戶空間始終運行在 EL0,因此該屬性將排除 EL0。
+
+
+exclude_kernel
+--------------
+
+該屬性排除內核空間。
+
+打開 VHE 時內核運行在 EL2,不打開 VHE 時內核運行在 EL1。客戶機
+內核總是運行在 EL1。
+
+對於宿主機,該屬性排除 EL1 和 VHE 上的 EL2。
+
+對於客戶機,該屬性排除 EL1。請注意客戶機從來不會運行在 EL2。
+
+
+exclude_hv
+----------
+
+該屬性排除虛擬機監控器。
+
+對於 VHE 宿主機該屬性將被忽略,此時我們認爲宿主機內核是虛擬機監
+控器。
+
+對於 non-VHE 宿主機該屬性將排除 EL2,因爲虛擬機監控器運行在 EL2
+的任何代碼主要用於客戶機和宿主機的切換。
+
+對於客戶機該屬性無效。請注意客戶機從來不會運行在 EL2。
+
+
+exclude_host / exclude_guest
+----------------------------
+
+這些屬性分別排除了 KVM 宿主機和客戶機。
+
+KVM 宿主機可能運行在 EL0(用戶空間),EL1(non-VHE 內核)和
+EL2(VHE 內核 或 non-VHE 虛擬機監控器)。
+
+KVM 客戶機可能運行在 EL0(用戶空間)和 EL1(內核)。
+
+由於宿主機和客戶機之間重疊的異常級別,我們不能僅僅依靠 PMU 的硬件異
+常過濾機制-因此我們必須啓用/禁用對於客戶機進入和退出的計數。而這在
+VHE 和 non-VHE 系統上表現不同。
+
+對於 non-VHE 系統的 exclude_host 屬性排除 EL2 - 在進入和退出客戶
+機時,我們會根據 exclude_host 和 exclude_guest 屬性在適當的情況下
+禁用/啓用該事件。
+
+對於 VHE 系統的 exclude_guest 屬性排除 EL1,而對其中的 exclude_host
+屬性同時排除 EL0,EL2。在進入和退出客戶機時,我們會適當地根據
+exclude_host 和 exclude_guest 屬性包括/排除 EL0。
+
+以上聲明也適用於在 not-VHE 客戶機使用這些屬性時,但是請注意客戶機從
+來不會運行在 EL2。
+
+
+準確性
+------
+
+在 non-VHE 宿主機上,我們在 EL2 進入/退出宿主機/客戶機的切換時啓用/
+關閉計數器 -但是在啓用/禁用計數器和進入/退出客戶機之間存在一段延時。
+對於 exclude_host, 我們可以通過過濾 EL2 消除在客戶機進入/退出邊界
+上用於計數客戶機事件的宿主機事件計數器。但是當使用 !exclude_hv 時,
+在客戶機進入/退出有一個小的停電窗口無法捕獲到宿主機的事件。
+
+在 VHE 系統沒有停電窗口。
+
diff --git a/Documentation/translations/zh_TW/arch/arm64/silicon-errata.txt b/Documentation/translations/zh_TW/arch/arm64/silicon-errata.txt
new file mode 100644
index 000000000000..16d73b6c309f
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/arm64/silicon-errata.txt
@@ -0,0 +1,79 @@
+SPDX-License-Identifier: GPL-2.0
+
+Chinese translated version of Documentation/arch/arm64/silicon-errata.rst
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly. However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help. Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+M: Will Deacon <will.deacon@arm.com>
+zh_CN: Fu Wei <wefu@redhat.com>
+zh_TW: Hu Haowen <2023002089@link.tyut.edu.cn>
+C: 1926e54f115725a9248d0c4c65c22acaf94de4c4
+---------------------------------------------------------------------
+Documentation/arch/arm64/silicon-errata.rst 的中文翻譯
+
+如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
+交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻
+譯存在問題,請聯繫中文版維護者。
+
+英文版維護者: Will Deacon <will.deacon@arm.com>
+中文版維護者: 傅煒 Fu Wei <wefu@redhat.com>
+中文版翻譯者: 傅煒 Fu Wei <wefu@redhat.com>
+中文版校譯者: 傅煒 Fu Wei <wefu@redhat.com>
+繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+本文翻譯提交時的 Git 檢出點爲: 1926e54f115725a9248d0c4c65c22acaf94de4c4
+
+以下爲正文
+---------------------------------------------------------------------
+ 芯片勘誤和軟件補救措施
+ ==================
+
+作者: Will Deacon <will.deacon@arm.com>
+日期: 2015年11月27日
+
+一個不幸的現實:硬件經常帶有一些所謂的“瑕疵(errata)”,導致其在
+某些特定情況下會違背構架定義的行爲。就基於 ARM 的硬件而言,這些瑕疵
+大體可分爲以下幾類:
+
+ A 類:無可行補救措施的嚴重缺陷。
+ B 類:有可接受的補救措施的重大或嚴重缺陷。
+ C 類:在正常操作中不會顯現的小瑕疵。
+
+更多資訊,請在 infocenter.arm.com (需註冊)中查閱“軟件開發者勘誤
+筆記”(“Software Developers Errata Notice”)文檔。
+
+對於 Linux 而言,B 類缺陷可能需要操作系統的某些特別處理。例如,避免
+一個特殊的代碼序列,或是以一種特定的方式配置處理器。在某種不太常見的
+情況下,爲將 A 類缺陷當作 C 類處理,可能需要用類似的手段。這些手段被
+統稱爲“軟件補救措施”,且僅在少數情況需要(例如,那些需要一個運行在
+非安全異常級的補救措施 *並且* 能被 Linux 觸發的情況)。
+
+對於尚在討論中的可能對未受瑕疵影響的系統產生干擾的軟件補救措施,有一個
+相應的內核配置(Kconfig)選項被加在 “內核特性(Kernel Features)”->
+“基於可選方法框架的 ARM 瑕疵補救措施(ARM errata workarounds via
+the alternatives framework)"。這些選項被默認開啓,若探測到受影響的CPU,
+補丁將在運行時被使用。至於對系統運行影響較小的補救措施,內核配置選項
+並不存在,且代碼以某種規避瑕疵的方式被構造(帶註釋爲宜)。
+
+這種做法對於在任意內核源代碼樹中準確地判斷出哪個瑕疵已被軟件方法所補救
+稍微有點麻煩,所以在 Linux 內核中此文件作爲軟件補救措施的註冊表,
+並將在新的軟件補救措施被提交和向後移植(backported)到穩定內核時被更新。
+
+| 實現者 | 受影響的組件 | 勘誤編號 | 內核配置 |
++----------------+-----------------+-----------------+-------------------------+
+| ARM | Cortex-A53 | #826319 | ARM64_ERRATUM_826319 |
+| ARM | Cortex-A53 | #827319 | ARM64_ERRATUM_827319 |
+| ARM | Cortex-A53 | #824069 | ARM64_ERRATUM_824069 |
+| ARM | Cortex-A53 | #819472 | ARM64_ERRATUM_819472 |
+| ARM | Cortex-A53 | #845719 | ARM64_ERRATUM_845719 |
+| ARM | Cortex-A53 | #843419 | ARM64_ERRATUM_843419 |
+| ARM | Cortex-A57 | #832075 | ARM64_ERRATUM_832075 |
+| ARM | Cortex-A57 | #852523 | N/A |
+| ARM | Cortex-A57 | #834220 | ARM64_ERRATUM_834220 |
+| | | | |
+| Cavium | ThunderX ITS | #22375, #24313 | CAVIUM_ERRATUM_22375 |
+| Cavium | ThunderX GICv3 | #23154 | CAVIUM_ERRATUM_23154 |
+
diff --git a/Documentation/translations/zh_TW/arch/arm64/tagged-pointers.txt b/Documentation/translations/zh_TW/arch/arm64/tagged-pointers.txt
new file mode 100644
index 000000000000..e86ffa893ef6
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/arm64/tagged-pointers.txt
@@ -0,0 +1,57 @@
+SPDX-License-Identifier: GPL-2.0
+
+Chinese translated version of Documentation/arch/arm64/tagged-pointers.rst
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly. However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help. Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Maintainer: Will Deacon <will.deacon@arm.com>
+Chinese maintainer: Fu Wei <wefu@redhat.com>
+Traditional Chinese maintainer: Hu Haowen <2023002089@link.tyut.edu.cn>
+---------------------------------------------------------------------
+Documentation/arch/arm64/tagged-pointers.rst 的中文翻譯
+
+如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
+交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻
+譯存在問題,請聯繫中文版維護者。
+
+英文版維護者: Will Deacon <will.deacon@arm.com>
+中文版維護者: 傅煒 Fu Wei <wefu@redhat.com>
+中文版翻譯者: 傅煒 Fu Wei <wefu@redhat.com>
+中文版校譯者: 傅煒 Fu Wei <wefu@redhat.com>
+繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+以下爲正文
+---------------------------------------------------------------------
+ Linux 在 AArch64 中帶標記的虛擬地址
+ =================================
+
+作者: Will Deacon <will.deacon@arm.com>
+日期: 2013 年 06 月 12 日
+
+本文檔簡述了在 AArch64 地址轉換系統中提供的帶標記的虛擬地址及其在
+AArch64 Linux 中的潛在用途。
+
+內核提供的地址轉換表配置使通過 TTBR0 完成的虛擬地址轉換(即用戶空間
+映射),其虛擬地址的最高 8 位(63:56)會被轉換硬件所忽略。這種機制
+讓這些位可供應用程序自由使用,其注意事項如下:
+
+ (1) 內核要求所有傳遞到 EL1 的用戶空間地址帶有 0x00 標記。
+ 這意味着任何攜帶用戶空間虛擬地址的系統調用(syscall)
+ 參數 *必須* 在陷入內核前使它們的最高字節被清零。
+
+ (2) 非零標記在傳遞信號時不被保存。這意味着在應用程序中利用了
+ 標記的信號處理函數無法依賴 siginfo_t 的用戶空間虛擬
+ 地址所攜帶的包含其內部域信息的標記。此規則的一個例外是
+ 當信號是在調試觀察點的異常處理程序中產生的,此時標記的
+ 信息將被保存。
+
+ (3) 當使用帶標記的指針時需特別留心,因爲僅對兩個虛擬地址
+ 的高字節,C 編譯器很可能無法判斷它們是不同的。
+
+此構架會阻止對帶標記的 PC 指針的利用,因此在異常返回時,其高字節
+將被設置成一個爲 “55” 的擴展符。
+
diff --git a/Documentation/translations/zh_TW/arch/index.rst b/Documentation/translations/zh_TW/arch/index.rst
new file mode 100644
index 000000000000..7c0490589465
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/index.rst
@@ -0,0 +1,29 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+處理器體系結構
+==============
+
+以下文檔提供了具體架構實現的編程細節。
+
+.. toctree::
+ :maxdepth: 2
+
+ mips/index
+ arm64/index
+ openrisc/index
+ parisc/index
+ loongarch/index
+
+TODOList:
+
+* arm/index
+* m68k/index
+* nios2/index
+* powerpc/index
+* s390/index
+* sh/index
+* sparc/index
+* x86/index
+* xtensa/index
+* ../riscv/index
+
diff --git a/Documentation/translations/zh_TW/arch/loongarch/booting.rst b/Documentation/translations/zh_TW/arch/loongarch/booting.rst
new file mode 100644
index 000000000000..88291090cea1
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/loongarch/booting.rst
@@ -0,0 +1,49 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: Documentation/arch/loongarch/booting.rst
+
+:翻譯:
+
+ 司延騰 Yanteng Si <siyanteng@loongson.cn>
+
+====================
+啓動 Linux/LoongArch
+====================
+
+:作者: 司延騰 <siyanteng@loongson.cn>
+:日期: 2022年11月18日
+
+BootLoader傳遞給內核的信息
+==========================
+
+LoongArch支持ACPI和FDT啓動,需要傳遞給內核的信息包括memmap、initrd、cmdline、可
+選的ACPI/FDT表等。
+
+內核在 `kernel_entry` 入口處被傳遞以下參數:
+
+ - a0 = efi_boot: `efi_boot` 是一個標誌,表示這個啓動環境是否完全符合UEFI
+ 的要求。
+
+ - a1 = cmdline: `cmdline` 是一個指向內核命令行的指針。
+
+ - a2 = systemtable: `systemtable` 指向EFI的系統表,在這個階段涉及的所有
+ 指針都是物理地址。
+
+Linux/LoongArch內核鏡像文件頭
+=============================
+
+內核鏡像是EFI鏡像。作爲PE文件,它們有一個64字節的頭部結構體,如下所示::
+
+ u32 MZ_MAGIC /* "MZ", MS-DOS 頭 */
+ u32 res0 = 0 /* 保留 */
+ u64 kernel_entry /* 內核入口點 */
+ u64 _end - _text /* 內核鏡像有效大小 */
+ u64 load_offset /* 加載內核鏡像相對內存起始地址的偏移量 */
+ u64 res1 = 0 /* 保留 */
+ u64 res2 = 0 /* 保留 */
+ u64 res3 = 0 /* 保留 */
+ u32 LINUX_PE_MAGIC /* 魔術數 */
+ u32 pe_header - _head /* 到PE頭的偏移量 */
+
diff --git a/Documentation/translations/zh_TW/arch/loongarch/features.rst b/Documentation/translations/zh_TW/arch/loongarch/features.rst
new file mode 100644
index 000000000000..c2175fd32b54
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/loongarch/features.rst
@@ -0,0 +1,9 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: Documentation/arch/loongarch/features.rst
+:Translator: Huacai Chen <chenhuacai@loongson.cn>
+
+.. kernel-feat:: features loongarch
+
diff --git a/Documentation/translations/zh_TW/arch/loongarch/index.rst b/Documentation/translations/zh_TW/arch/loongarch/index.rst
new file mode 100644
index 000000000000..7281e050fe1c
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/loongarch/index.rst
@@ -0,0 +1,28 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: Documentation/arch/loongarch/index.rst
+:Translator: Huacai Chen <chenhuacai@loongson.cn>
+
+=================
+LoongArch體系結構
+=================
+
+.. toctree::
+ :maxdepth: 2
+ :numbered:
+
+ introduction
+ booting
+ irq-chip-model
+
+ features
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
+
diff --git a/Documentation/translations/zh_TW/arch/loongarch/introduction.rst b/Documentation/translations/zh_TW/arch/loongarch/introduction.rst
new file mode 100644
index 000000000000..a5603f9b0a1b
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/loongarch/introduction.rst
@@ -0,0 +1,354 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: Documentation/arch/loongarch/introduction.rst
+:Translator: Huacai Chen <chenhuacai@loongson.cn>
+
+=============
+LoongArch介紹
+=============
+
+LoongArch是一種新的RISC ISA,在一定程度上類似於MIPS和RISC-V。LoongArch指令集
+包括一個精簡32位版(LA32R)、一個標準32位版(LA32S)、一個64位版(LA64)。
+LoongArch定義了四個特權級(PLV0~PLV3),其中PLV0是最高特權級,用於內核;而PLV3
+是最低特權級,用於應用程序。本文檔介紹了LoongArch的寄存器、基礎指令集、虛擬內
+存以及其他一些主題。
+
+寄存器
+======
+
+LoongArch的寄存器包括通用寄存器(GPRs)、浮點寄存器(FPRs)、向量寄存器(VRs)
+和用於特權模式(PLV0)的控制狀態寄存器(CSRs)。
+
+通用寄存器
+----------
+
+LoongArch包括32個通用寄存器( ``$r0`` ~ ``$r31`` ),LA32中每個寄存器爲32位寬,
+LA64中每個寄存器爲64位寬。 ``$r0`` 的內容總是固定爲0,而其他寄存器在體系結構層面
+沒有特殊功能。( ``$r1`` 算是一個例外,在BL指令中固定用作鏈接返回寄存器。)
+
+內核使用了一套LoongArch寄存器約定,定義在LoongArch ELF psABI規範中,詳細描述參見
+:ref:`參考文獻 <loongarch-references-zh_TW>`:
+
+================= =============== =================== ==========
+寄存器名 別名 用途 跨調用保持
+================= =============== =================== ==========
+``$r0`` ``$zero`` 常量0 不使用
+``$r1`` ``$ra`` 返回地址 否
+``$r2`` ``$tp`` TLS/線程信息指針 不使用
+``$r3`` ``$sp`` 棧指針 是
+``$r4``-``$r11`` ``$a0``-``$a7`` 參數寄存器 否
+``$r4``-``$r5`` ``$v0``-``$v1`` 返回值 否
+``$r12``-``$r20`` ``$t0``-``$t8`` 臨時寄存器 否
+``$r21`` ``$u0`` 每CPU變量基地址 不使用
+``$r22`` ``$fp`` 幀指針 是
+``$r23``-``$r31`` ``$s0``-``$s8`` 靜態寄存器 是
+================= =============== =================== ==========
+
+.. note::
+ 注意: ``$r21`` 寄存器在ELF psABI中保留未使用,但是在Linux內核用於保
+ 存每CPU變量基地址。該寄存器沒有ABI命名,不過在內核中稱爲 ``$u0`` 。在
+ 一些遺留代碼中有時可能見到 ``$v0`` 和 ``$v1`` ,它們是 ``$a0`` 和
+ ``$a1`` 的別名,屬於已經廢棄的用法。
+
+浮點寄存器
+----------
+
+當系統中存在FPU時,LoongArch有32個浮點寄存器( ``$f0`` ~ ``$f31`` )。在LA64
+的CPU核上,每個寄存器均爲64位寬。
+
+浮點寄存器的使用約定與LoongArch ELF psABI規範的描述相同:
+
+================= ================== =================== ==========
+寄存器名 別名 用途 跨調用保持
+================= ================== =================== ==========
+``$f0``-``$f7`` ``$fa0``-``$fa7`` 參數寄存器 否
+``$f0``-``$f1`` ``$fv0``-``$fv1`` 返回值 否
+``$f8``-``$f23`` ``$ft0``-``$ft15`` 臨時寄存器 否
+``$f24``-``$f31`` ``$fs0``-``$fs7`` 靜態寄存器 是
+================= ================== =================== ==========
+
+.. note::
+ 注意:在一些遺留代碼中有時可能見到 ``$fv0`` 和 ``$fv1`` ,它們是
+ ``$fa0`` 和 ``$fa1`` 的別名,屬於已經廢棄的用法。
+
+
+向量寄存器
+----------
+
+LoongArch現有兩種向量擴展:
+
+- 128位向量擴展LSX(全稱Loongson SIMD eXtention),
+- 256位向量擴展LASX(全稱Loongson Advanced SIMD eXtention)。
+
+LSX使用 ``$v0`` ~ ``$v31`` 向量寄存器,而LASX則使用 ``$x0`` ~ ``$x31`` 。
+
+浮點寄存器和向量寄存器是複用的,比如:在一個實現了LSX和LASX的核上, ``$x0`` 的
+低128位與 ``$v0`` 共用, ``$v0`` 的低64位與 ``$f0`` 共用,其他寄存器依此類推。
+
+控制狀態寄存器
+--------------
+
+控制狀態寄存器只能在特權模式(PLV0)下訪問:
+
+================= ==================================== ==========
+地址 全稱描述 簡稱
+================= ==================================== ==========
+0x0 當前模式信息 CRMD
+0x1 異常前模式信息 PRMD
+0x2 擴展部件使能 EUEN
+0x3 雜項控制 MISC
+0x4 異常配置 ECFG
+0x5 異常狀態 ESTAT
+0x6 異常返回地址 ERA
+0x7 出錯(Faulting)虛擬地址 BADV
+0x8 出錯(Faulting)指令字 BADI
+0xC 異常入口地址 EENTRY
+0x10 TLB索引 TLBIDX
+0x11 TLB表項高位 TLBEHI
+0x12 TLB表項低位0 TLBELO0
+0x13 TLB表項低位1 TLBELO1
+0x18 地址空間標識符 ASID
+0x19 低半地址空間頁全局目錄基址 PGDL
+0x1A 高半地址空間頁全局目錄基址 PGDH
+0x1B 頁全局目錄基址 PGD
+0x1C 頁表遍歷控制低半部分 PWCL
+0x1D 頁表遍歷控制高半部分 PWCH
+0x1E STLB頁大小 STLBPS
+0x1F 縮減虛地址配置 RVACFG
+0x20 CPU編號 CPUID
+0x21 特權資源配置信息1 PRCFG1
+0x22 特權資源配置信息2 PRCFG2
+0x23 特權資源配置信息3 PRCFG3
+0x30+n (0≤n≤15) 數據保存寄存器 SAVEn
+0x40 定時器編號 TID
+0x41 定時器配置 TCFG
+0x42 定時器值 TVAL
+0x43 計時器補償 CNTC
+0x44 定時器中斷清除 TICLR
+0x60 LLBit相關控制 LLBCTL
+0x80 實現相關控制1 IMPCTL1
+0x81 實現相關控制2 IMPCTL2
+0x88 TLB重填異常入口地址 TLBRENTRY
+0x89 TLB重填異常出錯(Faulting)虛地址 TLBRBADV
+0x8A TLB重填異常返回地址 TLBRERA
+0x8B TLB重填異常數據保存 TLBRSAVE
+0x8C TLB重填異常表項低位0 TLBRELO0
+0x8D TLB重填異常表項低位1 TLBRELO1
+0x8E TLB重填異常表項高位 TLBEHI
+0x8F TLB重填異常前模式信息 TLBRPRMD
+0x90 機器錯誤控制 MERRCTL
+0x91 機器錯誤信息1 MERRINFO1
+0x92 機器錯誤信息2 MERRINFO2
+0x93 機器錯誤異常入口地址 MERRENTRY
+0x94 機器錯誤異常返回地址 MERRERA
+0x95 機器錯誤異常數據保存 MERRSAVE
+0x98 高速緩存標籤 CTAG
+0x180+n (0≤n≤3) 直接映射配置窗口n DMWn
+0x200+2n (0≤n≤31) 性能監測配置n PMCFGn
+0x201+2n (0≤n≤31) 性能監測計數器n PMCNTn
+0x300 內存讀寫監視點整體控制 MWPC
+0x301 內存讀寫監視點整體狀態 MWPS
+0x310+8n (0≤n≤7) 內存讀寫監視點n配置1 MWPnCFG1
+0x311+8n (0≤n≤7) 內存讀寫監視點n配置2 MWPnCFG2
+0x312+8n (0≤n≤7) 內存讀寫監視點n配置3 MWPnCFG3
+0x313+8n (0≤n≤7) 內存讀寫監視點n配置4 MWPnCFG4
+0x380 取指監視點整體控制 FWPC
+0x381 取指監視點整體狀態 FWPS
+0x390+8n (0≤n≤7) 取指監視點n配置1 FWPnCFG1
+0x391+8n (0≤n≤7) 取指監視點n配置2 FWPnCFG2
+0x392+8n (0≤n≤7) 取指監視點n配置3 FWPnCFG3
+0x393+8n (0≤n≤7) 取指監視點n配置4 FWPnCFG4
+0x500 調試寄存器 DBG
+0x501 調試異常返回地址 DERA
+0x502 調試數據保存 DSAVE
+================= ==================================== ==========
+
+ERA,TLBRERA,MERRERA和DERA有時也分別稱爲EPC,TLBREPC,MERREPC和DEPC。
+
+基礎指令集
+==========
+
+指令格式
+--------
+
+LoongArch的指令字長爲32位,一共有9種基本指令格式(以及一些變體):
+
+=========== ==========================
+格式名稱 指令構成
+=========== ==========================
+2R Opcode + Rj + Rd
+3R Opcode + Rk + Rj + Rd
+4R Opcode + Ra + Rk + Rj + Rd
+2RI8 Opcode + I8 + Rj + Rd
+2RI12 Opcode + I12 + Rj + Rd
+2RI14 Opcode + I14 + Rj + Rd
+2RI16 Opcode + I16 + Rj + Rd
+1RI21 Opcode + I21L + Rj + I21H
+I26 Opcode + I26L + I26H
+=========== ==========================
+
+Opcode是指令操作碼,Rj和Rk是源操作數(寄存器),Rd是目標操作數(寄存器),Ra是
+4R-type格式特有的附加操作數(寄存器)。I8/I12/I14/I16/I21/I26分別是8位/12位/14位/
+16位/21位/26位的立即數。其中較長的21位和26位立即數在指令字中被分割爲高位部分與低位
+部分,所以你們在這裏的格式描述中能夠看到I21L/I21H和I26L/I26H這樣帶後綴的表述。
+
+指令列表
+--------
+
+爲了簡便起見,我們在此只羅列一下指令名稱(助記符),需要詳細信息請閱讀
+:ref:`參考文獻 <loongarch-references-zh_TW>` 中的文檔。
+
+1. 算術運算指令::
+
+ ADD.W SUB.W ADDI.W ADD.D SUB.D ADDI.D
+ SLT SLTU SLTI SLTUI
+ AND OR NOR XOR ANDN ORN ANDI ORI XORI
+ MUL.W MULH.W MULH.WU DIV.W DIV.WU MOD.W MOD.WU
+ MUL.D MULH.D MULH.DU DIV.D DIV.DU MOD.D MOD.DU
+ PCADDI PCADDU12I PCADDU18I
+ LU12I.W LU32I.D LU52I.D ADDU16I.D
+
+2. 移位運算指令::
+
+ SLL.W SRL.W SRA.W ROTR.W SLLI.W SRLI.W SRAI.W ROTRI.W
+ SLL.D SRL.D SRA.D ROTR.D SLLI.D SRLI.D SRAI.D ROTRI.D
+
+3. 位域操作指令::
+
+ EXT.W.B EXT.W.H CLO.W CLO.D SLZ.W CLZ.D CTO.W CTO.D CTZ.W CTZ.D
+ BYTEPICK.W BYTEPICK.D BSTRINS.W BSTRINS.D BSTRPICK.W BSTRPICK.D
+ REVB.2H REVB.4H REVB.2W REVB.D REVH.2W REVH.D BITREV.4B BITREV.8B BITREV.W BITREV.D
+ MASKEQZ MASKNEZ
+
+4. 分支轉移指令::
+
+ BEQ BNE BLT BGE BLTU BGEU BEQZ BNEZ B BL JIRL
+
+5. 訪存讀寫指令::
+
+ LD.B LD.BU LD.H LD.HU LD.W LD.WU LD.D ST.B ST.H ST.W ST.D
+ LDX.B LDX.BU LDX.H LDX.HU LDX.W LDX.WU LDX.D STX.B STX.H STX.W STX.D
+ LDPTR.W LDPTR.D STPTR.W STPTR.D
+ PRELD PRELDX
+
+6. 原子操作指令::
+
+ LL.W SC.W LL.D SC.D
+ AMSWAP.W AMSWAP.D AMADD.W AMADD.D AMAND.W AMAND.D AMOR.W AMOR.D AMXOR.W AMXOR.D
+ AMMAX.W AMMAX.D AMMIN.W AMMIN.D
+
+7. 柵障指令::
+
+ IBAR DBAR
+
+8. 特殊指令::
+
+ SYSCALL BREAK CPUCFG NOP IDLE ERTN(ERET) DBCL(DBGCALL) RDTIMEL.W RDTIMEH.W RDTIME.D
+ ASRTLE.D ASRTGT.D
+
+9. 特權指令::
+
+ CSRRD CSRWR CSRXCHG
+ IOCSRRD.B IOCSRRD.H IOCSRRD.W IOCSRRD.D IOCSRWR.B IOCSRWR.H IOCSRWR.W IOCSRWR.D
+ CACOP TLBP(TLBSRCH) TLBRD TLBWR TLBFILL TLBCLR TLBFLUSH INVTLB LDDIR LDPTE
+
+虛擬內存
+========
+
+LoongArch可以使用直接映射虛擬內存和分頁映射虛擬內存。
+
+直接映射虛擬內存通過CSR.DMWn(n=0~3)來進行配置,虛擬地址(VA)和物理地址(PA)
+之間有簡單的映射關係::
+
+ VA = PA + 固定偏移
+
+分頁映射的虛擬地址(VA)和物理地址(PA)有任意的映射關係,這種關係記錄在TLB和頁
+表中。LoongArch的TLB包括一個全相聯的MTLB(Multiple Page Size TLB,多樣頁大小TLB)
+和一個組相聯的STLB(Single Page Size TLB,單一頁大小TLB)。
+
+缺省狀態下,LA32的整個虛擬地址空間配置如下:
+
+============ =========================== ===========================
+區段名 地址範圍 屬性
+============ =========================== ===========================
+``UVRANGE`` ``0x00000000 - 0x7FFFFFFF`` 分頁映射, 可緩存, PLV0~3
+``KPRANGE0`` ``0x80000000 - 0x9FFFFFFF`` 直接映射, 非緩存, PLV0
+``KPRANGE1`` ``0xA0000000 - 0xBFFFFFFF`` 直接映射, 可緩存, PLV0
+``KVRANGE`` ``0xC0000000 - 0xFFFFFFFF`` 分頁映射, 可緩存, PLV0
+============ =========================== ===========================
+
+用戶態(PLV3)只能訪問UVRANGE,對於直接映射的KPRANGE0和KPRANGE1,將虛擬地址的第
+30~31位清零就等於物理地址。例如:物理地址0x00001000對應的非緩存直接映射虛擬地址
+是0x80001000,而其可緩存直接映射虛擬地址是0xA0001000。
+
+缺省狀態下,LA64的整個虛擬地址空間配置如下:
+
+============ ====================== ==================================
+區段名 地址範圍 屬性
+============ ====================== ==================================
+``XUVRANGE`` ``0x0000000000000000 - 分頁映射, 可緩存, PLV0~3
+ 0x3FFFFFFFFFFFFFFF``
+``XSPRANGE`` ``0x4000000000000000 - 直接映射, 可緩存 / 非緩存, PLV0
+ 0x7FFFFFFFFFFFFFFF``
+``XKPRANGE`` ``0x8000000000000000 - 直接映射, 可緩存 / 非緩存, PLV0
+ 0xBFFFFFFFFFFFFFFF``
+``XKVRANGE`` ``0xC000000000000000 - 分頁映射, 可緩存, PLV0
+ 0xFFFFFFFFFFFFFFFF``
+============ ====================== ==================================
+
+用戶態(PLV3)只能訪問XUVRANGE,對於直接映射的XSPRANGE和XKPRANGE,將虛擬地址的第
+60~63位清零就等於物理地址,而其緩存屬性是通過虛擬地址的第60~61位配置的(0表示強序
+非緩存,1表示一致可緩存,2表示弱序非緩存)。
+
+目前,我們僅用XKPRANGE來進行直接映射,XSPRANGE保留給以後用。
+
+此處給出一個直接映射的例子:物理地址0x00000000_00001000的強序非緩存直接映射虛擬地址
+(在XKPRANGE中)是0x80000000_00001000,其一致可緩存直接映射虛擬地址(在XKPRANGE中)
+是0x90000000_00001000,而其弱序非緩存直接映射虛擬地址(在XKPRANGE中)是0xA0000000_
+00001000。
+
+Loongson與LoongArch的關係
+=========================
+
+LoongArch是一種RISC指令集架構(ISA),不同於現存的任何一種ISA,而Loongson(即龍
+芯)是一個處理器家族。龍芯包括三個系列:Loongson-1(龍芯1號)是32位處理器系列,
+Loongson-2(龍芯2號)是低端64位處理器系列,而Loongson-3(龍芯3號)是高端64位處理
+器系列。舊的龍芯處理器基於MIPS架構,而新的龍芯處理器基於LoongArch架構。以龍芯3號
+爲例:龍芯3A1000/3B1500/3A2000/3A3000/3A4000都是兼容MIPS的,而龍芯3A5000(以及將
+來的型號)都是基於LoongArch的。
+
+.. _loongarch-references-zh_TW:
+
+參考文獻
+========
+
+Loongson官方網站(龍芯中科技術股份有限公司):
+
+ http://www.loongson.cn/
+
+Loongson與LoongArch的開發者網站(軟件與文檔資源):
+
+ http://www.loongnix.cn/
+
+ https://github.com/loongson/
+
+ https://loongson.github.io/LoongArch-Documentation/
+
+LoongArch指令集架構的文檔:
+
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.02-CN.pdf (中文版)
+
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.02-EN.pdf (英文版)
+
+LoongArch的ELF psABI文檔:
+
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v2.01-CN.pdf (中文版)
+
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v2.01-EN.pdf (英文版)
+
+Loongson與LoongArch的Linux內核源碼倉庫:
+
+ https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson.git
+
diff --git a/Documentation/translations/zh_TW/arch/loongarch/irq-chip-model.rst b/Documentation/translations/zh_TW/arch/loongarch/irq-chip-model.rst
new file mode 100644
index 000000000000..dbe9595bbf16
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/loongarch/irq-chip-model.rst
@@ -0,0 +1,158 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: Documentation/arch/loongarch/irq-chip-model.rst
+:Translator: Huacai Chen <chenhuacai@loongson.cn>
+
+==================================
+LoongArch的IRQ芯片模型(層級關係)
+==================================
+
+目前,基於LoongArch的處理器(如龍芯3A5000)只能與LS7A芯片組配合工作。LoongArch計算機
+中的中斷控制器(即IRQ芯片)包括CPUINTC(CPU Core Interrupt Controller)、LIOINTC(
+Legacy I/O Interrupt Controller)、EIOINTC(Extended I/O Interrupt Controller)、
+HTVECINTC(Hyper-Transport Vector Interrupt Controller)、PCH-PIC(LS7A芯片組的主中
+斷控制器)、PCH-LPC(LS7A芯片組的LPC中斷控制器)和PCH-MSI(MSI中斷控制器)。
+
+CPUINTC是一種CPU內部的每個核本地的中斷控制器,LIOINTC/EIOINTC/HTVECINTC是CPU內部的
+全局中斷控制器(每個芯片一個,所有核共享),而PCH-PIC/PCH-LPC/PCH-MSI是CPU外部的中
+斷控制器(在配套芯片組裏面)。這些中斷控制器(或者說IRQ芯片)以一種層次樹的組織形式
+級聯在一起,一共有兩種層級關係模型(傳統IRQ模型和擴展IRQ模型)。
+
+傳統IRQ模型
+===========
+
+在這種模型裏面,IPI(Inter-Processor Interrupt)和CPU本地時鐘中斷直接發送到CPUINTC,
+CPU串口(UARTs)中斷髮送到LIOINTC,而其他所有設備的中斷則分別發送到所連接的PCH-PIC/
+PCH-LPC/PCH-MSI,然後被HTVECINTC統一收集,再發送到LIOINTC,最後到達CPUINTC::
+
+ +-----+ +---------+ +-------+
+ | IPI | --> | CPUINTC | <-- | Timer |
+ +-----+ +---------+ +-------+
+ ^
+ |
+ +---------+ +-------+
+ | LIOINTC | <-- | UARTs |
+ +---------+ +-------+
+ ^
+ |
+ +-----------+
+ | HTVECINTC |
+ +-----------+
+ ^ ^
+ | |
+ +---------+ +---------+
+ | PCH-PIC | | PCH-MSI |
+ +---------+ +---------+
+ ^ ^ ^
+ | | |
+ +---------+ +---------+ +---------+
+ | PCH-LPC | | Devices | | Devices |
+ +---------+ +---------+ +---------+
+ ^
+ |
+ +---------+
+ | Devices |
+ +---------+
+
+擴展IRQ模型
+===========
+
+在這種模型裏面,IPI(Inter-Processor Interrupt)和CPU本地時鐘中斷直接發送到CPUINTC,
+CPU串口(UARTs)中斷髮送到LIOINTC,而其他所有設備的中斷則分別發送到所連接的PCH-PIC/
+PCH-LPC/PCH-MSI,然後被EIOINTC統一收集,再直接到達CPUINTC::
+
+ +-----+ +---------+ +-------+
+ | IPI | --> | CPUINTC | <-- | Timer |
+ +-----+ +---------+ +-------+
+ ^ ^
+ | |
+ +---------+ +---------+ +-------+
+ | EIOINTC | | LIOINTC | <-- | UARTs |
+ +---------+ +---------+ +-------+
+ ^ ^
+ | |
+ +---------+ +---------+
+ | PCH-PIC | | PCH-MSI |
+ +---------+ +---------+
+ ^ ^ ^
+ | | |
+ +---------+ +---------+ +---------+
+ | PCH-LPC | | Devices | | Devices |
+ +---------+ +---------+ +---------+
+ ^
+ |
+ +---------+
+ | Devices |
+ +---------+
+
+ACPI相關的定義
+==============
+
+CPUINTC::
+
+ ACPI_MADT_TYPE_CORE_PIC;
+ struct acpi_madt_core_pic;
+ enum acpi_madt_core_pic_version;
+
+LIOINTC::
+
+ ACPI_MADT_TYPE_LIO_PIC;
+ struct acpi_madt_lio_pic;
+ enum acpi_madt_lio_pic_version;
+
+EIOINTC::
+
+ ACPI_MADT_TYPE_EIO_PIC;
+ struct acpi_madt_eio_pic;
+ enum acpi_madt_eio_pic_version;
+
+HTVECINTC::
+
+ ACPI_MADT_TYPE_HT_PIC;
+ struct acpi_madt_ht_pic;
+ enum acpi_madt_ht_pic_version;
+
+PCH-PIC::
+
+ ACPI_MADT_TYPE_BIO_PIC;
+ struct acpi_madt_bio_pic;
+ enum acpi_madt_bio_pic_version;
+
+PCH-MSI::
+
+ ACPI_MADT_TYPE_MSI_PIC;
+ struct acpi_madt_msi_pic;
+ enum acpi_madt_msi_pic_version;
+
+PCH-LPC::
+
+ ACPI_MADT_TYPE_LPC_PIC;
+ struct acpi_madt_lpc_pic;
+ enum acpi_madt_lpc_pic_version;
+
+參考文獻
+========
+
+龍芯3A5000的文檔:
+
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/Loongson-3A5000-usermanual-1.02-CN.pdf (中文版)
+
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/Loongson-3A5000-usermanual-1.02-EN.pdf (英文版)
+
+龍芯LS7A芯片組的文檔:
+
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/Loongson-7A1000-usermanual-2.00-CN.pdf (中文版)
+
+ https://github.com/loongson/LoongArch-Documentation/releases/latest/download/Loongson-7A1000-usermanual-2.00-EN.pdf (英文版)
+
+.. note::
+ - CPUINTC:即《龍芯架構參考手冊卷一》第7.4節所描述的CSR.ECFG/CSR.ESTAT寄存器及其
+ 中斷控制邏輯;
+ - LIOINTC:即《龍芯3A5000處理器使用手冊》第11.1節所描述的“傳統I/O中斷”;
+ - EIOINTC:即《龍芯3A5000處理器使用手冊》第11.2節所描述的“擴展I/O中斷”;
+ - HTVECINTC:即《龍芯3A5000處理器使用手冊》第14.3節所描述的“HyperTransport中斷”;
+ - PCH-PIC/PCH-MSI:即《龍芯7A1000橋片用戶手冊》第5章所描述的“中斷控制器”;
+ - PCH-LPC:即《龍芯7A1000橋片用戶手冊》第24.3節所描述的“LPC中斷”。
+
diff --git a/Documentation/translations/zh_TW/arch/mips/booting.rst b/Documentation/translations/zh_TW/arch/mips/booting.rst
new file mode 100644
index 000000000000..7e104abf5a51
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/mips/booting.rst
@@ -0,0 +1,35 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: Documentation/arch/mips/booting.rst
+
+:翻譯:
+
+ 司延騰 Yanteng Si <siyanteng@loongson.cn>
+
+.. _tw_booting:
+
+BMIPS設備樹引導
+------------------------
+
+ 一些bootloaders只支持在內核鏡像開始地址處的單一入口點。而其它
+ bootloaders將跳轉到ELF的開始地址處。兩種方案都支持的;因爲
+ CONFIG_BOOT_RAW=y and CONFIG_NO_EXCEPT_FILL=y, 所以第一條指令
+ 會立即跳轉到kernel_entry()入口處執行。
+
+ 與arch/arm情況(b)類似,dt感知的引導加載程序需要設置以下寄存器:
+
+ a0 : 0
+
+ a1 : 0xffffffff
+
+ a2 : RAM中指向設備樹塊的物理指針(在chapterII中定義)。
+ 設備樹可以位於前512MB物理地址空間(0x00000000 -
+ 0x1fffffff)的任何位置,以64位邊界對齊。
+
+ 傳統bootloaders不會使用這樣的約定,並且它們不傳入DT塊。
+ 在這種情況下,Linux將通過選中CONFIG_DT_*查找DTB。
+
+ 以上約定只在32位系統中定義,因爲目前沒有任何64位的BMIPS實現。
+
diff --git a/Documentation/translations/zh_TW/arch/mips/features.rst b/Documentation/translations/zh_TW/arch/mips/features.rst
new file mode 100644
index 000000000000..3d3906c4d08e
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/mips/features.rst
@@ -0,0 +1,14 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: Documentation/arch/mips/features.rst
+
+:翻譯:
+
+ 司延騰 Yanteng Si <siyanteng@loongson.cn>
+
+.. _tw_features:
+
+.. kernel-feat:: features mips
+
diff --git a/Documentation/translations/zh_TW/arch/mips/index.rst b/Documentation/translations/zh_TW/arch/mips/index.rst
new file mode 100644
index 000000000000..4b7d28806489
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/mips/index.rst
@@ -0,0 +1,30 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: Documentation/arch/mips/index.rst
+
+:翻譯:
+
+ 司延騰 Yanteng Si <siyanteng@loongson.cn>
+
+===========================
+MIPS特性文檔
+===========================
+
+.. toctree::
+ :maxdepth: 2
+ :numbered:
+
+ booting
+ ingenic-tcu
+
+ features
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
+
diff --git a/Documentation/translations/zh_TW/arch/mips/ingenic-tcu.rst b/Documentation/translations/zh_TW/arch/mips/ingenic-tcu.rst
new file mode 100644
index 000000000000..4385c0f3e9cd
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/mips/ingenic-tcu.rst
@@ -0,0 +1,73 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: Documentation/arch/mips/ingenic-tcu.rst
+
+:翻譯:
+
+ 司延騰 Yanteng Si <siyanteng@loongson.cn>
+
+.. _tw_ingenic-tcu:
+
+===============================================
+君正 JZ47xx SoC定時器/計數器硬件單元
+===============================================
+
+君正 JZ47xx SoC中的定時器/計數器單元(TCU)是一個多功能硬件塊。它有多達
+8個通道,可以用作計數器,計時器,或脈衝寬度調製器。
+
+- JZ4725B, JZ4750, JZ4755 只有6個TCU通道。其它SoC都有8個通道。
+
+- JZ4725B引入了一個獨立的通道,稱爲操作系統計時器(OST)。這是一個32位可
+ 編程定時器。在JZ4760B及以上型號上,它是64位的。
+
+- 每個TCU通道都有自己的時鐘源,可以通過 TCSR 寄存器設置通道的父級時鐘
+ 源(pclk、ext、rtc)、開關以及分頻。
+
+ - 看門狗和OST硬件模塊在它們的寄存器空間中也有相同形式的TCSR寄存器。
+ - 用於關閉/開啓的 TCU 寄存器也可以關閉/開啓看門狗和 OST 時鐘。
+
+- 每個TCU通道在兩種模式的其中一種模式下運行:
+
+ - 模式 TCU1:通道無法在睡眠模式下運行,但更易於操作。
+ - 模式 TCU2:通道可以在睡眠模式下運行,但操作比 TCU1 通道複雜一些。
+
+- 每個 TCU 通道的模式取決於使用的SoC:
+
+ - 在最老的SoC(高於JZ4740),八個通道都運行在TCU1模式。
+ - 在 JZ4725B,通道5運行在TCU2,其它通道則運行在TCU1。
+ - 在最新的SoC(JZ4750及之後),通道1-2運行在TCU2,其它通道則運行
+ 在TCU1。
+
+- 每個通道都可以生成中斷。有些通道共享一條中斷線,而有些沒有,其在SoC型
+ 號之間的變更:
+
+ - 在很老的SoC(JZ4740及更低),通道0和通道1有它們自己的中斷線;通
+ 道2-7共享最後一條中斷線。
+ - 在 JZ4725B,通道0有它自己的中斷線;通道1-5共享一條中斷線;OST
+ 使用最後一條中斷線。
+ - 在比較新的SoC(JZ4750及以後),通道5有它自己的中斷線;通
+ 道0-4和(如果是8通道)6-7全部共享一條中斷線;OST使用最後一條中
+ 斷線。
+
+實現
+====
+
+TCU硬件的功能分佈在多個驅動程序:
+
+============== ===================================
+時鐘 drivers/clk/ingenic/tcu.c
+中斷 drivers/irqchip/irq-ingenic-tcu.c
+定時器 drivers/clocksource/ingenic-timer.c
+OST drivers/clocksource/ingenic-ost.c
+脈衝寬度調製器 drivers/pwm/pwm-jz4740.c
+看門狗 drivers/watchdog/jz4740_wdt.c
+============== ===================================
+
+因爲可以從相同的寄存器控制屬於不同驅動程序和框架的TCU的各種功能,所以
+所有這些驅動程序都通過相同的控制總線通用接口訪問它們的寄存器。
+
+有關TCU驅動程序的設備樹綁定的更多信息,請參閱:
+Documentation/devicetree/bindings/timer/ingenic,tcu.yaml.
+
diff --git a/Documentation/translations/zh_TW/arch/openrisc/index.rst b/Documentation/translations/zh_TW/arch/openrisc/index.rst
new file mode 100644
index 000000000000..7585960783fc
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/openrisc/index.rst
@@ -0,0 +1,33 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: Documentation/arch/openrisc/index.rst
+
+:翻譯:
+
+ 司延騰 Yanteng Si <siyanteng@loongson.cn>
+
+.. _tw_openrisc_index:
+
+=================
+OpenRISC 體系架構
+=================
+
+.. toctree::
+ :maxdepth: 2
+
+ openrisc_port
+ todo
+
+Todolist:
+ features
+
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
+
diff --git a/Documentation/translations/zh_TW/arch/openrisc/openrisc_port.rst b/Documentation/translations/zh_TW/arch/openrisc/openrisc_port.rst
new file mode 100644
index 000000000000..422fe9f7a3f2
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/openrisc/openrisc_port.rst
@@ -0,0 +1,128 @@
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: Documentation/arch/openrisc/openrisc_port.rst
+
+:翻譯:
+
+ 司延騰 Yanteng Si <siyanteng@loongson.cn>
+
+.. _tw_openrisc_port:
+
+==============
+OpenRISC Linux
+==============
+
+這是Linux對OpenRISC類微處理器的移植;具體來說,最早移植目標是32位
+OpenRISC 1000系列(或1k)。
+
+關於OpenRISC處理器和正在進行中的開發的信息:
+
+ ======= =============================
+ 網站 https://openrisc.io
+ 郵箱 openrisc@lists.librecores.org
+ ======= =============================
+
+---------------------------------------------------------------------
+
+OpenRISC工具鏈和Linux的構建指南
+===============================
+
+爲了構建和運行Linux for OpenRISC,你至少需要一個基本的工具鏈,或許
+還需要架構模擬器。 這裏概述了準備就位這些部分的步驟。
+
+1) 工具鏈
+
+工具鏈二進制文件可以從openrisc.io或我們的github發佈頁面獲得。不同
+工具鏈的構建指南可以在openrisc.io或Stafford的工具鏈構建和發佈腳本
+中找到。
+
+ ====== =================================================
+ 二進制 https://github.com/openrisc/or1k-gcc/releases
+ 工具鏈 https://openrisc.io/software
+ 構建 https://github.com/stffrdhrn/or1k-toolchain-build
+ ====== =================================================
+
+2) 構建
+
+像往常一樣構建Linux內核::
+
+ make ARCH=openrisc CROSS_COMPILE="or1k-linux-" defconfig
+ make ARCH=openrisc CROSS_COMPILE="or1k-linux-"
+
+3) 在FPGA上運行(可選)
+
+OpenRISC社區通常使用FuseSoC來管理構建和編程SoC到FPGA中。 下面是用
+OpenRISC SoC對De0 Nano開發板進行編程的一個例子。 在構建過程中,
+FPGA RTL是從FuseSoC IP核庫中下載的代碼,並使用FPGA供應商工具構建。
+二進制文件用openocd加載到電路板上。
+
+::
+
+ git clone https://github.com/olofk/fusesoc
+ cd fusesoc
+ sudo pip install -e .
+
+ fusesoc init
+ fusesoc build de0_nano
+ fusesoc pgm de0_nano
+
+ openocd -f interface/altera-usb-blaster.cfg \
+ -f board/or1k_generic.cfg
+
+ telnet localhost 4444
+ > init
+ > halt; load_image vmlinux ; reset
+
+4) 在模擬器上運行(可選)
+
+QEMU是一個處理器仿真器,我們推薦它來模擬OpenRISC平臺。 請按照QEMU網
+站上的OpenRISC說明,讓Linux在QEMU上運行。 你可以自己構建QEMU,但你的
+Linux發行版可能提供了支持OpenRISC的二進制包。
+
+ ============= ======================================================
+ qemu openrisc https://wiki.qemu.org/Documentation/Platforms/OpenRISC
+ ============= ======================================================
+
+---------------------------------------------------------------------
+
+術語表
+======
+
+代碼中使用了以下符號約定以將範圍限制在幾個特定處理器實現上:
+
+========= =======================
+openrisc: OpenRISC類型處理器
+or1k: OpenRISC 1000系列處理器
+or1200: OpenRISC 1200處理器
+========= =======================
+
+---------------------------------------------------------------------
+
+歷史
+====
+
+2003-11-18 Matjaz Breskvar (phoenix@bsemi.com)
+ 將linux初步移植到OpenRISC或32架構。
+ 所有的核心功能都實現了,並且可以使用。
+
+2003-12-08 Matjaz Breskvar (phoenix@bsemi.com)
+ 徹底改變TLB失誤處理。
+ 重寫異常處理。
+ 在默認的initrd中實現了sash-3.6的所有功能。
+ 大幅改進的版本。
+
+2004-04-10 Matjaz Breskvar (phoenix@bsemi.com)
+ 大量的bug修復。
+ 支持以太網,http和telnet服務器功能。
+ 可以運行許多標準的linux應用程序。
+
+2004-06-26 Matjaz Breskvar (phoenix@bsemi.com)
+ 移植到2.6.x。
+
+2004-11-30 Matjaz Breskvar (phoenix@bsemi.com)
+ 大量的bug修復和增強功能。
+ 增加了opencores framebuffer驅動。
+
+2010-10-09 Jonas Bonn (jonas@southpole.se)
+ 重大重寫,使其與上游的Linux 2.6.36看齊。
+
diff --git a/Documentation/translations/zh_TW/arch/openrisc/todo.rst b/Documentation/translations/zh_TW/arch/openrisc/todo.rst
new file mode 100644
index 000000000000..df261b9e3002
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/openrisc/todo.rst
@@ -0,0 +1,24 @@
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: Documentation/arch/openrisc/todo.rst
+
+:翻譯:
+
+ 司延騰 Yanteng Si <siyanteng@loongson.cn>
+
+.. _tw_openrisc_todo.rst:
+
+========
+待辦事項
+========
+
+OpenRISC Linux的移植已經完全投入使用,並且從 2.6.35 開始就一直在上游同步。
+然而,還有一些剩餘的項目需要在未來幾個月內完成。 下面是一個即將進行調查的已知
+不盡完美的項目列表,即我們的待辦事項列表。
+
+- 實現其餘的DMA API……dma_map_sg等。
+
+- 完成重命名清理工作……代碼中提到了or32,這是架構的一個老名字。 我們
+ 已經確定的名字是or1k,這個改變正在以緩慢積累的方式進行。 目前,or32相當
+ 於or1k。
+
diff --git a/Documentation/translations/zh_TW/arch/parisc/debugging.rst b/Documentation/translations/zh_TW/arch/parisc/debugging.rst
new file mode 100644
index 000000000000..c9ee804aebbd
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/parisc/debugging.rst
@@ -0,0 +1,46 @@
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: Documentation/arch/parisc/debugging.rst
+
+:翻譯:
+
+ 司延騰 Yanteng Si <siyanteng@loongson.cn>
+
+.. _tw_parisc_debugging:
+
+=================
+調試PA-RISC
+=================
+
+好吧,這裏有一些關於調試linux/parisc的較底層部分的信息。
+
+
+1. 絕對地址
+=====================
+
+很多彙編代碼目前運行在實模式下,這意味着會使用絕對地址,而不是像內核其他
+部分那樣使用虛擬地址。要將絕對地址轉換爲虛擬地址,你可以在System.map中查
+找,添加__PAGE_OFFSET(目前是0x10000000)。
+
+
+2. HPMCs
+========
+
+當實模式的代碼試圖訪問不存在的內存時,會出現HPMC(high priority machine
+check)而不是內核oops。若要調試HPMC,請嘗試找到系統響應程序/請求程序地址。
+系統請求程序地址應該與(某)處理器的HPA(I/O範圍內的高地址)相匹配;系統響應程
+序地址是實模式代碼試圖訪問的地址。
+
+系統響應程序地址的典型值是大於__PAGE_OFFSET (0x10000000)的地址,這意味着
+在實模式試圖訪問它之前,虛擬地址沒有被翻譯成物理地址。
+
+
+3. 有趣的Q位
+============
+
+某些非常關鍵的代碼必須清除PSW中的Q位。當Q位被清除時,CPU不會更新中斷處理
+程序所讀取的寄存器,以找出機器被中斷的位置——所以如果你在清除Q位的指令和再
+次設置Q位的RFI之間遇到中斷,你不知道它到底發生在哪裏。如果你幸運的話,IAOQ
+會指向清除Q位的指令,如果你不幸運的話,它會指向任何地方。通常Q位的問題會
+表現爲無法解釋的系統掛起或物理內存越界。
+
diff --git a/Documentation/translations/zh_TW/arch/parisc/index.rst b/Documentation/translations/zh_TW/arch/parisc/index.rst
new file mode 100644
index 000000000000..35941bf68c88
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/parisc/index.rst
@@ -0,0 +1,32 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: Documentation/arch/parisc/index.rst
+
+:翻譯:
+
+ 司延騰 Yanteng Si <siyanteng@loongson.cn>
+
+.. _tw_parisc_index:
+
+====================
+PA-RISC體系架構
+====================
+
+.. toctree::
+ :maxdepth: 2
+
+ debugging
+ registers
+
+Todolist:
+
+ features
+
+.. only:: subproject and html
+
+ Indices
+ =======
+
+ * :ref:`genindex`
+
diff --git a/Documentation/translations/zh_TW/arch/parisc/registers.rst b/Documentation/translations/zh_TW/arch/parisc/registers.rst
new file mode 100644
index 000000000000..695acb21134a
--- /dev/null
+++ b/Documentation/translations/zh_TW/arch/parisc/registers.rst
@@ -0,0 +1,157 @@
+.. include:: ../../disclaimer-zh_TW.rst
+
+:Original: Documentation/arch/parisc/registers.rst
+
+:翻譯:
+
+ 司延騰 Yanteng Si <siyanteng@loongson.cn>
+
+.. _tw_parisc_registers:
+
+=========================
+Linux/PA-RISC的寄存器用法
+=========================
+
+[ 用星號表示目前尚未實現的計劃用途。 ]
+
+ABI約定的通用寄存器
+===================
+
+控制寄存器
+----------
+
+============================ =================================
+CR 0 (恢復計數器) 用於ptrace
+CR 1-CR 7(無定義) 未使用
+CR 8 (Protection ID) 每進程值*
+CR 9, 12, 13 (PIDS) 未使用
+CR10 (CCR) FPU延遲保存*
+CR11 按照ABI的規定(SAR)
+CR14 (中斷向量) 初始化爲 fault_vector
+CR15 (EIEM) 所有位初始化爲1*
+CR16 (間隔計時器) 讀取週期數/寫入開始時間間隔計時器
+CR17-CR22 中斷參數
+CR19 中斷指令寄存器
+CR20 中斷空間寄存器
+CR21 中斷偏移量寄存器
+CR22 中斷 PSW
+CR23 (EIRR) 讀取未決中斷/寫入清除位
+CR24 (TR 0) 內核空間頁目錄指針
+CR25 (TR 1) 用戶空間頁目錄指針
+CR26 (TR 2) 不使用
+CR27 (TR 3) 線程描述符指針
+CR28 (TR 4) 不使用
+CR29 (TR 5) 不使用
+CR30 (TR 6) 當前 / 0
+CR31 (TR 7) 臨時寄存器,在不同地方使用
+============================ =================================
+
+空間寄存器(內核模式)
+----------------------
+
+======== ==============================
+SR0 臨時空間寄存器
+SR4-SR7 設置爲0
+SR1 臨時空間寄存器
+SR2 內核不應該破壞它
+SR3 用於用戶空間訪問(當前進程)
+======== ==============================
+
+空間寄存器(用戶模式)
+----------------------
+
+======== ============================
+SR0 臨時空間寄存器
+SR1 臨時空間寄存器
+SR2 保存Linux gateway page的空間
+SR3 在內核中保存用戶地址空間的值
+SR4-SR7 定義了用戶/內核的短地址空間
+======== ============================
+
+
+處理器狀態字
+------------
+
+====================== ================================================
+W (64位地址) 0
+E (小尾端) 0
+S (安全間隔計時器) 0
+T (產生分支陷阱) 0
+H (高特權級陷阱) 0
+L (低特權級陷阱) 0
+N (撤銷下一條指令) 被C代碼使用
+X (數據存儲中斷禁用) 0
+B (產生分支) 被C代碼使用
+C (代碼地址轉譯) 1, 在執行實模式代碼時爲0
+V (除法步長校正) 被C代碼使用
+M (HPMC 掩碼) 0, 在執行HPMC操作*時爲1
+C/B (進/借 位) 被C代碼使用
+O (有序引用) 1*
+F (性能監視器) 0
+R (回收計數器陷阱) 0
+Q (收集中斷狀態) 1 (在rfi之前的代碼中爲0)
+P (保護標識符) 1*
+D (數據地址轉譯) 1, 在執行實模式代碼時爲0
+I (外部中斷掩碼) 由cli()/sti()宏使用。
+====================== ================================================
+
+“隱形”寄存器(影子寄存器)
+---------------------------
+
+============= ===================
+PSW W 默認值 0
+PSW E 默認值 0
+影子寄存器 被中斷處理代碼使用
+TOC啓用位 1
+============= ===================
+
+----------------------------------------------------------
+
+PA-RISC架構定義了7個寄存器作爲“影子寄存器”。這些寄存器在
+RETURN FROM INTERRUPTION AND RESTORE指令中使用,通過消
+除中斷處理程序中對一般寄存器(GR)的保存和恢復的需要來減
+少狀態保存和恢復時間。影子寄存器是GRs 1, 8, 9, 16, 17,
+24和25。
+
+-------------------------------------------------------------------------
+
+寄存器使用說明,最初由John Marvin提供,並由Randolph Chung提供一些補充說明。
+
+對於通用寄存器:
+
+r1,r2,r19-r26,r28,r29 & r31可以在不保存它們的情況下被使用。當然,如果你
+關心它們,在調用另一個程序之前,你也需要保存它們。上面的一些寄存器確實
+有特殊的含義,你應該注意一下:
+
+ r1:
+ addil指令是硬性規定將其結果放在r1中,所以如果你使用這條指令要
+ 注意這點。
+
+ r2:
+ 這就是返回指針。一般來說,你不想使用它,因爲你需要這個指針來返
+ 回給你的調用者。然而,它與這組寄存器組合在一起,因爲調用者不能
+ 依賴你返回時的值是相同的,也就是說,你可以將r2複製到另一個寄存
+ 器,並在作廢r2後通過該寄存器返回,這應該不會給調用程序帶來問題。
+
+ r19-r22:
+ 這些通常被認爲是臨時寄存器。
+ 請注意,在64位中它們是arg7-arg4。
+
+ r23-r26:
+ 這些是arg3-arg0,也就是說,如果你不再關心傳入的值,你可以使用
+ 它們。
+
+ r28,r29:
+ 這倆是ret0和ret1。它們是你傳入返回值的地方。r28是主返回值。當返回
+ 小結構體時,r29也可以用來將數據傳回給調用程序。
+
+ r30:
+ 棧指針
+
+ r31:
+ ble指令將返回指針放在這裏。
+
+
+ r3-r18,r27,r30需要被保存和恢復。r3-r18只是一般用途的寄存器。
+ r27是數據指針,用來使對全局變量的引用更容易。r30是棧指針。
+
diff --git a/Documentation/translations/zh_TW/cpu-freq/core.rst b/Documentation/translations/zh_TW/cpu-freq/core.rst
new file mode 100644
index 000000000000..4f98d1e9f34b
--- /dev/null
+++ b/Documentation/translations/zh_TW/cpu-freq/core.rst
@@ -0,0 +1,110 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/cpu-freq/core.rst
+
+:翻譯:
+
+ 司延騰 Yanteng Si <siyanteng@loongson.cn>
+
+:校譯:
+
+ 唐藝舟 Tang Yizhou <tangyeechou@gmail.com>
+
+====================================
+CPUFreq核心和CPUFreq通知器的通用說明
+====================================
+
+作者:
+ - Dominik Brodowski <linux@brodo.de>
+ - David Kimdon <dwhedon@debian.org>
+ - Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ - Viresh Kumar <viresh.kumar@linaro.org>
+
+.. 目錄:
+
+ 1. CPUFreq核心和接口
+ 2. CPUFreq通知器
+ 3. 含有Operating Performance Point (OPP)的CPUFreq表的生成
+
+1. CPUFreq核心和接口
+======================
+
+cpufreq核心代碼位於drivers/cpufreq/cpufreq.c中。這些cpufreq代碼爲CPUFreq架構的驅
+動程序(那些執行硬件頻率切換的代碼)以及 "通知器" 提供了一個標準化的接口。
+包括設備驅動程序;需要了解策略變化(如 ACPI 熱量管理),或所有頻率變化(如計時代碼),
+甚至需要強制限制爲指定頻率(如 ARM 架構上的 LCD 驅動程序)的其它內核組件。
+此外,內核 "常數" loops_per_jiffy 會根據頻率變化而更新。
+
+cpufreq策略的引用計數由 cpufreq_cpu_get 和 cpufreq_cpu_put 來完成,以確保 cpufreq 驅
+動程序被正確地註冊到核心中,並且驅動程序在 cpufreq_put_cpu 被調用之前不會被卸載。這也保證
+了每個CPU核的cpufreq 策略在使用期間不會被釋放。
+
+2. CPUFreq 通知器
+====================
+
+CPUFreq通知器遵循標準的內核通知器接口。
+關於通知器的細節請參閱 linux/include/linux/notifier.h。
+
+這裏有兩個不同的CPUfreq通知器 - 策略通知器和轉換通知器。
+
+
+2.1 CPUFreq策略通知器
+----------------------------
+
+當創建或移除策略時,這些都會被通知。
+
+階段是在通知器的第二個參數中指定的。當第一次創建策略時,階段是CPUFREQ_CREATE_POLICY,當
+策略被移除時,階段是CPUFREQ_REMOVE_POLICY。
+
+第三個參數 ``void *pointer`` 指向一個結構體cpufreq_policy,其包括min,max(新策略的下限和
+上限(單位爲kHz))這幾個值。
+
+
+2.2 CPUFreq轉換通知器
+--------------------------------
+
+當CPUfreq驅動切換CPU核心頻率時,策略中的每個在線CPU都會收到兩次通知,這些變化沒有任何外部幹
+預。
+
+第二個參數指定階段 - CPUFREQ_PRECHANGE or CPUFREQ_POSTCHANGE.
+
+第三個參數是一個包含如下值的結構體cpufreq_freqs:
+
+====== ===============================
+policy 指向struct cpufreq_policy的指針
+old 舊頻率
+new 新頻率
+flags cpufreq驅動的標誌
+====== ===============================
+
+3. 含有Operating Performance Point (OPP)的CPUFreq表的生成
+==================================================================
+關於OPP的細節請參閱 Documentation/power/opp.rst
+
+dev_pm_opp_init_cpufreq_table -
+ 這個函數提供了一個隨時可用的轉換例程,用來將OPP層關於可用頻率的內部信息翻譯成一種
+ cpufreq易於處理的格式。
+
+ .. Warning::
+
+ 不要在中斷上下文中使用此函數。
+
+ 例如::
+
+ soc_pm_init()
+ {
+ /* Do things */
+ r = dev_pm_opp_init_cpufreq_table(dev, &freq_table);
+ if (!r)
+ policy->freq_table = freq_table;
+ /* Do other things */
+ }
+
+ .. note::
+
+ 該函數只有在CONFIG_PM_OPP之外還啓用了CONFIG_CPU_FREQ時纔可用。
+
+dev_pm_opp_free_cpufreq_table
+ 釋放dev_pm_opp_init_cpufreq_table分配的表。
+
diff --git a/Documentation/translations/zh_TW/cpu-freq/cpu-drivers.rst b/Documentation/translations/zh_TW/cpu-freq/cpu-drivers.rst
new file mode 100644
index 000000000000..add3de2d4523
--- /dev/null
+++ b/Documentation/translations/zh_TW/cpu-freq/cpu-drivers.rst
@@ -0,0 +1,258 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/cpu-freq/cpu-drivers.rst
+
+:翻譯:
+
+ 司延騰 Yanteng Si <siyanteng@loongson.cn>
+
+:校譯:
+
+ 唐藝舟 Tang Yizhou <tangyeechou@gmail.com>
+
+=======================================
+如何實現一個新的CPUFreq處理器驅動程序?
+=======================================
+
+作者:
+
+
+ - Dominik Brodowski <linux@brodo.de>
+ - Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ - Viresh Kumar <viresh.kumar@linaro.org>
+
+.. Contents
+
+ 1. 怎麼做?
+ 1.1 初始化
+ 1.2 Per-CPU 初始化
+ 1.3 驗證
+ 1.4 target/target_index 或 setpolicy?
+ 1.5 target/target_index
+ 1.6 setpolicy
+ 1.7 get_intermediate 與 target_intermediate
+ 2. 頻率表助手
+
+
+
+1. 怎麼做?
+===========
+
+如果,你剛剛得到了一個全新的CPU/芯片組及其數據手冊,並希望爲這個CPU/芯片組添加cpufreq
+支持?很好,這裏有一些至關重要的提示:
+
+
+1.1 初始化
+----------
+
+首先,在 __initcall level 7 (module_init())或更靠後的函數中檢查這個內核是否
+運行在正確的CPU和正確的芯片組上。如果是,則使用cpufreq_register_driver()向
+CPUfreq核心層註冊一個cpufreq_driver結構體。
+
+結構體cpufreq_driver應該包含什麼成員?
+
+ .name - 驅動的名字。
+
+ .init - 一個指向per-policy初始化函數的指針。
+
+ .verify - 一個指向"verification"函數的指針。
+
+ .setpolicy 或 .fast_switch 或 .target 或 .target_index - 差異見
+ 下文。
+
+其它可選成員
+
+ .flags - 給cpufreq核心的提示。
+
+ .driver_data - cpufreq驅動程序的特有數據。
+
+ .get_intermediate 和 target_intermediate - 用於在改變CPU頻率時切換到穩定
+ 的頻率。
+
+ .get - 返回CPU的當前頻率。
+
+ .bios_limit - 返回HW/BIOS對CPU的最大頻率限制值。
+
+ .exit - 一個指向per-policy清理函數的指針,該函數在CPU熱插拔過程的CPU_POST_DEAD
+ 階段被調用。
+
+ .suspend - 一個指向per-policy暫停函數的指針,該函數在關中斷且在該策略的調節器停止
+ 後被調用。
+
+ .resume - 一個指向per-policy恢復函數的指針,該函數在關中斷且在調節器再一次啓動前被
+ 調用。
+
+ .ready - 一個指向per-policy準備函數的指針,該函數在策略完全初始化之後被調用。
+
+ .attr - 一個指向NULL結尾的"struct freq_attr"列表的指針,該列表允許導出值到
+ sysfs。
+
+ .boost_enabled - 如果設置,則啓用提升(boost)頻率。
+
+ .set_boost - 一個指向per-policy函數的指針,該函數用來開啓/關閉提升(boost)頻率功能。
+
+
+1.2 Per-CPU 初始化
+------------------
+
+每當一個新的CPU被註冊到設備模型中,或者當cpufreq驅動註冊自身之後,如果此CPU的cpufreq策
+略不存在,則會調用per-policy的初始化函數cpufreq_driver.init。請注意,.init()和.exit()例程
+只爲某個策略調用一次,而不是對該策略管理的每個CPU調用一次。它需要一個 ``struct cpufreq_policy
+*policy`` 作爲參數。現在該怎麼做呢?
+
+如果有必要,請在你的CPU上激活CPUfreq功能支持。
+
+然後,驅動程序必須填寫以下值:
+
++-----------------------------------+--------------------------------------+
+|policy->cpuinfo.min_freq和 | 該CPU支持的最低和最高頻率(kHz) |
+|policy->cpuinfo.max_freq | |
+| | |
++-----------------------------------+--------------------------------------+
+|policy->cpuinfo.transition_latency | CPU在兩個頻率之間切換所需的時間,以 |
+| | 納秒爲單位(如不適用,設定爲 |
+| | CPUFREQ_ETERNAL) |
+| | |
++-----------------------------------+--------------------------------------+
+|policy->cur | 該CPU當前的工作頻率(如適用) |
+| | |
++-----------------------------------+--------------------------------------+
+|policy->min, | 必須包含該CPU的"默認策略"。稍後 |
+|policy->max, | 會用這些值調用 |
+|policy->policy and, if necessary, | cpufreq_driver.verify和下面函數 |
+|policy->governor | 之一:cpufreq_driver.setpolicy或 |
+| | cpufreq_driver.target/target_index |
+| | |
++-----------------------------------+--------------------------------------+
+|policy->cpus | 該policy通過DVFS框架影響的全部CPU |
+| | (即與本CPU共享"時鐘/電壓"對)構成 |
+| | 掩碼(同時包含在線和離線CPU),用掩碼 |
+| | 更新本字段 |
+| | |
++-----------------------------------+--------------------------------------+
+
+對於設置其中的一些值(cpuinfo.min[max]_freq, policy->min[max]),頻率表輔助函數可能會有幫
+助。關於它們的更多信息,請參見第2節。
+
+
+1.3 驗證
+--------
+
+當用戶決定設置一個新的策略(由"policy,governor,min,max組成")時,必須對這個策略進行驗證,
+以便糾正不兼容的值。爲了驗證這些值,cpufreq_verify_within_limits(``struct cpufreq_policy
+*policy``, ``unsigned int min_freq``, ``unsigned int max_freq``)函數可能會有幫助。
+關於頻率表輔助函數的詳細內容請參見第2節。
+
+您需要確保至少有一個有效頻率(或工作範圍)在 policy->min 和 policy->max 範圍內。如果有必
+要,先增大policy->max,只有在沒有解決方案的情況下,才減小policy->min。
+
+
+1.4 target 或 target_index 或 setpolicy 或 fast_switch?
+-------------------------------------------------------
+
+大多數cpufreq驅動甚至大多數CPU頻率升降算法只允許將CPU頻率設置爲預定義的固定值。對於這些,你
+可以使用->target(),->target_index()或->fast_switch()回調。
+
+有些具有硬件調頻能力的處理器可以自行依據某些限制來切換CPU頻率。它們應使用->setpolicy()回調。
+
+
+1.5. target/target_index
+------------------------
+
+target_index調用有兩個參數: ``struct cpufreq_policy * policy`` 和 ``unsigned int``
+索引(用於索引頻率表項)。
+
+當調用這裏時,CPUfreq驅動必須設置新的頻率。實際頻率必須由freq_table[index].frequency決定。
+
+在發生錯誤的情況下總是應該恢復到之前的頻率(即policy->restore_freq),即使我們已經切換到了
+中間頻率。
+
+已棄用
+----------
+target調用有三個參數。``struct cpufreq_policy * policy``, unsigned int target_frequency,
+unsigned int relation.
+
+CPUfreq驅動在調用這裏時必須設置新的頻率。實際的頻率必須使用以下規則來確定。
+
+- 儘量貼近"目標頻率"。
+- policy->min <= new_freq <= policy->max (這必須是有效的!!!)
+- 如果 relation==CPUFREQ_REL_L,嘗試選擇一個高於或等於 target_freq 的 new_freq。("L代表
+ 最低,但不能低於")
+- 如果 relation==CPUFREQ_REL_H,嘗試選擇一個低於或等於 target_freq 的 new_freq。("H代表
+ 最高,但不能高於")
+
+這裏,頻率表輔助函數可能會幫助你 -- 詳見第2節。
+
+1.6. fast_switch
+----------------
+
+這個函數用於從調度器的上下文進行頻率切換。並非所有的驅動都要實現它,因爲不允許在這個回調中睡眠。這
+個回調必須經過高度優化,以儘可能快地進行切換。
+
+這個函數有兩個參數: ``struct cpufreq_policy *policy`` 和 ``unsigned int target_frequency``。
+
+
+1.7 setpolicy
+-------------
+
+setpolicy調用只需要一個 ``struct cpufreq_policy * policy`` 作爲參數。需要將處理器內或芯片組內動態頻
+率切換的下限設置爲policy->min,上限設置爲policy->max,如果支持的話,當policy->policy爲
+CPUFREQ_POLICY_PERFORMANCE時選擇面向性能的設置,爲CPUFREQ_POLICY_POWERSAVE時選擇面向省電的設置。
+也可以查看drivers/cpufreq/longrun.c中的參考實現。
+
+1.8 get_intermediate 和 target_intermediate
+--------------------------------------------
+
+僅適用於未設置 target_index() 和 CPUFREQ_ASYNC_NOTIFICATION 的驅動。
+
+get_intermediate應該返回一個平臺想要切換到的穩定的中間頻率,target_intermediate()應該將CPU設置爲
+該頻率,然後再跳轉到'index'對應的頻率。cpufreq核心會負責發送通知,驅動不必在
+target_intermediate()或target_index()中處理它們。
+
+在驅動程序不想爲某個目標頻率切換到中間頻率的情況下,它們可以讓get_intermediate()返回'0'。
+在這種情況下,cpufreq核心將直接調用->target_index()。
+
+注意:->target_index()應該在發生失敗的情況下將頻率恢復到policy->restore_freq,
+因爲cpufreq核心會爲此發送通知。
+
+
+2. 頻率表輔助函數
+=================
+
+由於大多數支持cpufreq的處理器只允許被設置爲幾個特定的頻率,因此,"頻率表"和一些相關函數可能會輔助處理器驅動
+程序的一些工作。這樣的"頻率表"是一個由struct cpufreq_frequency_table的條目構成的數組,"driver_data"成員包
+含驅動程序的專用值,"frequency"成員包含了相應的頻率,此外還有標誌成員。在表的最後,需要添加一個
+cpufreq_frequency_table條目,頻率設置爲CPUFREQ_TABLE_END。如果想跳過表中的一個條目,則將頻率設置爲
+CPUFREQ_ENTRY_INVALID。這些條目不需要按照任何特定的順序排序,如果排序了,cpufreq核心執行DVFS會更快一點,
+因爲搜索最佳匹配會更快。
+
+如果在policy->freq_table字段中包含一個有效的頻率表指針,頻率表就會被cpufreq核心自動驗證。
+
+cpufreq_frequency_table_verify()保證至少有一個有效的頻率在policy->min和policy->max範圍內,並且所有其他
+準則都被滿足。這對->verify調用很有幫助。
+
+cpufreq_frequency_table_target()是對應於->target階段的頻率表輔助函數。只要把值傳遞給這個函數,這個函數就會返
+回包含CPU要設置的頻率的頻率表條目。
+
+以下宏可以作爲cpufreq_frequency_table的迭代器。
+
+cpufreq_for_each_entry(pos, table) - 遍歷頻率表的所有條目。
+
+cpufreq_for_each_valid_entry(pos, table) - 該函數遍歷所有條目,不包括CPUFREQ_ENTRY_INVALID頻率。
+使用參數"pos" -- 一個 ``cpufreq_frequency_table *`` 作爲循環指針,使用參數"table" -- 作爲你想迭代
+的 ``cpufreq_frequency_table *`` 。
+
+例如::
+
+ struct cpufreq_frequency_table *pos, *driver_freq_table;
+
+ cpufreq_for_each_entry(pos, driver_freq_table) {
+ /* Do something with pos */
+ pos->frequency = ...
+ }
+
+如果你需要在driver_freq_table中處理pos的位置,不要做指針減法,因爲它的代價相當高。作爲替代,使用宏
+cpufreq_for_each_entry_idx() 和 cpufreq_for_each_valid_entry_idx() 。
+
diff --git a/Documentation/translations/zh_TW/cpu-freq/cpufreq-stats.rst b/Documentation/translations/zh_TW/cpu-freq/cpufreq-stats.rst
new file mode 100644
index 000000000000..01ec8c837fe9
--- /dev/null
+++ b/Documentation/translations/zh_TW/cpu-freq/cpufreq-stats.rst
@@ -0,0 +1,134 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/cpu-freq/cpufreq-stats.rst
+
+:翻譯:
+
+ 司延騰 Yanteng Si <siyanteng@loongson.cn>
+
+:校譯:
+
+ 唐藝舟 Tang Yizhou <tangyeechou@gmail.com>
+
+==========================================
+sysfs CPUFreq Stats的一般說明
+==========================================
+
+爲使用者準備的信息
+
+
+作者: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+
+.. Contents
+
+ 1. 簡介
+ 2. 提供的統計數據(舉例說明)
+ 3. 配置cpufreq-stats
+
+
+1. 簡介
+===============
+
+cpufreq-stats是一種爲每個CPU提供CPU頻率統計的驅動。
+這些統計數據以/sysfs中一系列只讀接口的形式呈現。cpufreq-stats接口(若已配置)將爲每個CPU生成
+/sysfs(<sysfs root>/devices/system/cpu/cpuX/cpufreq/stats/)中cpufreq目錄下的stats目錄。
+各項統計數據將在stats目錄下形成對應的只讀文件。
+
+此驅動是以獨立於任何可能運行在你所用CPU上的特定cpufreq_driver的方式設計的。因此,它將能和任何
+cpufreq_driver協同工作。
+
+
+2. 已提供的統計數據(有例子)
+=====================================
+
+cpufreq stats提供了以下統計數據(在下面詳細解釋)。
+
+- time_in_state
+- total_trans
+- trans_table
+
+所有統計數據來自以下時間範圍:從統計驅動被加載的時間(或統計數據被重置的時間)開始,到某一統計數據被讀取的時間爲止。
+顯然,統計驅動不會保存它被加載之前的任何頻率轉換信息。
+
+::
+
+ <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # ls -l
+ total 0
+ drwxr-xr-x 2 root root 0 May 14 16:06 .
+ drwxr-xr-x 3 root root 0 May 14 15:58 ..
+ --w------- 1 root root 4096 May 14 16:06 reset
+ -r--r--r-- 1 root root 4096 May 14 16:06 time_in_state
+ -r--r--r-- 1 root root 4096 May 14 16:06 total_trans
+ -r--r--r-- 1 root root 4096 May 14 16:06 trans_table
+
+- **reset**
+
+只寫屬性,可用於重置統計計數器。這對於評估不同調節器的系統行爲非常有用,且無需重啓。
+
+
+- **time_in_state**
+
+此文件給出了在本CPU支持的每個頻率上分別花費的時間。cat輸出的每一行都是一個"<frequency>
+<time>"對,表示這個CPU在<frequency>上花費了<time>個usertime單位的時間。輸出的每一行對應
+一個CPU支持的頻率。這裏usertime單位是10mS(類似於/proc導出的其它時間)。
+
+::
+
+ <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat time_in_state
+ 3600000 2089
+ 3400000 136
+ 3200000 34
+ 3000000 67
+ 2800000 172488
+
+
+- **total_trans**
+
+此文件給出了這個CPU頻率轉換的總次數。cat的輸出是一個計數值,它就是頻率轉換的總次數。
+
+::
+
+ <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat total_trans
+ 20
+
+- **trans_table**
+
+本文件提供所有CPU頻率轉換的細粒度信息。這裏的cat輸出是一個二維矩陣,其中一個條目<i, j>(第
+i行,第j列)代表從Freq_i到Freq_j的轉換次數。Freq_i行和Freq_j列遵循驅動最初提供給cpufreq
+核心的頻率表的排列順序,因此可以已排序(升序或降序)或未排序。這裏的輸出也包含了實際
+頻率值,分別按行和按列顯示,以便更好地閱讀。
+
+如果轉換表大於PAGE_SIZE,讀取時將返回一個-EFBIG錯誤。
+
+::
+
+ <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat trans_table
+ From : To
+ : 3600000 3400000 3200000 3000000 2800000
+ 3600000: 0 5 0 0 0
+ 3400000: 4 0 2 0 0
+ 3200000: 0 1 0 2 0
+ 3000000: 0 0 1 0 3
+ 2800000: 0 0 0 2 0
+
+3. 配置cpufreq-stats
+============================
+
+按以下方式在你的內核中配置cpufreq-stats::
+
+ Config Main Menu
+ Power management options (ACPI, APM) --->
+ CPU Frequency scaling --->
+ [*] CPU Frequency scaling
+ [*] CPU frequency translation statistics
+
+
+"CPU Frequency scaling" (CONFIG_CPU_FREQ) 應該被啓用,以支持配置cpufreq-stats。
+
+"CPU frequency translation statistics" (CONFIG_CPU_FREQ_STAT)提供了包括
+time_in_state、total_trans和trans_table的統計數據。
+
+一旦啓用了這個選項,並且你的CPU支持cpufrequency,你就可以在/sysfs中看到CPU頻率統計。
+
diff --git a/Documentation/translations/zh_TW/cpu-freq/index.rst b/Documentation/translations/zh_TW/cpu-freq/index.rst
new file mode 100644
index 000000000000..a9df16870b21
--- /dev/null
+++ b/Documentation/translations/zh_TW/cpu-freq/index.rst
@@ -0,0 +1,48 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/cpu-freq/index.rst
+
+:翻譯:
+
+ 司延騰 Yanteng Si <siyanteng@loongson.cn>
+
+.. _tw_index.rst:
+
+=======================================================
+Linux CPUFreq - Linux(TM)內核中的CPU頻率和電壓升降代碼
+=======================================================
+
+Author: Dominik Brodowski <linux@brodo.de>
+
+ 時鐘升降允許你在運行中改變CPU的時鐘速度。這是一個很好的節省電池電量的方法,因爲時
+ 鐘速度越低,CPU消耗的電量越少。
+
+
+.. toctree::
+ :maxdepth: 1
+
+ core
+ cpu-drivers
+ cpufreq-stats
+
+郵件列表
+------------
+這裏有一個 CPU 頻率變化的 CVS 提交和通用列表,您可以在這裏報告bug、問題或提交補丁。要發
+布消息,請發送電子郵件到 linux-pm@vger.kernel.org。
+
+鏈接
+-----
+FTP檔案:
+* ftp://ftp.linux.org.uk/pub/linux/cpufreq/
+
+如何訪問CVS倉庫:
+* http://cvs.arm.linux.org.uk/
+
+CPUFreq郵件列表:
+* http://vger.kernel.org/vger-lists.html#linux-pm
+
+SA-1100的時鐘和電壓標度:
+* http://www.lartmaker.nl/projects/scaling
+
diff --git a/Documentation/translations/zh_TW/dev-tools/gcov.rst b/Documentation/translations/zh_TW/dev-tools/gcov.rst
new file mode 100644
index 000000000000..ce1c9a97de16
--- /dev/null
+++ b/Documentation/translations/zh_TW/dev-tools/gcov.rst
@@ -0,0 +1,265 @@
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/dev-tools/gcov.rst
+:Translator: 趙軍奎 Bernard Zhao <bernard@vivo.com>
+
+在Linux內核裏使用gcov做代碼覆蓋率檢查
+=====================================
+
+gcov分析核心支持在Linux內核中啓用GCC的覆蓋率測試工具 gcov_ ,Linux內核
+運行時的代碼覆蓋率數據會以gcov兼容的格式導出到“gcov”debugfs目錄中,可
+以通過gcov的 ``-o`` 選項(如下示例)獲得指定文件的代碼運行覆蓋率統計數據
+(需要跳轉到內核編譯路徑下並且要有root權限)::
+
+ # cd /tmp/linux-out
+ # gcov -o /sys/kernel/debug/gcov/tmp/linux-out/kernel spinlock.c
+
+這將在當前目錄中創建帶有執行計數註釋的源代碼文件。
+在獲得這些統計文件後,可以使用圖形化的gcov前端工具(比如 lcov_ ),來實現
+自動化處理Linux內核的覆蓋率運行數據,同時生成易於閱讀的HTML格式文件。
+
+可能的用途:
+
+* 調試(用來判斷每一行的代碼是否已經運行過)
+* 測試改進(如何修改測試代碼,儘可能地覆蓋到沒有運行過的代碼)
+* 內核最小化配置(對於某一個選項配置,如果關聯的代碼從來沒有運行過,
+ 是否還需要這個配置)
+
+.. _gcov: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html
+.. _lcov: http://ltp.sourceforge.net/coverage/lcov.php
+
+
+準備
+----
+
+內核打開如下配置::
+
+ CONFIG_DEBUG_FS=y
+ CONFIG_GCOV_KERNEL=y
+
+獲取整個內核的覆蓋率數據,還需要打開::
+
+ CONFIG_GCOV_PROFILE_ALL=y
+
+需要注意的是,整個內核開啓覆蓋率統計會造成內核鏡像文件尺寸的增大,
+同時內核運行也會變慢一些。
+另外,並不是所有的架構都支持整個內核開啓覆蓋率統計。
+
+代碼運行覆蓋率數據只在debugfs掛載完成後纔可以訪問::
+
+ mount -t debugfs none /sys/kernel/debug
+
+
+定製化
+------
+
+如果要單獨針對某一個路徑或者文件進行代碼覆蓋率統計,可以在內核相應路
+徑的Makefile中增加如下的配置:
+
+- 單獨統計單個文件(例如main.o)::
+
+ GCOV_PROFILE_main.o := y
+
+- 單獨統計某一個路徑::
+
+ GCOV_PROFILE := y
+
+如果要在整個內核的覆蓋率統計(開啓CONFIG_GCOV_PROFILE_ALL)中單獨排除
+某一個文件或者路徑,可以使用如下的方法::
+
+ GCOV_PROFILE_main.o := n
+
+和::
+
+ GCOV_PROFILE := n
+
+此機制僅支持鏈接到內核鏡像或編譯爲內核模塊的文件。
+
+
+相關文件
+--------
+
+gcov功能需要在debugfs中創建如下文件:
+
+``/sys/kernel/debug/gcov``
+ gcov相關功能的根路徑
+
+``/sys/kernel/debug/gcov/reset``
+ 全局復位文件:向該文件寫入數據後會將所有的gcov統計數據清0
+
+``/sys/kernel/debug/gcov/path/to/compile/dir/file.gcda``
+ gcov工具可以識別的覆蓋率統計數據文件,向該文件寫入數據後
+ 會將本文件的gcov統計數據清0
+
+``/sys/kernel/debug/gcov/path/to/compile/dir/file.gcno``
+ gcov工具需要的軟連接文件(指向編譯時生成的信息統計文件),這個文件是
+ 在gcc編譯時如果配置了選項 ``-ftest-coverage`` 時生成的。
+
+
+針對模塊的統計
+--------------
+
+內核中的模塊會動態的加載和卸載,模塊卸載時對應的數據會被清除掉。
+gcov提供了一種機制,通過保留相關數據的副本來收集這部分卸載模塊的覆蓋率數據。
+模塊卸載後這些備份數據在debugfs中會繼續存在。
+一旦這個模塊重新加載,模塊關聯的運行統計會被初始化成debugfs中備份的數據。
+
+可以通過對內核參數gcov_persist的修改來停用gcov對模塊的備份機制::
+
+ gcov_persist = 0
+
+在運行時,用戶還可以通過寫入模塊的數據文件或者寫入gcov復位文件來丟棄已卸
+載模塊的數據。
+
+
+編譯機和測試機分離
+------------------
+
+gcov的內核分析插樁支持內核的編譯和運行是在同一臺機器上,也可以編譯和運
+行是在不同的機器上。
+如果內核編譯和運行是不同的機器,那麼需要額外的準備工作,這取決於gcov工具
+是在哪裏使用的:
+
+.. _gcov-test_zh:
+
+a) 若gcov運行在測試機上
+
+ 測試機上面gcov工具的版本必須要跟內核編譯機器使用的gcc版本相兼容,
+ 同時下面的文件要從編譯機拷貝到測試機上:
+
+ 從源代碼中:
+ - 所有的C文件和頭文件
+
+ 從編譯目錄中:
+ - 所有的C文件和頭文件
+ - 所有的.gcda文件和.gcno文件
+ - 所有目錄的鏈接
+
+ 特別需要注意,測試機器上面的目錄結構跟編譯機器上面的目錄機構必須
+ 完全一致。
+ 如果文件是軟鏈接,需要替換成真正的目錄文件(這是由make的當前工作
+ 目錄變量CURDIR引起的)。
+
+.. _gcov-build_zh:
+
+b) 若gcov運行在編譯機上
+
+ 測試用例運行結束後,如下的文件需要從測試機中拷貝到編譯機上:
+
+ 從sysfs中的gcov目錄中:
+ - 所有的.gcda文件
+ - 所有的.gcno文件軟鏈接
+
+ 這些文件可以拷貝到編譯機的任意目錄下,gcov使用-o選項指定拷貝的
+ 目錄。
+
+ 比如一個是示例的目錄結構如下::
+
+ /tmp/linux: 內核源碼目錄
+ /tmp/out: 內核編譯文件路徑(make O=指定)
+ /tmp/coverage: 從測試機器上面拷貝的數據文件路徑
+
+ [user@build] cd /tmp/out
+ [user@build] gcov -o /tmp/coverage/tmp/out/init main.c
+
+
+關於編譯器的注意事項
+--------------------
+
+GCC和LLVM gcov工具不一定兼容。
+如果編譯器是GCC,使用 gcov_ 來處理.gcno和.gcda文件,如果是Clang編譯器,
+則使用 llvm-cov_ 。
+
+.. _gcov: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html
+.. _llvm-cov: https://llvm.org/docs/CommandGuide/llvm-cov.html
+
+GCC和Clang gcov之間的版本差異由Kconfig處理的。
+kconfig會根據編譯工具鏈的檢查自動選擇合適的gcov格式。
+
+問題定位
+--------
+
+可能出現的問題1
+ 編譯到鏈接階段報錯終止
+
+問題原因
+ 分析標誌指定在了源文件但是沒有鏈接到主內核,或者客製化了鏈接程序
+
+解決方法
+ 通過在相應的Makefile中使用 ``GCOV_PROFILE := n``
+ 或者 ``GCOV_PROFILE_basename.o := n`` 來將鏈接報錯的文件排除掉
+
+可能出現的問題2
+ 從sysfs複製的文件顯示爲空或不完整
+
+問題原因
+ 由於seq_file的工作方式,某些工具(例如cp或tar)可能無法正確地從
+ sysfs複製文件。
+
+解決方法
+ 使用 ``cat`` 讀取 ``.gcda`` 文件,使用 ``cp -d`` 複製鏈接,或者使用附錄B
+ 中所示的機制。
+
+
+附錄A:collect_on_build.sh
+--------------------------
+
+用於在編譯機上收集覆蓋率元文件的示例腳本
+(見 :ref:`編譯機和測試機分離 a. <gcov-test_zh>` )
+
+.. code-block:: sh
+
+ #!/bin/bash
+
+ KSRC=$1
+ KOBJ=$2
+ DEST=$3
+
+ if [ -z "$KSRC" ] || [ -z "$KOBJ" ] || [ -z "$DEST" ]; then
+ echo "Usage: $0 <ksrc directory> <kobj directory> <output.tar.gz>" >&2
+ exit 1
+ fi
+
+ KSRC=$(cd $KSRC; printf "all:\n\t@echo \${CURDIR}\n" | make -f -)
+ KOBJ=$(cd $KOBJ; printf "all:\n\t@echo \${CURDIR}\n" | make -f -)
+
+ find $KSRC $KOBJ \( -name '*.gcno' -o -name '*.[ch]' -o -type l \) -a \
+ -perm /u+r,g+r | tar cfz $DEST -P -T -
+
+ if [ $? -eq 0 ] ; then
+ echo "$DEST successfully created, copy to test system and unpack with:"
+ echo " tar xfz $DEST -P"
+ else
+ echo "Could not create file $DEST"
+ fi
+
+
+附錄B:collect_on_test.sh
+-------------------------
+
+用於在測試機上收集覆蓋率數據文件的示例腳本
+(見 :ref:`編譯機和測試機分離 b. <gcov-build_zh>` )
+
+.. code-block:: sh
+
+ #!/bin/bash -e
+
+ DEST=$1
+ GCDA=/sys/kernel/debug/gcov
+
+ if [ -z "$DEST" ] ; then
+ echo "Usage: $0 <output.tar.gz>" >&2
+ exit 1
+ fi
+
+ TEMPDIR=$(mktemp -d)
+ echo Collecting data..
+ find $GCDA -type d -exec mkdir -p $TEMPDIR/\{\} \;
+ find $GCDA -name '*.gcda' -exec sh -c 'cat < $0 > '$TEMPDIR'/$0' {} \;
+ find $GCDA -name '*.gcno' -exec sh -c 'cp -d $0 '$TEMPDIR'/$0' {} \;
+ tar czf $DEST -C $TEMPDIR sys
+ rm -rf $TEMPDIR
+
+ echo "$DEST successfully created, copy to build system and unpack with:"
+ echo " tar xfz $DEST"
+
diff --git a/Documentation/translations/zh_TW/dev-tools/gdb-kernel-debugging.rst b/Documentation/translations/zh_TW/dev-tools/gdb-kernel-debugging.rst
new file mode 100644
index 000000000000..c881e8872b19
--- /dev/null
+++ b/Documentation/translations/zh_TW/dev-tools/gdb-kernel-debugging.rst
@@ -0,0 +1,168 @@
+.. highlight:: none
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/dev-tools/gdb-kernel-debugging.rst
+:Translator: 高超 gao chao <gaochao49@huawei.com>
+
+通過gdb調試內核和模塊
+=====================
+
+Kgdb內核調試器、QEMU等虛擬機管理程序或基於JTAG的硬件接口,支持在運行時使用gdb
+調試Linux內核及其模塊。Gdb提供了一個強大的python腳本接口,內核也提供了一套
+輔助腳本以簡化典型的內核調試步驟。本文檔爲如何啓用和使用這些腳本提供了一個簡要的教程。
+此教程基於QEMU/KVM虛擬機,但文中示例也適用於其他gdb stub。
+
+
+環境配置要求
+------------
+
+- gdb 7.2+ (推薦版本: 7.4+) 且開啓python支持 (通常發行版上都已支持)
+
+設置
+----
+
+- 創建一個QEMU/KVM的linux虛擬機(詳情請參考 www.linux-kvm.org 和 www.qemu.org )。
+ 對於交叉開發,https://landley.net/aboriginal/bin 提供了一些鏡像和工具鏈,
+ 可以幫助搭建交叉開發環境。
+
+- 編譯內核時開啓CONFIG_GDB_SCRIPTS,關閉CONFIG_DEBUG_INFO_REDUCED。
+ 如果架構支持CONFIG_FRAME_POINTER,請保持開啓。
+
+- 在guest環境上安裝該內核。如有必要,通過在內核command line中添加“nokaslr”來關閉KASLR。
+ 此外,QEMU允許通過-kernel、-append、-initrd這些命令行選項直接啓動內核。
+ 但這通常僅在不依賴內核模塊時纔有效。有關此模式的更多詳細信息,請參閱QEMU文檔。
+ 在這種情況下,如果架構支持KASLR,應該在禁用CONFIG_RANDOMIZE_BASE的情況下構建內核。
+
+- 啓用QEMU/KVM的gdb stub,可以通過如下方式實現
+
+ - 在VM啓動時,通過在QEMU命令行中添加“-s”參數
+
+ 或
+
+ - 在運行時通過從QEMU監視控制檯發送“gdbserver”
+
+- 切換到/path/to/linux-build(內核源碼編譯)目錄
+
+- 啓動gdb:gdb vmlinux
+
+ 注意:某些發行版可能會將gdb腳本的自動加載限制在已知的安全目錄中。
+ 如果gdb報告拒絕加載vmlinux-gdb.py(相關命令找不到),請將::
+
+ add-auto-load-safe-path /path/to/linux-build
+
+ 添加到~/.gdbinit。更多詳細信息,請參閱gdb幫助信息。
+
+- 連接到已啓動的guest環境::
+
+ (gdb) target remote :1234
+
+
+使用Linux提供的gdb腳本的示例
+----------------------------
+
+- 加載模塊(以及主內核)符號::
+
+ (gdb) lx-symbols
+ loading vmlinux
+ scanning for modules in /home/user/linux/build
+ loading @0xffffffffa0020000: /home/user/linux/build/net/netfilter/xt_tcpudp.ko
+ loading @0xffffffffa0016000: /home/user/linux/build/net/netfilter/xt_pkttype.ko
+ loading @0xffffffffa0002000: /home/user/linux/build/net/netfilter/xt_limit.ko
+ loading @0xffffffffa00ca000: /home/user/linux/build/net/packet/af_packet.ko
+ loading @0xffffffffa003c000: /home/user/linux/build/fs/fuse/fuse.ko
+ ...
+ loading @0xffffffffa0000000: /home/user/linux/build/drivers/ata/ata_generic.ko
+
+- 對一些尚未加載的模塊中的函數函數設置斷點,例如::
+
+ (gdb) b btrfs_init_sysfs
+ Function "btrfs_init_sysfs" not defined.
+ Make breakpoint pending on future shared library load? (y or [n]) y
+ Breakpoint 1 (btrfs_init_sysfs) pending.
+
+- 繼續執行::
+
+ (gdb) c
+
+- 加載模塊並且能觀察到正在加載的符號以及斷點命中::
+
+ loading @0xffffffffa0034000: /home/user/linux/build/lib/libcrc32c.ko
+ loading @0xffffffffa0050000: /home/user/linux/build/lib/lzo/lzo_compress.ko
+ loading @0xffffffffa006e000: /home/user/linux/build/lib/zlib_deflate/zlib_deflate.ko
+ loading @0xffffffffa01b1000: /home/user/linux/build/fs/btrfs/btrfs.ko
+
+ Breakpoint 1, btrfs_init_sysfs () at /home/user/linux/fs/btrfs/sysfs.c:36
+ 36 btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj);
+
+- 查看內核的日誌緩衝區::
+
+ (gdb) lx-dmesg
+ [ 0.000000] Initializing cgroup subsys cpuset
+ [ 0.000000] Initializing cgroup subsys cpu
+ [ 0.000000] Linux version 3.8.0-rc4-dbg+ (...
+ [ 0.000000] Command line: root=/dev/sda2 resume=/dev/sda1 vga=0x314
+ [ 0.000000] e820: BIOS-provided physical RAM map:
+ [ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
+ [ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
+ ....
+
+- 查看當前task struct結構體的字段(僅x86和arm64支持)::
+
+ (gdb) p $lx_current().pid
+ $1 = 4998
+ (gdb) p $lx_current().comm
+ $2 = "modprobe\000\000\000\000\000\000\000"
+
+- 對當前或指定的CPU使用per-cpu函數::
+
+ (gdb) p $lx_per_cpu("runqueues").nr_running
+ $3 = 1
+ (gdb) p $lx_per_cpu("runqueues", 2).nr_running
+ $4 = 0
+
+- 使用container_of查看更多hrtimers信息::
+
+ (gdb) set $next = $lx_per_cpu("hrtimer_bases").clock_base[0].active.next
+ (gdb) p *$container_of($next, "struct hrtimer", "node")
+ $5 = {
+ node = {
+ node = {
+ __rb_parent_color = 18446612133355256072,
+ rb_right = 0x0 <irq_stack_union>,
+ rb_left = 0x0 <irq_stack_union>
+ },
+ expires = {
+ tv64 = 1835268000000
+ }
+ },
+ _softexpires = {
+ tv64 = 1835268000000
+ },
+ function = 0xffffffff81078232 <tick_sched_timer>,
+ base = 0xffff88003fd0d6f0,
+ state = 1,
+ start_pid = 0,
+ start_site = 0xffffffff81055c1f <hrtimer_start_range_ns+20>,
+ start_comm = "swapper/2\000\000\000\000\000\000"
+ }
+
+
+命令和輔助調試功能列表
+----------------------
+
+命令和輔助調試功能可能會隨着時間的推移而改進,此文顯示的是初始版本的部分示例::
+
+ (gdb) apropos lx
+ function lx_current -- Return current task
+ function lx_module -- Find module by name and return the module variable
+ function lx_per_cpu -- Return per-cpu variable
+ function lx_task_by_pid -- Find Linux task by PID and return the task_struct variable
+ function lx_thread_info -- Calculate Linux thread_info from task variable
+ lx-dmesg -- Print Linux kernel log buffer
+ lx-lsmod -- List currently loaded modules
+ lx-symbols -- (Re-)load symbols of Linux kernel and currently loaded modules
+
+可以通過“help <command-name>”或“help function <function-name>”命令
+獲取指定命令或指定調試功能的更多詳細信息。
+
diff --git a/Documentation/translations/zh_TW/dev-tools/index.rst b/Documentation/translations/zh_TW/dev-tools/index.rst
new file mode 100644
index 000000000000..0d38e5f80e54
--- /dev/null
+++ b/Documentation/translations/zh_TW/dev-tools/index.rst
@@ -0,0 +1,43 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/dev-tools/index.rst
+:Translator: 趙軍奎 Bernard Zhao <bernard@vivo.com>
+
+============
+內核開發工具
+============
+
+本文檔是有關內核開發工具文檔的合集。
+目前這些文檔已經整理在一起,不需要再花費額外的精力。
+歡迎任何補丁。
+
+有關測試專用工具的簡要概述,參見
+Documentation/translations/zh_TW/dev-tools/testing-overview.rst
+
+.. class:: toc-title
+
+ 目錄
+
+.. toctree::
+ :maxdepth: 2
+
+ testing-overview
+ sparse
+ gcov
+ kasan
+ gdb-kernel-debugging
+
+Todolist:
+
+ - coccinelle
+ - kcov
+ - ubsan
+ - kmemleak
+ - kcsan
+ - kfence
+ - kgdb
+ - kselftest
+ - kunit/index
+
diff --git a/Documentation/translations/zh_TW/dev-tools/kasan.rst b/Documentation/translations/zh_TW/dev-tools/kasan.rst
new file mode 100644
index 000000000000..979eb84bc58f
--- /dev/null
+++ b/Documentation/translations/zh_TW/dev-tools/kasan.rst
@@ -0,0 +1,463 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/dev-tools/kasan.rst
+:Translator: 萬家兵 Wan Jiabing <wanjiabing@vivo.com>
+
+內核地址消毒劑(KASAN)
+=====================
+
+概述
+----
+
+Kernel Address SANitizer(KASAN)是一種動態內存安全錯誤檢測工具,主要功能是
+檢查內存越界訪問和使用已釋放內存的問題。
+
+KASAN有三種模式:
+
+1. 通用KASAN
+2. 基於軟件標籤的KASAN
+3. 基於硬件標籤的KASAN
+
+用CONFIG_KASAN_GENERIC啓用的通用KASAN,是用於調試的模式,類似於用戶空
+間的ASan。這種模式在許多CPU架構上都被支持,但它有明顯的性能和內存開銷。
+
+基於軟件標籤的KASAN或SW_TAGS KASAN,通過CONFIG_KASAN_SW_TAGS啓用,
+可以用於調試和自我測試,類似於用戶空間HWASan。這種模式只支持arm64,但其
+適度的內存開銷允許在內存受限的設備上用真實的工作負載進行測試。
+
+基於硬件標籤的KASAN或HW_TAGS KASAN,用CONFIG_KASAN_HW_TAGS啓用,被
+用作現場內存錯誤檢測器或作爲安全緩解的模式。這種模式只在支持MTE(內存標籤
+擴展)的arm64 CPU上工作,但它的內存和性能開銷很低,因此可以在生產中使用。
+
+關於每種KASAN模式的內存和性能影響的細節,請參見相應的Kconfig選項的描述。
+
+通用模式和基於軟件標籤的模式通常被稱爲軟件模式。基於軟件標籤的模式和基於
+硬件標籤的模式被稱爲基於標籤的模式。
+
+支持
+----
+
+體系架構
+~~~~~~~~
+
+在x86_64、arm、arm64、powerpc、riscv、s390、xtensa和loongarch上支持通用KASAN,
+而基於標籤的KASAN模式只在arm64上支持。
+
+編譯器
+~~~~~~
+
+軟件KASAN模式使用編譯時工具在每個內存訪問之前插入有效性檢查,因此需要一個
+提供支持的編譯器版本。基於硬件標籤的模式依靠硬件來執行這些檢查,但仍然需要
+一個支持內存標籤指令的編譯器版本。
+
+通用KASAN需要GCC 8.3.0版本或更高版本,或者內核支持的任何Clang版本。
+
+基於軟件標籤的KASAN需要GCC 11+或者內核支持的任何Clang版本。
+
+基於硬件標籤的KASAN需要GCC 10+或Clang 12+。
+
+內存類型
+~~~~~~~~
+
+通用KASAN支持在所有的slab、page_alloc、vmap、vmalloc、堆棧和全局內存
+中查找錯誤。
+
+基於軟件標籤的KASAN支持slab、page_alloc、vmalloc和堆棧內存。
+
+基於硬件標籤的KASAN支持slab、page_alloc和不可執行的vmalloc內存。
+
+對於slab,兩種軟件KASAN模式都支持SLUB和SLAB分配器,而基於硬件標籤的
+KASAN只支持SLUB。
+
+用法
+----
+
+要啓用KASAN,請使用以下命令配置內核::
+
+ CONFIG_KASAN=y
+
+同時在 ``CONFIG_KASAN_GENERIC`` (啓用通用KASAN模式), ``CONFIG_KASAN_SW_TAGS``
+(啓用基於硬件標籤的KASAN模式),和 ``CONFIG_KASAN_HW_TAGS`` (啓用基於硬件標籤
+的KASAN模式)之間進行選擇。
+
+對於軟件模式,還可以在 ``CONFIG_KASAN_OUTLINE`` 和 ``CONFIG_KASAN_INLINE``
+之間進行選擇。outline和inline是編譯器插樁類型。前者產生較小的二進制文件,
+而後者快2倍。
+
+要將受影響的slab對象的alloc和free堆棧跟蹤包含到報告中,請啓用
+``CONFIG_STACKTRACE`` 。要包括受影響物理頁面的分配和釋放堆棧跟蹤的話,
+請啓用 ``CONFIG_PAGE_OWNER`` 並使用 ``page_owner=on`` 進行引導。
+
+啓動參數
+~~~~~~~~
+
+KASAN受到通用 ``panic_on_warn`` 命令行參數的影響。當它被啓用時,KASAN
+在打印出錯誤報告後會使內核恐慌。
+
+默認情況下,KASAN只對第一個無效的內存訪問打印錯誤報告。使用
+``kasan_multi_shot``,KASAN對每一個無效的訪問都打印一份報告。這會禁用
+了KASAN報告的 ``panic_on_warn``。
+
+另外,獨立於 ``panic_on_warn`` 、 ``kasan.fault=`` boot參數可以用
+來控制恐慌和報告行爲。
+
+- ``kasan.fault=report`` 或 ``=panic`` 控制是否只打印KASAN report或
+ 同時使內核恐慌(默認: ``report`` )。即使 ``kasan_multi_shot`` 被
+ 啓用,恐慌也會發生。
+
+基於軟件和硬件標籤的KASAN模式(見下面關於各種模式的部分)支持改變堆棧跟
+蹤收集行爲:
+
+- ``kasan.stacktrace=off`` 或 ``=on`` 禁用或啓用分配和釋放堆棧痕
+ 跡的收集(默認: ``on`` )。
+
+- ``kasan.stack_ring_size=<number of entries>`` 指定堆棧環的條
+ 目數(默認: ``32768`` )。
+
+基於硬件標籤的KASAN模式是爲了在生產中作爲一種安全緩解措施使用。因此,它
+支持額外的啓動參數,允許完全禁用KASAN或控制其功能。
+
+- ``kasan=off`` 或 ``=on`` 控制KASAN是否被啓用(默認: ``on`` )。
+
+- ``kasan.mode=sync``, ``=async`` or ``=asymm`` 控制KASAN是否
+ 被配置爲同步、異步或非對稱的執行模式(默認: ``同步`` )。
+ 同步模式:當標籤檢查異常發生時,會立即檢測到不良訪問。
+ 異步模式:不良訪問的檢測是延遲的。當標籤檢查異常發生時,信息被存儲在硬
+ 件中(對於arm64來說是在TFSR_EL1寄存器中)。內核週期性地檢查硬件,並\
+ 且只在這些檢查中報告標籤異常。
+ 非對稱模式:讀取時同步檢測不良訪問,寫入時異步檢測。
+
+- ``kasan.vmalloc=off`` or ``=on`` 禁用或啓用vmalloc分配的標記(默認: ``on`` )。
+
+錯誤報告
+~~~~~~~~
+
+典型的KASAN報告如下所示::
+
+ ==================================================================
+ BUG: KASAN: slab-out-of-bounds in kmalloc_oob_right+0xa8/0xbc [test_kasan]
+ Write of size 1 at addr ffff8801f44ec37b by task insmod/2760
+
+ CPU: 1 PID: 2760 Comm: insmod Not tainted 4.19.0-rc3+ #698
+ Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014
+ Call Trace:
+ dump_stack+0x94/0xd8
+ print_address_description+0x73/0x280
+ kasan_report+0x144/0x187
+ __asan_report_store1_noabort+0x17/0x20
+ kmalloc_oob_right+0xa8/0xbc [test_kasan]
+ kmalloc_tests_init+0x16/0x700 [test_kasan]
+ do_one_initcall+0xa5/0x3ae
+ do_init_module+0x1b6/0x547
+ load_module+0x75df/0x8070
+ __do_sys_init_module+0x1c6/0x200
+ __x64_sys_init_module+0x6e/0xb0
+ do_syscall_64+0x9f/0x2c0
+ entry_SYSCALL_64_after_hwframe+0x44/0xa9
+ RIP: 0033:0x7f96443109da
+ RSP: 002b:00007ffcf0b51b08 EFLAGS: 00000202 ORIG_RAX: 00000000000000af
+ RAX: ffffffffffffffda RBX: 000055dc3ee521a0 RCX: 00007f96443109da
+ RDX: 00007f96445cff88 RSI: 0000000000057a50 RDI: 00007f9644992000
+ RBP: 000055dc3ee510b0 R08: 0000000000000003 R09: 0000000000000000
+ R10: 00007f964430cd0a R11: 0000000000000202 R12: 00007f96445cff88
+ R13: 000055dc3ee51090 R14: 0000000000000000 R15: 0000000000000000
+
+ Allocated by task 2760:
+ save_stack+0x43/0xd0
+ kasan_kmalloc+0xa7/0xd0
+ kmem_cache_alloc_trace+0xe1/0x1b0
+ kmalloc_oob_right+0x56/0xbc [test_kasan]
+ kmalloc_tests_init+0x16/0x700 [test_kasan]
+ do_one_initcall+0xa5/0x3ae
+ do_init_module+0x1b6/0x547
+ load_module+0x75df/0x8070
+ __do_sys_init_module+0x1c6/0x200
+ __x64_sys_init_module+0x6e/0xb0
+ do_syscall_64+0x9f/0x2c0
+ entry_SYSCALL_64_after_hwframe+0x44/0xa9
+
+ Freed by task 815:
+ save_stack+0x43/0xd0
+ __kasan_slab_free+0x135/0x190
+ kasan_slab_free+0xe/0x10
+ kfree+0x93/0x1a0
+ umh_complete+0x6a/0xa0
+ call_usermodehelper_exec_async+0x4c3/0x640
+ ret_from_fork+0x35/0x40
+
+ The buggy address belongs to the object at ffff8801f44ec300
+ which belongs to the cache kmalloc-128 of size 128
+ The buggy address is located 123 bytes inside of
+ 128-byte region [ffff8801f44ec300, ffff8801f44ec380)
+ The buggy address belongs to the page:
+ page:ffffea0007d13b00 count:1 mapcount:0 mapping:ffff8801f7001640 index:0x0
+ flags: 0x200000000000100(slab)
+ raw: 0200000000000100 ffffea0007d11dc0 0000001a0000001a ffff8801f7001640
+ raw: 0000000000000000 0000000080150015 00000001ffffffff 0000000000000000
+ page dumped because: kasan: bad access detected
+
+ Memory state around the buggy address:
+ ffff8801f44ec200: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb
+ ffff8801f44ec280: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
+ >ffff8801f44ec300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03
+ ^
+ ffff8801f44ec380: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb
+ ffff8801f44ec400: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
+ ==================================================================
+
+報告標題總結了發生的錯誤類型以及導致該錯誤的訪問類型。緊隨其後的是錯誤訪問的
+堆棧跟蹤、所訪問內存分配位置的堆棧跟蹤(對於訪問了slab對象的情況)以及對象
+被釋放的位置的堆棧跟蹤(對於訪問已釋放內存的問題報告)。接下來是對訪問的
+slab對象的描述以及關於訪問的內存頁的信息。
+
+最後,報告展示了訪問地址周圍的內存狀態。在內部,KASAN單獨跟蹤每個內存顆粒的
+內存狀態,根據KASAN模式分爲8或16個對齊字節。報告的內存狀態部分中的每個數字
+都顯示了圍繞訪問地址的其中一個內存顆粒的狀態。
+
+對於通用KASAN,每個內存顆粒的大小爲8個字節。每個顆粒的狀態被編碼在一個影子字節
+中。這8個字節可以是可訪問的,部分訪問的,已釋放的或成爲Redzone的一部分。KASAN
+對每個影子字節使用以下編碼:00表示對應內存區域的所有8個字節都可以訪問;數字N
+(1 <= N <= 7)表示前N個字節可訪問,其他(8 - N)個字節不可訪問;任何負值都表示
+無法訪問整個8字節。KASAN使用不同的負值來區分不同類型的不可訪問內存,如redzones
+或已釋放的內存(參見 mm/kasan/kasan.h)。
+
+在上面的報告中,箭頭指向影子字節 ``03`` ,表示訪問的地址是部分可訪問的。
+
+對於基於標籤的KASAN模式,報告最後的部分顯示了訪問地址周圍的內存標籤
+(參考 `實施細則`_ 章節)。
+
+請注意,KASAN錯誤標題(如 ``slab-out-of-bounds`` 或 ``use-after-free`` )
+是儘量接近的:KASAN根據其擁有的有限信息打印出最可能的錯誤類型。錯誤的實際類型
+可能會有所不同。
+
+通用KASAN還報告兩個輔助調用堆棧跟蹤。這些堆棧跟蹤指向代碼中與對象交互但不直接
+出現在錯誤訪問堆棧跟蹤中的位置。目前,這包括 call_rcu() 和排隊的工作隊列。
+
+實施細則
+--------
+
+通用KASAN
+~~~~~~~~~
+
+軟件KASAN模式使用影子內存來記錄每個內存字節是否可以安全訪問,並使用編譯時工具
+在每次內存訪問之前插入影子內存檢查。
+
+通用KASAN將1/8的內核內存專用於其影子內存(16TB以覆蓋x86_64上的128TB),並使用
+具有比例和偏移量的直接映射將內存地址轉換爲其相應的影子地址。
+
+這是將地址轉換爲其相應影子地址的函數::
+
+ static inline void *kasan_mem_to_shadow(const void *addr)
+ {
+ return (void *)((unsigned long)addr >> KASAN_SHADOW_SCALE_SHIFT)
+ + KASAN_SHADOW_OFFSET;
+ }
+
+在這裏 ``KASAN_SHADOW_SCALE_SHIFT = 3`` 。
+
+編譯時工具用於插入內存訪問檢查。編譯器在每次訪問大小爲1、2、4、8或16的內存之前
+插入函數調用( ``__asan_load*(addr)`` , ``__asan_store*(addr)``)。這些函數通過
+檢查相應的影子內存來檢查內存訪問是否有效。
+
+使用inline插樁,編譯器不進行函數調用,而是直接插入代碼來檢查影子內存。此選項
+顯著地增大了內核體積,但與outline插樁內核相比,它提供了x1.1-x2的性能提升。
+
+通用KASAN是唯一一種通過隔離延遲重新使用已釋放對象的模式
+(參見 mm/kasan/quarantine.c 以瞭解實現)。
+
+基於軟件標籤的KASAN模式
+~~~~~~~~~~~~~~~~~~~~~~~
+
+基於軟件標籤的KASAN使用軟件內存標籤方法來檢查訪問有效性。目前僅針對arm64架構實現。
+
+基於軟件標籤的KASAN使用arm64 CPU的頂部字節忽略(TBI)特性在內核指針的頂部字節中
+存儲一個指針標籤。它使用影子內存來存儲與每個16字節內存單元相關的內存標籤(因此,
+它將內核內存的1/16專用於影子內存)。
+
+在每次內存分配時,基於軟件標籤的KASAN都會生成一個隨機標籤,用這個標籤標記分配
+的內存,並將相同的標籤嵌入到返回的指針中。
+
+基於軟件標籤的KASAN使用編譯時工具在每次內存訪問之前插入檢查。這些檢查確保正在
+訪問的內存的標籤等於用於訪問該內存的指針的標籤。如果標籤不匹配,基於軟件標籤
+的KASAN會打印錯誤報告。
+
+基於軟件標籤的KASAN也有兩種插樁模式(outline,發出回調來檢查內存訪問;inline,
+執行內聯的影子內存檢查)。使用outline插樁模式,會從執行訪問檢查的函數打印錯誤
+報告。使用inline插樁,編譯器會發出 ``brk`` 指令,並使用專用的 ``brk`` 處理程序
+來打印錯誤報告。
+
+基於軟件標籤的KASAN使用0xFF作爲匹配所有指針標籤(不檢查通過帶有0xFF指針標籤
+的指針進行的訪問)。值0xFE當前保留用於標記已釋放的內存區域。
+
+
+基於硬件標籤的KASAN模式
+~~~~~~~~~~~~~~~~~~~~~~~
+
+基於硬件標籤的KASAN在概念上類似於軟件模式,但它是使用硬件內存標籤作爲支持而
+不是編譯器插樁和影子內存。
+
+基於硬件標籤的KASAN目前僅針對arm64架構實現,並且基於ARMv8.5指令集架構中引入
+的arm64內存標記擴展(MTE)和最高字節忽略(TBI)。
+
+特殊的arm64指令用於爲每次內存分配指定內存標籤。相同的標籤被指定給指向這些分配
+的指針。在每次內存訪問時,硬件確保正在訪問的內存的標籤等於用於訪問該內存的指針
+的標籤。如果標籤不匹配,則會生成故障並打印報告。
+
+基於硬件標籤的KASAN使用0xFF作爲匹配所有指針標籤(不檢查通過帶有0xFF指針標籤的
+指針進行的訪問)。值0xFE當前保留用於標記已釋放的內存區域。
+
+如果硬件不支持MTE(ARMv8.5之前),則不會啓用基於硬件標籤的KASAN。在這種情況下,
+所有KASAN引導參數都將被忽略。
+
+請注意,啓用CONFIG_KASAN_HW_TAGS始終會導致啓用內核中的TBI。即使提供了
+``kasan.mode=off`` 或硬件不支持MTE(但支持TBI)。
+
+基於硬件標籤的KASAN只報告第一個發現的錯誤。之後,MTE標籤檢查將被禁用。
+
+影子內存
+--------
+
+本節的內容只適用於軟件KASAN模式。
+
+內核將內存映射到地址空間的幾個不同部分。內核虛擬地址的範圍很大:沒有足夠的真實
+內存來支持內核可以訪問的每個地址的真實影子區域。因此,KASAN只爲地址空間的某些
+部分映射真實的影子。
+
+默認行爲
+~~~~~~~~
+
+默認情況下,體系結構僅將實際內存映射到用於線性映射的陰影區域(以及可能的其他
+小區域)。對於所有其他區域 —— 例如vmalloc和vmemmap空間 —— 一個只讀頁面被映射
+到陰影區域上。這個只讀的影子頁面聲明所有內存訪問都是允許的。
+
+這給模塊帶來了一個問題:它們不存在於線性映射中,而是存在於專用的模塊空間中。
+通過連接模塊分配器,KASAN臨時映射真實的影子內存以覆蓋它們。例如,這允許檢測
+對模塊全局變量的無效訪問。
+
+這也造成了與 ``VMAP_STACK`` 的不兼容:如果堆棧位於vmalloc空間中,它將被分配
+只讀頁面的影子內存,並且內核在嘗試爲堆棧變量設置影子數據時會出錯。
+
+CONFIG_KASAN_VMALLOC
+~~~~~~~~~~~~~~~~~~~~
+
+使用 ``CONFIG_KASAN_VMALLOC`` ,KASAN可以以更大的內存使用爲代價覆蓋vmalloc
+空間。目前,這在arm64、x86、riscv、s390和powerpc上受支持。
+
+這通過連接到vmalloc和vmap並動態分配真實的影子內存來支持映射。
+
+vmalloc空間中的大多數映射都很小,需要不到一整頁的陰影空間。因此,爲每個映射
+分配一個完整的影子頁面將是一種浪費。此外,爲了確保不同的映射使用不同的影子
+頁面,映射必須與 ``KASAN_GRANULE_SIZE * PAGE_SIZE`` 對齊。
+
+相反,KASAN跨多個映射共享後備空間。當vmalloc空間中的映射使用影子區域的特定
+頁面時,它會分配一個後備頁面。此頁面稍後可以由其他vmalloc映射共享。
+
+KASAN連接到vmap基礎架構以懶清理未使用的影子內存。
+
+爲了避免交換映射的困難,KASAN預測覆蓋vmalloc空間的陰影區域部分將不會被早期
+的陰影頁面覆蓋,但是將不會被映射。這將需要更改特定於arch的代碼。
+
+這允許在x86上支持 ``VMAP_STACK`` ,並且可以簡化對沒有固定模塊區域的架構的支持。
+
+對於開發者
+----------
+
+忽略訪問
+~~~~~~~~
+
+軟件KASAN模式使用編譯器插樁來插入有效性檢查。此類檢測可能與內核的某些部分
+不兼容,因此需要禁用。
+
+內核的其他部分可能會訪問已分配對象的元數據。通常,KASAN會檢測並報告此類訪問,
+但在某些情況下(例如,在內存分配器中),這些訪問是有效的。
+
+對於軟件KASAN模式,要禁用特定文件或目錄的檢測,請將 ``KASAN_SANITIZE`` 添加
+到相應的內核Makefile中:
+
+- 對於單個文件(例如,main.o)::
+
+ KASAN_SANITIZE_main.o := n
+
+- 對於一個目錄下的所有文件::
+
+ KASAN_SANITIZE := n
+
+對於軟件KASAN模式,要在每個函數的基礎上禁用檢測,請使用KASAN特定的
+``__no_sanitize_address`` 函數屬性或通用的 ``noinstr`` 。
+
+請注意,禁用編譯器插樁(基於每個文件或每個函數)會使KASAN忽略在軟件KASAN模式
+的代碼中直接發生的訪問。當訪問是間接發生的(通過調用檢測函數)或使用沒有編譯器
+插樁的基於硬件標籤的模式時,它沒有幫助。
+
+對於軟件KASAN模式,要在當前任務的一部分內核代碼中禁用KASAN報告,請使用
+``kasan_disable_current()``/``kasan_enable_current()`` 部分註釋這部分代碼。
+這也會禁用通過函數調用發生的間接訪問的報告。
+
+對於基於標籤的KASAN模式,要禁用訪問檢查,請使用 ``kasan_reset_tag()`` 或
+``page_kasan_tag_reset()`` 。請注意,通過 ``page_kasan_tag_reset()``
+臨時禁用訪問檢查需要通過 ``page_kasan_tag`` / ``page_kasan_tag_set`` 保
+存和恢復每頁KASAN標籤。
+
+測試
+~~~~
+
+有一些KASAN測試可以驗證KASAN是否正常工作並可以檢測某些類型的內存損壞。
+測試由兩部分組成:
+
+1. 與KUnit測試框架集成的測試。使用 ``CONFIG_KASAN_KUNIT_TEST`` 啓用。
+這些測試可以通過幾種不同的方式自動運行和部分驗證;請參閱下面的說明。
+
+2. 與KUnit不兼容的測試。使用 ``CONFIG_KASAN_MODULE_TEST`` 啓用並且只能作爲模塊
+運行。這些測試只能通過加載內核模塊並檢查內核日誌以獲取KASAN報告來手動驗證。
+
+如果檢測到錯誤,每個KUnit兼容的KASAN測試都會打印多個KASAN報告之一,然後測試打印
+其編號和狀態。
+
+當測試通過::
+
+ ok 28 - kmalloc_double_kzfree
+
+當由於 ``kmalloc`` 失敗而導致測試失敗時::
+
+ # kmalloc_large_oob_right: ASSERTION FAILED at lib/test_kasan.c:163
+ Expected ptr is not null, but is
+ not ok 4 - kmalloc_large_oob_right
+
+當由於缺少KASAN報告而導致測試失敗時::
+
+ # kmalloc_double_kzfree: EXPECTATION FAILED at lib/test_kasan.c:974
+ KASAN failure expected in "kfree_sensitive(ptr)", but none occurred
+ not ok 44 - kmalloc_double_kzfree
+
+
+最後打印所有KASAN測試的累積狀態。成功::
+
+ ok 1 - kasan
+
+或者,如果其中一項測試失敗::
+
+ not ok 1 - kasan
+
+有幾種方法可以運行與KUnit兼容的KASAN測試。
+
+1. 可加載模塊
+
+ 啓用 ``CONFIG_KUNIT`` 後,KASAN-KUnit測試可以構建爲可加載模塊,並通過使用
+ ``insmod`` 或 ``modprobe`` 加載 ``test_kasan.ko`` 來運行。
+
+2. 內置
+
+ 通過內置 ``CONFIG_KUNIT`` ,也可以內置KASAN-KUnit測試。在這種情況下,
+ 測試將在啓動時作爲後期初始化調用運行。
+
+3. 使用kunit_tool
+
+ 通過內置 ``CONFIG_KUNIT`` 和 ``CONFIG_KASAN_KUNIT_TEST`` ,還可以使用
+ ``kunit_tool`` 以更易讀的方式查看KUnit測試結果。這不會打印通過測試
+ 的KASAN報告。有關 ``kunit_tool`` 更多最新信息,請參閱
+ `KUnit文檔 <https://www.kernel.org/doc/html/latest/dev-tools/kunit/index.html>`_ 。
+
+.. _KUnit: https://www.kernel.org/doc/html/latest/dev-tools/kunit/index.html
+
diff --git a/Documentation/translations/zh_TW/dev-tools/sparse.rst b/Documentation/translations/zh_TW/dev-tools/sparse.rst
new file mode 100644
index 000000000000..55f0ad2c0beb
--- /dev/null
+++ b/Documentation/translations/zh_TW/dev-tools/sparse.rst
@@ -0,0 +1,91 @@
+Chinese translated version of Documentation/dev-tools/sparse.rst
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly. However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help. Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Traditional Chinese maintainer: Hu Haowen <2023002089@link.tyut.edu.cn>
+-------------------------------------------------------------------------
+Documentation/dev-tools/sparse.rst 的繁體中文翻譯
+
+如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
+交流有困難的話,也可以向繁體中文版維護者求助。如果本翻譯更新不及時或
+者翻譯存在問題,請聯繫繁體中文版維護者。
+
+繁體中文版維護者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+繁體中文版翻譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+以下爲正文
+-------------------------------------------------------------------------
+
+Copyright 2004 Linus Torvalds
+Copyright 2004 Pavel Machek <pavel@ucw.cz>
+Copyright 2006 Bob Copeland <me@bobcopeland.com>
+
+使用 sparse 工具做類型檢查
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+"__bitwise" 是一種類型屬性,所以你應該這樣使用它::
+
+ typedef int __bitwise pm_request_t;
+
+ enum pm_request {
+ PM_SUSPEND = (__force pm_request_t) 1,
+ PM_RESUME = (__force pm_request_t) 2
+ };
+
+這樣會使 PM_SUSPEND 和 PM_RESUME 成爲位方式(bitwise)整數(使用"__force"
+是因爲 sparse 會抱怨改變位方式的類型轉換,但是這裡我們確實需要強制進行轉
+換)。而且因爲所有枚舉值都使用了相同的類型,這裡的"enum pm_request"也將
+會使用那個類型做爲底層實現。
+
+而且使用 gcc 編譯的時候,所有的 __bitwise/__force 都會消失,最後在 gcc
+看來它們只不過是普通的整數。
+
+坦白來說,你並不需要使用枚舉類型。上面那些實際都可以濃縮成一個特殊的"int
+__bitwise"類型。
+
+所以更簡單的辦法只要這樣做::
+
+ typedef int __bitwise pm_request_t;
+
+ #define PM_SUSPEND ((__force pm_request_t) 1)
+ #define PM_RESUME ((__force pm_request_t) 2)
+
+現在你就有了嚴格的類型檢查所需要的所有基礎架構。
+
+一個小提醒:常數整數"0"是特殊的。你可以直接把常數零當作位方式整數使用而
+不用擔心 sparse 會抱怨。這是因爲"bitwise"(恰如其名)是用來確保不同位方
+式類型不會被弄混(小尾模式,大尾模式,cpu尾模式,或者其他),對他們來說
+常數"0"確實是特殊的。
+
+獲取 sparse 工具
+~~~~~~~~~~~~~~~~
+
+你可以從 Sparse 的主頁獲取最新的發布版本:
+
+ https://www.kernel.org/pub/software/devel/sparse/dist/
+
+或者,你也可以使用 git 克隆最新的 sparse 開發版本:
+
+ git://git.kernel.org/pub/scm/devel/sparse/sparse.git
+
+一旦你下載了源碼,只要以普通用戶身份運行:
+
+ make
+ make install
+
+它將會被自動安裝到你的 ~/bin 目錄下。
+
+使用 sparse 工具
+~~~~~~~~~~~~~~~~
+
+用"make C=1"命令來編譯內核,會對所有重新編譯的 C 文件使用 sparse 工具。
+或者使用"make C=2"命令,無論文件是否被重新編譯都會對其使用 sparse 工具。
+如果你已經編譯了內核,用後一種方式可以很快地檢查整個源碼樹。
+
+make 的可選變量 CHECKFLAGS 可以用來向 sparse 工具傳遞參數。編譯系統會自
+動向 sparse 工具傳遞 -Wbitwise 參數。
+
diff --git a/Documentation/translations/zh_TW/dev-tools/testing-overview.rst b/Documentation/translations/zh_TW/dev-tools/testing-overview.rst
new file mode 100644
index 000000000000..3b08aad1da00
--- /dev/null
+++ b/Documentation/translations/zh_TW/dev-tools/testing-overview.rst
@@ -0,0 +1,162 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/dev-tools/testing-overview.rst
+:Translator: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+============
+內核測試指南
+============
+
+有許多不同的工具可以用於測試Linux內核,因此瞭解什麼時候使用它們可能
+很困難。本文檔粗略概述了它們之間的區別,並闡釋了它們是怎樣糅合在一起
+的。
+
+編寫和運行測試
+==============
+
+大多數內核測試都是用kselftest或KUnit框架之一編寫的。它們都讓運行測試
+更加簡化,併爲編寫新測試提供幫助。
+
+如果你想驗證內核的行爲——尤其是內核的特定部分——那你就要使用kUnit或
+kselftest。
+
+KUnit和kselftest的區別
+----------------------
+
+.. note::
+ 由於本文段中部分術語尚無較好的對應中文釋義,可能導致與原文含義
+ 存在些許差異,因此建議讀者結合原文
+ (Documentation/dev-tools/testing-overview.rst)輔助閱讀。
+ 如對部分翻譯有異議或有更好的翻譯意見,歡迎聯繫譯者進行修訂。
+
+KUnit(Documentation/dev-tools/kunit/index.rst)是用於“白箱”測
+試的一個完整的內核內部系統:因爲測試代碼是內核的一部分,所以它能夠訪
+問用戶空間不能訪問到的內部結構和功能。
+
+因此,KUnit測試最好針對內核中較小的、自包含的部分,以便能夠獨立地測
+試。“單元”測試的概念亦是如此。
+
+比如,一個KUnit測試可能測試一個單獨的內核功能(甚至通過一個函數測試
+一個單一的代碼路徑,例如一個錯誤處理案例),而不是整個地測試一個特性。
+
+這也使得KUnit測試構建和運行非常地快,從而能夠作爲開發流程的一部分被
+頻繁地運行。
+
+有關更詳細的介紹,請參閱KUnit測試代碼風格指南
+Documentation/dev-tools/kunit/style.rst
+
+kselftest(Documentation/dev-tools/kselftest.rst),相對來說,大量用
+於用戶空間,並且通常測試用戶空間的腳本或程序。
+
+這使得編寫複雜的測試,或者需要操作更多全局系統狀態的測試更加容易(諸
+如生成進程之類)。然而,從kselftest直接調用內核函數是不行的。這也就
+意味着只有通過某種方式(如系統調用、驅動設備、文件系統等)導出到了用
+戶空間的內核功能才能使用kselftest來測試。爲此,有些測試包含了一個伴
+生的內核模塊用於導出更多的信息和功能。不過,對於基本上或者完全在內核
+中運行的測試,KUnit可能是更佳工具。
+
+kselftest也因此非常適合於全部功能的測試,因爲這些功能會將接口暴露到
+用戶空間,從而能夠被測試,而不是展現實現細節。“system”測試和
+“end-to-end”測試亦是如此。
+
+比如,一個新的系統調用應該伴隨有新的kselftest測試。
+
+代碼覆蓋率工具
+==============
+
+支持兩種不同代碼之間的覆蓋率測量工具。它們可以用來驗證一項測試執行的
+確切函數或代碼行。這有助於決定內核被測試了多少,或用來查找合適的測試
+中沒有覆蓋到的極端情況。
+
+Documentation/translations/zh_CN/dev-tools/gcov.rst 是GCC的覆蓋率測試
+工具,能用於獲取內核的全局或每個模塊的覆蓋率。與KCOV不同的是,這個工具
+不記錄每個任務的覆蓋率。覆蓋率數據可以通過debugfs讀取,並通過常規的
+gcov工具進行解釋。
+
+Documentation/dev-tools/kcov.rst 是能夠構建在內核之中,用於在每個任務
+的層面捕捉覆蓋率的一個功能。因此,它對於模糊測試和關於代碼執行期間信
+息的其它情況非常有用,比如在一個單一系統調用裏使用它就很有用。
+
+動態分析工具
+============
+
+內核也支持許多動態分析工具,用以檢測正在運行的內核中出現的多種類型的
+問題。這些工具通常每個去尋找一類不同的缺陷,比如非法內存訪問,數據競
+爭等併發問題,或整型溢出等其他未定義行爲。
+
+如下所示:
+
+* kmemleak檢測可能的內存泄漏。參閱
+ Documentation/dev-tools/kmemleak.rst
+* KASAN檢測非法內存訪問,如數組越界和釋放後重用(UAF)。參閱
+ Documentation/dev-tools/kasan.rst
+* UBSAN檢測C標準中未定義的行爲,如整型溢出。參閱
+ Documentation/dev-tools/ubsan.rst
+* KCSAN檢測數據競爭。參閱 Documentation/dev-tools/kcsan.rst
+* KFENCE是一個低開銷的內存問題檢測器,比KASAN更快且能被用於批量構建。
+ 參閱 Documentation/dev-tools/kfence.rst
+* lockdep是一個鎖定正確性檢測器。參閱
+ Documentation/locking/lockdep-design.rst
+* 除此以外,在內核中還有一些其它的調試工具,大多數能在
+ lib/Kconfig.debug 中找到。
+
+這些工具傾向於對內核進行整體測試,並且不像kselftest和KUnit一樣“傳遞”。
+它們可以通過在啓用這些工具時運行內核測試以與kselftest或KUnit結合起來:
+之後你就能確保這些錯誤在測試過程中都不會發生了。
+
+一些工具與KUnit和kselftest集成,並且在檢測到問題時會自動打斷測試。
+
+靜態分析工具
+============
+
+除了測試運行中的內核,我們還可以使用**靜態分析**工具直接分析內核的源代
+碼(**在編譯時**)。內核中常用的工具允許人們檢查整個源代碼樹或其中的特
+定文件。它們使得在開發過程中更容易發現和修復問題。
+
+ Sparse可以通過執行類型檢查、鎖檢查、值範圍檢查來幫助測試內核,此外還
+ 可以在檢查代碼時報告各種錯誤和警告。關於如何使用它的細節,請參閱
+ Documentation/translations/zh_CN/dev-tools/sparse.rst。
+
+ Smatch擴展了Sparse,並提供了對編程邏輯錯誤的額外檢查,如開關語句中
+ 缺少斷點,錯誤檢查中未使用的返回值,忘記在錯誤路徑的返回中設置錯誤代
+ 碼等。Smatch也有針對更嚴重問題的測試,如整數溢出、空指針解除引用和內
+ 存泄漏。見項目頁面http://smatch.sourceforge.net/。
+
+ Coccinelle是我們可以使用的另一個靜態分析器。Coccinelle經常被用來
+ 幫助源代碼的重構和並行演化,但它也可以幫助避免常見代碼模式中出現的某
+ 些錯誤。可用的測試類型包括API測試、內核迭代器的正確使用測試、自由操
+ 作的合理性檢查、鎖定行爲的分析,以及已知的有助於保持內核使用一致性的
+ 進一步測試。詳情請見Documentation/dev-tools/coccinelle.rst。
+
+ 不過要注意的是,靜態分析工具存在**假陽性**的問題。在試圖修復錯誤和警
+ 告之前,需要仔細評估它們。
+
+何時使用Sparse和Smatch
+----------------------
+
+Sparse做類型檢查,例如驗證註釋的變量不會導致無符號的錯誤,檢測
+``__user`` 指針使用不當的地方,以及分析符號初始化器的兼容性。
+
+Smatch進行流程分析,如果允許建立函數數據庫,它還會進行跨函數分析。
+Smatch試圖回答一些問題,比如這個緩衝區是在哪裏分配的?它有多大?這
+個索引可以由用戶控制嗎?這個變量比那個變量大嗎?
+
+一般來說,在Smatch中寫檢查比在Sparse中寫檢查要容易。儘管如此,
+Sparse和Smatch的檢查還是有一些重疊的地方。
+
+Smatch和Coccinelle的強項
+------------------------
+
+Coccinelle可能是最容易寫檢查的。它在預處理器之前工作,所以用Coccinelle
+檢查宏中的錯誤更容易。Coccinelle還能爲你創建補丁,這是其他工具無法做到的。
+
+例如,用Coccinelle你可以從 ``kmalloc_array(x, size, GFP_KERNEL)``
+到 ``kmalloc_array(x, size, GFP_KERNEL)`` 進行大規模轉換,這真的很
+有用。如果你只是創建一個Smatch警告,並試圖把轉換的工作推給維護者,他們會很
+惱火。你將不得不爲每個警告爭論是否真的可以溢出。
+
+Coccinelle不對變量值進行分析,而這正是Smatch的強項。另一方面,Coccinelle
+允許你用簡單的方法做簡單的事情。
+
diff --git a/Documentation/translations/zh_TW/disclaimer-zh_TW.rst b/Documentation/translations/zh_TW/disclaimer-zh_TW.rst
new file mode 100644
index 000000000000..28b734c223b6
--- /dev/null
+++ b/Documentation/translations/zh_TW/disclaimer-zh_TW.rst
@@ -0,0 +1,11 @@
+:orphan:
+
+.. warning::
+ 此文件的目的是爲讓中文讀者更容易閱讀和理解,而不是作爲一個分支。因此,
+ 如果您對此文件有任何意見或改動,請先嘗試更新原始英文文件。如果要更改或
+ 修正某處翻譯文件,請將意見或補丁發送給維護者(聯繫方式見下)。
+
+.. note::
+ 如果您發現本文檔與原始文件有任何不同或者有翻譯問題,請聯繫該文件的譯者,
+ 或者發送電子郵件給胡皓文以獲取幫助:<2023002089@link.tyut.edu.cn>。
+
diff --git a/Documentation/translations/zh_TW/filesystems/debugfs.rst b/Documentation/translations/zh_TW/filesystems/debugfs.rst
new file mode 100644
index 000000000000..cda7d0e18b9b
--- /dev/null
+++ b/Documentation/translations/zh_TW/filesystems/debugfs.rst
@@ -0,0 +1,223 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/filesystems/debugfs.rst
+
+=======
+Debugfs
+=======
+
+譯者
+::
+
+ 中文版維護者: 羅楚成 Chucheng Luo <luochucheng@vivo.com>
+ 中文版翻譯者: 羅楚成 Chucheng Luo <luochucheng@vivo.com>
+ 中文版校譯者: 羅楚成 Chucheng Luo <luochucheng@vivo.com>
+ 繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+
+
+版權所有2020 羅楚成 <luochucheng@vivo.com>
+
+
+Debugfs是內核開發人員在用戶空間獲取信息的簡單方法。與/proc不同,proc只提供進程
+信息。也不像sysfs,具有嚴格的“每個文件一個值“的規則。debugfs根本沒有規則,開發
+人員可以在這裏放置他們想要的任何信息。debugfs文件系統也不能用作穩定的ABI接口。
+從理論上講,debugfs導出文件的時候沒有任何約束。但是[1]實際情況並不總是那麼
+簡單。即使是debugfs接口,也最好根據需要進行設計,並儘量保持接口不變。
+
+
+Debugfs通常使用以下命令安裝::
+
+ mount -t debugfs none /sys/kernel/debug
+
+(或等效的/etc/fstab行)。
+debugfs根目錄默認僅可由root用戶訪問。要更改對文件樹的訪問,請使用“ uid”,“ gid”
+和“ mode”掛載選項。請注意,debugfs API僅按照GPL協議導出到模塊。
+
+使用debugfs的代碼應包含<linux/debugfs.h>。然後,首先是創建至少一個目錄來保存
+一組debugfs文件::
+
+ struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
+
+如果成功,此調用將在指定的父目錄下創建一個名爲name的目錄。如果parent參數爲空,
+則會在debugfs根目錄中創建。創建目錄成功時,返回值是一個指向dentry結構體的指針。
+該dentry結構體的指針可用於在目錄中創建文件(以及最後將其清理乾淨)。ERR_PTR
+(-ERROR)返回值表明出錯。如果返回ERR_PTR(-ENODEV),則表明內核是在沒有debugfs
+支持的情況下構建的,並且下述函數都不會起作用。
+
+在debugfs目錄中創建文件的最通用方法是::
+
+ struct dentry *debugfs_create_file(const char *name, umode_t mode,
+ struct dentry *parent, void *data,
+ const struct file_operations *fops);
+
+在這裏,name是要創建的文件的名稱,mode描述了訪問文件應具有的權限,parent指向
+應該保存文件的目錄,data將存儲在產生的inode結構體的i_private字段中,而fops是
+一組文件操作函數,這些函數中實現文件操作的具體行爲。至少,read()和/或
+write()操作應提供;其他可以根據需要包括在內。同樣的,返回值將是指向創建文件
+的dentry指針,錯誤時返回ERR_PTR(-ERROR),系統不支持debugfs時返回值爲ERR_PTR
+(-ENODEV)。創建一個初始大小的文件,可以使用以下函數代替::
+
+ 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);
+
+file_size是初始文件大小。其他參數跟函數debugfs_create_file的相同。
+
+在許多情況下,沒必要自己去創建一組文件操作;對於一些簡單的情況,debugfs代碼提供
+了許多幫助函數。包含單個整數值的文件可以使用以下任何一項創建::
+
+ void debugfs_create_u8(const char *name, umode_t mode,
+ struct dentry *parent, u8 *value);
+ void 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);
+ void debugfs_create_u64(const char *name, umode_t mode,
+ struct dentry *parent, u64 *value);
+
+這些文件支持讀取和寫入給定值。如果某個文件不支持寫入,只需根據需要設置mode
+參數位。這些文件中的值以十進制表示;如果需要使用十六進制,可以使用以下函數
+替代::
+
+ void debugfs_create_x8(const char *name, umode_t mode,
+ struct dentry *parent, u8 *value);
+ void debugfs_create_x16(const char *name, umode_t mode,
+ struct dentry *parent, u16 *value);
+ void debugfs_create_x32(const char *name, umode_t mode,
+ struct dentry *parent, u32 *value);
+ void debugfs_create_x64(const char *name, umode_t mode,
+ struct dentry *parent, u64 *value);
+
+這些功能只有在開發人員知道導出值的大小的時候纔有用。某些數據類型在不同的架構上
+有不同的寬度,這樣會使情況變得有些複雜。在這種特殊情況下可以使用以下函數::
+
+ void debugfs_create_size_t(const char *name, umode_t mode,
+ struct dentry *parent, size_t *value);
+
+不出所料,此函數將創建一個debugfs文件來表示類型爲size_t的變量。
+
+同樣地,也有導出無符號長整型變量的函數,分別以十進制和十六進制表示如下::
+
+ struct dentry *debugfs_create_ulong(const char *name, umode_t mode,
+ struct dentry *parent,
+ unsigned long *value);
+ void debugfs_create_xul(const char *name, umode_t mode,
+ struct dentry *parent, unsigned long *value);
+
+布爾值可以通過以下方式放置在debugfs中::
+
+ struct dentry *debugfs_create_bool(const char *name, umode_t mode,
+ struct dentry *parent, bool *value);
+
+
+讀取結果文件將產生Y(對於非零值)或N,後跟換行符寫入的時候,它只接受大寫或小寫
+值或1或0。任何其他輸入將被忽略。
+
+同樣,atomic_t類型的值也可以放置在debugfs中::
+
+ void debugfs_create_atomic_t(const char *name, umode_t mode,
+ struct dentry *parent, atomic_t *value)
+
+讀取此文件將獲得atomic_t值,寫入此文件將設置atomic_t值。
+
+另一個選擇是通過以下結構體和函數導出一個任意二進制數據塊::
+
+ struct debugfs_blob_wrapper {
+ void *data;
+ unsigned long size;
+ };
+
+ struct dentry *debugfs_create_blob(const char *name, umode_t mode,
+ struct dentry *parent,
+ struct debugfs_blob_wrapper *blob);
+
+讀取此文件將返回由指針指向debugfs_blob_wrapper結構體的數據。一些驅動使用“blobs”
+作爲一種返回幾行(靜態)格式化文本的簡單方法。這個函數可用於導出二進制信息,但
+似乎在主線中沒有任何代碼這樣做。請注意,使用debugfs_create_blob()命令創建的
+所有文件是隻讀的。
+
+如果您要轉儲一個寄存器塊(在開發過程中經常會這麼做,但是這樣的調試代碼很少上傳
+到主線中。Debugfs提供兩個函數:一個用於創建僅寄存器文件,另一個把一個寄存器塊
+插入一個順序文件中::
+
+ struct debugfs_reg32 {
+ char *name;
+ unsigned long offset;
+ };
+
+ struct debugfs_regset32 {
+ struct debugfs_reg32 *regs;
+ int nregs;
+ void __iomem *base;
+ };
+
+ 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, struct debugfs_reg32 *regs,
+ int nregs, void __iomem *base, char *prefix);
+
+“base”參數可能爲0,但您可能需要使用__stringify構建reg32數組,實際上有許多寄存器
+名稱(宏)是寄存器塊在基址上的字節偏移量。
+
+如果要在debugfs中轉儲u32數組,可以使用以下函數創建文件::
+
+ void debugfs_create_u32_array(const char *name, umode_t mode,
+ struct dentry *parent,
+ u32 *array, u32 elements);
+
+“array”參數提供數據,而“elements”參數爲數組中元素的數量。注意:數組創建後,數組
+大小無法更改。
+
+有一個函數來創建與設備相關的seq_file::
+
+ struct dentry *debugfs_create_devm_seqfile(struct device *dev,
+ const char *name,
+ struct dentry *parent,
+ int (*read_fn)(struct seq_file *s,
+ void *data));
+
+“dev”參數是與此debugfs文件相關的設備,並且“read_fn”是一個函數指針,這個函數在
+打印seq_file內容的時候被回調。
+
+還有一些其他的面向目錄的函數::
+
+ struct dentry *debugfs_rename(struct dentry *old_dir,
+ struct dentry *old_dentry,
+ struct dentry *new_dir,
+ const char *new_name);
+
+ struct dentry *debugfs_create_symlink(const char *name,
+ struct dentry *parent,
+ const char *target);
+
+調用debugfs_rename()將爲現有的debugfs文件重命名,可能同時切換目錄。 new_name
+函數調用之前不能存在;返回值爲old_dentry,其中包含更新的信息。可以使用
+debugfs_create_symlink()創建符號鏈接。
+
+所有debugfs用戶必須考慮的一件事是:
+
+debugfs不會自動清除在其中創建的任何目錄。如果一個模塊在不顯式刪除debugfs目錄的
+情況下卸載模塊,結果將會遺留很多野指針,從而導致系統不穩定。因此,所有debugfs
+用戶-至少是那些可以作爲模塊構建的用戶-必須做模塊卸載的時候準備刪除在此創建的
+所有文件和目錄。一份文件可以通過以下方式刪除::
+
+ void debugfs_remove(struct dentry *dentry);
+
+dentry值可以爲NULL或錯誤值,在這種情況下,不會有任何文件被刪除。
+
+很久以前,內核開發者使用debugfs時需要記錄他們創建的每個dentry指針,以便最後所有
+文件都可以被清理掉。但是,現在debugfs用戶能調用以下函數遞歸清除之前創建的文件::
+
+ void debugfs_remove_recursive(struct dentry *dentry);
+
+如果將對應頂層目錄的dentry傳遞給以上函數,則該目錄下的整個層次結構將會被刪除。
+
+註釋:
+[1] http://lwn.net/Articles/309298/
+
diff --git a/Documentation/translations/zh_TW/filesystems/index.rst b/Documentation/translations/zh_TW/filesystems/index.rst
new file mode 100644
index 000000000000..88f0e632bfe2
--- /dev/null
+++ b/Documentation/translations/zh_TW/filesystems/index.rst
@@ -0,0 +1,31 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/filesystems/index.rst <filesystems_index>`
+:Translator: Wang Wenhu <wenhu.wang@vivo.com>
+ Hu Haowen <2023002089@link.tyut.edu.cn>
+
+.. _tw_filesystems_index:
+
+========================
+Linux Kernel中的文件系統
+========================
+
+這份正在開發的手冊或許在未來某個輝煌的日子裏以易懂的形式將Linux虛擬\
+文件系統(VFS)層以及基於其上的各種文件系統如何工作呈現給大家。當前\
+可以看到下面的內容。
+
+文件系統
+========
+
+文件系統實現文檔。
+
+.. toctree::
+ :maxdepth: 2
+
+ virtiofs
+ debugfs
+ tmpfs
+
+
diff --git a/Documentation/translations/zh_TW/filesystems/sysfs.txt b/Documentation/translations/zh_TW/filesystems/sysfs.txt
new file mode 100644
index 000000000000..978462d5fe14
--- /dev/null
+++ b/Documentation/translations/zh_TW/filesystems/sysfs.txt
@@ -0,0 +1,377 @@
+SPDX-License-Identifier: GPL-2.0
+
+Chinese translated version of Documentation/filesystems/sysfs.rst
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly. However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help. Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Maintainer: Patrick Mochel <mochel@osdl.org>
+ Mike Murphy <mamurph@cs.clemson.edu>
+Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
+---------------------------------------------------------------------
+Documentation/filesystems/sysfs.rst 的中文翻譯
+
+如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
+交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻
+譯存在問題,請聯繫中文版維護者。
+英文版維護者: Patrick Mochel <mochel@osdl.org>
+ Mike Murphy <mamurph@cs.clemson.edu>
+中文版維護者: 傅煒 Fu Wei <tekkamanninja@gmail.com>
+中文版翻譯者: 傅煒 Fu Wei <tekkamanninja@gmail.com>
+中文版校譯者: 傅煒 Fu Wei <tekkamanninja@gmail.com>
+繁體中文版校譯者:胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+
+以下爲正文
+---------------------------------------------------------------------
+sysfs - 用於導出內核對象(kobject)的文件系統
+
+Patrick Mochel <mochel@osdl.org>
+Mike Murphy <mamurph@cs.clemson.edu>
+
+修訂: 16 August 2011
+原始版本: 10 January 2003
+
+
+sysfs 簡介:
+~~~~~~~~~~
+
+sysfs 是一個最初基於 ramfs 且位於內存的文件系統。它提供導出內核
+數據結構及其屬性,以及它們之間的關聯到用戶空間的方法。
+
+sysfs 始終與 kobject 的底層結構緊密相關。請閱讀
+Documentation/core-api/kobject.rst 文檔以獲得更多關於 kobject 接口的
+信息。
+
+
+使用 sysfs
+~~~~~~~~~~~
+
+只要內核配置中定義了 CONFIG_SYSFS ,sysfs 總是被編譯進內核。你可
+通過以下命令掛載它:
+
+ mount -t sysfs sysfs /sys
+
+
+創建目錄
+~~~~~~~~
+
+任何 kobject 在系統中註冊,就會有一個目錄在 sysfs 中被創建。這個
+目錄是作爲該 kobject 的父對象所在目錄的子目錄創建的,以準確地傳遞
+內核的對象層次到用戶空間。sysfs 中的頂層目錄代表着內核對象層次的
+共同祖先;例如:某些對象屬於某個子系統。
+
+Sysfs 在與其目錄關聯的 kernfs_node 對象中內部保存一個指向實現
+目錄的 kobject 的指針。以前,這個 kobject 指針被 sysfs 直接用於
+kobject 文件打開和關閉的引用計數。而現在的 sysfs 實現中,kobject
+引用計數只能通過 sysfs_schedule_callback() 函數直接修改。
+
+
+屬性
+~~~~
+
+kobject 的屬性可在文件系統中以普通文件的形式導出。Sysfs 爲屬性定義
+了面向文件 I/O 操作的方法,以提供對內核屬性的讀寫。
+
+
+屬性應爲 ASCII 碼文本文件。以一個文件只存儲一個屬性值爲宜。但一個
+文件只包含一個屬性值可能影響效率,所以一個包含相同數據類型的屬性值
+數組也被廣泛地接受。
+
+混合類型、表達多行數據以及一些怪異的數據格式會遭到強烈反對。這樣做是
+很丟臉的,而且其代碼會在未通知作者的情況下被重寫。
+
+
+一個簡單的屬性結構定義如下:
+
+struct attribute {
+ char * name;
+ struct module *owner;
+ umode_t mode;
+};
+
+
+int sysfs_create_file(struct kobject * kobj, const struct attribute * attr);
+void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr);
+
+
+一個單獨的屬性結構並不包含讀寫其屬性值的方法。子系統最好爲增刪特定
+對象類型的屬性定義自己的屬性結構體和封裝函數。
+
+例如:驅動程序模型定義的 device_attribute 結構體如下:
+
+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);
+};
+
+int device_create_file(struct device *, const struct device_attribute *);
+void device_remove_file(struct device *, const struct device_attribute *);
+
+爲了定義設備屬性,同時定義了一下輔助宏:
+
+#define DEVICE_ATTR(_name, _mode, _show, _store) \
+struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
+
+例如:聲明
+
+static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo);
+
+等同於如下代碼:
+
+static struct device_attribute dev_attr_foo = {
+ .attr = {
+ .name = "foo",
+ .mode = S_IWUSR | S_IRUGO,
+ .show = show_foo,
+ .store = store_foo,
+ },
+};
+
+
+子系統特有的回調函數
+~~~~~~~~~~~~~~~~~~~
+
+當一個子系統定義一個新的屬性類型時,必須實現一系列的 sysfs 操作,
+以幫助讀寫調用實現屬性所有者的顯示和儲存方法。
+
+struct sysfs_ops {
+ ssize_t (*show)(struct kobject *, struct attribute *, char *);
+ ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
+};
+
+[子系統應已經定義了一個 struct kobj_type 結構體作爲這個類型的
+描述符,並在此保存 sysfs_ops 的指針。更多的信息參見 kobject 的
+文檔]
+
+sysfs 會爲這個類型調用適當的方法。當一個文件被讀寫時,這個方法會
+將一般的kobject 和 attribute 結構體指針轉換爲適當的指針類型後
+調用相關聯的函數。
+
+
+示例:
+
+#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) {
+ printk("dev_attr_show: %pS returned bad count\n",
+ dev_attr->show);
+ }
+ return ret;
+}
+
+
+
+讀寫屬性數據
+~~~~~~~~~~~~
+
+在聲明屬性時,必須指定 show() 或 store() 方法,以實現屬性的
+讀或寫。這些方法的類型應該和以下的設備屬性定義一樣簡單。
+
+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);
+
+也就是說,他們應只以一個處理對象、一個屬性和一個緩衝指針作爲參數。
+
+sysfs 會分配一個大小爲 (PAGE_SIZE) 的緩衝區並傳遞給這個方法。
+Sysfs 將會爲每次讀寫操作調用一次這個方法。這使得這些方法在執行時
+會出現以下的行爲:
+
+- 在讀方面(read(2)),show() 方法應該填充整個緩衝區。回想屬性
+ 應只導出了一個屬性值或是一個同類型屬性值的數組,所以這個代價將
+ 不會不太高。
+
+ 這使得用戶空間可以局部地讀和任意的向前搜索整個文件。如果用戶空間
+ 向後搜索到零或使用‘0’偏移執行一個pread(2)操作,show()方法將
+ 再次被調用,以重新填充緩存。
+
+- 在寫方面(write(2)),sysfs 希望在第一次寫操作時得到整個緩衝區。
+ 之後 Sysfs 傳遞整個緩衝區給 store() 方法。
+
+ 當要寫 sysfs 文件時,用戶空間進程應首先讀取整個文件,修該想要
+ 改變的值,然後回寫整個緩衝區。
+
+ 在讀寫屬性值時,屬性方法的執行應操作相同的緩衝區。
+
+註記:
+
+- 寫操作導致的 show() 方法重載,會忽略當前文件位置。
+
+- 緩衝區應總是 PAGE_SIZE 大小。對於i386,這個值爲4096。
+
+- show() 方法應該返回寫入緩衝區的字節數,也就是 scnprintf()的
+ 返回值。
+
+- show() 方法在將格式化返回值返回用戶空間的時候,禁止使用snprintf()。
+ 如果可以保證不會發生緩衝區溢出,可以使用sprintf(),否則必須使用
+ scnprintf()。
+
+- store() 應返回緩衝區的已用字節數。如果整個緩存都已填滿,只需返回
+ count 參數。
+
+- show() 或 store() 可以返回錯誤值。當得到一個非法值,必須返回一個
+ 錯誤值。
+
+- 一個傳遞給方法的對象將會通過 sysfs 調用對象內嵌的引用計數固定在
+ 內存中。儘管如此,對象代表的物理實體(如設備)可能已不存在。如有必要,
+ 應該實現一個檢測機制。
+
+一個簡單的(未經實驗證實的)設備屬性實現如下:
+
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "%s\n", dev->name);
+}
+
+static ssize_t store_name(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ snprintf(dev->name, sizeof(dev->name), "%.*s",
+ (int)min(count, sizeof(dev->name) - 1), buf);
+ return count;
+}
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, store_name);
+
+
+(注意:真正的實現不允許用戶空間設置設備名。)
+
+頂層目錄佈局
+~~~~~~~~~~~~
+
+sysfs 目錄的安排顯示了內核數據結構之間的關係。
+
+頂層 sysfs 目錄如下:
+
+block/
+bus/
+class/
+dev/
+devices/
+firmware/
+net/
+fs/
+
+devices/ 包含了一個設備樹的文件系統表示。他直接映射了內部的內核
+設備樹,反映了設備的層次結構。
+
+bus/ 包含了內核中各種總線類型的平面目錄佈局。每個總線目錄包含兩個
+子目錄:
+
+ devices/
+ drivers/
+
+devices/ 包含了系統中出現的每個設備的符號鏈接,他們指向 root/ 下的
+設備目錄。
+
+drivers/ 包含了每個已爲特定總線上的設備而掛載的驅動程序的目錄(這裏
+假定驅動沒有跨越多個總線類型)。
+
+fs/ 包含了一個爲文件系統設立的目錄。現在每個想要導出屬性的文件系統必須
+在 fs/ 下創建自己的層次結構(參見Documentation/filesystems/fuse.rst)。
+
+dev/ 包含兩個子目錄: char/ 和 block/。在這兩個子目錄中,有以
+<major>:<minor> 格式命名的符號鏈接。這些符號鏈接指向 sysfs 目錄
+中相應的設備。/sys/dev 提供一個通過一個 stat(2) 操作結果,查找
+設備 sysfs 接口快捷的方法。
+
+更多有關 driver-model 的特性信息可以在 Documentation/driver-api/driver-model/
+中找到。
+
+
+TODO: 完成這一節。
+
+
+當前接口
+~~~~~~~~
+
+以下的接口層普遍存在於當前的sysfs中:
+
+- 設備 (include/linux/device.h)
+----------------------------------
+結構體:
+
+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);
+};
+
+聲明:
+
+DEVICE_ATTR(_name, _mode, _show, _store);
+
+增/刪屬性:
+
+int device_create_file(struct device *dev, const struct device_attribute * attr);
+void device_remove_file(struct device *dev, const struct device_attribute * attr);
+
+
+- 總線驅動程序 (include/linux/device.h)
+--------------------------------------
+結構體:
+
+struct bus_attribute {
+ struct attribute attr;
+ ssize_t (*show)(const struct bus_type *, char * buf);
+ ssize_t (*store)(const struct bus_type *, const char * buf, size_t count);
+};
+
+聲明:
+
+BUS_ATTR(_name, _mode, _show, _store)
+
+增/刪屬性:
+
+int bus_create_file(struct bus_type *, struct bus_attribute *);
+void bus_remove_file(struct bus_type *, struct bus_attribute *);
+
+
+- 設備驅動程序 (include/linux/device.h)
+-----------------------------------------
+
+結構體:
+
+struct driver_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct device_driver *, char * buf);
+ ssize_t (*store)(struct device_driver *, const char * buf,
+ size_t count);
+};
+
+聲明:
+
+DRIVER_ATTR(_name, _mode, _show, _store)
+
+增/刪屬性:
+
+int driver_create_file(struct device_driver *, const struct driver_attribute *);
+void driver_remove_file(struct device_driver *, const struct driver_attribute *);
+
+
+文檔
+~~~~
+
+sysfs 目錄結構以及其中包含的屬性定義了一個內核與用戶空間之間的 ABI。
+對於任何 ABI,其自身的穩定和適當的文檔是非常重要的。所有新的 sysfs
+屬性必須在 Documentation/ABI 中有文檔。詳見 Documentation/ABI/README。
+
diff --git a/Documentation/translations/zh_TW/filesystems/tmpfs.rst b/Documentation/translations/zh_TW/filesystems/tmpfs.rst
new file mode 100644
index 000000000000..aed61cc3064d
--- /dev/null
+++ b/Documentation/translations/zh_TW/filesystems/tmpfs.rst
@@ -0,0 +1,147 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/filesystems/tmpfs.rst
+
+translated by Wang Qing<wangqing@vivo.com>
+
+=====
+Tmpfs
+=====
+
+Tmpfs是一個將所有文件都保存在虛擬內存中的文件系統。
+
+tmpfs中的所有內容都是臨時的,也就是說沒有任何文件會在硬盤上創建。
+如果卸載tmpfs實例,所有保存在其中的文件都會丟失。
+
+tmpfs將所有文件保存在內核緩存中,隨着文件內容增長或縮小可以將不需要的
+頁面swap出去。它具有最大限制,可以通過“mount -o remount ...”調整。
+
+和ramfs(創建tmpfs的模板)相比,tmpfs包含交換和限制檢查。和tmpfs相似的另
+一個東西是RAM磁盤(/dev/ram*),可以在物理RAM中模擬固定大小的硬盤,並在
+此之上創建一個普通的文件系統。Ramdisks無法swap,因此無法調整它們的大小。
+
+由於tmpfs完全保存於頁面緩存和swap中,因此所有tmpfs頁面將在/proc/meminfo
+中顯示爲“Shmem”,而在free(1)中顯示爲“Shared”。請注意,這些計數還包括
+共享內存(shmem,請參閱ipcs(1))。獲得計數的最可靠方法是使用df(1)和du(1)。
+
+tmpfs具有以下用途:
+
+1) 內核總有一個無法看到的內部掛載,用於共享匿名映射和SYSV共享內存。
+
+ 掛載不依賴於CONFIG_TMPFS。如果CONFIG_TMPFS未設置,tmpfs對用戶不可見。
+ 但是內部機制始終存在。
+
+2) glibc 2.2及更高版本期望將tmpfs掛載在/dev/shm上以用於POSIX共享內存
+ (shm_open,shm_unlink)。添加內容到/etc/fstab應注意如下:
+
+ tmpfs /dev/shm tmpfs defaults 0 0
+
+ 使用時需要記住創建掛載tmpfs的目錄。
+
+ SYSV共享內存無需掛載,內部已默認支持。(在2.3內核版本中,必須掛載
+ tmpfs的前身(shm fs)才能使用SYSV共享內存)
+
+3) 很多人(包括我)都覺的在/tmp和/var/tmp上掛載非常方便,並具有較大的
+ swap分區。目前循環掛載tmpfs可以正常工作,所以大多數發佈都應當可以
+ 使用mkinitrd通過/tmp訪問/tmp。
+
+4) 也許還有更多我不知道的地方:-)
+
+
+tmpfs有三個用於調整大小的掛載選項:
+
+========= ===========================================================
+size tmpfs實例分配的字節數限制。默認值是不swap時物理RAM的一半。
+ 如果tmpfs實例過大,機器將死鎖,因爲OOM處理將無法釋放該內存。
+nr_blocks 與size相同,但以PAGE_SIZE爲單位。
+nr_inodes tmpfs實例的最大inode個數。默認值是物理內存頁數的一半,或者
+ (有高端內存的機器)低端內存RAM的頁數,二者以較低者爲準。
+========= ===========================================================
+
+這些參數接受後綴k,m或g表示千,兆和千兆字節,可以在remount時更改。
+size參數也接受後綴%用來限制tmpfs實例佔用物理RAM的百分比:
+未指定size或nr_blocks時,默認值爲size=50%
+
+如果nr_blocks=0(或size=0),block個數將不受限制;如果nr_inodes=0,
+inode個數將不受限制。這樣掛載通常是不明智的,因爲它允許任何具有寫權限的
+用戶通過訪問tmpfs耗盡機器上的所有內存;但同時這樣做也會增強在多個CPU的
+場景下的訪問。
+
+tmpfs具有爲所有文件設置NUMA內存分配策略掛載選項(如果啓用了CONFIG_NUMA),
+可以通過“mount -o remount ...”調整
+
+======================== =========================
+mpol=default 採用進程分配策略
+ (請參閱 set_mempolicy(2))
+mpol=prefer:Node 傾向從給定的節點分配
+mpol=bind:NodeList 只允許從指定的鏈表分配
+mpol=interleave 傾向於依次從每個節點分配
+mpol=interleave:NodeList 依次從每個節點分配
+mpol=local 優先本地節點分配內存
+======================== =========================
+
+NodeList格式是以逗號分隔的十進制數字表示大小和範圍,最大和最小範圍是用-
+分隔符的十進制數來表示。例如,mpol=bind0-3,5,7,9-15
+
+帶有有效NodeList的內存策略將按指定格式保存,在創建文件時使用。當任務在該
+文件系統上創建文件時,會使用到掛載時的內存策略NodeList選項,如果設置的話,
+由調用任務的cpuset[請參見Documentation/admin-guide/cgroup-v1/cpusets.rst]
+以及下面列出的可選標誌約束。如果NodeLists爲設置爲空集,則文件的內存策略將
+恢復爲“默認”策略。
+
+NUMA內存分配策略有可選標誌,可以用於模式結合。在掛載tmpfs時指定這些可選
+標誌可以在NodeList之前生效。
+Documentation/admin-guide/mm/numa_memory_policy.rst列出所有可用的內存
+分配策略模式標誌及其對內存策略。
+
+::
+
+ =static 相當於 MPOL_F_STATIC_NODES
+ =relative 相當於 MPOL_F_RELATIVE_NODES
+
+例如,mpol=bind=staticNodeList相當於MPOL_BIND|MPOL_F_STATIC_NODES的分配策略
+
+請注意,如果內核不支持NUMA,那麼使用mpol選項掛載tmpfs將會失敗;nodelist指定不
+在線的節點也會失敗。如果您的系統依賴於此,但內核會運行不帶NUMA功能(也許是安全
+revocery內核),或者具有較少的節點在線,建議從自動模式中省略mpol選項掛載選項。
+可以在以後通過“mount -o remount,mpol=Policy:NodeList MountPoint”添加到掛載點。
+
+要指定初始根目錄,可以使用如下掛載選項:
+
+==== ====================
+模式 權限用八進制數字表示
+uid 用戶ID
+gid 組ID
+==== ====================
+
+這些選項對remount沒有任何影響。您可以通過chmod(1),chown(1)和chgrp(1)的更改
+已經掛載的參數。
+
+tmpfs具有選擇32位還是64位inode的掛載選項:
+
+======= =============
+inode64 使用64位inode
+inode32 使用32位inode
+======= =============
+
+在32位內核上,默認是inode32,掛載時指定inode64會被拒絕。
+在64位內核上,默認配置是CONFIG_TMPFS_INODE64。inode64避免了單個設備上可能有多個
+具有相同inode編號的文件;比如32位應用程序使用glibc如果長期訪問tmpfs,一旦達到33
+位inode編號,就有EOVERFLOW失敗的危險,無法打開大於2GiB的文件,並返回EINVAL。
+
+所以'mount -t tmpfs -o size=10G,nr_inodes=10k,mode=700 tmpfs /mytmpfs'將在
+/mytmpfs上掛載tmpfs實例,分配只能由root用戶訪問的10GB RAM/SWAP,可以有10240個
+inode的實例。
+
+
+:作者:
+ Christoph Rohland <cr@sap.com>, 1.12.01
+:更新:
+ Hugh Dickins, 4 June 2007
+:更新:
+ KOSAKI Motohiro, 16 Mar 2010
+:更新:
+ Chris Down, 13 July 2020
+
diff --git a/Documentation/translations/zh_TW/filesystems/virtiofs.rst b/Documentation/translations/zh_TW/filesystems/virtiofs.rst
new file mode 100644
index 000000000000..704a0ee44fd2
--- /dev/null
+++ b/Documentation/translations/zh_TW/filesystems/virtiofs.rst
@@ -0,0 +1,60 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/filesystems/virtiofs.rst <virtiofs_index>`
+
+譯者
+::
+
+ 中文版維護者: 王文虎 Wang Wenhu <wenhu.wang@vivo.com>
+ 中文版翻譯者: 王文虎 Wang Wenhu <wenhu.wang@vivo.com>
+ 中文版校譯者: 王文虎 Wang Wenhu <wenhu.wang@vivo.com>
+ 繁體中文版校譯者:胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+===========================================
+virtiofs: virtio-fs 主機<->客機共享文件系統
+===========================================
+
+- Copyright (C) 2020 Vivo Communication Technology Co. Ltd.
+
+介紹
+====
+Linux的virtiofs文件系統實現了一個半虛擬化VIRTIO類型“virtio-fs”設備的驅動,通過該\
+類型設備實現客機<->主機文件系統共享。它允許客機掛載一個已經導出到主機的目錄。
+
+客機通常需要訪問主機或者遠程系統上的文件。使用場景包括:在新客機安裝時讓文件對其\
+可見;從主機上的根文件系統啓動;對無狀態或臨時客機提供持久存儲和在客機之間共享目錄。
+
+儘管在某些任務可能通過使用已有的網絡文件系統完成,但是卻需要非常難以自動化的配置\
+步驟,且將存儲網絡暴露給客機。而virtio-fs設備通過提供不經過網絡的文件系統訪問文件\
+的設計方式解決了這些問題。
+
+另外,virto-fs設備發揮了主客機共存的優點提高了性能,並且提供了網絡文件系統所不具備
+的一些語義功能。
+
+用法
+====
+以``myfs``標籤將文件系統掛載到``/mnt``:
+
+.. code-block:: sh
+
+ guest# mount -t virtiofs myfs /mnt
+
+請查閱 https://virtio-fs.gitlab.io/ 瞭解配置QEMU和virtiofsd守護程序的詳細信息。
+
+內幕
+====
+由於virtio-fs設備將FUSE協議用於文件系統請求,因此Linux的virtiofs文件系統與FUSE文\
+件系統客戶端緊密集成在一起。客機充當FUSE客戶端而主機充當FUSE服務器,內核與用戶空\
+間之間的/dev/fuse接口由virtio-fs設備接口代替。
+
+FUSE請求被置於虛擬隊列中由主機處理。主機填充緩衝區中的響應部分,而客機處理請求的完成部分。
+
+將/dev/fuse映射到虛擬隊列需要解決/dev/fuse和虛擬隊列之間語義上的差異。每次讀取\
+/dev/fuse設備時,FUSE客戶端都可以選擇要傳輸的請求,從而可以使某些請求優先於其他\
+請求。虛擬隊列有其隊列語義,無法更改已入隊請求的順序。在虛擬隊列已滿的情況下尤
+其關鍵,因爲此時不可能加入高優先級的請求。爲了解決此差異,virtio-fs設備採用“hiprio”\
+(高優先級)虛擬隊列,專門用於有別於普通請求的高優先級請求。
+
+
diff --git a/Documentation/translations/zh_TW/gpio.txt b/Documentation/translations/zh_TW/gpio.txt
new file mode 100644
index 000000000000..b9b48012c62e
--- /dev/null
+++ b/Documentation/translations/zh_TW/gpio.txt
@@ -0,0 +1,591 @@
+Chinese translated version of Documentation/admin-guide/gpio
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly. However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help. Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Maintainer: Grant Likely <grant.likely@secretlab.ca>
+ Linus Walleij <linus.walleij@linaro.org>
+Traditional Chinese maintainer: Hu Haowen <2023002089@link.tyut.edu.cn>
+---------------------------------------------------------------------
+Documentation/admin-guide/gpio 的繁體中文翻譯
+
+如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
+交流有困難的話,也可以向繁體中文版維護者求助。如果本翻譯更新不及時或
+者翻譯存在問題,請聯繫繁體中文版維護者。
+
+英文版維護者: Grant Likely <grant.likely@secretlab.ca>
+ Linus Walleij <linus.walleij@linaro.org>
+繁體中文版維護者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+繁體中文版翻譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+以下爲正文
+---------------------------------------------------------------------
+GPIO 接口
+
+本文檔提供了一個在Linux下訪問GPIO的公約概述。
+
+這些函數以 gpio_* 作爲前綴。其他的函數不允許使用這樣的前綴或相關的
+__gpio_* 前綴。
+
+
+什麼是GPIO?
+==========
+"通用輸入/輸出口"(GPIO)是一個靈活的由軟體控制的數位訊號。他們可
+由多種晶片提供,且對於從事嵌入式和定製硬體的 Linux 開發者來說是
+比較熟悉。每個GPIO 都代表一個連接到特定引腳或球柵陣列(BGA)封裝中
+「球珠」的一個位。電路板原理圖顯示了 GPIO 與外部硬體的連接關係。
+驅動可以編寫成通用代碼,以使板級啓動代碼可傳遞引腳配置數據給驅動。
+
+片上系統 (SOC) 處理器對 GPIO 有很大的依賴。在某些情況下,每個
+非專用引腳都可配置爲 GPIO,且大多數晶片都最少有一些 GPIO。
+可編程邏輯器件(類似 FPGA) 可以方便地提供 GPIO。像電源管理和
+音頻編解碼器這樣的多功能晶片經常留有一些這樣的引腳來幫助那些引腳
+匱乏的 SOC。同時還有通過 I2C 或 SPI 串行總線連接的「GPIO擴展器」
+晶片。大多數 PC 的南橋有一些擁有 GPIO 能力的引腳 (只有BIOS
+固件才知道如何使用他們)。
+
+GPIO 的實際功能因系統而異。通常用法有:
+
+ - 輸出值可寫 (高電平=1,低電平=0)。一些晶片也有如何驅動這些值的選項,
+ 例如只允許輸出一個值、支持「線與」及其他取值類似的模式(值得注意的是
+ 「開漏」信號)
+
+ - 輸入值可讀(1、0)。一些晶片支持引腳在配置爲「輸出」時回讀,這對於類似
+ 「線與」的情況(以支持雙向信號)是非常有用的。GPIO 控制器可能有輸入
+ 去毛刺/消抖邏輯,這有時需要軟體控制。
+
+ - 輸入通常可作爲 IRQ 信號,一般是沿觸發,但有時是電平觸發。這樣的 IRQ
+ 可能配置爲系統喚醒事件,以將系統從低功耗狀態下喚醒。
+
+ - 通常一個 GPIO 根據不同產品電路板的需求,可以配置爲輸入或輸出,也有僅
+ 支持單向的。
+
+ - 大部分 GPIO 可以在持有自旋鎖時訪問,但是通常由串行總線擴展的 GPIO
+ 不允許持有自旋鎖。但某些系統也支持這種類型。
+
+對於給定的電路板,每個 GPIO 都用於某個特定的目的,如監控 MMC/SD 卡的
+插入/移除、檢測卡的防寫狀態、驅動 LED、配置收發器、模擬串行總線、
+復位硬體看門狗、感知開關狀態等等。
+
+
+GPIO 公約
+=========
+注意,這個叫做「公約」,因爲這不是強制性的,不遵循這個公約是無傷大雅的,
+因爲此時可移植性並不重要。GPIO 常用於板級特定的電路邏輯,甚至可能
+隨著電路板的版本而改變,且不可能在不同走線的電路板上使用。僅有在少數
+功能上才具有可移植性,其他功能是平台特定。這也是由於「膠合」的邏輯造成的。
+
+此外,這不需要任何的執行框架,只是一個接口。某個平台可能通過一個簡單地
+訪問晶片寄存器的內聯函數來實現它,其他平台可能通過委託一系列不同的GPIO
+控制器的抽象函數來實現它。(有一些可選的代碼能支持這種策略的實現,本文檔
+後面會介紹,但作爲 GPIO 接口的客戶端驅動程序必須與它的實現無關。)
+
+也就是說,如果在他們的平台上支持這個公約,驅動應儘可能的使用它。同時,平台
+必須在 Kconfig 中選擇 ARCH_REQUIRE_GPIOLIB 或者 ARCH_WANT_OPTIONAL_GPIOLIB
+選項。那些調用標準 GPIO 函數的驅動應該在 Kconfig 入口中聲明依賴GENERIC_GPIO。
+當驅動包含文件:
+
+ #include <linux/gpio.h>
+
+則 GPIO 函數是可用,無論是「真實代碼」還是經優化過的語句。如果你遵守
+這個公約,當你的代碼完成後,對其他的開發者來說會更容易看懂和維護。
+
+注意,這些操作包含所用平台的 I/O 屏障代碼,驅動無須顯式地調用他們。
+
+
+標識 GPIO
+---------
+GPIO 是通過無符號整型來標識的,範圍是 0 到 MAX_INT。保留「負」數
+用於其他目的,例如標識信號「在這個板子上不可用」或指示錯誤。未接觸底層
+硬體的代碼會忽略這些整數。
+
+平台會定義這些整數的用法,且通常使用 #define 來定義 GPIO,這樣
+板級特定的啓動代碼可以直接關聯相應的原理圖。相對來說,驅動應該僅使用
+啓動代碼傳遞過來的 GPIO 編號,使用 platform_data 保存板級特定
+引腳配置數據 (同時還有其他須要的板級特定數據),避免可能出現的問題。
+
+例如一個平台使用編號 32-159 來標識 GPIO,而在另一個平台使用編號0-63
+標識一組 GPIO 控制器,64-79標識另一類 GPIO 控制器,且在一個含有
+FPGA 的特定板子上使用 80-95。編號不一定要連續,那些平台中,也可以
+使用編號2000-2063來標識一個 I2C 接口的 GPIO 擴展器中的 GPIO。
+
+如果你要初始化一個帶有無效 GPIO 編號的結構體,可以使用一些負編碼
+(如"-EINVAL"),那將使其永遠不會是有效。來測試這樣一個結構體中的編號
+是否關聯一個 GPIO,你可使用以下斷言:
+
+ int gpio_is_valid(int number);
+
+如果編號不存在,則請求和釋放 GPIO 的函數將拒絕執行相關操作(見下文)。
+其他編號也可能被拒絕,比如一個編號可能存在,但暫時在給定的電路上不可用。
+
+一個平台是否支持多個 GPIO 控制器爲平台特定的實現問題,就像是否可以
+在 GPIO 編號空間中有「空洞」和是否可以在運行時添加新的控制器一樣。
+這些問題會影響其他事情,包括相鄰的 GPIO 編號是否存在等。
+
+使用 GPIO
+---------
+對於一個 GPIO,系統應該做的第一件事情就是通過 gpio_request()
+函數分配它,見下文。
+
+接下來是設置I/O方向,這通常是在板級啓動代碼中爲所使用的 GPIO 設置
+platform_device 時完成。
+
+ /* 設置爲輸入或輸出, 返回 0 或負的錯誤代碼 */
+ int gpio_direction_input(unsigned gpio);
+ int gpio_direction_output(unsigned gpio, int value);
+
+返回值爲零代表成功,否則返回一個負的錯誤代碼。這個返回值需要檢查,因爲
+get/set(獲取/設置)函數調用沒法返回錯誤,且有可能是配置錯誤。通常,
+你應該在進程上下文中調用這些函數。然而,對於自旋鎖安全的 GPIO,在板子
+啓動的早期、進程啓動前使用他們也是可以的。
+
+對於作爲輸出的 GPIO,爲其提供初始輸出值,對於避免在系統啓動期間出現
+信號毛刺是很有幫助的。
+
+爲了與傳統的 GPIO 接口兼容, 在設置一個 GPIO 方向時,如果它還未被申請,
+則隱含了申請那個 GPIO 的操作(見下文)。這種兼容性正在從可選的 gpiolib
+框架中移除。
+
+如果這個 GPIO 編碼不存在,或者特定的 GPIO 不能用於那種模式,則方向
+設置可能失敗。依賴啓動固件來正確地設置方向通常是一個壞主意,因爲它可能
+除了啓動Linux,並沒有做更多的驗證工作。(同理, 板子的啓動代碼可能需要
+將這個復用的引腳設置爲 GPIO,並正確地配置上拉/下拉電阻。)
+
+
+訪問自旋鎖安全的 GPIO
+-------------------
+大多數 GPIO 控制器可以通過內存讀/寫指令來訪問。這些指令不會休眠,可以
+安全地在硬(非線程)中斷例程和類似的上下文中完成。
+
+對於那些 GPIO,使用以下的函數訪問:
+
+ /* GPIO 輸入:返回零或非零 */
+ int gpio_get_value(unsigned gpio);
+
+ /* GPIO 輸出 */
+ void gpio_set_value(unsigned gpio, int value);
+
+GPIO值是布爾值,零表示低電平,非零表示高電平。當讀取一個輸出引腳的值時,
+返回值應該是引腳上的值。這個值不總是和輸出值相符,因爲存在開漏輸出信號和
+輸出延遲問題。
+
+以上的 get/set 函數無錯誤返回值,因爲之前 gpio_direction_*()應已檢查過
+其是否爲「無效GPIO」。此外,還需要注意的是並不是所有平台都可以從輸出引腳
+中讀取數據,對於不能讀取的引腳應總返回零。另外,對那些在原子上下文中無法
+安全訪問的 GPIO (譯者註:因爲訪問可能導致休眠)使用這些函數是不合適的
+(見下文)。
+
+在 GPIO 編號(還有輸出、值)爲常數的情況下,鼓勵通過平台特定的實現來優化
+這兩個函數來訪問 GPIO 值。這種情況(讀寫一個硬體寄存器)下只需要幾條指令
+是很正常的,且無須自旋鎖。這種優化函數比起那些在子程序上花費許多指令的
+函數可以使得模擬接口(譯者注:例如 GPIO 模擬 I2C、1-wire 或 SPI)的
+應用(在空間和時間上都)更具效率。
+
+
+訪問可能休眠的 GPIO
+-----------------
+某些 GPIO 控制器必須通過基於總線(如 I2C 或 SPI)的消息訪問。讀或寫這些
+GPIO 值的命令需要等待其信息排到隊首才發送命令,再獲得其反饋。期間需要
+休眠,這不能在 IRQ 例程(中斷上下文)中執行。
+
+爲了訪問這種 GPIO,內核定義了一套不同的函數:
+
+ /* GPIO 輸入:返回零或非零 ,可能會休眠 */
+ int gpio_get_value_cansleep(unsigned gpio);
+
+ /* GPIO 輸出,可能會休眠 */
+ void gpio_set_value_cansleep(unsigned gpio, int value);
+
+訪問這樣的 GPIO 需要一個允許休眠的上下文,例如線程 IRQ 處理例程,並用以上的
+訪問函數替換那些沒有 cansleep()後綴的自旋鎖安全訪問函數。
+
+除了這些訪問函數可能休眠,且它們操作的 GPIO 不能在硬體 IRQ 處理例程中訪問的
+事實,這些處理例程實際上和自旋鎖安全的函數是一樣的。
+
+** 除此之外 ** 調用設置和配置此類 GPIO 的函數也必須在允許休眠的上下文中,
+因爲它們可能也需要訪問 GPIO 控制器晶片: (這些設置函數通常在板級啓動代碼或者
+驅動探測/斷開代碼中,所以這是一個容易滿足的約束條件。)
+
+ gpio_direction_input()
+ gpio_direction_output()
+ gpio_request()
+
+## gpio_request_one()
+## gpio_request_array()
+## gpio_free_array()
+
+ gpio_free()
+
+
+
+聲明和釋放 GPIO
+----------------------------
+爲了有助於捕獲系統配置錯誤,定義了兩個函數。
+
+ /* 申請 GPIO, 返回 0 或負的錯誤代碼.
+ * 非空標籤可能有助於診斷.
+ */
+ int gpio_request(unsigned gpio, const char *label);
+
+ /* 釋放之前聲明的 GPIO */
+ void gpio_free(unsigned gpio);
+
+將無效的 GPIO 編碼傳遞給 gpio_request()會導致失敗,申請一個已使用這個
+函數聲明過的 GPIO 也會失敗。gpio_request()的返回值必須檢查。你應該在
+進程上下文中調用這些函數。然而,對於自旋鎖安全的 GPIO,在板子啓動的早期、
+進入進程之前是可以申請的。
+
+這個函數完成兩個基本的目標。一是標識那些實際上已作爲 GPIO 使用的信號線,
+這樣便於更好地診斷;系統可能需要服務幾百個可用的 GPIO,但是對於任何一個
+給定的電路板通常只有一些被使用。另一個目的是捕獲衝突,查明錯誤:如兩個或
+更多驅動錯誤地認爲他們已經獨占了某個信號線,或是錯誤地認爲移除一個管理著
+某個已激活信號的驅動是安全的。也就是說,申請 GPIO 的作用類似一種鎖機制。
+
+某些平台可能也使用 GPIO 作爲電源管理激活信號(例如通過關閉未使用晶片區和
+簡單地關閉未使用時鐘)。
+
+對於 GPIO 使用 pinctrl 子系統已知的引腳,子系統應該被告知其使用情況;
+一個 gpiolib 驅動的 .request()操作應調用 pinctrl_gpio_request(),
+而 gpiolib 驅動的 .free()操作應調用 pinctrl_gpio_free()。pinctrl
+子系統允許 pinctrl_gpio_request()在某個引腳或引腳組以復用形式「屬於」
+一個設備時都成功返回。
+
+任何須將 GPIO 信號導向適當引腳的引腳復用硬體的編程應該發生在 GPIO
+驅動的 .direction_input()或 .direction_output()函數中,以及
+任何輸出 GPIO 值的設置之後。這樣可使從引腳特殊功能到 GPIO 的轉換
+不會在引腳產生毛刺波形。有時當用一個 GPIO 實現其信號驅動一個非 GPIO
+硬體模塊的解決方案時,就需要這種機制。
+
+某些平台允許部分或所有 GPIO 信號使用不同的引腳。類似的,GPIO 或引腳的
+其他方面也需要配置,如上拉/下拉。平台軟體應該在對這些 GPIO 調用
+gpio_request()前將這類細節配置好,例如使用 pinctrl 子系統的映射表,
+使得 GPIO 的用戶無須關注這些細節。
+
+還有一個值得注意的是在釋放 GPIO 前,你必須停止使用它。
+
+
+注意:申請一個 GPIO 並沒有以任何方式配置它,只不過標識那個 GPIO 處於使用
+狀態。必須有另外的代碼來處理引腳配置(如控制 GPIO 使用的引腳、上拉/下拉)。
+考慮到大多數情況下聲明 GPIO 之後就會立即配置它們,所以定義了以下三個輔助函數:
+
+ /* 申請一個 GPIO 信號, 同時通過特定的'flags'初始化配置,
+ * 其他和 gpio_request()的參數和返回值相同
+ *
+ */
+ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
+
+ /* 在單個函數中申請多個 GPIO
+ */
+ int gpio_request_array(struct gpio *array, size_t num);
+
+ /* 在單個函數中釋放多個 GPIO
+ */
+ void gpio_free_array(struct gpio *array, size_t num);
+
+這裡 'flags' 當前定義可指定以下屬性:
+
+ * GPIOF_DIR_IN - 配置方向爲輸入
+ * GPIOF_DIR_OUT - 配置方向爲輸出
+
+ * GPIOF_INIT_LOW - 在作爲輸出時,初始值爲低電平
+ * GPIOF_INIT_HIGH - 在作爲輸出時,初始值爲高電平
+
+因爲 GPIOF_INIT_* 僅有在配置爲輸出的時候才存在,所以有效的組合爲:
+
+ * GPIOF_IN - 配置爲輸入
+ * GPIOF_OUT_INIT_LOW - 配置爲輸出,並初始化爲低電平
+ * GPIOF_OUT_INIT_HIGH - 配置爲輸出,並初始化爲高電平
+
+更進一步,爲了更簡單地聲明/釋放多個 GPIO,'struct gpio'被引進來封裝所有
+這三個領域:
+
+ struct gpio {
+ unsigned gpio;
+ unsigned long flags;
+ const char *label;
+ };
+
+一個典型的用例:
+
+ static struct gpio leds_gpios[] = {
+ { 32, GPIOF_OUT_INIT_HIGH, "Power LED" }, /* 默認開啓 */
+ { 33, GPIOF_OUT_INIT_LOW, "Green LED" }, /* 默認關閉 */
+ { 34, GPIOF_OUT_INIT_LOW, "Red LED" }, /* 默認關閉 */
+ { 35, GPIOF_OUT_INIT_LOW, "Blue LED" }, /* 默認關閉 */
+ { ... },
+ };
+
+ err = gpio_request_one(31, GPIOF_IN, "Reset Button");
+ if (err)
+ ...
+
+ err = gpio_request_array(leds_gpios, ARRAY_SIZE(leds_gpios));
+ if (err)
+ ...
+
+ gpio_free_array(leds_gpios, ARRAY_SIZE(leds_gpios));
+
+
+GPIO 映射到 IRQ
+--------------------
+GPIO 編號是無符號整數;IRQ 編號也是。這些構成了兩個邏輯上不同的命名空間
+(GPIO 0 不一定使用 IRQ 0)。你可以通過以下函數在它們之間實現映射:
+
+ /* 映射 GPIO 編號到 IRQ 編號 */
+ int gpio_to_irq(unsigned gpio);
+
+它們的返回值爲對應命名空間的相關編號,或是負的錯誤代碼(如果無法映射)。
+(例如,某些 GPIO 無法做爲 IRQ 使用。)以下的編號錯誤是未經檢測的:使用一個
+未通過 gpio_direction_input()配置爲輸入的 GPIO 編號,或者使用一個
+並非來源於gpio_to_irq()的 IRQ 編號。
+
+這兩個映射函數可能會在信號編號的加減計算過程上花些時間。它們不可休眠。
+
+gpio_to_irq()返回的非錯誤值可以傳遞給 request_irq()或者 free_irq()。
+它們通常通過板級特定的初始化代碼存放到平台設備的 IRQ 資源中。注意:IRQ
+觸發選項是 IRQ 接口的一部分,如 IRQF_TRIGGER_FALLING,系統喚醒能力
+也是如此。
+
+
+模擬開漏信號
+----------------------------
+有時在只有低電平信號作爲實際驅動結果(譯者注:多個輸出連接於一點,邏輯電平
+結果爲所有輸出的邏輯與)的時候,共享的信號線需要使用「開漏」信號。(該術語
+適用於 CMOS 管;而 TTL 用「集電極開路」。)一個上拉電阻使信號爲高電平。這
+有時被稱爲「線與」。實際上,從負邏輯(低電平爲真)的角度來看,這是一個「線或」。
+
+一個開漏信號的常見例子是共享的低電平使能 IRQ 信號線。此外,有時雙向數據總線
+信號也使用漏極開路信號。
+
+某些 GPIO 控制器直接支持開漏輸出,還有許多不支持。當你需要開漏信號,但
+硬體又不直接支持的時候,一個常用的方法是用任何即可作輸入也可作輸出的 GPIO
+引腳來模擬:
+
+ LOW: gpio_direction_output(gpio, 0) ... 這代碼驅動信號並覆蓋
+ 上拉配置。
+
+ HIGH: gpio_direction_input(gpio) ... 這代碼關閉輸出,所以上拉電阻
+ (或其他的一些器件)控制了信號。
+
+如果你將信號線「驅動」爲高電平,但是 gpio_get_value(gpio)報告了一個
+低電平(在適當的上升時間後),你就可以知道是其他的一些組件將共享信號線拉低了。
+這不一定是錯誤的。一個常見的例子就是 I2C 時鐘的延長:一個需要較慢時鐘的
+從設備延遲 SCK 的上升沿,而 I2C 主設備相應地調整其信號傳輸速率。
+
+
+這些公約忽略了什麼?
+================
+這些公約忽略的最大一件事就是引腳復用,因爲這屬於高度晶片特定的屬性且
+沒有可移植性。某個平台可能不需要明確的復用信息;有的對於任意給定的引腳
+可能只有兩個功能選項;有的可能每個引腳有八個功能選項;有的可能可以將
+幾個引腳中的任何一個作爲給定的 GPIO。(是的,這些例子都來自於當前運行
+Linux 的系統。)
+
+在某些系統中,與引腳復用相關的是配置和使能集成的上、下拉模式。並不是所有
+平台都支持這種模式,或者不會以相同的方式來支持這種模式;且任何給定的電路板
+可能使用外置的上拉(或下拉)電阻,這時晶片上的就不應該使用。(當一個電路需要
+5kOhm 的拉動電阻,晶片上的 100 kOhm 電阻就不能做到。)同樣的,驅動能力
+(2 mA vs 20 mA)和電壓(1.8V vs 3.3V)是平台特定問題,就像模型一樣在
+可配置引腳和 GPIO 之間(沒)有一一對應的關係。
+
+還有其他一些系統特定的機制沒有在這裡指出,例如上述的輸入去毛刺和線與輸出
+選項。硬體可能支持批量讀或寫 GPIO,但是那一般是配置相關的:對於處於同一
+塊區(bank)的GPIO。(GPIO 通常以 16 或 32 個組成一個區塊,一個給定的
+片上系統一般有幾個這樣的區塊。)某些系統可以通過輸出 GPIO 觸發 IRQ,
+或者從並非以 GPIO 管理的引腳取值。這些機制的相關代碼沒有必要具有可移植性。
+
+當前,動態定義 GPIO 並不是標準的,例如作爲配置一個帶有某些 GPIO 擴展器的
+附加電路板的副作用。
+
+GPIO 實現者的框架 (可選)
+=====================
+前面提到了,有一個可選的實現框架,讓平台使用相同的編程接口,更加簡單地支持
+不同種類的 GPIO 控制器。這個框架稱爲"gpiolib"。
+
+作爲一個輔助調試功能,如果 debugfs 可用,就會有一個 /sys/kernel/debug/gpio
+文件。通過這個框架,它可以列出所有註冊的控制器,以及當前正在使用中的 GPIO
+的狀態。
+
+
+控制器驅動: gpio_chip
+-------------------
+在框架中每個 GPIO 控制器都包裝爲一個 "struct gpio_chip",他包含了
+該類型的每個控制器的常用信息:
+
+ - 設置 GPIO 方向的方法
+ - 用於訪問 GPIO 值的方法
+ - 告知調用其方法是否可能休眠的標誌
+ - 可選的 debugfs 信息導出方法 (顯示類似上拉配置一樣的額外狀態)
+ - 診斷標籤
+
+也包含了來自 device.platform_data 的每個實例的數據:它第一個 GPIO 的
+編號和它可用的 GPIO 的數量。
+
+實現 gpio_chip 的代碼應支持多控制器實例,這可能使用驅動模型。那些代碼要
+配置每個 gpio_chip,並發起gpiochip_add()。卸載一個 GPIO 控制器很少見,
+但在必要的時候可以使用 gpiochip_remove()。
+
+大部分 gpio_chip 是一個實例特定結構體的一部分,而並不將 GPIO 接口單獨
+暴露出來,比如編址、電源管理等。類似編解碼器這樣的晶片會有複雜的非 GPIO
+狀態。
+
+任何一個 debugfs 信息導出方法通常應該忽略還未申請作爲 GPIO 的信號線。
+他們可以使用 gpiochip_is_requested()測試,當這個 GPIO 已經申請過了
+就返回相關的標籤,否則返回 NULL。
+
+
+平台支持
+-------
+爲了支持這個框架,一個平台的 Kconfig 文件將會 "select"(選擇)
+ARCH_REQUIRE_GPIOLIB 或 ARCH_WANT_OPTIONAL_GPIOLIB,並讓它的
+<asm/gpio.h> 包含 <asm-generic/gpio.h>,同時定義二個方法:
+gpio_get_value()、gpio_set_value()。
+
+它也應提供一個 ARCH_NR_GPIOS 的定義值,這樣可以更好地反映該平台 GPIO
+的實際數量,節省靜態表的空間。(這個定義值應該包含片上系統內建 GPIO 和
+GPIO 擴展器中的數據。)
+
+ARCH_REQUIRE_GPIOLIB 意味著 gpiolib 核心在這個構架中將總是編譯進內核。
+
+ARCH_WANT_OPTIONAL_GPIOLIB 意味著 gpiolib 核心默認關閉,且用戶可以
+使能它,並將其編譯進內核(可選)。
+
+如果這些選項都沒被選擇,該平台就不通過 GPIO-lib 支持 GPIO,且代碼不可以
+被用戶使能。
+
+以下這些方法的實現可以直接使用框架代碼,並總是通過 gpio_chip 調度:
+
+ #define gpio_get_value __gpio_get_value
+ #define gpio_set_value __gpio_set_value
+
+這些定義可以用更理想的實現方法替代,那就是使用經過邏輯優化的內聯函數來訪問
+基於特定片上系統的 GPIO。例如,若引用的 GPIO (寄存器位偏移)是常量「12」,
+讀取或設置它可能只需少則兩或三個指令,且不會休眠。當這樣的優化無法實現時,
+那些函數必須使用框架提供的代碼,那就至少要幾十條指令才可以實現。對於用 GPIO
+模擬的 I/O 接口, 如此精簡指令是很有意義的。
+
+對於片上系統,平台特定代碼爲片上 GPIO 每個區(bank)定義並註冊 gpio_chip
+實例。那些 GPIO 應該根據晶片廠商的文檔進行編碼/標籤,並直接和電路板原理圖
+對應。他們應該開始於零並終止於平台特定的限制。這些 GPIO(代碼)通常從
+arch_initcall()或者更早的地方集成進平台初始化代碼,使這些 GPIO 總是可用,
+且他們通常可以作爲 IRQ 使用。
+
+板級支持
+-------
+對於外部 GPIO 控制器(例如 I2C 或 SPI 擴展器、專用晶片、多功能器件、FPGA
+或 CPLD),大多數常用板級特定代碼都可以註冊控制器設備,並保證他們的驅動知道
+gpiochip_add()所使用的 GPIO 編號。他們的起始編號通常跟在平台特定的 GPIO
+編號之後。
+
+例如板級啓動代碼應該創建結構體指明晶片公開的 GPIO 範圍,並使用 platform_data
+將其傳遞給每個 GPIO 擴展器晶片。然後晶片驅動中的 probe()例程可以將這個
+數據傳遞給 gpiochip_add()。
+
+初始化順序很重要。例如,如果一個設備依賴基於 I2C 的(擴展)GPIO,那麼它的
+probe()例程就應該在那個 GPIO 有效以後才可以被調用。這意味著設備應該在
+GPIO 可以工作之後才可被註冊。解決這類依賴的的一種方法是讓這種 gpio_chip
+控制器向板級特定代碼提供 setup()和 teardown()回調函數。一旦所有必須的
+資源可用之後,這些板級特定的回調函數將會註冊設備,並可以在這些 GPIO 控制器
+設備變成無效時移除它們。
+
+
+用戶空間的 Sysfs 接口(可選)
+========================
+使用「gpiolib」實現框架的平台可以選擇配置一個 GPIO 的 sysfs 用戶接口。
+這不同於 debugfs 接口,因爲它提供的是對 GPIO方向和值的控制,而不只顯示
+一個GPIO 的狀態摘要。此外,它可以出現在沒有調試支持的產品級系統中。
+
+例如,通過適當的系統硬體文檔,用戶空間可以知道 GIOP #23 控制 Flash
+存儲器的防寫(用於保護其中 Bootloader 分區)。產品的系統升級可能需要
+臨時解除這個保護:首先導入一個 GPIO,改變其輸出狀態,然後在重新使能防寫
+前升級代碼。通常情況下,GPIO #23 是不會被觸及的,並且內核也不需要知道他。
+
+根據適當的硬體文檔,某些系統的用戶空間 GPIO 可以用於確定系統配置數據,
+這些數據是標準內核不知道的。在某些任務中,簡單的用戶空間 GPIO 驅動可能是
+系統真正需要的。
+
+注意:標準內核驅動中已經存在通用的「LED 和按鍵」GPIO 任務,分別是:
+"leds-gpio" 和 "gpio_keys"。請使用這些來替代直接訪問 GPIO,因爲集成在
+內核框架中的這類驅動比你在用戶空間的代碼更好。
+
+
+Sysfs 中的路徑
+--------------
+在/sys/class/gpio 中有 3 類入口:
+
+ - 用於在用戶空間控制 GPIO 的控制接口;
+
+ - GPIOs 本身;以及
+
+ - GPIO 控制器 ("gpio_chip" 實例)。
+
+除了這些標準的文件,還包含「device」符號連結。
+
+控制接口是只寫的:
+
+ /sys/class/gpio/
+
+ "export" ... 用戶空間可以通過寫其編號到這個文件,要求內核導出
+ 一個 GPIO 的控制到用戶空間。
+
+ 例如: 如果內核代碼沒有申請 GPIO #19,"echo 19 > export"
+ 將會爲 GPIO #19 創建一個 "gpio19" 節點。
+
+ "unexport" ... 導出到用戶空間的逆操作。
+
+ 例如: "echo 19 > unexport" 將會移除使用"export"文件導出的
+ "gpio19" 節點。
+
+GPIO 信號的路徑類似 /sys/class/gpio/gpio42/ (對於 GPIO #42 來說),
+並有如下的讀/寫屬性:
+
+ /sys/class/gpio/gpioN/
+
+ "direction" ... 讀取得到 "in" 或 "out"。這個值通常運行寫入。
+ 寫入"out" 時,其引腳的默認輸出爲低電平。爲了確保無故障運行,
+ "low" 或 "high" 的電平值應該寫入 GPIO 的配置,作爲初始輸出值。
+
+ 注意:如果內核不支持改變 GPIO 的方向,或者在導出時內核代碼沒有
+ 明確允許用戶空間可以重新配置 GPIO 方向,那麼這個屬性將不存在。
+
+ "value" ... 讀取得到 0 (低電平) 或 1 (高電平)。如果 GPIO 配置爲
+ 輸出,這個值允許寫操作。任何非零值都以高電平看待。
+
+ 如果引腳可以配置爲中斷信號,且如果已經配置了產生中斷的模式
+ (見"edge"的描述),你可以對這個文件使用輪詢操作(poll(2)),
+ 且輪詢操作會在任何中斷觸發時返回。如果你使用輪詢操作(poll(2)),
+ 請在 events 中設置 POLLPRI 和 POLLERR。如果你使用輪詢操作
+ (select(2)),請在 exceptfds 設置你期望的文件描述符。在
+ 輪詢操作(poll(2))返回之後,既可以通過 lseek(2)操作讀取
+ sysfs 文件的開始部分,也可以關閉這個文件並重新打開它來讀取數據。
+
+ "edge" ... 讀取得到「none」、「rising」、「falling」或者「both」。
+ 將這些字符串寫入這個文件可以選擇沿觸發模式,會使得輪詢操作
+ (select(2))在"value"文件中返回。
+
+ 這個文件僅有在這個引腳可以配置爲可產生中斷輸入引腳時,才存在。
+
+ "active_low" ... 讀取得到 0 (假) 或 1 (真)。寫入任何非零值可以
+ 翻轉這個屬性的(讀寫)值。已存在或之後通過"edge"屬性設置了"rising"
+ 和 "falling" 沿觸發模式的輪詢操作(poll(2))將會遵循這個設置。
+
+GPIO 控制器的路徑類似 /sys/class/gpio/gpiochip42/ (對於從#42 GPIO
+開始實現控制的控制器),並有著以下只讀屬性:
+
+ /sys/class/gpio/gpiochipN/
+
+ "base" ... 與以上的 N 相同,代表此晶片管理的第一個 GPIO 的編號
+
+ "label" ... 用於診斷 (並不總是只有唯一值)
+
+ "ngpio" ... 此控制器所管理的 GPIO 數量(而 GPIO 編號從 N 到
+ N + ngpio - 1)
+
+大多數情況下,電路板的文檔應當標明每個 GPIO 的使用目的。但是那些編號並不總是
+固定的,例如在擴展卡上的 GPIO會根據所使用的主板或所在堆疊架構中其他的板子而
+有所不同。在這種情況下,你可能需要使用 gpiochip 節點(儘可能地結合電路圖)來
+確定給定信號所用的 GPIO 編號。
diff --git a/Documentation/translations/zh_TW/index.rst b/Documentation/translations/zh_TW/index.rst
new file mode 100644
index 000000000000..660a74d2023c
--- /dev/null
+++ b/Documentation/translations/zh_TW/index.rst
@@ -0,0 +1,134 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. raw:: latex
+
+ \renewcommand\thesection*
+ \renewcommand\thesubsection*
+ \kerneldocCJKon
+ \kerneldocBeginTC{
+
+.. _linux_doc_zh_tw:
+
+繁體中文翻譯
+============
+
+
+.. note::
+ 內核文檔繁體中文版的翻譯工作正在進行中。如果您願意並且有時間參與這項工
+ 作,歡迎提交補丁給胡皓文 <2023002089@link.tyut.edu.cn>。
+
+與Linux 內核社區一起工作
+------------------------
+
+與內核開發社區進行協作並將工作推向上游的基本指南。
+
+.. toctree::
+ :maxdepth: 1
+
+ process/development-process
+ process/submitting-patches
+ 行爲準則 <process/code-of-conduct>
+ 完整開發流程文檔 <process/index>
+
+TODOList:
+
+* maintainer/index
+
+內部API文檔
+-----------
+
+開發人員使用的內核內部交互接口手冊。
+
+TODOList:
+
+* core-api/index
+* driver-api/index
+* 內核中的鎖 <locking/index>
+* subsystem-apis
+
+開發工具和流程
+--------------
+
+爲所有內核開發人員提供有用信息的各種其他手冊。
+
+.. toctree::
+ :maxdepth: 1
+
+ process/license-rules
+ dev-tools/index
+
+TODOList:
+
+* doc-guide/index
+* dev-tools/testing-overview
+* kernel-hacking/index
+* rust/index
+* trace/index
+* fault-injection/index
+* livepatch/index
+
+面向用戶的文檔
+--------------
+
+下列手冊針對
+希望內核在給定系統上以最佳方式工作的*用戶*,
+和查找內核用戶空間API信息的程序開發人員。
+
+.. toctree::
+ :maxdepth: 1
+
+ admin-guide/index
+ admin-guide/reporting-issues.rst
+
+TODOList:
+
+* userspace-api/index
+* 內核構建系統 <kbuild/index>
+* 用戶空間工具 <tools/index>
+
+也可參考獨立於內核文檔的 `Linux 手冊頁 <https://www.kernel.org/doc/man-pages/>`_ 。
+
+固件相關文檔
+------------
+
+下列文檔描述了內核需要的平臺固件相關信息。
+
+TODOList:
+
+* devicetree/index
+* firmware-guide/index
+
+體系結構文檔
+------------
+
+.. toctree::
+ :maxdepth: 1
+
+ arch/index
+
+其他文檔
+--------
+
+有幾份未分類的文檔似乎不適合放在文檔的其他部分,或者可能需要進行一些調整和/或
+轉換爲reStructureText格式,也有可能太舊。
+
+TODOList:
+
+* staging/index
+
+術語表
+------
+
+TODOList:
+
+* glossary
+
+
+索引和表格
+----------
+
+* :ref:`genindex`
+
+.. raw:: latex
+
+ }\kerneldocEndTC
diff --git a/Documentation/translations/zh_TW/io_ordering.txt b/Documentation/translations/zh_TW/io_ordering.txt
new file mode 100644
index 000000000000..00b374092d7e
--- /dev/null
+++ b/Documentation/translations/zh_TW/io_ordering.txt
@@ -0,0 +1,68 @@
+Chinese translated version of Documentation/driver-api/io_ordering.rst
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly. However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help. Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Traditional Chinese maintainer: Hu Haowen <2023002089@link.tyut.edu.cn>
+---------------------------------------------------------------------
+Documentation/driver-api/io_ordering.rst 的繁體中文翻譯
+
+如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
+交流有困難的話,也可以向繁體中文版維護者求助。如果本翻譯更新不及時或
+者翻譯存在問題,請聯繫繁體中文版維護者。
+
+繁體中文版維護者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+繁體中文版翻譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+
+以下爲正文
+---------------------------------------------------------------------
+
+在某些平台上,所謂的內存映射I/O是弱順序。在這些平台上,驅動開發者有責任
+保證I/O內存映射地址的寫操作按程序圖意的順序達到設備。通常讀取一個「安全」
+設備寄存器或橋寄存器,觸發IO晶片清刷未處理的寫操作到達設備後才處理讀操作,
+而達到保證目的。驅動程序通常在spinlock保護的臨界區退出之前使用這種技術。
+這也可以保證後面的寫操作只在前面的寫操作之後到達設備(這非常類似於內存
+屏障操作,mb(),不過僅適用於I/O)。
+
+假設一個設備驅動程的具體例子:
+
+ ...
+CPU A: spin_lock_irqsave(&dev_lock, flags)
+CPU A: val = readl(my_status);
+CPU A: ...
+CPU A: writel(newval, ring_ptr);
+CPU A: spin_unlock_irqrestore(&dev_lock, flags)
+ ...
+CPU B: spin_lock_irqsave(&dev_lock, flags)
+CPU B: val = readl(my_status);
+CPU B: ...
+CPU B: writel(newval2, ring_ptr);
+CPU B: spin_unlock_irqrestore(&dev_lock, flags)
+ ...
+
+上述例子中,設備可能會先接收到newval2的值,然後接收到newval的值,問題就
+發生了。不過很容易通過下面方法來修復:
+
+ ...
+CPU A: spin_lock_irqsave(&dev_lock, flags)
+CPU A: val = readl(my_status);
+CPU A: ...
+CPU A: writel(newval, ring_ptr);
+CPU A: (void)readl(safe_register); /* 配置寄存器?*/
+CPU A: spin_unlock_irqrestore(&dev_lock, flags)
+ ...
+CPU B: spin_lock_irqsave(&dev_lock, flags)
+CPU B: val = readl(my_status);
+CPU B: ...
+CPU B: writel(newval2, ring_ptr);
+CPU B: (void)readl(safe_register); /* 配置寄存器?*/
+CPU B: spin_unlock_irqrestore(&dev_lock, flags)
+
+在解決方案中,讀取safe_register寄存器,觸發IO晶片清刷未處理的寫操作,
+再處理後面的讀操作,防止引發數據不一致問題。
+
diff --git a/Documentation/translations/zh_TW/process/1.Intro.rst b/Documentation/translations/zh_TW/process/1.Intro.rst
new file mode 100644
index 000000000000..345c4cbe9b55
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/1.Intro.rst
@@ -0,0 +1,199 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/1.Intro.rst <development_process_intro>`
+
+:Translator:
+
+ 時奎亮 Alex Shi <alex.shi@linux.alibaba.com>
+
+:校譯:
+
+ 吳想成 Wu XiangCheng <bobwxc@email.cn>
+ 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+.. _tw_development_process_intro:
+
+引言
+====
+
+內容提要
+--------
+
+本節的其餘部分涵蓋了內核開發的過程,以及開發人員及其僱主在這方面可能遇到的
+各種問題。有很多原因使內核代碼應被合併到正式的(“主線”)內核中,包括對用戶
+的自動可用性、多種形式的社區支持以及影響內核開發方向的能力。提供給Linux內核
+的代碼必須在與GPL兼容的許可證下可用。
+
+:ref:`tw_development_process` 介紹了開發過程、內核發佈週期和合並窗口的機制。
+涵蓋了補丁開發、審查和合並週期中的各個階段。還有一些關於工具和郵件列表的討論?
+鼓勵希望開始內核開發的開發人員跟蹤並修復缺陷以作爲初步練習。
+
+
+:ref:`tw_development_early_stage` 包括項目的早期規劃,重點是儘快讓開發社區
+參與進來。
+
+:ref:`tw_development_coding` 是關於編程過程的;介紹了其他開發人員遇到的幾個
+陷阱。也涵蓋了對補丁的一些要求,並且介紹了一些工具,這些工具有助於確保內核
+補丁是正確的。
+
+:ref:`tw_development_posting` 描述發佈補丁以供評審的過程。爲了讓開發社區能
+認真對待,補丁必須被正確格式化和描述,並且必須發送到正確的地方。遵循本節中的
+建議有助於確保您的工作能被較好地接納。
+
+:ref:`tw_development_followthrough` 介紹了發佈補丁之後發生的事情;工作在這時
+還遠遠沒有完成。與審閱者一起工作是開發過程中的一個重要部分;本節提供了一些
+關於如何在這個重要階段避免問題的提示。當補丁被合併到主線中時,開發人員要注意
+不要假定任務已經完成。
+
+:ref:`tw_development_advancedtopics` 介紹了兩個“高級”主題:使用Git管理補丁
+和查看其他人發佈的補丁。
+
+:ref:`tw_development_conclusion` 總結了有關內核開發的更多信息,附帶有相關資源
+鏈接。
+
+這個文檔是關於什麼的
+--------------------
+
+Linux內核有超過800萬行代碼,每個版本的貢獻者超過1000人,是現存最大、最活躍的
+免費軟件項目之一。從1991年開始,這個內核已經發展成爲一個最好的操作系統組件,
+運行在袖珍數字音樂播放器、臺式電腦、現存最大的超級計算機以及所有類型的系統上。
+它是一種適用於幾乎任何情況的健壯、高效和可擴展的解決方案。
+
+隨着Linux的發展,希望參與其開發的開發人員(和公司)的數量也在增加。硬件供應商
+希望確保Linux能夠很好地支持他們的產品,使這些產品對Linux用戶具有吸引力。嵌入
+式系統供應商使用Linux作爲集成產品的組件,希望Linux能夠儘可能地勝任手頭的任務。
+分銷商和其他基於Linux的軟件供應商切實關心Linux內核的功能、性能和可靠性。最終
+用戶也常常希望修改Linux,使之能更好地滿足他們的需求。
+
+Linux最引人注目的特性之一是這些開發人員可以訪問它;任何具備必要技能的人都可以
+改進Linux並影響其開發方向。專有產品不能提供這種開放性,這是自由軟件的一個特點。
+如果有什麼不同的話,那就是內核比大多數其他自由軟件項目更開放。一個典型的三個
+月內核開發週期可以涉及1000多個開發人員,他們爲100多個不同的公司(或者根本不
+隸屬公司)工作。
+
+與內核開發社區合作並不是特別困難。但儘管如此,仍有許多潛在的貢獻者在嘗試做
+內核工作時遇到了困難。內核社區已經發展出自己獨特的操作方式,使其能夠在每天
+都要更改數千行代碼的環境中順利運行(並生成高質量的產品)。因此,Linux內核開發
+過程與專有的開發模式有很大的不同也就不足爲奇了。
+
+對於新開發人員來說,內核的開發過程可能會讓人感到奇怪和恐懼,但這背後有充分的
+理由和堅實的經驗。一個不瞭解內核社區工作方式的開發人員(或者更糟的是,他們
+試圖拋棄或規避之)會得到令人沮喪的體驗。開發社區在幫助那些試圖學習的人的同時,
+沒有時間幫助那些不願意傾聽或不關心開發過程的人。
+
+希望閱讀本文的人能夠避免這種令人沮喪的經歷。這些材料很長,但閱讀它們時所做的
+努力會在短時間內得到回報。開發社區總是需要能讓內核變更好的開發人員;下面的
+文字應該幫助您或爲您工作的人員加入我們的社區。
+
+致謝
+----
+
+本文檔由Jonathan Corbet <corbet@lwn.net> 撰寫。以下人員的建議使之更爲完善:
+Johannes Berg, James Berry, Alex Chiang, Roland Dreier, Randy Dunlap,
+Jake Edge, Jiri Kosina, Matt Mackall, Arthur Marsh, Amanda McPherson,
+Andrew Morton, Andrew Price, Tsugikazu Shibata 和 Jochen Voß 。
+
+這項工作得到了Linux基金會的支持,特別感謝Amanda McPherson,他看到了這項工作
+的價值並將其變成現實。
+
+代碼進入主線的重要性
+--------------------
+
+有些公司和開發人員偶爾會想,爲什麼他們要費心學習如何與內核社區合作,並將代碼
+放入主線內核(“主線”是由Linus Torvalds維護的內核,Linux發行商將其用作基礎)。
+在短期內,貢獻代碼看起來像是一種可以避免的開銷;維護獨立代碼並直接支持用戶
+似乎更容易。事實上,保持代碼獨立(“樹外”)是在經濟上是錯誤的。
+
+爲了說明樹外代碼成本,下面給出內核開發過程的一些相關方面;本文稍後將更詳細地
+討論其中的大部分內容。請考慮:
+
+- 所有Linux用戶都可以使用合併到主線內核中的代碼。它將自動出現在所有啓用它的
+ 發行版上。無需驅動程序磁盤、額外下載,也不需要爲多個發行版的多個版本提供
+ 支持;這一切將方便所有開發人員和用戶。併入主線解決了大量的分發和支持問題。
+
+- 當內核開發人員努力維護一個穩定的用戶空間接口時,內核內部API處於不斷變化之中。
+ 不維持穩定的內部接口是一個慎重的設計決策;它允許在任何時候進行基本的改進,
+ 併產出更高質量的代碼。但該策略導致結果是,若要使用新的內核,任何樹外代碼都
+ 需要持續的維護。維護樹外代碼會需要大量的工作才能使代碼保持正常運行。
+
+ 相反,位於主線中的代碼不需要這樣做,因爲基本規則要求進行API更改的任何開發
+ 人員也必須修復由於該更改而破壞的任何代碼。因此,合併到主線中的代碼大大降低
+ 了維護成本。
+
+- 除此之外,內核中的代碼通常會被其他開發人員改進。您授權的用戶社區和客戶對您
+ 產品的改進可能會令人驚喜。
+
+- 內核代碼在合併到主線之前和之後都要經過審查。無論原始開發人員的技能有多強,
+ 這個審查過程總是能找到改進代碼的方法。審查經常發現嚴重的錯誤和安全問題。
+ 對於在封閉環境中開發的代碼尤其如此;這種代碼從外部開發人員的審查中獲益匪淺。
+ 樹外代碼是低質量代碼。
+
+- 參與開發過程是您影響內核開發方向的方式。旁觀者的抱怨會被聽到,但是活躍的
+ 開發人員有更強的聲音——並且能夠實現使內核更好地滿足其需求的更改。
+
+- 當單獨維護代碼時,總是存在第三方爲類似功能提供不同實現的可能性。如果發生
+ 這種情況,合併代碼將變得更加困難——甚至成爲不可能。之後,您將面臨以下令人
+ 不快的選擇:(1)無限期地維護樹外的非標準特性,或(2)放棄代碼並將用戶遷移
+ 到樹內版本。
+
+- 代碼的貢獻是使整個流程工作的根本。通過貢獻代碼,您可以向內核添加新功能,並
+ 提供其他內核開發人員使用的功能和示例。如果您已經爲Linux開發了代碼(或者正在
+ 考慮這樣做),那麼您顯然對這個平臺的持續成功感興趣;貢獻代碼是確保成功的
+ 最好方法之一。
+
+上述所有理由都適用於任何樹外內核代碼,包括以專有的、僅二進制形式分發的代碼。
+然而,在考慮任何類型的純二進制內核代碼分佈之前,還需要考慮其他因素。包括:
+
+- 圍繞專有內核模塊分發的法律問題其實較爲模糊;相當多的內核版權所有者認爲,
+ 大多數僅二進制的模塊是內核的派生產品,因此,它們的分發違反了GNU通用公共
+ 許可證(下面將詳細介紹)。本文作者不是律師,本文檔中的任何內容都不可能被
+ 視爲法律建議。封閉源代碼模塊的真實法律地位只能由法院決定。但不管怎樣,困擾
+ 這些模塊的不確定性仍然存在。
+
+- 二進制模塊大大增加了調試內核問題的難度,以至於大多數內核開發人員甚至都不會
+ 嘗試。因此,只分發二進制模塊將使您的用戶更難從社區獲得支持。
+
+- 對於僅二進制的模塊的發行者來說,支持也更加困難,他們必須爲他們希望支持的
+ 每個發行版和每個內核版本提供不同版本的模塊。爲了提供較爲全面的覆蓋範圍,
+ 可能需要一個模塊的幾十個構建,並且每次升級內核時,您的用戶都必須單獨升級
+ 這些模塊。
+
+- 上面提到的關於代碼評審的所有問題都更加存在於封閉源代碼中。由於該代碼根本
+ 不可得,因此社區無法對其進行審查,毫無疑問,它將存在嚴重問題。
+
+尤其是嵌入式系統的製造商,可能會傾向於忽視本節中所說的大部分內容;因爲他們
+相信自己正在商用一種使用凍結內核版本的獨立產品,在發佈後不需要再進行開發。
+這個論點忽略了廣泛的代碼審查的價值以及允許用戶向產品添加功能的價值。但這些
+產品的商業壽命有限,之後必須發佈新版本的產品。在這一點上,代碼在主線上並得到
+良好維護的供應商將能夠更好地佔位,以使新產品快速上市。
+
+許可
+----
+
+代碼是根據一些許可證提供給Linux內核的,但是所有代碼都必須與GNU通用公共許可
+證(GPLV2)的版本2兼容,該版本是覆蓋整個內核分發的許可證。在實踐中,這意味
+着所有代碼貢獻都由GPLv2(可選地,語言允許在更高版本的GPL下分發)或3子句BSD
+許可(New BSD License,譯者注)覆蓋。任何不包含在兼容許可證中的貢獻都不會
+被接受到內核中。
+
+貢獻給內核的代碼不需要(或請求)版權分配。合併到主線內核中的所有代碼都保留
+其原始所有權;因此,內核現在擁有數千個所有者。
+
+這種所有權結構也暗示着,任何改變內核許可的嘗試都註定會失敗。很少有實際情況
+可以獲得所有版權所有者的同意(或者從內核中刪除他們的代碼)。因此,尤其是在
+可預見的將來,許可證不大可能遷移到GPL的版本3。
+
+所有貢獻給內核的代碼都必須是合法的免費軟件。因此,不接受匿名(或化名)貢獻
+者的代碼。所有貢獻者都需要在他們的代碼上“sign off(簽發)”,聲明代碼可以
+在GPL下與內核一起分發。無法提供未被其所有者許可爲免費軟件的代碼,或可能爲
+內核造成版權相關問題的代碼(例如,由缺乏適當保護的反向工程工作派生的代碼)
+不能被接受。
+
+有關版權問題的提問在Linux開發郵件列表中很常見。這樣的問題通常會得到不少答案,
+但請記住,回答這些問題的人不是律師,不能提供法律諮詢。如果您有關於Linux源代碼
+的法律問題,沒有什麼可以代替諮詢瞭解這一領域的律師。依賴從技術郵件列表中獲得
+的答案是一件冒險的事情。
+
+
diff --git a/Documentation/translations/zh_TW/process/2.Process.rst b/Documentation/translations/zh_TW/process/2.Process.rst
new file mode 100644
index 000000000000..f45ddba6238f
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/2.Process.rst
@@ -0,0 +1,369 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/2.Process.rst <development_process>`
+
+:Translator:
+
+ 時奎亮 Alex Shi <alex.shi@linux.alibaba.com>
+
+:校譯:
+
+ 吳想成 Wu XiangCheng <bobwxc@email.cn>
+ 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+.. _tw_development_process:
+
+開發流程如何進行
+================
+
+90年代早期的Linux內核開發是一件相當鬆散的事情,涉及的用戶和開發人員相對較少。
+由於擁有數以百萬計的用戶羣,且每年有大約2000名開發人員參與進來,內核因此必須
+發展出許多既定流程來保證開發的順利進行。要參與到流程中來,需要對此流程的進行
+方式有一個紮實的理解。
+
+總覽
+----
+
+內核開發人員使用一個鬆散的基於時間的發佈過程,每兩到三個月發佈一次新的主要
+內核版本。最近的發佈歷史記錄如下:
+
+ ====== =================
+ 5.0 2019年3月3日
+ 5.1 2019年5月5日
+ 5.2 2019年7月7日
+ 5.3 2019年9月15日
+ 5.4 2019年11月24日
+ 5.5 2020年1月6日
+ ====== =================
+
+每個5.x版本都是一個主要的內核版本,具有新特性、內部API更改等等。一個典型的5.x
+版本包含大約13000個變更集,變更了幾十萬行代碼。因此,5.x是Linux內核開發的前
+沿;內核使用滾動開發模型,不斷集成重大變化。
+
+對於每個版本的補丁合併,遵循一個相對簡單的規則。在每個開發週期的開頭,“合併
+窗口”被打開。這時,被認爲足夠穩定(並且被開發社區接受)的代碼被合併到主線內
+核中。在這段時間內,新開發週期的大部分變更(以及所有主要變更)將以接近每天
+1000次變更(“補丁”或“變更集”)的速度合併。
+
+(順便說一句,值得注意的是,合併窗口期間集成的更改並不是憑空產生的;它們是經
+提前收集、測試和分級的。稍後將詳細描述該過程的工作方式。)
+
+合併窗口持續大約兩週。在這段時間結束時,Linus Torvalds將聲明窗口已關閉,並
+釋放第一個“rc”內核。例如,對於目標爲5.6的內核,在合併窗口結束時發生的釋放
+將被稱爲5.6-rc1。-rc1 版本是一個信號,表示合併新特性的時間已經過去,穩定下一
+個內核的時間已經到來。
+
+在接下來的6到10周內,只有修復問題的補丁才應該提交給主線。有時會允許更大的
+更改,但這種情況很少發生;試圖在合併窗口外合併新功能的開發人員往往受不到
+友好的接待。一般來說,如果您錯過了給定特性的合併窗口,最好的做法是等待下一
+個開發週期。(偶爾會對未支持硬件的驅動程序進行例外;如果它們不改變已有代碼,
+則不會導致迴歸,應該可以隨時被安全地加入)。
+
+隨着修復程序進入主線,補丁速度將隨着時間的推移而變慢。Linus大約每週發佈一次
+新的-rc內核;在內核被認爲足夠穩定並最終發佈前,一般會達到-rc6到-rc9之間。
+然後,整個過程又重新開始了。
+
+例如,這裏是5.4的開發週期進行情況(2019年):
+
+ ============== ==============================
+ 九月 15 5.3 穩定版發佈
+ 九月 30 5.4-rc1 合併窗口關閉
+ 十月 6 5.4-rc2
+ 十月 13 5.4-rc3
+ 十月 20 5.4-rc4
+ 十月 27 5.4-rc5
+ 十一月 3 5.4-rc6
+ 十一月 10 5.4-rc7
+ 十一月 17 5.4-rc8
+ 十一月 24 5.4 穩定版發佈
+ ============== ==============================
+
+開發人員如何決定何時結束開發週期並創建穩定版本?最重要的指標是以前版本的
+迴歸列表。不歡迎出現任何錯誤,但是那些破壞了以前能工作的系統的錯誤被認爲是
+特別嚴重的。因此,導致迴歸的補丁是不受歡迎的,很可能在穩定期內刪除。
+
+開發人員的目標是在穩定發佈之前修復所有已知的迴歸。在現實世界中,這種完美是
+很難實現的;在這種規模的項目中,變數太多了。需要說明的是,延遲最終版本只會
+使問題變得更糟;等待下一個合併窗口的更改將變多,導致下次出現更多的迴歸錯誤。
+因此,大多數5.x內核都有一些已知的迴歸錯誤,不過,希望沒有一個是嚴重的。
+
+一旦一個穩定的版本發佈,它的持續維護工作就被移交給“穩定團隊”,目前由
+Greg Kroah-Hartman領導。穩定團隊將使用5.x.y編號方案不定期地發佈穩定版本的
+更新。要合入更新版本,補丁必須(1)修復一個重要的缺陷,且(2)已經合併到
+下一個開發版本主線中。內核通常會在其初始版本後的一個以上的開發週期內收到
+穩定版更新。例如,5.2內核的歷史如下(2019年):
+
+ ============== ===============================
+ 七月 7 5.2 穩定版發佈
+ 七月 13 5.2.1
+ 七月 21 5.2.2
+ 七月 26 5.2.3
+ 七月 28 5.2.4
+ 七月 31 5.2.5
+ ... ...
+ 十月 11 5.2.21
+ ============== ===============================
+
+5.2.21是5.2版本的最終穩定更新。
+
+有些內核被指定爲“長期”內核;它們將得到更長時間的支持。在本文中,當前的長期
+內核及其維護者是:
+
+ ====== ================================ ================
+ 3.16 Ben Hutchings (長期穩定內核)
+ 4.4 Greg Kroah-Hartman & Sasha Levin (長期穩定內核)
+ 4.9 Greg Kroah-Hartman & Sasha Levin
+ 4.14 Greg Kroah-Hartman & Sasha Levin
+ 4.19 Greg Kroah-Hartman & Sasha Levin
+ 5.4 Greg Kroah-Hartman & Sasha Levin
+ ====== ================================ ================
+
+長期支持內核的選擇純粹是維護人員是否有需求和時間來維護該版本的問題。
+目前還沒有爲即將發佈的任何特定版本提供長期支持的已知計劃。
+
+補丁的生命週期
+--------------
+
+補丁不會直接從開發人員的鍵盤進入主線內核。相反,有一個稍微複雜(如果有些非
+正式)的過程,旨在確保對每個補丁進行質量審查,並確保每個補丁實現了一個在主線
+中需要的更改。對於小的修復,這個過程可能會很快完成,,而對於較大或有爭議的
+變更,可能會持續數年。許多開發人員的沮喪來自於對這個過程缺乏理解或者試圖繞過它。
+
+爲了減少這種挫敗,本文將描述補丁如何進入內核。下面的介紹以一種較爲理想化的
+方式描述了這個過程。更詳細的過程將在後面的章節中介紹。
+
+補丁通常要經歷以下階段:
+
+- 設計。這就是補丁的真正需求——以及滿足這些需求的方式——所在。設計工作通常
+ 是在不涉及社區的情況下完成的,但是如果可能的話,最好是在公開的情況下完成
+ 這項工作;這樣可以節省很多稍後再重新設計的時間。
+
+- 早期評審。補丁被髮布到相關的郵件列表中,列表中的開發人員會回覆他們可能有
+ 的任何評論。如果一切順利的話,這個過程應該會發現補丁的任何主要問題。
+
+- 更廣泛的評審。當補丁接近準備好納入主線時,它應該被相關的子系統維護人員
+ 接受——儘管這種接受並不能保證補丁會一直延伸到主線。補丁將出現在維護人員的
+ 子系統樹中,並進入 -next 樹(如下所述)。當流程進行時,此步驟將會對補丁
+ 進行更廣泛的審查,並發現由於將此補丁與其他人所做的工作合併而導致的任何
+ 問題。
+
+- 請注意,大多數維護人員也有日常工作,因此合併補丁可能不是他們的最優先工作。
+ 如果您的補丁得到了需要更改的反饋,那麼您應該進行這些更改,或者解釋爲何
+ 不應該進行這些更改。如果您的補丁沒有評審意見,也沒有被其相應的子系統或
+ 驅動程序維護者接受,那麼您應該堅持不懈地將補丁更新到當前內核使其可被正常
+ 應用,並不斷地發送它以供審查和合並。
+
+- 合併到主線。最終,一個成功的補丁將被合併到由LinusTorvalds管理的主線存儲庫
+ 中。此時可能會出現更多的評論和/或問題;對開發人員來說應對這些問題並解決
+ 出現的任何問題仍很重要。
+
+- 穩定版發佈。大量用戶可能受此補丁影響,因此可能再次出現新的問題。
+
+- 長期維護。雖然開發人員在合併代碼後可能會忘記代碼,但這種行爲往往會給開發
+ 社區留下不良印象。合併代碼消除了一些維護負擔,因爲其他人將修復由API更改
+ 引起的問題。但是,如果代碼要長期保持可用,原始開發人員應該繼續爲代碼負責。
+
+內核開發人員(或他們的僱主)犯的最大錯誤之一是試圖將流程簡化爲一個“合併到
+主線”步驟。這種方法總是會讓所有相關人員感到沮喪。
+
+補丁如何進入內核
+----------------
+
+只有一個人可以將補丁合併到主線內核存儲庫中:Linus Torvalds。但是,在進入
+2.6.38內核的9500多個補丁中,只有112個(大約1.3%)是由Linus自己直接選擇的。
+內核項目已經發展到一個沒有一個開發人員可以在沒有支持的情況下檢查和選擇每個
+補丁的規模。內核開發人員處理這種增長的方式是使用圍繞信任鏈構建的助理系統。
+
+內核代碼庫在邏輯上被分解爲一組子系統:網絡、特定體系結構支持、內存管理、視
+頻設備等。大多數子系統都有一個指定的維護人員,其總體負責該子系統中的代碼。
+這些子系統維護者(鬆散地)是他們所管理的內核部分的“守門員”;他們(通常)
+會接受一個補丁以包含到主線內核中。
+
+子系統維護人員每個人都管理着自己版本的內核源代碼樹,通常(並非總是)使用Git。
+Git等工具(以及Quilt或Mercurial等相關工具)允許維護人員跟蹤補丁列表,包括作者
+信息和其他元數據。在任何給定的時間,維護人員都可以確定他或她的存儲庫中的哪
+些補丁在主線中找不到。
+
+當合並窗口打開時,頂級維護人員將要求Linus從存儲庫中“拉出”他們爲合併選擇
+的補丁。如果Linus同意,補丁流將流向他的存儲庫,成爲主線內核的一部分。
+Linus對拉取中接收到的特定補丁的關注程度各不相同。很明顯,有時他看起來很
+關注。但是一般來說,Linus相信子系統維護人員不會向上遊發送壞補丁。
+
+子系統維護人員反過來也可以從其他維護人員那裏獲取補丁。例如,網絡樹是由首先
+在專用於網絡設備驅動程序、無線網絡等的樹中積累的補丁構建的。此存儲鏈可以
+任意長,但很少超過兩個或三個鏈接。由於鏈中的每個維護者都信任那些管理較低
+級別樹的維護者,所以這個過程稱爲“信任鏈”。
+
+顯然,在這樣的系統中,獲取內核補丁取決於找到正確的維護者。直接向Linus發送
+補丁通常不是正確的方法。
+
+Next 樹
+-------
+
+子系統樹鏈引導補丁流到內核,但它也提出了一個有趣的問題:如果有人想查看爲
+下一個合併窗口準備的所有補丁怎麼辦?開發人員將感興趣的是,還有什麼其他的
+更改有待解決,以瞭解是否存在需要擔心的衝突;例如,更改核心內核函數原型的
+修補程序將與使用該函數舊形式的任何其他修補程序衝突。審查人員和測試人員希望
+在所有這些變更到達主線內核之前,能夠訪問它們的集成形式的變更。您可以從所有
+相關的子系統樹中提取更改,但這將是一項複雜且容易出錯的工作。
+
+解決方案以-next樹的形式出現,在這裏子系統樹被收集以供測試和審查。這些樹中
+由Andrew Morton維護的較老的一個,被稱爲“-mm”(用於內存管理,創建時爲此)。
+-mm 樹集成了一長串子系統樹中的補丁;它還包含一些旨在幫助調試的補丁。
+
+除此之外,-mm 還包含大量由Andrew直接選擇的補丁。這些補丁可能已經發布在郵件
+列表上,或者它們可能應用於內核中未指定子系統樹的部分。同時,-mm 作爲最後
+手段的子系統樹;如果沒有其他明顯的路徑可以讓補丁進入主線,那麼它很可能最
+終選擇-mm 樹。累積在-mm 中的各種補丁最終將被轉發到適當的子系統樹,或者直接
+發送到Linus。在典型的開發週期中,大約5-10%的補丁通過-mm 進入主線。
+
+當前-mm 補丁可在“mmotm”(-mm of the moment)目錄中找到:
+
+ https://www.ozlabs.org/~akpm/mmotm/
+
+然而,使用MMOTM樹可能會十分令人頭疼;它甚至可能無法編譯。
+
+下一個週期補丁合併的主要樹是linux-next,由Stephen Rothwell 維護。根據設計
+linux-next 是下一個合併窗口關閉後主線的快照。linux-next樹在Linux-kernel 和
+Linux-next 郵件列表中發佈,可從以下位置下載:
+
+ https://www.kernel.org/pub/linux/kernel/next/
+
+Linux-next 已經成爲內核開發過程中不可或缺的一部分;在一個給定的合併窗口中合併
+的所有補丁都應該在合併窗口打開之前的一段時間內找到進入Linux-next 的方法。
+
+Staging 樹
+----------
+
+內核源代碼樹包含drivers/staging/目錄,其中有許多驅動程序或文件系統的子目錄
+正在被添加到內核樹中。它們在仍然需要更多的修正的時候可以保留在driver/staging/
+目錄中;一旦完成,就可以將它們移到內核中。這是一種跟蹤不符合Linux內核編碼或
+質量標準的驅動程序的方法,人們可能希望使用它們並跟蹤開發。
+
+Greg Kroah Hartman 目前負責維護staging 樹。仍需要修正的驅動程序將發送給他,
+每個驅動程序在drivers/staging/中都有自己的子目錄。除了驅動程序源文件之外,
+目錄中還應該有一個TODO文件。TODO文件列出了驅動程序需要接受的暫停的工作,
+以及驅動程序的任何補丁都應該抄送的人員列表。當前的規則要求,staging的驅動
+程序必須至少正確編譯。
+
+Staging 是一種讓新的驅動程序進入主線的相對容易的方法,它們會幸運地引起其他
+開發人員的注意,並迅速改進。然而,進入staging並不是故事的結尾;staging中
+沒有看到常規進展的代碼最終將被刪除。經銷商也傾向於相對不願意使用staging驅動
+程序。因此,在成爲一個合適的主線驅動的路上,staging 僅是一箇中轉站。
+
+工具
+----
+
+從上面的文本可以看出,內核開發過程在很大程度上依賴於在不同方向上聚集補丁的
+能力。如果沒有適當強大的工具,整個系統將無法在任何地方正常工作。關於如何使用
+這些工具的教程遠遠超出了本文檔的範圍,但還是用一點篇幅介紹一些關鍵點。
+
+到目前爲止,內核社區使用的主要源代碼管理系統是git。Git是在自由軟件社區中開發
+的許多分佈式版本控制系統之一。它非常適合內核開發,因爲它在處理大型存儲庫和
+大量補丁時性能非常好。它也以難以學習和使用而著稱,儘管隨着時間的推移它變得
+更好了。對於內核開發人員來說,對Git的某種熟悉幾乎是一種要求;即使他們不將它
+用於自己的工作,他們也需要Git來跟上其他開發人員(以及主線)正在做的事情。
+
+現在幾乎所有的Linux發行版都打包了Git。Git主頁位於:
+
+ https://git-scm.com/
+
+此頁面包含了文檔和教程的鏈接。
+
+在不使用git的內核開發人員中,最流行的選擇幾乎肯定是Mercurial:
+
+ http://www.seleric.com/mercurial/
+
+Mercurial與Git共享許多特性,但它提供了一個界面,許多人覺得它更易於使用。
+
+另一個值得了解的工具是Quilt:
+
+ https://savannah.nongnu.org/projects/quilt
+
+Quilt 是一個補丁管理系統,而不是源代碼管理系統。它不會隨着時間的推移跟蹤歷史;
+相反,它面向根據不斷發展的代碼庫跟蹤一組特定的更改。一些主要的子系統維護人員
+使用Quilt來管理打算向上遊移動的補丁。對於某些樹的管理(例如-mm),quilt 是
+最好的工具。
+
+郵件列表
+--------
+
+大量的Linux內核開發工作是通過郵件列表完成的。如果不加入至少一個某個列表,
+就很難成爲社區中的一個“全功能”成員。但是,Linux郵件列表對開發人員來說也是
+一個潛在的危險,他們可能會被一堆電子郵件淹沒、違反Linux列表上使用的約定,
+或者兩者兼而有之。
+
+大多數內核郵件列表都在vger.kernel.org上運行;主列表位於:
+
+ http://vger.kernel.org/vger-lists.html
+
+不過,也有一些列表託管在別處;其中一些列表位於
+redhat.com/mailman/listinfo。
+
+當然,內核開發的核心郵件列表是linux-kernel。這個列表是一個令人生畏的地方:
+每天的信息量可以達到500條,噪音很高,談話技術性很強,且參與者並不總是表現出
+高度的禮貌。但是,沒有其他地方可以讓內核開發社區作爲一個整體聚集在一起;
+不使用此列表的開發人員將錯過重要信息。
+
+以下一些提示可以幫助在linux-kernel生存:
+
+- 將郵件轉移到單獨的文件夾,而不是主郵箱文件夾。我們必須能夠持續地忽略洪流。
+
+- 不要試圖跟上每一次談話——沒人會這樣。重要的是要篩選感興趣的主題(但請注意
+ 長時間的對話可能會偏離原來的主題,儘管未改變電子郵件的主題)和參與的人。
+
+- 不要回復挑事的人。如果有人試圖激起憤怒,請忽略他們。
+
+- 當回覆Linux內核電子郵件(或其他列表上的電子郵件)時,請爲所有相關人員保留
+ Cc: 抄送頭。如果沒有確實的理由(如明確的請求),則不應刪除收件人。一定要
+ 確保你要回復的人在抄送列表中。這個慣例也使你不必在回覆郵件時明確要求被抄送。
+
+- 在提出問題之前,搜索列表存檔(和整個網絡)。有些開發人員可能會對那些顯然
+ 沒有完成家庭作業的人感到不耐煩。
+
+- 避免頂部回覆(把你的答案放在你要回復的引文上面的做法)。這會讓你的回答更難
+ 理解,印象也很差。
+
+- 在正確的郵件列表發問。linux-kernel 可能是通用的討論場所,但它不是尋找所有
+ 子系統開發人員的最佳場所。
+
+最後一點——找到正確的郵件列表——是開發人員常出錯的地方。在linux-kernel上
+提出與網絡相關的問題的人幾乎肯定會收到一個禮貌的建議,轉到netdev列表上提出,
+因爲這是大多數網絡開發人員經常出現的列表。還有其他列表可用於scsi、video4linux、
+ide、filesystem等子系統。查找郵件列表的最佳位置是與內核源代碼一起打包的
+MAINTAINERS文件。
+
+開始內核開發
+------------
+
+關於如何開始內核開發過程的問題很常見——個人和公司皆然。同樣常見的是失誤,這
+使得關係的開始比本應的更困難。
+
+公司通常希望聘請知名的開發人員來啓動開發團隊。實際上,這是一種有效的技術。
+但它也往往是昂貴的,而且對增加有經驗的內核開發人員的數量沒有多大幫助。考
+慮到時間投入,可以讓內部開發人員加快Linux內核的開發速度。利用這段時間可以
+讓僱主擁有一批既瞭解內核又瞭解公司的開發人員,還可以幫助培訓其他人。從中期
+來看,這通常是更有利可圖的方法。
+
+可以理解的是,單個開發人員往往對起步感到茫然。從一個大型項目開始可能會很
+嚇人;人們往往想先用一些較小的東西來試試水。由此,一些開發人員開始創建修補
+拼寫錯誤或輕微編碼風格問題的補丁。不幸的是,這樣的補丁會產生一定程度的噪音,
+這會分散整個開發社區的注意力,因此,它們越來越被人不看重。希望向社區介紹
+自己的新開發人員將無法通過這些方式獲得他們期待的反響。
+
+Andrew Morton 爲有抱負的內核開發人員提供瞭如下建議
+
+::
+
+ 所有內核開發者的第一個項目肯定應該是“確保內核在您可以操作的所有
+ 機器上始終完美運行”。通常的方法是和其他人一起解決問題(這可能需
+ 要堅持!),但就是如此——這是內核開發的一部分。
+
+(http://lwn.net/Articles/283982/)
+
+在沒有明顯問題需要解決的情況下,通常建議開發人員查看當前的迴歸和開放缺陷
+列表。從來都不缺少需要解決的問題;通過解決這些問題,開發人員將從該過程獲得
+經驗,同時與開發社區的其他成員建立相互尊重。
+
diff --git a/Documentation/translations/zh_TW/process/3.Early-stage.rst b/Documentation/translations/zh_TW/process/3.Early-stage.rst
new file mode 100644
index 000000000000..a58fc9e0ea99
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/3.Early-stage.rst
@@ -0,0 +1,172 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/3.Early-stage.rst <development_early_stage>`
+
+:Translator:
+
+ 時奎亮 Alex Shi <alex.shi@linux.alibaba.com>
+
+:校譯:
+
+ 吳想成 Wu XiangCheng <bobwxc@email.cn>
+ 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+.. _tw_development_early_stage:
+
+早期規劃
+========
+
+當考慮一個Linux內核開發項目時,很可能會直接跳進去開始編碼。然而,與任何重要
+的項目一樣,許多成功的基礎最好是在第一行代碼編寫之前就打下。在早期計劃和
+溝通中花費一些時間可以在之後節省更多的時間。
+
+搞清問題
+--------
+
+與任何工程項目一樣,成功的內核改善從清晰描述要解決的問題開始。在某些情況
+下,這個步驟很容易:例如當某個特定硬件需要驅動程序時。不過,在其他情況下,
+很容易將實際問題與建議的解決方案混在一起,這可能會導致麻煩。
+
+舉個例子:幾年前,Linux音頻的開發人員尋求一種方法來運行應用程序,而不會因
+系統延遲過大而導致退出或其他問題。他們得到的解決方案是一個連接到Linux安全
+模塊(LSM)框架中的內核模塊;這個模塊可以配置爲允許特定的應用程序訪問實時
+調度程序。這個模塊被實現併發到linux-kernel郵件列表,在那裏它立即遇到了麻煩。
+
+對於音頻開發人員來說,這個安全模塊足以解決他們當前的問題。但是,對於更廣泛的
+內核社區來說,這被視爲對LSM框架的濫用(LSM框架並不打算授予他們原本不具備的
+進程特權),並對系統穩定性造成風險。他們首選的解決方案包括短期的通過rlimit
+機制進行實時調度訪問,以及長期的減少延遲的工作。
+
+然而,音頻社區無法超越他們實施的特定解決方案來看問題;他們不願意接受替代方案。
+由此產生的分歧使這些開發人員對整個內核開發過程感到失望;其中一個開發人員返回
+到audio列表併發布了以下內容:
+
+ 有很多非常好的Linux內核開發人員,但他們往往會被一羣傲慢的傻瓜所壓倒。
+ 試圖向這些人傳達用戶需求是浪費時間。他們太“聰明”了,根本聽不到少數
+ 人的話。
+
+(http://lwn.net/Articles/131776/)
+
+實際情況卻是不同的;與特定模塊相比,內核開發人員更關心繫統穩定性、長期維護
+以及找到問題的正確解決方案。這個故事的寓意是把重點放在問題上——而不是具體的
+解決方案上——並在開始編寫代碼之前與開發社區討論這個問題。
+
+因此,在考慮一個內核開發項目時,我們應該得到一組簡短問題的答案:
+
+ - 需要解決的問題究竟是什麼?
+
+ - 受此問題影響的用戶有哪些?解決方案應該解決哪些使用案例?
+
+ - 內核現在爲何沒能解決這個問題?
+
+只有這樣,才能開始考慮可能的解決方案。
+
+
+早期討論
+--------
+
+在計劃內核開發項目時,在開始實施之前與社區進行討論是很有意義的。早期溝通可以
+通過多種方式節省時間和麻煩:
+
+ - 很可能問題是由內核以您不理解的方式解決的。Linux內核很大,具有許多不明顯
+ 的特性和功能。並不是所有的內核功能都像人們所希望的那樣有文檔記錄,而且很
+ 容易遺漏一些東西。某作者發佈了一個完整的驅動程序,重複了一個其不
+ 知道的現有驅動程序。重新發明現有輪子的代碼不僅浪費,而且不會被接受到主線
+ 內核中。
+
+ - 建議的解決方案中可能有一些要素不適合併入主線。在編寫代碼之前,最好先了解
+ 這樣的問題。
+
+ - 其他開發人員完全有可能考慮過這個問題;他們可能有更好的解決方案的想法,並且
+ 可能願意幫助創建這個解決方案。
+
+在內核開發社區的多年經驗給了我們一個明確的教訓:閉門設計和開發的內核代碼總是
+有一些問題,這些問題只有在代碼發佈到社區中時纔會被發現。有時這些問題很嚴重,
+需要數月或數年的努力才能使代碼達到內核社區的標準。例如:
+
+ - 設計並實現了單處理器系統的DeviceScape網絡棧。只有使其適合於多處理器系統,
+ 才能將其合併到主線中。在代碼中修改鎖等等是一項困難的任務;因此,這段代碼
+ (現在稱爲mac80211)的合併被推遲了一年多。
+
+ - Reiser4文件系統包含許多功能,核心內核開發人員認爲這些功能應該在虛擬文件
+ 系統層中實現。它還包括一些特性,這些特性在不將系統暴露於用戶引起的死鎖的
+ 情況下是不容易實現的。這些問題過遲發現——以及拒絕處理其中一些問題——已經
+ 導致Reiser4置身主線內核之外。
+
+ - Apparmor安全模塊以被認爲不安全和不可靠的方式使用內部虛擬文件系統數據結構。
+ 這種擔心(包括其他)使Apparmor多年來無法進入主線。
+
+在這些情況下,與內核開發人員的早期討論,可以避免大量的痛苦和額外的工作。
+
+找誰交流?
+----------
+
+當開發人員決定公開他們的計劃時,下一個問題是:我們從哪裏開始?答案是找到正確
+的郵件列表和正確的維護者。對於郵件列表,最好的方法是在維護者(MAINTAINERS)文件
+中查找要發佈的相關位置。如果有一個合適的子系統列表,那麼其上發佈通常比在
+linux-kernel上發佈更可取;您更有可能接觸到在相關子系統中具有專業知識的開發
+人員,並且環境可能具支持性。
+
+找到維護人員可能會有點困難。同樣,維護者文件是開始的地方。但是,該文件往往不
+是最新的,並且並非所有子系統都在那裏顯示。實際上,維護者文件中列出的人員可能
+不是當前實際擔任該角色的人員。因此,當對聯繫誰有疑問時,一個有用的技巧是使用
+git(尤其是“git-log”)查看感興趣的子系統中當前活動的用戶。看看誰在寫補丁、
+誰會在這些補丁上加上Signed-off-by行簽名(如有)。這些人將是幫助新開發項目的
+最佳人選。
+
+找到合適的維護者有時是非常具有挑戰性的,以至於內核開發人員添加了一個腳本來
+簡化這個過程:
+
+::
+
+ .../scripts/get_maintainer.pl
+
+當給定“-f”選項時,此腳本將返回指定文件或目錄的當前維護者。如果在命令行上
+給出了一個補丁,它將列出可能接收補丁副本的維護人員。有許多選項可以調節
+get_maintainer.pl搜索維護者的嚴格程度;請小心使用更激進的選項,因爲最終結果
+可能會包括對您正在修改的代碼沒有真正興趣的開發人員。
+
+如果所有其他方法都失敗了,那麼與Andrew Morton交流是跟蹤特定代碼段維護人員
+的一種有效方法。
+
+何時郵寄?
+----------
+
+如果可能的話,在早期階段發佈你的計劃只會更有幫助。描述正在解決的問題以及已經
+制定的關於如何實施的任何計劃。您可以提供的任何信息都可以幫助開發社區爲項目
+提供有用的輸入。
+
+在這個階段可能發生的一件令人沮喪的事情不是得到反對意見,而是很少或根本沒有
+反饋。令人傷心的事實是:(1)內核開發人員往往很忙;(2)不缺少有宏偉計劃但
+代碼(甚至代碼設想)很少的人去支持他們;(3)沒有人有義務審查或評論別人發表
+的想法。除此之外,高層級的設計常常隱藏着一些問題,這些問題只有在有人真正嘗試
+實現這些設計時纔會被發現;因此,內核開發人員寧願看到代碼。
+
+如果發佈請求評論(RFC)並沒得到什麼有用的評論,不要以爲這意味着無人對此項目
+有興趣,同時你也不能假設你的想法沒有問題。在這種情況下,最好的做法是繼續進
+行,把你的進展隨時通知社區。
+
+獲得官方認可
+-----------------------
+
+如果您的工作是在公司環境中完成的,就像大多數Linux內核工作一樣;顯然,在您將
+公司的計劃或代碼發佈到公共郵件列表之前,必須獲得有適當權利經理的許可。發佈
+不確定是否兼容GPL的代碼尤其會帶來問題;公司的管理層和法律人員越早能夠就發佈
+內核開發項目達成一致,對參與的每個人都越好。
+
+一些讀者可能會認爲他們的核心工作是爲了支持還沒有正式承認存在的產品。將僱主
+的計劃公佈在公共郵件列表上可能不是一個可行的選擇。在這種情況下,有必要考慮
+保密是否真的是必要的;通常不需要把開發計劃關在門內。
+
+的確,有些情況下一家公司在開發過程的早期無法合法地披露其計劃。擁有經驗豐富
+的內核開發人員的公司可能選擇以開環的方式進行開發,前提是他們以後能夠避免
+嚴重的集成問題。對於沒有這種內部專業知識的公司,最好的選擇往往是聘請外部
+開發者根據保密協議審查計劃。Linux基金會運行了一個NDA程序,旨在幫助解決這種
+情況;更多信息參見:
+
+ http://www.linuxfoundation.org/nda/
+
+這種審查通常足以避免以後出現嚴重問題,而無需公開披露項目。
+
diff --git a/Documentation/translations/zh_TW/process/4.Coding.rst b/Documentation/translations/zh_TW/process/4.Coding.rst
new file mode 100644
index 000000000000..bdd2abe4daf4
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/4.Coding.rst
@@ -0,0 +1,297 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/4.Coding.rst <development_coding>`
+
+:Translator:
+
+ 時奎亮 Alex Shi <alex.shi@linux.alibaba.com>
+
+:校譯:
+
+ 吳想成 Wu XiangCheng <bobwxc@email.cn>
+ 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+.. _tw_development_coding:
+
+使代碼正確
+======================
+
+雖然一個堅實的、面向社區的設計過程有很多值得說道的,但是任何內核開發項目工作
+的證明都反映在代碼中。它是將由其他開發人員檢查併合並(或不合並)到主線樹中
+的代碼。所以這段代碼的質量決定了項目的最終成功。
+
+本節將檢查編碼過程。我們將從內核開發人員常犯的幾種錯誤開始。然後重點將轉移
+到正確的做法和相關有用的工具上。
+
+陷阱
+----
+
+代碼風格
+********
+
+內核長期以來都有其標準的代碼風格,如
+:ref:`Documentation/translations/zh_CN/process/coding-style.rst <tw_codingstyle>`
+中所述。在多數時候,該文檔中描述的準則至多被認爲是建議性的。因此,內核中存在
+大量不符合代碼風格準則的代碼。這種代碼的存在會給內核開發人員帶來兩方面的危害。
+
+首先,相信內核代碼標準並不重要,也不強制執行。但事實上,如果沒有按照標準
+編寫代碼,那麼新代碼將很難加入到內核中;許多開發人員甚至會在審查代碼之前要求
+對代碼進行重新格式化。一個像內核這麼大的代碼庫需要一些統一格式的代碼,以使
+開發人員能夠快速理解其中的任何部分。所以再也經不起奇怪格式的代碼的折騰了。
+
+內核的代碼風格偶爾會與僱主的強制風格發生衝突。在這種情況下,必須在代碼合併
+之前遵從內核代碼風格。將代碼放入內核意味着以多種方式放棄一定程度的控制權——
+包括控制代碼樣式。
+
+另一個危害是認爲已經在內核中的代碼迫切需要修復代碼樣式。開發者可能會開始編寫
+重新格式化補丁,作爲熟悉開發過程的一種方式,或者作爲將其名字寫入內核變更日誌
+的一種方式,或者兩者兼而有之。但是純代碼風格的修復被開發社區視爲噪音,它們往
+往受到冷遇。因此,最好避免編寫這種類型的補丁。在由於其他原因處理一段代碼的
+同時順帶修復其樣式是很自然的,但是不應該僅爲了更改代碼樣式而更改之。
+
+代碼風格文檔也不應該被視爲絕對不可違反的規則。如果有一個足夠的理由反對這種
+樣式(例如爲了80列限制拆分行會導致可讀性大大降低),那麼就這樣做吧。
+
+注意您還可以使用 ``clang-format`` 工具來幫助您處理這些規則,快速自動重新格式
+化部分代碼,和審閱完整的文件以發現代碼樣式錯誤、拼寫錯誤和可能的改進。它還
+可以方便地排序 ``#includes`` 、對齊變量/宏、重排文本和其他類似任務。有關詳細
+信息,請參閱文檔 :ref:`Documentation/process/clang-format.rst <clangformat>`
+
+抽象層
+******
+
+計算機科學教授教學生以靈活性和信息隱藏的名義廣泛使用抽象層。當然,內核廣泛
+地使用了抽象;任何涉及數百萬行代碼的項目都必須做到這一點以存續下來。但經驗
+表明,過度或過早的抽象可能和過早的優化一樣有害。抽象應用在適當層級,
+不要過度。
+
+簡單點,先考慮一個調用時始終只有一個參數且總爲零的函數。我們可以保留這個參數,
+以在需要使用它時提供的額外靈活性。不過,在那時實現了這個額外參數的代碼很有
+可能以某種從未被注意到的微妙方式被破壞——因爲它從未被使用過。或者當需要額外
+的靈活性時,它並未以符合程序員當初期望的方式來實現。內核開發人員通常會提交
+補丁來刪除未使用的參數;一般來說,一開始就不應該添加這些參數。
+
+隱藏硬件訪問的抽象層——通常爲了允許大量的驅動程序兼容多個操作系統——尤其不受
+歡迎。這樣的層使代碼變得模糊,可能會造成性能損失;它們不屬於Linux內核。
+
+另一方面,如果您發現自己從另一個內核子系統複製了大量的代碼,那麼是時候
+瞭解一下:是否需要將這些代碼中的部分提取到單獨的庫中,或者在更高的層次上
+實現這些功能。在整個內核中複製相同的代碼沒有價值。
+
+#ifdef 和預處理
+***************
+
+C預處理器似乎給一些C程序員帶來了強大的誘惑,他們認爲它是一種將大量靈活性加入
+源代碼中的方法。但是預處理器不是C,大量使用它會導致代碼對其他人來說更難閱讀,
+對編譯器來說更難檢查正確性。使用了大量預處理器幾乎總是代碼需要一些
+清理工作的標誌。
+
+使用#ifdef的條件編譯實際上是一個強大的功能,它在內核中使用。但是很少有人希望
+看到代碼被鋪滿#ifdef塊。一般規定,ifdef的使用應儘可能限制在頭文件中。條件
+編譯代碼可以限制函數,如果代碼不存在,這些函數就直接變成空的。然後編譯器將
+悄悄地優化對空函數的調用。使得代碼更加清晰,更容易理解。
+
+C預處理器宏存在許多危險性,包括可能對具有副作用且沒有類型安全的表達式進行多
+重評估。如果您試圖定義宏,請考慮創建一個內聯函數替代。結果相同的代碼,內聯
+函數更容易閱讀,不會多次計算其參數,並且允許編譯器對參數和返回值執行類型檢查。
+
+內聯函數
+********
+
+不過,內聯函數本身也存在風險。程序員可以傾心於避免函數調用和用內聯函數填充源
+文件所固有的效率。然而,這些功能實際上會降低性能。因爲它們的代碼在每個調用站
+點都被複制一遍,所以最終會增加編譯內核的大小。此外,這也對處理器的內存緩存
+造成壓力,從而大大降低執行速度。通常內聯函數應該非常小,而且相對較少。畢竟
+函數調用的成本並不高;大量創建內聯函數是過早優化的典型例子。
+
+一般來說,內核程序員會自冒風險忽略緩存效果。在數據結構課程開頭中的經典
+時間/空間權衡通常不適用於當代硬件。空間 *就是* 時間,因爲一個大的程序比一個
+更緊湊的程序運行得慢。
+
+較新的編譯器越來越激進地決定一個給定函數是否應該內聯。因此,隨意放置使用
+“inline”關鍵字可能不僅僅是過度的,也可能是無用的。
+
+鎖
+**
+
+2006年5月,“deviceescape”網絡堆棧在前呼後擁下以GPL發佈,並被納入主線內核。
+這是一個受歡迎的消息;Linux中對無線網絡的支持充其量被認爲是不合格的,而
+Deviceescape堆棧承諾修復這種情況。然而直到2007年6月(2.6.22),這段代碼才真
+正進入主線。發生了什麼?
+
+這段代碼出現了許多閉門造車的跡象。但一個大麻煩是,它並不是爲多處理器系統而
+設計。在合併這個網絡堆棧(現在稱爲mac80211)之前,需要對其進行一個鎖方案的
+改造。
+
+曾經,Linux內核代碼可以在不考慮多處理器系統所帶來的併發性問題的情況下進行
+開發。然而現在,這個文檔就是在雙核筆記本電腦上寫的。即使在單處理器系統上,
+爲提高響應能力所做的工作也會提高內核內的併發性水平。編寫內核代碼而不考慮鎖
+的日子早已遠去。
+
+可以由多個線程併發訪問的任何資源(數據結構、硬件寄存器等)必須由鎖保護。新
+的代碼應該謹記這一要求;事後修改鎖是一項相當困難的任務。內核開發人員應該花
+時間充分了解可用的鎖原語,以便爲工作選擇正確的工具。對併發性缺乏關注的代碼
+很難進入主線。
+
+迴歸
+****
+
+最後一個值得一提的危險是迴歸:它可能會引起導致現有用戶的某些東西中斷的改變
+(這也可能會帶來很大的改進)。這種變化被稱爲“迴歸”,迴歸已經成爲主線內核
+最不受歡迎的問題。除了少數例外情況,如果迴歸不能及時修正,會導致迴歸的修改
+將被取消。最好首先避免迴歸發生。
+
+人們常常爭論,如果迴歸帶來的功能遠超過產生的問題,那麼迴歸是否爲可接受的。
+如果它破壞了一個系統卻爲十個系統帶來新的功能,爲何不改改態度呢?2007年7月,
+Linus對這個問題給出了最佳答案:
+
+::
+
+ 所以我們不會通過引入新問題來修復錯誤。這種方式是靠不住的,沒人知道
+ 是否真的有進展。是前進兩步、後退一步,還是前進一步、後退兩步?
+
+(http://lwn.net/Articles/243460/)
+
+特別不受歡迎的一種迴歸類型是用戶空間ABI的任何變化。一旦接口被導出到用戶空間,
+就必須無限期地支持它。這一事實使得用戶空間接口的創建特別具有挑戰性:因爲它們
+不能以不兼容的方式進行更改,所以必須一次就對。因此,用戶空間接口總是需要大量
+的思考、清晰的文檔和廣泛的審查。
+
+
+代碼檢查工具
+------------
+
+至少目前,編寫無錯誤代碼仍然是我們中很少人能達到的理想狀態。不過,我們希望做
+的是,在代碼進入主線內核之前,儘可能多地捕獲並修復這些錯誤。爲此,內核開發人
+員已經提供了一系列令人印象深刻的工具,可以自動捕獲各種各樣的隱藏問題。計算機
+發現的任何問題都是一個以後不會困擾用戶的問題,因此,只要有可能,就應該使用
+自動化工具。
+
+第一步是注意編譯器產生的警告。當前版本的GCC可以檢測(並警告)大量潛在錯誤。
+通常,這些警告都指向真正的問題。提交以供審閱的代碼一般不會產生任何編譯器警告。
+在消除警告時,注意瞭解真正的原因,並儘量避免僅“修復”使警告消失而不解決其原因。
+
+請注意,並非所有編譯器警告都默認啓用。使用“make KCFLAGS=-W”構建內核以
+獲得完整集合。
+
+內核提供了幾個配置選項,可以打開調試功能;大多數配置選項位於“kernel hacking”
+子菜單中。對於任何用於開發或測試目的的內核,都應該啓用其中幾個選項。特別是,
+您應該打開:
+
+ - FRAME_WARN 獲取大於給定數量的堆棧幀的警告。
+ 這些警告生成的輸出可能比較冗長,但您不必擔心來自內核其他部分的警告。
+
+ - DEBUG_OBJECTS 將添加代碼以跟蹤內核創建的各種對象的生命週期,並在出現問題
+ 時發出警告。如果你要添加創建(和導出)關於其自己的複雜對象的子系統,請
+ 考慮打開對象調試基礎結構的支持。
+
+ - DEBUG_SLAB 可以發現各種內存分配和使用錯誤;它應該用於大多數開發內核。
+
+ - DEBUG_SPINLOCK, DEBUG_ATOMIC_SLEEP 和 DEBUG_MUTEXES 會發現許多常見的
+ 鎖錯誤。
+
+還有很多其他調試選項,其中一些將在下面討論。其中一些有顯著的性能影響,不應
+一直使用。在學習可用選項上花費一些時間,可能會在短期內得到許多回報。
+
+其中一個較重的調試工具是鎖檢查器或“lockdep”。該工具將跟蹤系統中每個鎖
+(spinlock或mutex)的獲取和釋放、獲取鎖的相對順序、當前中斷環境等等。然後,
+它可以確保總是以相同的順序獲取鎖,相同的中斷假設適用於所有情況等等。換句話
+說,lockdep可以找到許多導致系統死鎖的場景。在部署的系統中,這種問題可能會
+很痛苦(對於開發人員和用戶而言);LockDep允許提前以自動方式發現問題。具有
+任何類型的非普通鎖的代碼在提交合並前應在啓用lockdep的情況下運行測試。
+
+作爲一個勤奮的內核程序員,毫無疑問,您將檢查任何可能失敗的操作(如內存分配)
+的返回狀態。然而,事實上,最終的故障復現路徑可能完全沒有經過測試。未測試的
+代碼往往會出問題;如果所有這些錯誤處理路徑都被執行了幾次,那麼您可能對代碼
+更有信心。
+
+內核提供了一個可以做到這一點的錯誤注入框架,特別是在涉及內存分配的情況下。
+啓用故障注入後,內存分配的可配置失敗的百分比;這些失敗可以限定在特定的代碼
+範圍內。在啓用了故障注入的情況下運行,程序員可以看到當情況惡化時代碼如何響
+應。有關如何使用此工具的詳細信息,請參閱
+Documentation/fault-injection/fault-injection.rst。
+
+“sparse”靜態分析工具可以發現其他類型的錯誤。sparse可以警告程序員用戶空間
+和內核空間地址之間的混淆、大端序與小端序的混淆、在需要一組位標誌的地方傳遞
+整數值等等。sparse必須單獨安裝(如果您的分發服務器沒有將其打包,
+可以在 https://sparse.wiki.kernel.org/index.php/Main_page 找到),
+然後可以通過在make命令中添加“C=1”在代碼上運行它。
+
+“Coccinelle”工具 :ref:`http://coccinelle.lip6.fr/ <devtools_coccinelle>`
+能夠發現各種潛在的編碼問題;它還可以爲這些問題提出修復方案。在
+scripts/coccinelle目錄下已經打包了相當多的內核“語義補丁”;運行
+“make coccicheck”將運行這些語義補丁並報告發現的任何問題。有關詳細信息,請參閱
+:ref:`Documentation/dev-tools/coccinelle.rst <devtools_coccinelle>`
+
+
+其他類型的可移植性錯誤最好通過爲其他體系結構編譯代碼來發現。如果沒有S/390系統
+或Blackfin開發板,您仍然可以執行編譯步驟。可以在以下位置找到一大堆用於x86系統的
+交叉編譯器:
+
+ https://www.kernel.org/pub/tools/crosstool/
+
+花一些時間安裝和使用這些編譯器將有助於避免以後的尷尬。
+
+文檔
+----
+
+文檔通常比內核開發規則更爲例外。即便如此,足夠的文檔將有助於簡化將新代碼合併
+到內核中的過程,使其他開發人員的生活更輕鬆,並對您的用戶有所幫助。在許多情況
+下,添加文檔已基本上是強制性的。
+
+任何補丁的第一個文檔是其關聯的變更日誌。日誌條目應該描述正在解決的問題、解決
+方案的形式、處理補丁的人員、對性能的任何相關影響,以及理解補丁可能需要的任何
+其他內容。確保變更日誌說明了*爲什麼*補丁值得應用;大量開發者未能提供這些信息。
+
+任何添加新用戶空間接口的代碼——包括新的sysfs或/proc文件——都應該包含該接口
+的文檔,該文檔使用戶空間開發人員能夠知道他們在使用什麼。請參閱
+Documentation/ABI/README,瞭解如何此文檔格式以及需要提供哪些信息。
+
+文檔 :ref:`Documentation/admin-guide/kernel-parameters.rst <kernelparameters>`
+描述了內核的所有引導時間參數。任何添加新參數的補丁都應該向該文檔添加適當的
+條目。
+
+任何新的配置選項都必須附有幫助文本,幫助文本需清楚地解釋這些選項以及用戶可能
+希望何時使用它們。
+
+許多子系統的內部API信息通過專門格式化的註釋進行記錄;這些註釋可以通過
+“kernel-doc”腳本以多種方式提取和格式化。如果您在具有kerneldoc註釋的子系統中
+工作,則應該維護它們,並根據需要爲外部可用的功能添加它們。即使在沒有如此記錄
+的領域中,爲將來添加kerneldoc註釋也沒有壞處;實際上,這對於剛開始開發內核的人
+來說是一個有用的活動。這些註釋的格式以及如何創建kerneldoc模板的一些信息可以在
+:ref:`Documentation/doc-guide/ <doc_guide>` 上找到。
+
+任何閱讀大量現有內核代碼的人都會注意到,註釋的缺失往往是最值得注意的。同時,
+對新代碼的要求比過去更高;合併未註釋的代碼將更加困難。這就是說,人們並不期望
+詳細註釋的代碼。代碼本身應該是自解釋的,註釋闡釋了更微妙的方面。
+
+某些事情應該總是被註釋。使用內存屏障時,應附上一行文字,解釋爲什麼需要設置內存
+屏障。數據結構的鎖規則通常需要在某個地方解釋。一般來說,主要數據結構需要全面
+的文檔。應該指出代碼中分立的位之間不明顯的依賴性。任何可能誘使代碼管理人進行
+錯誤的“清理”的事情都需要一個註釋來說明爲什麼要這樣做。等等。
+
+
+內部API更改
+-----------
+
+內核提供給用戶空間的二進制接口不能被破壞,除非逼不得已。而內核的內部編程接口
+是高度流動的,當需要時可以更改。如果你發現自己不得不處理一個內核API,或者僅
+僅因爲它不滿足你的需求導致無法使用特定的功能,這可能是API需要改變的一個標誌。
+作爲內核開發人員,您有權進行此類更改。
+
+的確可以進行API更改,但更改必須是合理的。因此任何進行內部API更改的補丁都應該
+附帶關於更改內容和必要原因的描述。這種變化也應該拆分成一個單獨的補丁,而不是
+埋在一個更大的補丁中。
+
+另一個要點是,更改內部API的開發人員通常要負責修復內核樹中被更改破壞的任何代碼。
+對於一個廣泛使用的函數,這個責任可以導致成百上千的變化,其中許多變化可能與其他
+開發人員正在做的工作相沖突。不用說,這可能是一項大工程,所以最好確保理由是
+可靠的。請注意,coccinelle工具可以幫助進行廣泛的API更改。
+
+在進行不兼容的API更改時,應儘可能確保編譯器捕獲未更新的代碼。這將幫助您確保找
+到該接口的樹內用處。它還將警告開發人員樹外代碼存在他們需要響應的更改。支持樹外
+代碼不是內核開發人員需要擔心的事情,但是我們也不必使樹外開發人員的生活有不必要
+的困難。
+
diff --git a/Documentation/translations/zh_TW/process/5.Posting.rst b/Documentation/translations/zh_TW/process/5.Posting.rst
new file mode 100644
index 000000000000..7d66a1c638be
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/5.Posting.rst
@@ -0,0 +1,250 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/5.Posting.rst <development_posting>`
+
+:Translator:
+
+ 時奎亮 Alex Shi <alex.shi@linux.alibaba.com>
+
+:校譯:
+
+ 吳想成 Wu XiangCheng <bobwxc@email.cn>
+ 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+.. _tw_development_posting:
+
+發佈補丁
+========
+
+您的工作遲早會準備好提交給社區進行審查,並最終包含到主線內核中。毫不稀奇,
+內核開發社區已經發展出一套用於發佈補丁的約定和過程;遵循這些約定和過程將使
+參與其中的每個人的生活更加輕鬆。本文檔試圖描述這些約定的部分細節;更多信息
+也可在以下文檔中找到
+:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <tw_submittingpatches>`
+和 :ref:`Documentation/translations/zh_CN/process/submit-checklist.rst <tw_submitchecklist>`。
+
+何時寄送
+--------
+
+在補丁完全“準備好”之前,避免發佈補丁是一種持續的誘惑。對於簡單的補丁,這
+不是問題。但是如果正在完成的工作很複雜,那麼在工作完成之前從社區獲得反饋就
+可以獲得很多好處。因此,您應該考慮發佈正在進行的工作,甚至維護一個可用的Git
+樹,以便感興趣的開發人員可以隨時趕上您的工作。
+
+當發佈中有尚未準備好被包含的代碼,最好在發佈中說明。還應提及任何有待完成的
+主要工作和任何已知問題。很少有人會願意看那些被認爲是半生不熟的補丁,但是
+那些願意的人會帶着他們的點子來一起幫助你把工作推向正確的方向。
+
+創建補丁之前
+------------
+
+在考慮將補丁發送到開發社區之前,有許多事情應該做。包括:
+
+ - 儘可能地測試代碼。利用內核的調試工具,確保內核使用了所有可能的配置選項組合
+ 進行構建,使用交叉編譯器爲不同的體系結構進行構建等。
+
+ - 確保您的代碼符合內核代碼風格指南。
+
+ - 您的更改是否具有性能影響?如果是這樣,您應該運行基準測試來顯示您的變更的
+ 影響(或好處);結果的摘要應該包含在補丁中。
+
+ - 確保您有權發佈代碼。如果這項工作是爲僱主完成的,僱主對這項工作具有所有權,
+ 並且必須同意根據GPL對其進行發佈。
+
+一般來說,在發佈代碼之前進行一些額外的思考,幾乎總是能在短時間內得到回報。
+
+補丁準備
+--------
+
+準備補丁發佈的工作量可能很驚人,但在此嘗試節省時間通常是不明智的,即使在短期
+內亦然。
+
+必須針對內核的特定版本準備補丁。一般來說,補丁應該基於Linus的Git樹中的當前
+主線。當以主線爲基礎時,請從一個衆所周知的發佈點開始——如穩定版本或 -rc
+版本發佈點——而不是在一個任意的主線分支點。
+
+也可能需要針對-mm、linux-next或子系統樹生成版本,以便於更廣泛的測試和審查。
+根據補丁的區域以及其他地方的情況,針對其他樹建立的補丁可能需要大量的工作來
+解決衝突和處理API更改。
+
+只有最簡單的更改才應格式化爲單個補丁;其他所有更改都應作爲一系列邏輯更改進行。
+分割補丁是一門藝術;一些開發人員花了很長時間來弄清楚如何按照社區期望的方式來
+分割。不過,這些經驗法則也許有幫助:
+
+ - 您發佈的補丁系列幾乎肯定不會是開發過程中版本控制系統中的一系列更改。相反,
+ 需要對您所做更改的最終形式加以考慮,然後以有意義的方式進行拆分。開發人員對
+ 離散的、自包含的更改感興趣,而不是您創造這些更改的原始路徑。
+
+ - 每個邏輯上獨立的變更都應該格式化爲單獨的補丁。這些更改可以是小的(如“向
+ 此結構體添加字段”)或大的(如添加一個重要的新驅動程序),但它們在概念上
+ 應該是小的,並且可以在一行內簡述。每個補丁都應該做一個特定的、可以單獨
+ 檢查並驗證它所做的事情的更改。
+
+ - 換種方式重申上述準則,也就是說:不要在同一補丁中混合不同類型的更改。如果
+ 一個補丁修復了一個關鍵的安全漏洞,又重新排列了一些結構,還重新格式化了代
+ 碼,那麼它很有可能會被忽略,從而導致重要的修復丟失。
+
+ - 每個補丁都應該能創建一個可以正確地構建和運行的內核;如果補丁系列在中間被
+ 斷開,那麼結果仍應是一個正常工作的內核。部分應用一系列補丁是使用
+ “git bisct”工具查找回歸的一個常見場景;如果結果是一個損壞的內核,那麼將使
+ 那些從事追蹤問題的高尚工作的開發人員和用戶的生活更加艱難。
+
+ - 不要過分分割。一位開發人員曾經將一組針對單個文件的編輯分成500個單獨的補丁
+ 發佈,這並沒有使他成爲內核郵件列表中最受歡迎的人。一個補丁可以相當大,
+ 只要它仍然包含一個單一的 *邏輯* 變更。
+
+ - 用一系列補丁添加一個全新的基礎設施,但是該設施在系列中的最後一個補丁啓用
+ 整個變更之前不能使用,這看起來很誘人。如果可能的話,應該避免這種誘惑;
+ 如果這個系列增加了迴歸,那麼二分法將指出最後一個補丁是導致問題的補丁,
+ 即使真正的bug在其他地方。只要有可能,添加新代碼的補丁程序應該立即激活該
+ 代碼。
+
+創建完美補丁系列的工作可能是一個令人沮喪的過程,在完成“真正的工作”之後需要
+花費大量的時間和思考。但是如果做得好,花費的時間就是值得的。
+
+補丁格式和更改日誌
+------------------
+
+所以現在你有了一系列完美的補丁可以發佈,但是這項工作還沒有完成。每個補丁都
+需要被格式化成一條消息,以快速而清晰地將其目的傳達到世界其他地方。爲此,
+每個補丁將由以下部分組成:
+
+ - 可選的“From”行,表明補丁作者。只有當你通過電子郵件發送別人的補丁時,這一行
+ 纔是必須的,但是爲防止疑問加上它也不會有什麼壞處。
+
+ - 一行描述,說明補丁的作用。對於在沒有其他上下文的情況下看到該消息的讀者來說,
+ 該消息應足以確定修補程序的範圍;此行將顯示在“short form(簡短格式)”變更
+ 日誌中。此消息通常需要先加上子系統名稱前綴,然後是補丁的目的。例如:
+
+ ::
+
+ gpio: fix build on CONFIG_GPIO_SYSFS=n
+
+ - 一行空白,後接補丁內容的詳細描述。此描述可以是任意需要的長度;它應該說明補丁
+ 的作用以及爲什麼它應該應用於內核。
+
+ - 一個或多個標記行,至少有一個由補丁作者的 Signed-off-by 簽名。標記將在下面
+ 詳細描述。
+
+上面的項目一起構成補丁的變更日誌。寫一則好的變更日誌是一門至關重要但常常被
+忽視的藝術;值得花一點時間來討論這個問題。當你編寫變更日誌時,你應該記住有
+很多不同的人會讀你的話。其中包括子系統維護人員和審查人員,他們需要決定是否
+應該合併補丁,分銷商和其他維護人員試圖決定是否應該將補丁反向移植到其他內核,
+缺陷搜尋人員想知道補丁是否導致他們正在追查的問題,以及想知道內核如何變化的
+用戶等等。一個好的變更日誌以最直接和最簡潔的方式向所有這些人傳達所需的信息。
+
+在結尾,總結行應該描述變更的影響和動機,以及在一行約束條件下可能發生的變化。
+然後,詳細的描述可以詳述這些主題,並提供任何需要的附加信息。如果補丁修復了
+一個缺陷,請引用引入該缺陷的提交(如果可能,請在引用提交時同時提供其 id 和
+標題)。如果某個問題與特定的日誌或編譯器輸出相關聯,請包含該輸出以幫助其他
+人搜索同一問題的解決方案。如果更改是爲了支持以後補丁中的其他更改,那麼應當
+說明。如果更改了內部API,請詳細說明這些更改以及其他開發人員應該如何響應。
+一般來說,你越把自己放在每個閱讀你變更日誌的人的位置上,變更日誌(和內核
+作爲一個整體)就越好。
+
+不需要說,變更日誌是將變更提交到版本控制系統時使用的文本。接下來將是:
+
+ - 補丁本身,採用統一的(“-u”)補丁格式。使用“-p”選項來diff將使函數名與
+ 更改相關聯,從而使結果補丁更容易被其他人讀取。
+
+您應該避免在補丁中包括與更改不相關文件(例如,構建過程生成的文件或編輯器
+備份文件)。文檔目錄中的“dontdiff”文件在這方面有幫助;使用“-X”選項將
+其傳遞給diff。
+
+上面提到的標籤(tag)用於描述各種開發人員如何與這個補丁的開發相關聯。
+:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <tw_submittingpatches>`
+文檔中對它們進行了詳細描述;下面是一個簡短的總結。每一行的格式如下:
+
+::
+
+ tag: Full Name <email address> optional-other-stuff
+
+常用的標籤有:
+
+ - Signed-off-by: 這是一個開發人員的證明,證明他或她有權提交補丁以包含到內核
+ 中。這表明同意開發者來源認證協議,其全文見
+ :ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <tw_submittingpatches>`
+ 如果沒有合適的簽字,則不能合併到主線中。
+
+ - Co-developed-by: 聲明補丁是由多個開發人員共同創建的;當幾個人在一個補丁上
+ 工作時,它用於給出共同作者(除了 From: 所給出的作者之外)。由於
+ Co-developed-by: 表示作者身份,所以每個共同開發人,必須緊跟在相關合作作者
+ 的Signed-off-by之後。具體內容和示例見以下文件
+ :ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <tw_submittingpatches>`
+
+ - Acked-by: 表示另一個開發人員(通常是相關代碼的維護人員)同意補丁適合包含
+ 在內核中。
+
+ - Tested-by: 聲明某人已經測試了補丁並確認它可以工作。
+
+ - Reviewed-by: 表示某開發人員已經審查了補丁的正確性;有關詳細信息,請參閱
+ :ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <tw_submittingpatches>`
+
+ - Reported-by: 指定報告此補丁修復的問題的用戶;此標記用於表示感謝。
+
+ - Cc:指定某人收到了補丁的副本,並有機會對此發表評論。
+
+在補丁中添加標籤時要小心:只有Cc:才適合在沒有指定人員明確許可的情況下添加。
+
+寄送補丁
+--------
+
+在寄送補丁之前,您還需要注意以下幾點:
+
+ - 您確定您的郵件發送程序不會損壞補丁嗎?被郵件客戶端更改空白或修飾了行的補丁
+ 無法被另一端接受,並且通常不會進行任何詳細檢查。如果有任何疑問,先把補丁寄
+ 給你自己,讓你自己確定它是完好無損的。
+
+ :ref:`Documentation/translations/zh_CN/process/email-clients.rst <tw_email_clients>`
+ 提供了一些有用的提示,可以讓特定的郵件客戶端正常發送補丁。
+
+ - 你確定你的補丁沒有荒唐的錯誤嗎?您應該始終通過scripts/checkpatch.pl檢查
+ 補丁程序,並解決它提出的問題。請記住,checkpatch.pl,雖然體現了對內核補丁
+ 應該是什麼樣的大量思考,但它並不比您聰明。如果修復checkpatch.pl給的問題會
+ 使代碼變得更糟,請不要這樣做。
+
+補丁應始終以純文本形式發送。請不要將它們作爲附件發送;這使得審閱者在答覆中更難
+引用補丁的部分。相反,只需將補丁直接放到您的消息中。
+
+寄出補丁時,重要的是將副本發送給任何可能感興趣的人。與其他一些項目不同,內核
+鼓勵人們甚至錯誤地發送過多的副本;不要假定相關人員會看到您在郵件列表中的發佈。
+尤其是,副本應發送至:
+
+ - 受影響子系統的維護人員。如前所述,維護人員文件是查找這些人員的首選地方。
+
+ - 其他在同一領域工作的開發人員,尤其是那些現在可能在那裏工作的開發人員。使用
+ git查看還有誰修改了您正在處理的文件,這很有幫助。
+
+ - 如果您對某錯誤報告或功能請求做出響應,也可以抄送原始發送人。
+
+ - 將副本發送到相關郵件列表,或者若無相關列表,則發送到linux-kernel列表。
+
+ - 如果您正在修復一個缺陷,請考慮該修復是否應進入下一個穩定更新。如果是這樣,
+ 補丁副本也應發到stable@vger.kernel.org 。另外,在補丁本身的標籤中添加一個
+ “Cc: stable@vger.kernel.org”;這將使穩定版團隊在修復進入主線時收到通知。
+
+當爲一個補丁選擇接收者時,最好清楚你認爲誰最終會接受這個補丁並將其合併。雖然
+可以將補丁直接發給Linus Torvalds並讓他合併,但通常情況下不會這樣做。Linus很
+忙,並且有子系統維護人員負責監視內核的特定部分。通常您會希望維護人員合併您的
+補丁。如果沒有明顯的維護人員,Andrew Morton通常是最後的補丁接收者。
+
+補丁需要好的主題行。補丁主題行的規範格式如下:
+
+::
+
+ [PATCH nn/mm] subsys: one-line description of the patch
+
+其中“nn”是補丁的序號,“mm”是系列中補丁的總數,“subsys”是受影響子系統的
+名稱。當然,一個單獨的補丁可以省略nn/mm。
+
+如果您有一系列重要的補丁,那麼通常發送一個簡介作爲第〇部分。不過,這個約定
+並沒有得到普遍遵循;如果您使用它,請記住簡介中的信息不會進入內核變更日誌。
+因此,請確保補丁本身具有完整的變更日誌信息。
+
+一般來說,多部分補丁的第二部分和後續部分應作爲對第一部分的回覆發送,以便它們
+在接收端都連接在一起。像git和coilt這樣的工具有命令,可以通過適當的線程發送
+一組補丁。但是,如果您有一長串補丁,並正使用git,請不要使用–-chain-reply-to
+選項,以避免創建過深的嵌套。
+
diff --git a/Documentation/translations/zh_TW/process/6.Followthrough.rst b/Documentation/translations/zh_TW/process/6.Followthrough.rst
new file mode 100644
index 000000000000..f3b195966632
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/6.Followthrough.rst
@@ -0,0 +1,156 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/6.Followthrough.rst <development_followthrough>`
+
+:Translator:
+
+ 時奎亮 Alex Shi <alex.shi@linux.alibaba.com>
+
+:校譯:
+
+ 吳想成 Wu XiangCheng <bobwxc@email.cn>
+ 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+.. _tw_development_followthrough:
+
+跟進
+====
+
+此時,您已經遵循了到目前爲止給出的指導方針,並且,隨着您自己的工程技能的增加,
+已經發布了一系列完美的補丁。即使是經驗豐富的內核開發人員也能犯的最大錯誤之一
+是,認爲他們的工作現在已經完成了。事實上,發佈補丁意味着進入流程的下一個階段,
+可能還需要做很多工作。
+
+一個補丁在首次發佈時就非常出色、沒有改進的餘地,這是很罕見的。內核開發流程已
+認識到這一事實,因此它非常注重對已發佈代碼的改進。作爲代碼的作者,您應該與
+內核社區合作,以確保您的代碼符合內核的質量標準。如果不參與這個過程,很可能會
+無法將補丁合併到主線中。
+
+與審閱者合作
+------------
+
+任何意義上的補丁都會導致其他開發人員在審查代碼時發表大量評論。對於許多開發
+人員來說,與審閱人員合作可能是內核開發過程中最令人生畏的部分。但是如果你
+記住一些事情,生活會變得容易得多:
+
+ - 如果你已經很好地解釋了你的補丁,審閱人員會理解它的價值,以及爲什麼你會
+ 費盡心思去寫它。但是這個並不能阻止他們提出一個基本的問題:在五年或十年後
+ 維護含有此代碼的內核會怎麼樣?你可能被要求做出的許多改變——從編碼風格的
+ 調整到大量的重寫——都來自於對Linux的理解,即從現在起十年後,Linux仍將
+ 在開發中。
+
+ - 代碼審查是一項艱苦的工作,這是一項相對喫力不討好的工作;人們記得誰編寫了
+ 內核代碼,但對於那些審查它的人來說,幾乎沒有什麼長久的名聲。因此,審閱
+ 人員可能會變得暴躁,尤其是當他們看到同樣的錯誤被一遍又一遍地犯下時。如果
+ 你得到了一個看起來憤怒、侮辱或完全冒犯你的評論,請抑制以同樣方式回應的衝動。
+ 代碼審查是關於代碼的,而不是關於人的,代碼審閱人員不會親自攻擊您。
+
+ - 同樣,代碼審閱人員也不想以犧牲你僱主的利益爲代價來宣傳他們僱主的議程。
+ 內核開發人員通常希望今後幾年能在內核上工作,但他們明白他們的僱主可能會改
+ 變。他們真的,幾乎毫無例外地,致力於創造他們所能做到的最好的內核;他們並
+ 沒有試圖給僱主的競爭對手造成不適。
+
+所有這些歸根結底就是,當審閱者向您發送評論時,您需要注意他們正在進行的技術
+評論。不要讓他們的表達方式或你自己的驕傲阻止此事。當你在一個補丁上得到評論
+時,花點時間去理解評論人想說什麼。如果可能的話,請修復審閱者要求您修復的內
+容。然後回覆審閱者:謝謝他們,並描述你將如何回答他們的問題。
+
+請注意,您不必同意審閱者建議的每個更改。如果您認爲審閱者誤解了您的代碼,請
+解釋到底發生了什麼。如果您對建議的更改有技術上的異議,請描述它並證明您對該
+問題的解決方案是正確的。如果你的解釋有道理,審閱者會接受的。不過,如果你的
+解釋證明缺乏說服力,尤其是當其他人開始同意審稿人的觀點時,請花些時間重新考慮
+一下。你很容易對自己解決問題的方法視而不見,以至於你沒有意識到某些東西完全
+是錯誤的,或者你甚至沒有解決正確的問題。
+
+Andrew Morton建議,每一個不會導致代碼更改的審閱評論都應該產生一個額外的代碼
+註釋;這可以幫助未來的審閱人員避免第一次出現的問題。
+
+一個致命的錯誤是忽視評論,希望它們會消失。它們不會走的。如果您在沒有對之前
+收到的評論做出響應的情況下重新發布代碼,那麼很可能會發現補丁毫無用處。
+
+說到重新發布代碼:請記住,審閱者不會記住您上次發佈的代碼的所有細節。因此,
+提醒審閱人員以前提出的問題以及您如何處理這些問題總是一個好主意;補丁變更
+日誌是提供此類信息的好地方。審閱者不必搜索列表檔案來熟悉上次所說的內容;
+如果您幫助他們直接開始,當他們重新查看您的代碼時,心情會更好。
+
+如果你已經試着做正確的事情,但事情仍然沒有進展呢?大多數技術上的分歧都可以
+通過討論來解決,但有時人們仍需要做出決定。如果你真的認爲這個決定對你不利,
+你可以試着向有更高權力的人上訴。對於本文,更高權力的人是 Andrew Morton 。
+Andrew 在內核開發社區中非常受尊敬;他經常爲似乎被絕望阻塞的事情清障。儘管
+如此,不應輕易就直接找 Andrew ,也不應在所有其他替代方案都被嘗試之前找他。
+當然,記住,他也可能不同意你的意見。
+
+接下來會發生什麼
+----------------
+
+如果一個補丁被認爲適合添加到內核中,並且大多數審查問題得到解決,下一步通常
+是進入子系統維護人員的樹中。工作方式因子系統而異;每個維護人員都有自己的
+工作方式。特別是可能有不止一棵樹——也許一棵樹專門用於計劃下一個合併窗口的
+補丁,另一棵樹用於長期工作。
+
+對於應用到不屬於明顯子系統樹(例如內存管理修補程序)的區域的修補程序,默認樹
+通常上溯到-mm。影響多個子系統的補丁也可以最終進入-mm樹。
+
+包含在子系統樹中可以提高補丁的可見性。現在,使用該樹的其他開發人員將默認獲
+得補丁。子系統樹通常也爲Linux提供支持,使其內容對整個開發社區可見。在這一點
+上,您很可能會從一組新的審閱者那裏得到更多的評論;這些評論需要像上一輪那樣
+得到回應。
+
+在這時也會發生點什麼,這取決於你的補丁的性質,是否與其他人正在做的工作發生
+衝突。在最壞的情況下,嚴重的補丁衝突可能會導致一些工作被擱置,以便剩餘的補丁
+可以成形併合並。另一些時候,衝突解決將涉及到與其他開發人員合作,可能還會
+在樹之間移動一些補丁,以確保所有的應用都是乾淨的。這項工作可能是一件痛苦的
+事情,但也需慶幸現在的幸福:在linux-next樹出現之前,這些衝突通常只在合併窗口
+中出現,必須迅速解決。現在可以在合併窗口打開之前的空閒時間解決這些問題。
+
+有朝一日,如果一切順利,您將登錄並看到您的補丁已經合併到主線內核中。祝賀你!
+然而,一旦慶祝完了(並且您已經將自己添加到維護人員文件中),就一定要記住
+一個重要的小事實:工作仍然沒有完成。併入主線也帶來了它的挑戰。
+
+首先,補丁的可見性再次提高。可能會有以前不知道這個補丁的開發者的新一輪評論。
+忽略它們可能很有誘惑力,因爲您的代碼不再存在任何被合併的問題。但是,要抵制
+這種誘惑,您仍然需要對有問題或建議的開發人員作出響應。
+
+不過,更重要的是:將代碼包含在主線中會將代碼交給更多的一些測試人員。即使您
+爲尚未可用的硬件提供了驅動程序,您也會驚訝於有多少人會將您的代碼構建到內核
+中。當然,如果有測試人員,也可能會有錯誤報告。
+
+最糟糕的錯誤報告是迴歸。如果你的補丁導致迴歸,你會發現多到讓你不舒服的眼睛盯
+着你;迴歸需要儘快修復。如果您不願意或無法修復迴歸(其他人都不會爲您修復),
+那麼在穩定期內,您的補丁幾乎肯定會被移除。除了否定您爲使補丁進入主線所做的
+所有工作之外,如果由於未能修復迴歸而取消補丁,很可能會使將來的工作更難被合併。
+
+在處理完任何迴歸之後,可能還有其他普通缺陷需要處理。穩定期是修復這些錯誤並
+確保代碼在主線內核版本中的首次發佈儘可能可靠的最好機會。所以,請回應錯誤
+報告,並儘可能解決問題。這就是穩定期的目的;一旦解決了舊補丁的任何問題,就
+可以開始盡情創建新補丁。
+
+別忘了,還有其他節點也可能會創建缺陷報告:下一個主線穩定版本,當著名的發行
+商選擇包含您補丁的內核版本時等等。繼續響應這些報告是您工作的基本素養。但是
+如果這不能提供足夠的動機,那麼也需要考慮:開發社區會記住那些在合併後對代碼
+失去興趣的開發人員。下一次你發佈補丁時,他們會以你以後不會持續維護它爲前提
+來評估它。
+
+其他可能發生的事情
+------------------
+
+某天,當你打開你的郵件客戶端時,看到有人給你寄了一個代碼補丁。畢竟,這是
+讓您的代碼公開存在的好處之一。如果您同意這個補丁,您可以將它轉發給子系統
+維護人員(確保包含一個正確的From:行,這樣屬性是正確的,並添加一個您自己的
+signoff ),或者回復一個 Acked-by: 讓原始發送者向上發送它。
+
+如果您不同意補丁,請禮貌地回覆,解釋原因。如果可能的話,告訴作者需要做哪些
+更改才能讓您接受補丁。合併代碼的編寫者和維護者所反對的補丁的確存在着一定的
+阻力,但僅此而已。如果你被認爲不必要的阻礙了好的工作,那麼這些補丁最終會
+繞過你並進入主線。在Linux內核中,沒有人對任何代碼擁有絕對的否決權。可能除
+了Linus。
+
+在非常罕見的情況下,您可能會看到完全不同的東西:另一個開發人員發佈了針對您
+的問題的不同解決方案。在這時,兩個補丁之一可能不會被合併,“我的補丁首先
+發佈”不被認爲是一個令人信服的技術論據。如果有別人的補丁取代了你的補丁而進
+入了主線,那麼只有一種方法可以回應你:很高興你的問題解決了,請繼續工作吧。
+以這種方式把某人的工作推到一邊可能導致傷心和氣餒,但是社區會記住你的反應,
+即使很久以後他們已經忘記了誰的補丁真正被合併。
+
diff --git a/Documentation/translations/zh_TW/process/7.AdvancedTopics.rst b/Documentation/translations/zh_TW/process/7.AdvancedTopics.rst
new file mode 100644
index 000000000000..b449d67e3ad9
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/7.AdvancedTopics.rst
@@ -0,0 +1,137 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/7.AdvancedTopics.rst <development_advancedtopics>`
+
+:Translator:
+
+ 時奎亮 Alex Shi <alex.shi@linux.alibaba.com>
+
+:校譯:
+
+ 吳想成 Wu XiangCheng <bobwxc@email.cn>
+ 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+.. _tw_development_advancedtopics:
+
+高級主題
+========
+
+現在,希望您能夠掌握開發流程的工作方式。然而,還有更多的東西要學!本節將介紹
+一些主題,這些主題對希望成爲Linux內核開發過程常規部分的開發人員有幫助。
+
+使用Git管理補丁
+---------------
+
+內核使用分佈式版本控制始於2002年初,當時Linus首次開始使用專有的Bitkeeper應用
+程序。雖然BitKeeper存在爭議,但它所體現的軟件版本管理方法卻肯定不是。分佈式
+版本控制可以立即加速內核開發項目。現在有好幾種免費的BitKeeper替代品。
+但無論好壞,內核項目都已經選擇了Git作爲其工具。
+
+使用Git管理補丁可以使開發人員的生活更加輕鬆,尤其是隨着補丁數量的增長。Git也
+有其粗糙的邊角和一定的危險性,它是一個年輕和強大的工具,仍然在其開發人員完善
+中。本文檔不會試圖教會讀者如何使用git;這會是個巨長的文檔。相反,這裏的重點
+將是Git如何特別適合內核開發過程。想要加快用Git速度的開發人員可以在以下網站上
+找到更多信息:
+
+ https://git-scm.com/
+
+ https://www.kernel.org/pub/software/scm/git/docs/user-manual.html
+
+同時網上也能找到各種各樣的教程。
+
+在嘗試使用它生成補丁供他人使用之前,第一要務是閱讀上述網頁,對Git的工作方式
+有一個紮實的瞭解。使用Git的開發人員應能進行拉取主線存儲庫的副本,查詢修訂
+歷史,提交對樹的更改,使用分支等操作。瞭解Git用於重寫歷史的工具(如rebase)
+也很有用。Git有自己的術語和概念;Git的新用戶應該瞭解引用、遠程分支、索引、
+快進合併、推拉、遊離頭等。一開始可能有點嚇人,但這些概念不難通過一點學習來
+理解。
+
+使用git生成通過電子郵件提交的補丁是提高速度的一個很好的練習。
+
+當您準備好開始建立Git樹供其他人查看時,無疑需要一個可以從中拉取的服務器。
+如果您有一個可以訪問因特網的系統,那麼使用git-daemon設置這樣的服務器相對
+簡單。同時,免費的公共託管網站(例如github)也開始出現在網絡上。成熟的開發
+人員可以在kernel.org上獲得一個帳戶,但這些帳戶並不容易得到;更多有關信息,
+請參閱 https://kernel.org/faq/ 。
+
+正常的Git工作流程涉及到許多分支的使用。每一條開發線都可以分爲單獨的“主題
+分支”,並獨立維護。Git的分支很容易使用,沒有理由不使用它們。而且,在任何
+情況下,您都不應該在任何您打算讓其他人從中拉取的分支中進行開發。應該小心地
+創建公開可用的分支;當開發分支處於完整狀態並已準備好時(而不是之前)才合併
+開發分支的補丁。
+
+Git提供了一些強大的工具,可以讓您重寫開發歷史。一個不方便的補丁(比如說,
+一個打破二分法的補丁,或者有其他一些明顯的缺陷)可以在適當的位置修復,或者
+完全從歷史中消失。一個補丁系列可以被重寫,就好像它是在今天的主線上寫的一樣,
+即使你已經花了幾個月的時間在寫它。可以透明地將更改從一個分支轉移到另一個
+分支。等等。明智地使用git修改歷史的能力可以幫助創建問題更少的乾淨補丁集。
+
+然而,過度使用這種功能可能會導致其他問題,而不僅僅是對創建完美項目歷史的
+簡單癡迷。重寫歷史將重寫該歷史中包含的更改,將經過測試(希望如此)的內核樹
+變爲未經測試的內核樹。除此之外,如果開發人員沒有共享項目歷史,他們就無法
+輕鬆地協作;如果您重寫了其他開發人員拉入他們存儲庫的歷史,您將使這些開發
+人員的生活更加困難。因此,這裏有一個簡單的經驗法則:被導出到其他地方的歷史
+在此後通常被認爲是不可變的。
+
+因此,一旦將一組更改推送到公開可用的服務器上,就不應該重寫這些更改。如果您
+嘗試強制進行無法快進合併的更改(即不共享同一歷史記錄的更改),Git將嘗試強制
+執行此規則。這可能覆蓋檢查,有時甚至需要重寫導出的樹。在樹之間移動變更集以
+避免linux-next中的衝突就是一個例子。但這種行爲應該是罕見的。這就是爲什麼
+開發應該在私有分支中進行(必要時可以重寫)並且只有在公共分支處於合理的較新
+狀態時才轉移到公共分支中的原因之一。
+
+當主線(或其他一組變更所基於的樹)前進時,很容易與該樹合併以保持領先地位。
+對於一個私有的分支,rebasing 可能是一個很容易跟上另一棵樹的方法,但是一旦
+一棵樹被導出到外界,rebasing就不可取了。一旦發生這種情況,就必須進行完全
+合併(merge)。合併有時是很有意義的,但是過於頻繁的合併會不必要地擾亂歷史。
+在這種情況下建議的做法是不要頻繁合併,通常只在特定的發佈點(如主線-rc發佈)
+合併。如果您對特定的更改感到緊張,則可以始終在私有分支中執行測試合併。在
+這種情況下,git“rerere”工具很有用;它能記住合併衝突是如何解決的,這樣您
+就不必重複相同的工作。
+
+關於Git這樣的工具的一個最大的反覆抱怨是:補丁從一個存儲庫到另一個存儲庫的
+大量移動使得很容易陷入錯誤建議的變更中,這些變更避開審查雷達進入主線。當內
+核開發人員看到這種情況發生時,他們往往會感到不高興;在Git樹上放置未審閱或
+主題外的補丁可能會影響您將來讓樹被拉取的能力。引用Linus的話:
+
+::
+
+ 你可以給我發補丁,但當我從你那裏拉取一個Git補丁時,我需要知道你清楚
+ 自己在做什麼,我需要能夠相信事情而 *無需* 手動檢查每個單獨的更改。
+
+(http://lwn.net/Articles/224135/)。
+
+爲了避免這種情況,請確保給定分支中的所有補丁都與相關主題緊密相關;“驅動程序
+修復”分支不應更改核心內存管理代碼。而且,最重要的是,不要使用Git樹來繞過
+審查過程。不時的將樹的摘要發佈到相關的列表中,在合適時候請求linux-next中
+包含該樹。
+
+如果其他人開始發送補丁以包含到您的樹中,不要忘記審閱它們。還要確保您維護正確
+的作者信息; git “am”工具在這方面做得最好,但是如果補丁通過第三方轉發給您,
+您可能需要在補丁中添加“From:”行。
+
+請求拉取時,請務必提供所有相關信息:樹的位置、要拉取的分支以及拉取將導致的
+更改。在這方面 git request-pull 命令非常有用;它將按照其他開發人員所期望的
+格式化請求,並檢查以確保您已記得將這些更改推送到公共服務器。
+
+審閱補丁
+--------
+
+一些讀者顯然會反對將本節與“高級主題”放在一起,因爲即使是剛開始的內核開發人員
+也應該審閱補丁。當然,沒有比查看其他人發佈的代碼更好的方法來學習如何在內核環境
+中編程了。此外,審閱者永遠供不應求;通過審閱代碼,您可以對整個流程做出重大貢獻。
+
+審查代碼可能是一副令人生畏的圖景,特別是對一個新的內核開發人員來說,他們
+可能會對公開詢問代碼感到緊張,而這些代碼是由那些有更多經驗的人發佈的。不過,
+即使是最有經驗的開發人員編寫的代碼也可以得到改進。也許對(所有)審閱者最好
+的建議是:把審閱評論當成問題而不是批評。詢問“在這條路徑中如何釋放鎖?”
+總是比說“這裏的鎖是錯誤的”更好。
+
+不同的開發人員將從不同的角度審查代碼。部分人會主要關注代碼風格以及代碼行是
+否有尾隨空格。其他人會主要關注補丁作爲一個整體實現的變更是否對內核有好處。
+同時也有人會檢查是否存在鎖問題、堆棧使用過度、可能的安全問題、在其他地方
+發現的代碼重複、足夠的文檔、對性能的不利影響、用戶空間ABI更改等。所有類型
+的檢查,只要它們能引導更好的代碼進入內核,都是受歡迎和值得的。
+
diff --git a/Documentation/translations/zh_TW/process/8.Conclusion.rst b/Documentation/translations/zh_TW/process/8.Conclusion.rst
new file mode 100644
index 000000000000..d1634421b62c
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/8.Conclusion.rst
@@ -0,0 +1,73 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/8.Conclusion.rst <development_conclusion>`
+:Translator:
+
+ 時奎亮 Alex Shi <alex.shi@linux.alibaba.com>
+
+:校譯:
+
+ 吳想成 Wu XiangCheng <bobwxc@email.cn>
+ 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+.. _tw_development_conclusion:
+
+更多信息
+========
+
+關於Linux內核開發和相關主題的信息來源很多。首先是在內核源代碼分發中找到的
+文檔目錄。頂級
+:ref:`Documentation/translations/zh_CN/process/howto.rst <tw_process_howto>`
+文件是一個重要的起點;
+:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <tw_submittingpatches>`
+也是所有內核開發人員都應該閱讀的內容。許多內部內核API都是使用kerneldoc機制
+記錄的;“make htmldocs”或“make pdfdocs”可用於以HTML或PDF格式生成這些文檔
+(儘管某些發行版提供的tex版本會遇到內部限制,無法正確處理文檔)。
+
+不同的網站在各個細節層次上討論內核開發。本文作者想謙虛地建議用 https://lwn.net/
+作爲來源;有關許多特定內核主題的信息可以通過以下網址的 LWN 內核索引找到:
+
+ http://lwn.net/kernel/index/
+
+除此之外,內核開發人員的一個寶貴資源是:
+
+ https://kernelnewbies.org/
+
+當然,也不應該忘記 https://kernel.org/ ,這是內核發佈信息的最終位置。
+
+關於內核開發有很多書:
+
+ 《Linux設備驅動程序》第三版(Jonathan Corbet、Alessandro Rubini和Greg Kroah Hartman)
+ 線上版本在 http://lwn.net/kernel/ldd3/
+
+ 《Linux內核設計與實現》(Robert Love)
+
+ 《深入理解Linux內核》(Daniel Bovet和Marco Cesati)
+
+然而,所有這些書都有一個共同的缺點:它們上架時就往往有些過時,而且已經上架
+一段時間了。不過,在那裏還是可以找到相當多的好信息。
+
+有關git的文檔,請訪問:
+
+ https://www.kernel.org/pub/software/scm/git/docs/
+
+ https://www.kernel.org/pub/software/scm/git/docs/user-manual.html
+
+結論
+====
+
+祝賀所有通過這篇冗長的文檔的人。希望它能夠幫助您理解Linux內核是如何開發的,
+以及您如何參與這個過程。
+
+最後,重要的是參與。任何開源軟件項目都不會超過其貢獻者投入其中的總和。Linux
+內核的發展速度和以前一樣快,因爲它得到了大量開發人員的幫助,他們都在努力使它
+變得更好。內核是一個最成功的例子,說明了當成千上萬的人爲了一個共同的目標一起
+工作時,可以做出什麼。
+
+不過,內核總是可以從更大的開發人員基礎中獲益。總有更多的工作要做。但是同樣
+重要的是,Linux生態系統中的大多數其他參與者可以通過爲內核做出貢獻而受益。使
+代碼進入主線是提高代碼質量、降低維護和分發成本、提高對內核開發方向的影響程度
+等的關鍵。這是一種共贏的局面。啓動你的編輯器,來加入我們吧;你會非常受歡迎的。
+
diff --git a/Documentation/translations/zh_TW/process/code-of-conduct-interpretation.rst b/Documentation/translations/zh_TW/process/code-of-conduct-interpretation.rst
new file mode 100644
index 000000000000..fbe66b001322
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/code-of-conduct-interpretation.rst
@@ -0,0 +1,112 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/code-of-conduct-interpretation.rst <code_of_conduct_interpretation>`
+:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+ Hu Haowen <2023002089@link.tyut.edu.cn>
+
+.. _tw_code_of_conduct_interpretation:
+
+Linux內核貢獻者契約行爲準則解釋
+===============================
+
+:ref:`tw_code_of_conduct` 準則是一個通用文檔,旨在爲幾乎所有開源社區提供一套規則。
+每個開源社區都是獨一無二的,Linux內核也不例外。因此,本文描述了Linux內核社區中
+如何解釋它。我們也不希望這種解釋隨着時間的推移是靜態的,並將根據需要進行調整。
+
+與開發軟件的“傳統”方法相比,Linux內核開發工作是一個非常個人化的過程。你的貢獻
+和背後的想法將被仔細審查,往往導致批判和批評。審查將幾乎總是需要改進,材料才
+能包括在內核中。要知道這是因爲所有相關人員都希望看到Linux整體成功的最佳解決方
+案。這個開發過程已經被證明可以創建有史以來最健壯的操作系統內核,我們不想做任何
+事情來導致提交質量和最終結果的下降。
+
+維護者
+------
+
+行爲準則多次使用“維護者”一詞。在內核社區中,“維護者”是負責子系統、驅動程序或
+文件的任何人,並在內核源代碼樹的維護者文件中列出。
+
+責任
+----
+
+《行爲準則》提到了維護人員的權利和責任,這需要進一步澄清。
+
+首先,最重要的是,有一個合理的期望是由維護人員通過實例來領導。
+
+也就是說,我們的社區是廣闊的,對維護者沒有新的要求,他們單方面處理其他人在
+他們活躍的社區的行爲。這一責任由我們所有人承擔,最終《行爲準則》記錄了最終的
+上訴路徑,以防有關行爲問題的問題懸而未決。
+
+維護人員應該願意在出現問題時提供幫助,並在需要時與社區中的其他人合作。如果您
+不確定如何處理出現的情況,請不要害怕聯繫技術諮詢委員會(TAB)或其他維護人員。
+除非您願意,否則不會將其視爲違規報告。如果您不確定是否該聯繫TAB 或任何其他維
+護人員,請聯繫我們的衝突調解人 Mishi Choudhary <mishi@linux.com>。
+
+最後,“善待對方”纔是每個人的最終目標。我們知道每個人都是人,有時我們都會失敗,
+但我們所有人的首要目標應該是努力友好地解決問題。執行行爲準則將是最後的選擇。
+
+我們的目標是創建一個強大的、技術先進的操作系統,以及所涉及的技術複雜性,這自
+然需要專業知識和決策。
+
+所需的專業知識因貢獻領域而異。它主要由上下文和技術複雜性決定,其次由貢獻者和
+維護者的期望決定。
+
+專家的期望和決策都要經過討論,但在最後,爲了取得進展,必須能夠做出決策。這一
+特權掌握在維護人員和項目領導的手中,預計將善意使用。
+
+因此,設定專業知識期望、作出決定和拒絕不適當的貢獻不被視爲違反行爲準則。
+
+雖然維護人員一般都歡迎新來者,但他們幫助(新)貢獻者克服障礙的能力有限,因此
+他們必須確定優先事項。這也不應被視爲違反了行爲準則。內核社區意識到這一點,並
+以各種形式提供入門級節目,如 kernelnewbies.org 。
+
+範圍
+----
+
+Linux內核社區主要在一組公共電子郵件列表上進行交互,這些列表分佈在由多個不同
+公司或個人控制的多個不同服務器上。所有這些列表都在內核源代碼樹中的
+MAINTAINERS 文件中定義。發送到這些郵件列表的任何電子郵件都被視爲包含在行爲
+準則中。
+
+使用 kernel.org bugzilla和其他子系統bugzilla 或bug跟蹤工具的開發人員應該遵循
+行爲準則的指導原則。Linux內核社區沒有“官方”項目電子郵件地址或“官方”社交媒體
+地址。使用kernel.org電子郵件帳戶執行的任何活動必須遵循爲kernel.org發佈的行爲
+準則,就像任何使用公司電子郵件帳戶的個人必須遵循該公司的特定規則一樣。
+
+行爲準則並不禁止在郵件列表消息、內核更改日誌消息或代碼註釋中繼續包含名稱、
+電子郵件地址和相關注釋。
+
+其他論壇中的互動包括在適用於上述論壇的任何規則中,通常不包括在行爲準則中。
+除了在極端情況下可考慮的例外情況。
+
+提交給內核的貢獻應該使用適當的語言。在行爲準則之前已經存在的內容現在不會被
+視爲違反。然而,不適當的語言可以被視爲一個bug;如果任何相關方提交補丁,
+這樣的bug將被更快地修復。當前屬於用戶/內核API的一部分的表達式,或者反映已
+發佈標準或規範中使用的術語的表達式,不被視爲bug。
+
+執行
+----
+
+行爲準則中列出的地址屬於行爲準則委員會。https://kernel.org/code-of-conduct.html
+列出了在任何給定時間接收這些電子郵件的確切成員。成員不能訪問在加入委員會之前
+或離開委員會之後所做的報告。
+
+最初的行爲準則委員會由TAB的志願者以及作爲中立第三方的專業調解人組成。委員會
+的首要任務是建立文件化的流程,並將其公開。
+
+如果報告人不希望將整個委員會納入投訴或關切,可直接聯繫委員會的任何成員,包括
+調解人。
+
+行爲準則委員會根據流程審查案例(見上文),並根據需要和適當與TAB協商,例如請求
+和接收有關內核社區的信息。
+
+委員會做出的任何決定都將提交到表中,以便在必要時與相關維護人員一起執行。行爲
+準則委員會的決定可以通過三分之二的投票推翻。
+
+每季度,行爲準則委員會和標籤將提供一份報告,概述行爲準則委員會收到的匿名報告
+及其狀態,以及任何否決決定的細節,包括完整和可識別的投票細節。
+
+我們希望在啓動期之後爲行爲準則委員會人員配備建立一個不同的流程。發生此情況時,
+將使用該信息更新此文檔。
+
diff --git a/Documentation/translations/zh_TW/process/code-of-conduct.rst b/Documentation/translations/zh_TW/process/code-of-conduct.rst
new file mode 100644
index 000000000000..d24f1695bd02
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/code-of-conduct.rst
@@ -0,0 +1,76 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/code-of-conduct.rst <code_of_conduct>`
+:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+ Hu Haowen <2023002089@link.tyut.edu.cn>
+
+.. _tw_code_of_conduct:
+
+貢獻者契約行爲準則
+++++++++++++++++++
+
+我們的誓言
+==========
+
+爲了營造一個開放、友好的環境,我們作爲貢獻者和維護人承諾,讓我們的社區和參
+與者,擁有一個無騷擾的體驗,無論年齡、體型、殘疾、種族、性別特徵、性別認同
+和表達、經驗水平、教育程度、社會狀況,經濟地位、國籍、個人外貌、種族、宗教
+或性身份和取向。
+
+我們的標準
+==========
+
+有助於創造積極環境的行爲包括:
+
+* 使用歡迎和包容的語言
+* 尊重不同的觀點和經驗
+* 優雅地接受建設性的批評
+* 關注什麼對社區最有利
+* 對其他社區成員表示同情
+
+參與者的不可接受行爲包括:
+
+* 使用性意味的語言或意象以及不受歡迎的性注意或者更過分的行爲
+* 煽動、侮辱/貶損評論以及個人或政治攻擊
+* 公開或私下騷擾
+* 未經明確許可,發佈他人的私人信息,如物理或電子地址。
+* 在專業場合被合理認爲不適當的其他行爲
+
+我們的責任
+==========
+
+維護人員負責澄清可接受行爲的標準,並應針對任何不可接受行爲採取適當和公平的
+糾正措施。
+
+維護人員有權和責任刪除、編輯或拒絕與本行爲準則不一致的評論、承諾、代碼、
+wiki編輯、問題和其他貢獻,或暫時或永久禁止任何貢獻者從事他們認爲不適當、
+威脅、冒犯或有害的其他行爲。
+
+範圍
+====
+
+當個人代表項目或其社區時,本行爲準則既適用於項目空間,也適用於公共空間。
+代表一個項目或社區的例子包括使用一個正式的項目電子郵件地址,通過一個正式
+的社交媒體帳戶發佈,或者在在線或離線事件中擔任指定的代表。項目維護人員可以
+進一步定義和澄清項目的表示。
+
+執行
+====
+
+如有濫用、騷擾或其他不可接受的行爲,可聯繫行爲準則委員會<conduct@kernel.org>。
+所有投訴都將接受審查和調查,並將得到必要和適當的答覆。行爲準則委員會有義務
+對事件報告人保密。具體執行政策的進一步細節可單獨公佈。
+
+歸屬
+====
+
+本行爲準則改編自《貢獻者契約》,版本1.4,可從
+https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 獲取。
+
+解釋
+====
+
+有關Linux內核社區如何解釋此文檔,請參閱 :ref:`tw_code_of_conduct_interpretation`
+
diff --git a/Documentation/translations/zh_TW/process/coding-style.rst b/Documentation/translations/zh_TW/process/coding-style.rst
new file mode 100644
index 000000000000..f11dbb65ca21
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/coding-style.rst
@@ -0,0 +1,1087 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/process/coding-style.rst
+
+.. _tw_codingstyle:
+
+:譯者:
+ - 張樂 Zhang Le <r0bertz@gentoo.org>
+ - Andy Deng <theandy.deng@gmail.com>
+ - 吳想成 <bobwxc@email.cn>
+
+:校譯:
+ - 王聰 Wang Cong <xiyou.wangcong@gmail.com>
+ - wheelz <kernel.zeng@gmail.com>
+ - 管旭東 Xudong Guan <xudong.guan@gmail.com>
+ - Li Zefan <lizf@cn.fujitsu.com>
+ - Wang Chen <wangchen@cn.fujitsu.com>
+ - Hu Haowen <2023002089@link.tyut.edu.cn>
+
+Linux 內核代碼風格
+==================
+
+這是一個簡短的文檔,描述了 linux 內核的首選代碼風格。代碼風格是因人而異的,
+而且我不願意把自己的觀點強加給任何人,但這就像我去做任何事情都必須遵循的原則
+那樣,我也希望在絕大多數事上保持這種的態度。請 (在寫代碼時) 至少考慮一下這裏
+的代碼風格。
+
+首先,我建議你打印一份 GNU 代碼規範,然後不要讀。燒了它,這是一個具有重大象徵
+性意義的動作。
+
+不管怎樣,現在我們開始:
+
+
+1) 縮進
+-------
+
+製表符是 8 個字符,所以縮進也是 8 個字符。有些異端運動試圖將縮進變爲 4 (甚至
+2!) 字符深,這幾乎相當於嘗試將圓周率的值定義爲 3。
+
+理由:縮進的全部意義就在於清楚的定義一個控制塊起止於何處。尤其是當你盯着你的
+屏幕連續看了 20 小時之後,你將會發現大一點的縮進會使你更容易分辨縮進。
+
+現在,有些人會抱怨 8 個字符的縮進會使代碼向右邊移動的太遠,在 80 個字符的終端
+屏幕上就很難讀這樣的代碼。這個問題的答案是,如果你需要 3 級以上的縮進,不管用
+何種方式你的代碼已經有問題了,應該修正你的程序。
+
+簡而言之,8 個字符的縮進可以讓代碼更容易閱讀,還有一個好處是當你的函數嵌套太
+深的時候可以給你警告。留心這個警告。
+
+在 switch 語句中消除多級縮進的首選的方式是讓 ``switch`` 和從屬於它的 ``case``
+標籤對齊於同一列,而不要 ``兩次縮進`` ``case`` 標籤。比如:
+
+.. code-block:: c
+
+ switch (suffix) {
+ case 'G':
+ case 'g':
+ mem <<= 30;
+ break;
+ case 'M':
+ case 'm':
+ mem <<= 20;
+ break;
+ case 'K':
+ case 'k':
+ mem <<= 10;
+ fallthrough;
+ default:
+ break;
+ }
+
+不要把多個語句放在一行裏,除非你有什麼東西要隱藏:
+
+.. code-block:: c
+
+ if (condition) do_this;
+ do_something_everytime;
+
+不要使用逗號來避免使用大括號:
+
+.. code-block:: c
+
+ if (condition)
+ do_this(), do_that();
+
+使用大括號包裹多語句:
+
+.. code-block:: c
+
+ if (condition) {
+ do_this();
+ do_that();
+ }
+
+也不要在一行裏放多個賦值語句。內核代碼風格超級簡單。就是避免可能導致別人誤讀
+的表達式。
+
+除了註釋、文檔和 Kconfig 之外,不要使用空格來縮進,前面的例子是例外,是有意爲
+之。
+
+選用一個好的編輯器,不要在行尾留空格。
+
+
+2) 把長的行和字符串打散
+-----------------------
+
+代碼風格的意義就在於使用平常使用的工具來維持代碼的可讀性和可維護性。
+
+每一行的長度的限制是 80 列,我們強烈建議您遵守這個慣例。
+
+長於 80 列的語句要打散成有意義的片段。除非超過 80 列能顯著增加可讀性,並且不
+會隱藏信息。
+
+子片段要明顯短於母片段,並明顯靠右。一種非常常用的樣式是將子體與函數左括號對齊。
+
+這同樣適用於有着很長參數列表的函數頭。
+
+然而,絕對不要打散對用戶可見的字符串,例如 printk 信息,因爲這樣就
+很難對它們 grep。
+
+
+3) 大括號和空格的放置
+---------------------
+
+C 語言風格中另外一個常見問題是大括號的放置。和縮進大小不同,選擇或棄用某種放
+置策略並沒有多少技術上的原因,不過首選的方式,就像 Kernighan 和 Ritchie 展示
+給我們的,是把起始大括號放在行尾,而把結束大括號放在行首,所以:
+
+.. code-block:: c
+
+ if (x is true) {
+ we do y
+ }
+
+這適用於所有的非函數語句塊 (if, switch, for, while, do)。比如:
+
+.. code-block:: c
+
+ switch (action) {
+ case KOBJ_ADD:
+ return "add";
+ case KOBJ_REMOVE:
+ return "remove";
+ case KOBJ_CHANGE:
+ return "change";
+ default:
+ return NULL;
+ }
+
+不過,有一個例外,那就是函數:函數的起始大括號放置於下一行的開頭,所以:
+
+.. code-block:: c
+
+ int function(int x)
+ {
+ body of function
+ }
+
+全世界的異端可能會抱怨這個不一致性是……呃……不一致,不過所有思維健全的人
+都知道 (a) K&R 是 **正確的** 並且 (b) K&R 是正確的。此外,不管怎樣函數都是特
+殊的 (C 函數是不能嵌套的)。
+
+注意結束大括號獨自佔據一行,除非它後面跟着同一個語句的剩餘部分,也就是 do 語
+句中的 ``while`` 或者 if 語句中的 ``else`` ,像這樣:
+
+.. code-block:: c
+
+ do {
+ body of do-loop
+ } while (condition);
+
+和
+
+.. code-block:: c
+
+ if (x == y) {
+ ..
+ } else if (x > y) {
+ ...
+ } else {
+ ....
+ }
+
+理由:K&R。
+
+也請注意這種大括號的放置方式也能使空 (或者差不多空的) 行的數量最小化,同時不
+失可讀性。因此,由於你的屏幕上的新行是不可再生資源 (想想 25 行的終端屏幕),你
+將會有更多的空行來放置註釋。
+
+當只有一個單獨的語句的時候,不用加不必要的大括號。
+
+.. code-block:: c
+
+ if (condition)
+ action();
+
+和
+
+.. code-block:: c
+
+ if (condition)
+ do_this();
+ else
+ do_that();
+
+這並不適用於只有一個條件分支是單語句的情況;這時所有分支都要使用大括號:
+
+.. code-block:: c
+
+ if (condition) {
+ do_this();
+ do_that();
+ } else {
+ otherwise();
+ }
+
+3.1) 空格
+*********
+
+Linux 內核的空格使用方式 (主要) 取決於它是用於函數還是關鍵字。(大多數) 關鍵字
+後要加一個空格。值得注意的例外是 sizeof, typeof, alignof 和 __attribute__,這
+些關鍵字某些程度上看起來更像函數 (它們在 Linux 裏也常常伴隨小括號而使用,儘管
+在 C 裏這樣的小括號不是必需的,就像 ``struct fileinfo info;`` 聲明過後的
+``sizeof info``)。
+
+所以在這些關鍵字之後放一個空格::
+
+ if, switch, case, for, do, while
+
+但是不要在 sizeof, typeof, alignof 或者 __attribute__ 這些關鍵字之後放空格。
+例如,
+
+.. code-block:: c
+
+ s = sizeof(struct file);
+
+不要在小括號裏的表達式兩側加空格。這是一個 **反例** :
+
+.. code-block:: c
+
+ s = sizeof( struct file );
+
+當聲明指針類型或者返回指針類型的函數時, ``*`` 的首選使用方式是使之靠近變量名
+或者函數名,而不是靠近類型名。例子:
+
+.. code-block:: c
+
+ char *linux_banner;
+ unsigned long long memparse(char *ptr, char **retptr);
+ char *match_strdup(substring_t *s);
+
+在大多數二元和三元操作符兩側使用一個空格,例如下面所有這些操作符::
+
+ = + - < > * / % | & ^ <= >= == != ? :
+
+但是一元操作符後不要加空格::
+
+ & * + - ~ ! sizeof typeof alignof __attribute__ defined
+
+後綴自加和自減一元操作符前不加空格::
+
+ ++ --
+
+前綴自加和自減一元操作符後不加空格::
+
+ ++ --
+
+``.`` 和 ``->`` 結構體成員操作符前後不加空格。
+
+不要在行尾留空白。有些可以自動縮進的編輯器會在新行的行首加入適量的空白,然後
+你就可以直接在那一行輸入代碼。不過假如你最後沒有在那一行輸入代碼,有些編輯器
+就不會移除已經加入的空白,就像你故意留下一個只有空白的行。包含行尾空白的行就
+這樣產生了。
+
+當 git 發現補丁包含了行尾空白的時候會警告你,並且可以應你的要求去掉行尾空白;
+不過如果你是正在打一系列補丁,這樣做會導致後面的補丁失敗,因爲你改變了補丁的
+上下文。
+
+
+4) 命名
+-------
+
+C 是一個簡樸的語言,你的命名也應該這樣。和 Modula-2 和 Pascal 程序員不同,
+C 程序員不使用類似 ThisVariableIsATemporaryCounter 這樣華麗的名字。C 程序員會
+稱那個變量爲 ``tmp`` ,這樣寫起來會更容易,而且至少不會令其難於理解。
+
+不過,雖然混用大小寫的名字是不提倡使用的,但是全局變量還是需要一個具描述性的
+名字。稱一個全局函數爲 ``foo`` 是一個難以饒恕的錯誤。
+
+全局變量 (只有當你 **真正** 需要它們的時候再用它) 需要有一個具描述性的名字,就
+像全局函數。如果你有一個可以計算活動用戶數量的函數,你應該叫它
+``count_active_users()`` 或者類似的名字,你不應該叫它 ``cntuser()`` 。
+
+在函數名中包含函數類型 (所謂的匈牙利命名法) 是腦子出了問題——編譯器知道那些類
+型而且能夠檢查那些類型,這樣做只能把程序員弄糊塗了。
+
+本地變量名應該簡短,而且能夠表達相關的含義。如果你有一些隨機的整數型的循環計
+數器,它應該被稱爲 ``i`` 。叫它 ``loop_counter`` 並無益處,如果它沒有被誤解的
+可能的話。類似的, ``tmp`` 可以用來稱呼任意類型的臨時變量。
+
+如果你怕混淆了你的本地變量名,你就遇到另一個問題了,叫做函數增長荷爾蒙失衡綜
+合徵。請看第六章 (函數)。
+
+對於符號名稱和文檔,避免引入新的“master/slave”(或獨立於“master”的“slave”)
+和“blacklist/whitelist”。
+
+“master/slave”推薦替換爲:
+ '{primary,main} / {secondary,replica,subordinate}'
+ '{initiator,requester} / {target,responder}'
+ '{controller,host} / {device,worker,proxy}'
+ 'leader/follower'
+ 'director/performer'
+
+“blacklist/whitelist”推薦替換爲:
+ 'denylist/allowlist'
+ 'blocklist/passlist'
+
+引入新用法的例外情況是:維護用戶空間ABI/API,或更新現有(截至2020年)硬件或
+協議規範的代碼時要求這些術語。對於新規範,儘可能將術語的規範用法轉換爲內核
+編碼標準。
+
+.. warning::
+ 以上主從、黑白名單規則不適用於中文文檔,請勿更改中文術語!
+
+5) Typedef
+----------
+
+不要使用類似 ``vps_t`` 之類的東西。
+
+對結構體和指針使用 typedef 是一個 **錯誤** 。當你在代碼裏看到:
+
+.. code-block:: c
+
+ vps_t a;
+
+這代表什麼意思呢?
+
+相反,如果是這樣
+
+.. code-block:: c
+
+ struct virtual_container *a;
+
+你就知道 ``a`` 是什麼了。
+
+很多人認爲 typedef ``能提高可讀性`` 。實際不是這樣的。它們只在下列情況下有用:
+
+ (a) 完全不透明的對象 (這種情況下要主動使用 typedef 來 **隱藏** 這個對象實際上
+ 是什麼)。
+
+ 例如: ``pte_t`` 等不透明對象,你只能用合適的訪問函數來訪問它們。
+
+ .. note::
+
+ 不透明性和“訪問函數”本身是不好的。我們使用 pte_t 等類型的原因在於真
+ 的是完全沒有任何共用的可訪問信息。
+
+ (b) 清楚的整數類型,如此,這層抽象就可以 **幫助** 消除到底是 ``int`` 還是
+ ``long`` 的混淆。
+
+ u8/u16/u32 是完全沒有問題的 typedef,不過它們更符合類別 (d) 而不是這裏。
+
+ .. note::
+
+ 要這樣做,必須事出有因。如果某個變量是 ``unsigned long`` ,那麼沒有必要
+
+ typedef unsigned long myflags_t;
+
+ 不過如果有一個明確的原因,比如它在某種情況下可能會是一個 ``unsigned int``
+ 而在其他情況下可能爲 ``unsigned long`` ,那麼就不要猶豫,請務必使用
+ typedef。
+
+ (c) 當你使用 sparse 按字面的創建一個 **新** 類型來做類型檢查的時候。
+
+ (d) 和標準 C99 類型相同的類型,在某些例外的情況下。
+
+ 雖然讓眼睛和腦筋來適應新的標準類型比如 ``uint32_t`` 不需要花很多時間,可
+ 是有些人仍然拒絕使用它們。
+
+ 因此,Linux 特有的等同於標準類型的 ``u8/u16/u32/u64`` 類型和它們的有符號
+ 類型是被允許的——儘管在你自己的新代碼中,它們不是強制要求要使用的。
+
+ 當編輯已經使用了某個類型集的已有代碼時,你應該遵循那些代碼中已經做出的選
+ 擇。
+
+ (e) 可以在用戶空間安全使用的類型。
+
+ 在某些用戶空間可見的結構體裏,我們不能要求 C99 類型而且不能用上面提到的
+ ``u32`` 類型。因此,我們在與用戶空間共享的所有結構體中使用 __u32 和類似
+ 的類型。
+
+可能還有其他的情況,不過基本的規則是 **永遠不要** 使用 typedef,除非你可以明
+確的應用上述某個規則中的一個。
+
+總的來說,如果一個指針或者一個結構體裏的元素可以合理的被直接訪問到,那麼它們
+就不應該是一個 typedef。
+
+
+6) 函數
+-------
+
+函數應該簡短而漂亮,並且只完成一件事情。函數應該可以一屏或者兩屏顯示完 (我們
+都知道 ISO/ANSI 屏幕大小是 80x24),只做一件事情,而且把它做好。
+
+一個函數的最大長度是和該函數的複雜度和縮進級數成反比的。所以,如果你有一個理
+論上很簡單的只有一個很長 (但是簡單) 的 case 語句的函數,而且你需要在每個 case
+裏做很多很小的事情,這樣的函數儘管很長,但也是可以的。
+
+不過,如果你有一個複雜的函數,而且你懷疑一個天分不是很高的高中一年級學生可能
+甚至搞不清楚這個函數的目的,你應該嚴格遵守前面提到的長度限制。使用輔助函數,
+併爲之取個具描述性的名字 (如果你覺得它們的性能很重要的話,可以讓編譯器內聯它
+們,這樣的效果往往會比你寫一個複雜函數的效果要好。)
+
+函數的另外一個衡量標準是本地變量的數量。此數量不應超過 5-10 個,否則你的函數
+就有問題了。重新考慮一下你的函數,把它分拆成更小的函數。人的大腦一般可以輕鬆
+的同時跟蹤 7 個不同的事物,如果再增多的話,就會糊塗了。即便你聰穎過人,你也可
+能會記不清你 2 個星期前做過的事情。
+
+在源文件裏,使用空行隔開不同的函數。如果該函數需要被導出,它的 **EXPORT** 宏
+應該緊貼在它的結束大括號之下。比如:
+
+.. code-block:: c
+
+ int system_is_up(void)
+ {
+ return system_state == SYSTEM_RUNNING;
+ }
+ EXPORT_SYMBOL(system_is_up);
+
+6.1) 函數原型
+*************
+
+在函數原型中包含參數名和它們的數據類型。雖然 C 語言裏沒有這樣的要求,但在
+Linux 裏這是提倡的做法,因爲這樣可以很簡單的給讀者提供更多的有價值的信息。
+
+不要在函數聲明裏使用 ``extern`` 關鍵字,因爲這會導致代碼行變長,並且不是嚴格
+必需的。
+
+寫函數原型時,請保持 `元素順序規則 <https://lore.kernel.org/mm-commits/CAHk-=wiOCLRny5aifWNhr621kYrJwhfURsa0vFPeUEm8mF0ufg@mail.gmail.com/>`_ 。
+例如下列函數聲明::
+
+ __init void * __must_check action(enum magic value, size_t size, u8 count,
+ char *fmt, ...) __printf(4, 5) __malloc;
+
+推薦的函數原型元素順序是:
+
+- 儲存類型(下方的 ``static __always_inline`` ,注意 ``__always_inline``
+ 技術上來講是個屬性但被當做 ``inline`` )
+- 儲存類型屬性(上方的 ``__init`` ——即節聲明,但也像 ``__cold`` )
+- 返回類型(上方的 ``void *`` )
+- 返回類型屬性(上方的 ``__must_check`` )
+- 函數名(上方的 ``action`` )
+- 函數參數(上方的 ``(enum magic value, size_t size, u8 count, char *fmt, ...)`` ,
+ 注意必須寫上參數名)
+- 函數參數屬性(上方的 ``__printf(4, 5)`` )
+- 函數行爲屬性(上方的 ``__malloc`` )
+
+請注意,對於函數 **定義** (即實際函數體),編譯器不允許在函數參數之後添加函
+數參數屬性。在這種情況下,它們應該跟隨存儲類型屬性(例如,與上面的 **聲明**
+示例相比,請注意下面的 ``__printf(4, 5)`` 的位置發生了變化)::
+
+ static __always_inline __init __printf(4, 5) void * __must_check action(enum magic value,
+ size_t size, u8 count, char *fmt, ...) __malloc
+ {
+ ...
+ }
+
+7) 集中的函數退出途徑
+---------------------
+
+雖然被某些人聲稱已經過時,但是 goto 語句的等價物還是經常被編譯器所使用,具體
+形式是無條件跳轉指令。
+
+當一個函數從多個位置退出,並且需要做一些類似清理的常見操作時,goto 語句就很方
+便了。如果並不需要清理操作,那麼直接 return 即可。
+
+選擇一個能夠說明 goto 行爲或它爲何存在的標籤名。如果 goto 要釋放 ``buffer``,
+一個不錯的名字可以是 ``out_free_buffer:`` 。別去使用像 ``err1:`` 和 ``err2:``
+這樣的GW_BASIC 名稱,因爲一旦你添加或刪除了 (函數的) 退出路徑,你就必須對它們
+重新編號,這樣會難以去檢驗正確性。
+
+使用 goto 的理由是:
+
+- 無條件語句容易理解和跟蹤
+- 嵌套程度減小
+- 可以避免由於修改時忘記更新個別的退出點而導致錯誤
+- 讓編譯器省去刪除冗餘代碼的工作 ;)
+
+.. code-block:: c
+
+ int fun(int a)
+ {
+ int result = 0;
+ char *buffer;
+
+ buffer = kmalloc(SIZE, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ if (condition1) {
+ while (loop1) {
+ ...
+ }
+ result = 1;
+ goto out_free_buffer;
+ }
+ ...
+ out_free_buffer:
+ kfree(buffer);
+ return result;
+ }
+
+一個需要注意的常見錯誤是 ``單 err 錯誤`` ,就像這樣:
+
+.. code-block:: c
+
+ err:
+ kfree(foo->bar);
+ kfree(foo);
+ return ret;
+
+這段代碼的錯誤是,在某些退出路徑上 ``foo`` 是 NULL。通常情況下,通過把它分離
+成兩個錯誤標籤 ``err_free_bar:`` 和 ``err_free_foo:`` 來修復這個錯誤:
+
+.. code-block:: c
+
+ err_free_bar:
+ kfree(foo->bar);
+ err_free_foo:
+ kfree(foo);
+ return ret;
+
+理想情況下,你應該模擬錯誤來測試所有退出路徑。
+
+
+8) 註釋
+-------
+
+註釋是好的,不過有過度註釋的危險。永遠不要在註釋裏解釋你的代碼是如何運作的:
+更好的做法是讓別人一看你的代碼就可以明白,解釋寫的很差的代碼是浪費時間。
+
+一般來說你用註釋告訴別人你的代碼做了什麼,而不是怎麼做的。也請你不要把
+註釋放在一個函數體內部:如果函數複雜到你需要獨立的註釋其中的一部分,你很可能
+需要回到第六章看一看。你可以做一些小注釋來註明或警告某些很聰明 (或者槽糕) 的
+做法,但不要加太多。你應該做的,是把註釋放在函數的頭部,告訴人們它做了什麼,
+也可以加上它做這些事情的原因。
+
+當註釋內核 API 函數時,請使用 kernel-doc 格式。詳見
+Documentation/translations/zh_CN/doc-guide/index.rst 和 scripts/kernel-doc 。
+
+長 (多行) 註釋的首選風格是:
+
+.. code-block:: c
+
+ /*
+ * This is the preferred style for multi-line
+ * comments in the Linux kernel source code.
+ * Please use it consistently.
+ *
+ * Description: A column of asterisks on the left side,
+ * with beginning and ending almost-blank lines.
+ */
+
+對於在 net/ 和 drivers/net/ 的文件,首選的長 (多行) 註釋風格有些不同。
+
+.. code-block:: c
+
+ /* The preferred comment style for files in net/ and drivers/net
+ * looks like this.
+ *
+ * It is nearly the same as the generally preferred comment style,
+ * but there is no initial almost-blank line.
+ */
+
+註釋數據也是很重要的,不管是基本類型還是衍生類型。爲了方便實現這一點,每一行
+應只聲明一個數據 (不要使用逗號來一次聲明多個數據)。這樣你就有空間來爲每個數據
+寫一段小注釋來解釋它們的用途了。
+
+
+9) 你已經把事情弄糟了
+---------------------
+
+這沒什麼,我們都是這樣。可能你長期使用 Unix 的朋友已經告訴你
+``GNU emacs`` 能自動幫你格式化 C 源代碼,而且你也注意到了,確實是這樣,不過它
+所使用的默認值和我們想要的相去甚遠 (實際上,甚至比隨機打的還要差——無數個猴子
+在 GNU emacs 裏打字永遠不會創造出一個好程序)
+*(譯註:Infinite Monkey Theorem)*
+
+所以你要麼放棄 GNU emacs,要麼改變它讓它使用更合理的設定。要採用後一個方案,
+你可以把下面這段粘貼到你的 .emacs 文件裏。
+
+.. code-block:: elisp
+
+ (defun c-lineup-arglist-tabs-only (ignored)
+ "Line up argument lists by tabs, not spaces"
+ (let* ((anchor (c-langelem-pos c-syntactic-element))
+ (column (c-langelem-2nd-pos c-syntactic-element))
+ (offset (- (1+ column) anchor))
+ (steps (floor offset c-basic-offset)))
+ (* (max steps 1)
+ c-basic-offset)))
+
+ (dir-locals-set-class-variables
+ 'linux-kernel
+ '((c-mode . (
+ (c-basic-offset . 8)
+ (c-label-minimum-indentation . 0)
+ (c-offsets-alist . (
+ (arglist-close . c-lineup-arglist-tabs-only)
+ (arglist-cont-nonempty .
+ (c-lineup-gcc-asm-reg c-lineup-arglist-tabs-only))
+ (arglist-intro . +)
+ (brace-list-intro . +)
+ (c . c-lineup-C-comments)
+ (case-label . 0)
+ (comment-intro . c-lineup-comment)
+ (cpp-define-intro . +)
+ (cpp-macro . -1000)
+ (cpp-macro-cont . +)
+ (defun-block-intro . +)
+ (else-clause . 0)
+ (func-decl-cont . +)
+ (inclass . +)
+ (inher-cont . c-lineup-multi-inher)
+ (knr-argdecl-intro . 0)
+ (label . -1000)
+ (statement . 0)
+ (statement-block-intro . +)
+ (statement-case-intro . +)
+ (statement-cont . +)
+ (substatement . +)
+ ))
+ (indent-tabs-mode . t)
+ (show-trailing-whitespace . t)
+ ))))
+
+ (dir-locals-set-directory-class
+ (expand-file-name "~/src/linux-trees")
+ 'linux-kernel)
+
+這會讓 emacs 在 ``~/src/linux-trees`` 下的 C 源文件獲得更好的內核代碼風格。
+
+不過就算你嘗試讓 emacs 正確的格式化代碼失敗了,也並不意味着你失去了一切:還可
+以用 ``indent`` 。
+
+不過,GNU indent 也有和 GNU emacs 一樣有問題的設定,所以你需要給它一些命令選
+項。不過,這還不算太糟糕,因爲就算是 GNU indent 的作者也認同 K&R 的權威性
+(GNU 的人並不是壞人,他們只是在這個問題上被嚴重的誤導了),所以你只要給 indent
+指定選項 ``-kr -i8`` (代表 ``K&R,8 字符縮進``),或使用 ``scripts/Lindent``
+這樣就可以以最時髦的方式縮進源代碼。
+
+``indent`` 有很多選項,特別是重新格式化註釋的時候,你可能需要看一下它的手冊。
+不過記住: ``indent`` 不能修正壞的編程習慣。
+
+請注意,您還可以使用 ``clang-format`` 工具幫助您處理這些規則,快速自動重新格
+式化部分代碼,並審閱整個文件以發現代碼風格錯誤、打字錯誤和可能的改進。它還可
+以方便地排序 ``#include`` ,對齊變量/宏,重排文本和其他類似任務。
+詳見 Documentation/process/clang-format.rst 。
+
+
+10) Kconfig 配置文件
+--------------------
+
+對於遍佈源碼樹的所有 Kconfig* 配置文件來說,它們縮進方式有所不同。緊挨着
+``config`` 定義的行,用一個製表符縮進,然而 help 信息的縮進則額外增加 2 個空
+格。舉個例子::
+
+ 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). Does not do system-call
+ auditing without CONFIG_AUDITSYSCALL.
+
+而那些危險的功能 (比如某些文件系統的寫支持) 應該在它們的提示字符串裏顯著的聲
+明這一點::
+
+ config ADFS_FS_RW
+ bool "ADFS write support (DANGEROUS)"
+ depends on ADFS_FS
+ ...
+
+要查看配置文件的完整文檔,請看 Documentation/kbuild/kconfig-language.rst 。
+
+
+11) 數據結構
+------------
+
+如果一個數據結構,在創建和銷燬它的單線執行環境之外可見,那麼它必須要有一個引
+用計數器。內核裏沒有垃圾收集 (並且內核之外的垃圾收集慢且效率低下),這意味着你
+絕對需要記錄你對這種數據結構的使用情況。
+
+引用計數意味着你能夠避免上鎖,並且允許多個用戶並行訪問這個數據結構——而不需要
+擔心這個數據結構僅僅因爲暫時不被使用就消失了,那些用戶可能不過是沉睡了一陣或
+者做了一些其他事情而已。
+
+注意上鎖 **不能** 取代引用計數。上鎖是爲了保持數據結構的一致性,而引用計數是一
+個內存管理技巧。通常二者都需要,不要把兩個搞混了。
+
+很多數據結構實際上有 2 級引用計數,它們通常有不同 ``類`` 的用戶。子類計數器統
+計子類用戶的數量,每當子類計數器減至零時,全局計數器減一。
+
+這種 ``多級引用計數`` 的例子可以在內存管理 (``struct mm_struct``: mm_users 和
+mm_count),和文件系統 (``struct super_block``: s_count 和 s_active) 中找到。
+
+記住:如果另一個執行線索可以找到你的數據結構,但這個數據結構沒有引用計數器,
+這裏幾乎肯定是一個 bug。
+
+
+12) 宏,枚舉和RTL
+-----------------
+
+用於定義常量的宏的名字及枚舉裏的標籤需要大寫。
+
+.. code-block:: c
+
+ #define CONSTANT 0x12345
+
+在定義幾個相關的常量時,最好用枚舉。
+
+宏的名字請用大寫字母,不過形如函數的宏的名字可以用小寫字母。
+
+通常如果能寫成內聯函數就不要寫成像函數的宏。
+
+含有多個語句的宏應該被包含在一個 do-while 代碼塊裏:
+
+.. code-block:: c
+
+ #define macrofun(a, b, c) \
+ do { \
+ if (a == 5) \
+ do_this(b, c); \
+ } while (0)
+
+使用宏的時候應避免的事情:
+
+1) 影響控制流程的宏:
+
+.. code-block:: c
+
+ #define FOO(x) \
+ do { \
+ if (blah(x) < 0) \
+ return -EBUGGERED; \
+ } while (0)
+
+**非常** 不好。它看起來像一個函數,不過卻能導致 ``調用`` 它的函數退出;不要打
+亂讀者大腦裏的語法分析器。
+
+2) 依賴於一個固定名字的本地變量的宏:
+
+.. code-block:: c
+
+ #define FOO(val) bar(index, val)
+
+可能看起來像是個不錯的東西,不過它非常容易把讀代碼的人搞糊塗,而且容易導致看起
+來不相關的改動帶來錯誤。
+
+3) 作爲左值的帶參數的宏: FOO(x) = y;如果有人把 FOO 變成一個內聯函數的話,這
+ 種用法就會出錯了。
+
+4) 忘記了優先級:使用表達式定義常量的宏必須將表達式置於一對小括號之內。帶參數
+ 的宏也要注意此類問題。
+
+.. code-block:: c
+
+ #define CONSTANT 0x4000
+ #define CONSTEXP (CONSTANT | 3)
+
+5) 在宏裏定義類似函數的本地變量時命名衝突:
+
+.. code-block:: c
+
+ #define FOO(x) \
+ ({ \
+ typeof(x) ret; \
+ ret = calc_ret(x); \
+ (ret); \
+ })
+
+ret 是本地變量的通用名字—— __foo_ret 更不容易與一個已存在的變量衝突。
+
+cpp 手冊對宏的講解很詳細。gcc internals 手冊也詳細講解了 RTL,內核裏的彙編語
+言經常用到它。
+
+
+13) 打印內核消息
+----------------
+
+內核開發者應該看起來有文化。請一定注意內核信息的拼寫,以給人良好的印象。
+不要用不規範的單詞比如 ``dont``,而要用 ``do not`` 或者 ``don't`` 。保證這些信
+息簡單明瞭、無歧義。
+
+內核信息不必以英文句號結束。
+
+在小括號裏打印數字 (%d) 沒有任何價值,應該避免這樣做。
+
+<linux/device.h> 裏有一些驅動模型診斷宏,你應該使用它們,以確保信息對應於正確
+的設備和驅動,並且被標記了正確的消息級別。這些宏有:dev_err(), dev_warn(),
+dev_info() 等等。對於那些不和某個特定設備相關連的信息,<linux/printk.h> 定義
+了 pr_notice(), pr_info(), pr_warn(), pr_err() 和其他。
+
+寫出好的調試信息可以是一個很大的挑戰;一旦你寫出後,這些信息在遠程除錯時能提
+供極大的幫助。然而打印調試信息的處理方式同打印非調試信息不同。其他 pr_XXX()
+函數能無條件地打印,pr_debug() 卻不;默認情況下它不會被編譯,除非定義了 DEBUG
+或設定了 CONFIG_DYNAMIC_DEBUG。實際這同樣是爲了 dev_dbg(),一個相關約定是在一
+個已經開啓了 DEBUG 時,使用 VERBOSE_DEBUG 來添加 dev_vdbg()。
+
+許多子系統擁有 Kconfig 調試選項來開啓對應 Makefile 裏面的 -DDEBUG;在其他
+情況下,特殊文件使用 #define DEBUG。當一條調試信息需要被無條件打印時,例如,
+如果已經包含一個調試相關的 #ifdef 條件,printk(KERN_DEBUG ...) 就可被使用。
+
+
+14) 分配內存
+------------
+
+內核提供了下面的一般用途的內存分配函數:
+kmalloc(), kzalloc(), kmalloc_array(), kcalloc(), vmalloc() 和 vzalloc()。
+請參考 API 文檔以獲取有關它們的詳細信息:
+Documentation/translations/zh_CN/core-api/memory-allocation.rst 。
+
+傳遞結構體大小的首選形式是這樣的:
+
+.. code-block:: c
+
+ p = kmalloc(sizeof(*p), ...);
+
+另外一種傳遞方式中,sizeof 的操作數是結構體的名字,這樣會降低可讀性,並且可能
+會引入 bug。有可能指針變量類型被改變時,而對應的傳遞給內存分配函數的 sizeof
+的結果不變。
+
+強制轉換一個 void 指針返回值是多餘的。C 語言本身保證了從 void 指針到其他任何
+指針類型的轉換是沒有問題的。
+
+分配一個數組的首選形式是這樣的:
+
+.. code-block:: c
+
+ p = kmalloc_array(n, sizeof(...), ...);
+
+分配一個零長數組的首選形式是這樣的:
+
+.. code-block:: c
+
+ p = kcalloc(n, sizeof(...), ...);
+
+兩種形式都會檢查分配 n * sizeof(...) 大小時內存的溢出,如果溢出返回 NULL。
+
+在沒有 __GFP_NOWARN 的情況下使用時,這些通用分配函數都會在失敗時發起堆棧轉儲,
+因此當返回NULL時,沒有必要發出額外的失敗消息。
+
+15) 內聯弊病
+------------
+
+有一個常見的誤解是 ``內聯`` 是 gcc 提供的可以讓代碼運行更快的一個選項。雖然使
+用內聯函數有時候是恰當的 (比如作爲一種替代宏的方式,請看第十二章),不過很多情
+況下不是這樣。inline 的過度使用會使內核變大,從而使整個系統運行速度變慢。
+因爲體積大內核會佔用更多的指令高速緩存,而且會導致 pagecache 的可用內存減少。
+想象一下,一次 pagecache 未命中就會導致一次磁盤尋址,將耗時 5 毫秒。5 毫秒的
+時間內 CPU 能執行很多很多指令。
+
+一個基本的原則是如果一個函數有 3 行以上,就不要把它變成內聯函數。這個原則的一
+個例外是,如果你知道某個參數是一個編譯時常量,而且因爲這個常量你確定編譯器在
+編譯時能優化掉你的函數的大部分代碼,那仍然可以給它加上 inline 關鍵字。
+kmalloc() 內聯函數就是一個很好的例子。
+
+人們經常主張給 static 的而且只用了一次的函數加上 inline,如此不會有任何損失,
+因爲沒有什麼好權衡的。雖然從技術上說這是正確的,但是實際上這種情況下即使不加
+inline gcc 也可以自動使其內聯。而且其他用戶可能會要求移除 inline,由此而來的
+爭論會抵消 inline 自身的潛在價值,得不償失。
+
+
+16) 函數返回值及命名
+--------------------
+
+函數可以返回多種不同類型的值,最常見的一種是表明函數執行成功或者失敗的值。這樣
+的一個值可以表示爲一個錯誤代碼整數 (-Exxx=失敗,0=成功) 或者一個 ``成功``
+布爾值 (0=失敗,非0=成功)。
+
+混合使用這兩種表達方式是難於發現的 bug 的來源。如果 C 語言本身嚴格區分整形和
+布爾型變量,那麼編譯器就能夠幫我們發現這些錯誤... 不過 C 語言不區分。爲了避免
+產生這種 bug,請遵循下面的慣例::
+
+ 如果函數的名字是一個動作或者強制性的命令,那麼這個函數應該返回錯誤代
+ 碼整數。如果是一個判斷,那麼函數應該返回一個“成功”布爾值。
+
+比如, ``add work`` 是一個命令,所以 add_work() 在成功時返回 0,在失敗時返回
+-EBUSY。類似的,因爲 ``PCI device present`` 是一個判斷,所以 pci_dev_present()
+在成功找到一個匹配的設備時應該返回 1,如果找不到時應該返回 0。
+
+所有 EXPORTed 函數都必須遵守這個慣例,所有的公共函數也都應該如此。私有
+(static) 函數不需要如此,但是我們也推薦這樣做。
+
+返回值是實際計算結果而不是計算是否成功的標誌的函數不受此慣例的限制。通常
+他們通過返回一些正常值範圍之外的結果來表示出錯。典型的例子是返回指針的函數,
+他們使用 NULL 或者 ERR_PTR 機制來報告錯誤。
+
+17) 使用布爾類型
+----------------
+
+Linux內核布爾(bool)類型是C99 _Bool類型的別名。布爾值只能爲0或1,而對布爾的
+隱式或顯式轉換將自動將值轉換爲true或false。在使用布爾類型時 **不需要** 構造,
+它會消除一類錯誤。
+
+使用布爾值時,應使用true和false定義,而不是1和0。
+
+布爾函數返回類型和堆棧變量總是可以在適當的時候使用。鼓勵使用布爾來提高可讀性,
+並且布爾值在存儲時通常比“int”更好。
+
+如果緩存行佈局或值的大小很重要,請不要使用布爾,因爲其大小和對齊方式根據編譯
+的體系結構而不同。針對對齊和大小進行優化的結構體不應使用布爾。
+
+如果一個結構體有多個true/false值,請考慮將它們合併爲具有1比特成員的位域,或使
+用適當的固定寬度類型,如u8。
+
+類似地,對於函數參數,多個true/false值可以合併爲單個按位的“標誌”參數,如果調
+用點具有裸true/false常量,“標誌”參數通常是更具可讀性的替代方法。
+
+總之,在結構體和參數中有限地使用布爾可以提高可讀性。
+
+18) 不要重新發明內核宏
+----------------------
+
+頭文件 include/linux/kernel.h 包含了一些宏,你應該使用它們,而不要自己寫一些
+它們的變種。比如,如果你需要計算一個數組的長度,使用這個宏
+
+.. code-block:: c
+
+ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+類似的,如果你要計算某結構體成員的大小,使用
+
+.. code-block:: c
+
+ #define sizeof_field(t, f) (sizeof(((t*)0)->f))
+
+還有可以做嚴格的類型檢查的 min() 和 max() 宏,如果你需要可以使用它們。你可以
+自己看看那個頭文件裏還定義了什麼你可以拿來用的東西,如果有定義的話,你就不應
+在你的代碼裏自己重新定義。
+
+
+19) 編輯器模式行和其他需要羅嗦的事情
+------------------------------------
+
+有一些編輯器可以解釋嵌入在源文件裏的由一些特殊標記標明的配置信息。比如,emacs
+能夠解析被標記成這樣的行:
+
+.. code-block:: c
+
+ -*- mode: c -*-
+
+或者這樣的:
+
+.. code-block:: c
+
+ /*
+ Local Variables:
+ compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c"
+ End:
+ */
+
+Vim 能夠解析這樣的標記:
+
+.. code-block:: c
+
+ /* vim:set sw=8 noet */
+
+不要在源代碼中包含任何這樣的內容。每個人都有他自己的編輯器配置,你的源文件不
+應該覆蓋別人的配置。這包括有關縮進和模式配置的標記。人們可以使用他們自己定製
+的模式,或者使用其他可以產生正確的縮進的巧妙方法。
+
+
+20) 內聯彙編
+------------
+
+在特定架構的代碼中,你可能需要內聯彙編與 CPU 和平臺相關功能連接。需要這麼做時
+就不要猶豫。然而,當 C 可以完成工作時,不要平白無故地使用內聯彙編。在可能的情
+況下,你可以並且應該用 C 和硬件溝通。
+
+請考慮去寫捆綁通用位元 (wrap common bits) 的內聯彙編的簡單輔助函數,別去重複
+地寫下只有細微差異內聯彙編。記住內聯彙編可以使用 C 參數。
+
+大型,有一定複雜度的彙編函數應該放在 .S 文件內,用相應的 C 原型定義在 C 頭文
+件中。彙編函數的 C 原型應該使用 ``asmlinkage`` 。
+
+你可能需要把彙編語句標記爲 volatile,用來阻止 GCC 在沒發現任何副作用後就把它
+移除了。你不必總是這樣做,儘管,這不必要的舉動會限制優化。
+
+在寫一個包含多條指令的單個內聯彙編語句時,把每條指令用引號分割而且各佔一行,
+除了最後一條指令外,在每個指令結尾加上 ``\n\t`` ,讓彙編輸出時可以正確地縮進
+下一條指令:
+
+.. code-block:: c
+
+ asm ("magic %reg1, #42\n\t"
+ "more_magic %reg2, %reg3"
+ : /* outputs */ : /* inputs */ : /* clobbers */);
+
+
+21) 條件編譯
+------------
+
+只要可能,就不要在 .c 文件裏面使用預處理條件 (#if, #ifdef);這樣做會讓代碼更難
+閱讀並且更難去跟蹤邏輯。替代方案是,在頭文件中用預處理條件提供給那些 .c 文件
+使用,再給 #else 提供一個空樁 (no-op stub) 版本,然後在 .c 文件內無條件地調用
+那些 (定義在頭文件內的) 函數。這樣做,編譯器會避免爲樁函數 (stub) 的調用生成
+任何代碼,產生的結果是相同的,但邏輯將更加清晰。
+
+最好傾向於編譯整個函數,而不是函數的一部分或表達式的一部分。與其放一個 ifdef
+在表達式內,不如分解出部分或全部表達式,放進一個單獨的輔助函數,並應用預處理
+條件到這個輔助函數內。
+
+如果你有一個在特定配置中,可能變成未使用的函數或變量,編譯器會警告它定義了但
+未使用,請把它標記爲 __maybe_unused 而不是將它包含在一個預處理條件中。(然而,
+如果一個函數或變量總是未使用,就直接刪除它。)
+
+在代碼中,儘可能地使用 IS_ENABLED 宏來轉化某個 Kconfig 標記爲 C 的布爾
+表達式,並在一般的 C 條件中使用它:
+
+.. code-block:: c
+
+ if (IS_ENABLED(CONFIG_SOMETHING)) {
+ ...
+ }
+
+編譯器會做常量摺疊,然後就像使用 #ifdef 那樣去包含或排除代碼塊,所以這不會帶
+來任何運行時開銷。然而,這種方法依舊允許 C 編譯器查看塊內的代碼,並檢查它的正
+確性 (語法,類型,符號引用,等等)。因此,如果條件不滿足,代碼塊內的引用符號就
+不存在時,你還是必須去用 #ifdef。
+
+在任何有意義的 #if 或 #ifdef 塊的末尾 (超過幾行的),在 #endif 同一行的後面寫下
+註解,註釋這個條件表達式。例如:
+
+.. code-block:: c
+
+ #ifdef CONFIG_SOMETHING
+ ...
+ #endif /* CONFIG_SOMETHING */
+
+
+附錄 I) 參考資料
+----------------
+
+The C Programming Language, 2nd Edition
+作者:Brian W. Kernighan 和 Denni M. Ritchie.
+Prentice Hall, Inc., 1988.
+ISBN 0-13-110362-8 (平裝), 0-13-110370-9 (精裝).
+
+.. note::
+
+ 《C程序設計語言(第2版)》
+ 作者:[美] Brian W. Kernighan / [美] Dennis M. Ritchie
+ 譯者:徐寶文 / 李志 / 尤晉元(審校)
+ 出版社:機械工業出版社,2019
+ ISBN:9787111617945
+
+The Practice of Programming
+作者:Brian W. Kernighan 和 Rob Pike.
+Addison-Wesley, Inc., 1999.
+ISBN 0-201-61586-X.
+
+.. note::
+
+ 《程序設計實踐》
+ 作者:[美] Brian W. Kernighan / [美] Rob Pike
+ 出版社:機械工業出版社,2005
+ ISBN:9787111091578
+
+ 《程序設計實踐》
+ 作者:[美] Brian W. Kernighan / Rob Pike
+ 譯者:裘宗燕
+ 出版社:機械工業出版社,2000
+ ISBN:9787111075738
+
+GNU 手冊 - 遵循 K&R 標準和此文本 - cpp, gcc, gcc internals and indent,
+都可以從 https://www.gnu.org/manual/ 找到
+
+WG14 是 C 語言的國際標準化工作組,URL: http://www.open-std.org/JTC1/SC22/WG14/
+
+內核文檔 Documentation/process/coding-style.rst,
+作者 greg@kroah.com 發表於 OLS 2002:
+http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
+
diff --git a/Documentation/translations/zh_TW/process/development-process.rst b/Documentation/translations/zh_TW/process/development-process.rst
new file mode 100644
index 000000000000..305d9472b017
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/development-process.rst
@@ -0,0 +1,30 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/development-process.rst <development_process_main>`
+:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+ Hu Haowen <2023002089@link.tyut.edu.cn>
+
+.. _tw_development_process_main:
+
+內核開發過程指南
+================
+
+本文檔的目的是幫助開發人員(及其經理)以最小的挫折感與開發社區合作。它試圖記錄這個社區如何以一種不熟悉Linux內核開發(或者實際上是自由軟體開發)的人可以訪問的方式工作。雖然這裡有一些技術資料,但這是一個面向過程的討論,不需要深入了解內核編程就可以理解。
+
+.. toctree::
+ :caption: 內容
+ :numbered:
+ :maxdepth: 2
+
+ 1.Intro
+ 2.Process
+ 3.Early-stage
+ 4.Coding
+ 5.Posting
+ 6.Followthrough
+ 7.AdvancedTopics
+ 8.Conclusion
+
+本文檔的目的是幫助開發人員(及其經理)以最小的挫折感與開發社區合作。它試圖記錄這個社區如何以一種不熟悉Linux內核開發(或者實際上是自由軟件開發)的人可以訪問的方式工作。雖然這裏有一些技術資料,但這是一個面向過程的討論,不需要深入瞭解內核編程就可以理解。
diff --git a/Documentation/translations/zh_TW/process/email-clients.rst b/Documentation/translations/zh_TW/process/email-clients.rst
new file mode 100644
index 000000000000..a5ac9400a9f5
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/email-clients.rst
@@ -0,0 +1,329 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+.. include:: ../disclaimer-zh_TW.rst
+
+.. _tw_email_clients:
+
+:Original: Documentation/process/email-clients.rst
+
+:譯者:
+ - 賈威威 Harry Wei <harryxiyou@gmail.com>
+ - 時奎亮 Alex Shi <alexs@kernel.org>
+ - 吳想成 Wu XiangCheng <bobwxc@email.cn>
+
+:校譯:
+ - Yinglin Luan <synmyth@gmail.com>
+ - Xiaochen Wang <wangxiaochen0@gmail.com>
+ - yaxinsn <yaxinsn@163.com>
+ - Hu Haowen <2023002089@link.tyut.edu.cn>
+
+Linux郵件客戶端配置信息
+=======================
+
+Git
+---
+
+現在大多數開發人員使用 ``git send-email`` 而不是常規的電子郵件客戶端。這方面
+的手冊非常好。在接收端,維護人員使用 ``git am`` 加載補丁。
+
+如果你是 ``git`` 新手,那麼把你的第一個補丁發送給你自己。將其保存爲包含所有
+標題的原始文本。運行 ``git am raw_email.txt`` ,然後使用 ``git log`` 查看更
+改日誌。如果工作正常,再將補丁發送到相應的郵件列表。
+
+
+通用配置
+--------
+
+Linux內核補丁是通過郵件被提交的,最好把補丁作爲郵件體的內嵌文本。有些維護者
+接收附件,但是附件的內容格式應該是"text/plain"。然而,附件一般是不贊成的,
+因爲這會使補丁的引用部分在評論過程中變的很困難。
+
+同時也強烈建議在補丁或其他郵件的正文中使用純文本格式。https://useplaintext.email
+有助於瞭解如何配置你喜歡的郵件客戶端,並在您還沒有首選的情況下列出一些推薦的
+客戶端。
+
+用來發送Linux內核補丁的郵件客戶端在發送補丁時應該處於文本的原始狀態。例如,
+他們不能改變或者刪除製表符或者空格,甚至是在每一行的開頭或者結尾。
+
+不要通過"format=flowed"模式發送補丁。這樣會引起不可預期以及有害的斷行。
+
+不要讓你的郵件客戶端進行自動換行。這樣也會破壞你的補丁。
+
+郵件客戶端不能改變文本的字符集編碼方式。要發送的補丁只能是ASCII或者UTF-8編碼
+方式,如果你使用UTF-8編碼方式發送郵件,那麼你將會避免一些可能發生的字符集問題。
+
+郵件客戶端應該生成並且保持“References:”或者“In-Reply-To:”郵件頭,這樣郵件會話
+就不會中斷。
+
+複製粘帖(或者剪貼粘帖)通常不能用於補丁,因爲製表符會轉換爲空格。使用xclipboard,
+xclip或者xcutsel也許可以,但是最好測試一下或者避免使用複製粘帖。
+
+不要在使用PGP/GPG簽名的郵件中包含補丁。這樣會使得很多腳本不能讀取和適用於你的
+補丁。(這個問題應該是可以修復的)
+
+在給內核郵件列表發送補丁之前,給自己發送一個補丁是個不錯的主意,保存接收到的
+郵件,將補丁用'patch'命令打上,如果成功了,再給內核郵件列表發送。
+
+
+一些郵件客戶端提示
+------------------
+
+這裏給出一些詳細的MUA配置提示,可以用於給Linux內核發送補丁。這些並不意味是
+所有的軟件包配置總結。
+
+說明:
+
+- TUI = 以文本爲基礎的用戶接口
+- GUI = 圖形界面用戶接口
+
+Alpine (TUI)
+************
+
+配置選項:
+
+在 :menuselection:`Sending Preferences` 菜單:
+
+- :menuselection:`Do Not Send Flowed Text` 必須開啓
+- :menuselection:`Strip Whitespace Before Sending` 必須關閉
+
+當寫郵件時,光標應該放在補丁會出現的地方,然後按下 :kbd:`CTRL-R` 組合鍵,使指
+定的補丁文件嵌入到郵件中。
+
+Claws Mail (GUI)
+****************
+
+可以用,有人用它成功地發過補丁。
+
+用 :menuselection:`Message-->Insert File` (:kbd:`CTRL-I`) 或外置編輯器插入補丁。
+
+若要在Claws編輯窗口重修改插入的補丁,需關閉
+:menuselection:`Configuration-->Preferences-->Compose-->Wrapping`
+的 `Auto wrapping` 。
+
+Evolution (GUI)
+***************
+
+一些開發者成功的使用它發送補丁。
+
+撰寫郵件時:
+從 :menuselection:`格式-->段落樣式-->預格式化` (:kbd:`CTRL-7`)
+或工具欄選擇 :menuselection:`預格式化` ;
+
+然後使用:
+:menuselection:`插入-->文本文件...` (:kbd:`ALT-N x`) 插入補丁文件。
+
+你還可以 ``diff -Nru old.c new.c | xclip`` ,選擇 :menuselection:`預格式化` ,
+然後使用鼠標中鍵進行粘帖。
+
+Kmail (GUI)
+***********
+
+一些開發者成功的使用它發送補丁。
+
+默認撰寫設置禁用HTML格式是合適的;不要啓用它。
+
+當書寫一封郵件的時候,在選項下面不要選擇自動換行。唯一的缺點就是你在郵件中輸
+入的任何文本都不會被自動換行,因此你必須在發送補丁之前手動換行。最簡單的方法
+就是啓用自動換行來書寫郵件,然後把它保存爲草稿。一旦你在草稿中再次打開它,它
+已經全部自動換行了,那麼你的郵件雖然沒有選擇自動換行,但是還不會失去已有的自
+動換行。
+
+在郵件的底部,插入補丁之前,放上常用的補丁定界符:三個連字符(``---``)。
+
+然後在 :menuselection:`信件` 菜單,選擇 :menuselection:`插入文本文件` ,接
+着選取你的補丁文件。還有一個額外的選項,你可以通過它配置你的創建新郵件工具欄,
+加上 :menuselection:`插入文本文件` 圖標。
+
+將編輯器窗口拉到足夠寬避免折行。對於KMail 1.13.5 (KDE 4.5.4),它會在發送郵件
+時對編輯器窗口中顯示折行的地方自動換行。在選項菜單中取消自動換行仍不能解決。
+因此,如果你的補丁中有非常長的行,必須在發送之前把編輯器窗口拉得非常寬。
+參見:https://bugs.kde.org/show_bug.cgi?id=174034
+
+你可以安全地用GPG簽名附件,但是內嵌補丁最好不要使用GPG簽名它們。作爲內嵌文本
+插入的簽名補丁將使其難以從7-bit編碼中提取。
+
+如果你非要以附件的形式發送補丁,那麼就右鍵點擊附件,然後選擇
+:menuselection:`屬性` ,打開 :menuselection:`建議自動顯示` ,使附件內聯更容
+易讓讀者看到。
+
+當你要保存將要發送的內嵌文本補丁,你可以從消息列表窗格選擇包含補丁的郵件,然
+後右鍵選擇 :menuselection:`另存爲` 。如果整個電子郵件的組成正確,您可直接將
+其作爲補丁使用。電子郵件以當前用戶可讀寫權限保存,因此您必須 ``chmod`` ,以
+使其在複製到別處時用戶組和其他人可讀。
+
+Lotus Notes (GUI)
+*****************
+
+不要使用它。
+
+IBM Verse (Web GUI)
+*******************
+
+同上條。
+
+Mutt (TUI)
+**********
+
+很多Linux開發人員使用mutt客戶端,這證明它肯定工作得非常漂亮。
+
+Mutt不自帶編輯器,所以不管你使用什麼編輯器,不自動斷行就行。大多數編輯器都有
+:menuselection:`插入文件` 選項,它可以在不改變文件內容的情況下插入文件。
+
+用 ``vim`` 作爲mutt的編輯器::
+
+ set editor="vi"
+
+如果使用xclip,敲入以下命令::
+
+ :set paste
+
+然後再按中鍵或者shift-insert或者使用::
+
+ :r filename
+
+把補丁插入爲內嵌文本。
+在未設置 ``set paste`` 時(a)ttach工作的很好。
+
+你可以通過 ``git format-patch`` 生成補丁,然後用 Mutt發送它們::
+
+ $ mutt -H 0001-some-bug-fix.patch
+
+配置選項:
+
+它應該以默認設置的形式工作。
+然而,把 ``send_charset`` 設置一下也是一個不錯的主意::
+
+ set send_charset="us-ascii:utf-8"
+
+Mutt 是高度可配置的。 這裏是個使用mutt通過 Gmail 發送的補丁的最小配置::
+
+ # .muttrc
+ # ================ IMAP ====================
+ set imap_user = 'yourusername@gmail.com'
+ set imap_pass = 'yourpassword'
+ set spoolfile = imaps://imap.gmail.com/INBOX
+ set folder = imaps://imap.gmail.com/
+ set record="imaps://imap.gmail.com/[Gmail]/Sent Mail"
+ set postponed="imaps://imap.gmail.com/[Gmail]/Drafts"
+ set mbox="imaps://imap.gmail.com/[Gmail]/All Mail"
+
+ # ================ SMTP ====================
+ set smtp_url = "smtp://username@smtp.gmail.com:587/"
+ set smtp_pass = $imap_pass
+ set ssl_force_tls = yes # Require encrypted connection
+
+ # ================ Composition ====================
+ set editor = `echo \$EDITOR`
+ set edit_headers = yes # See the headers when editing
+ set charset = UTF-8 # value of $LANG; also fallback for send_charset
+ # Sender, email address, and sign-off line must match
+ unset use_domain # because joe@localhost is just embarrassing
+ set realname = "YOUR NAME"
+ set from = "username@gmail.com"
+ set use_from = yes
+
+Mutt文檔含有更多信息:
+
+ https://gitlab.com/muttmua/mutt/-/wikis/UseCases/Gmail
+
+ http://www.mutt.org/doc/manual/
+
+Pine (TUI)
+**********
+
+Pine過去有一些空格刪減問題,但是這些現在應該都被修復了。
+
+如果可以,請使用alpine(pine的繼承者)。
+
+配置選項:
+
+- 最近的版本需要 ``quell-flowed-text``
+- ``no-strip-whitespace-before-send`` 選項也是需要的。
+
+
+Sylpheed (GUI)
+**************
+
+- 內嵌文本可以很好的工作(或者使用附件)。
+- 允許使用外部的編輯器。
+- 收件箱較多時非常慢。
+- 如果通過non-SSL連接,無法使用TLS SMTP授權。
+- 撰寫窗口的標尺很有用。
+- 將地址添加到通訊簿時無法正確理解顯示的名稱。
+
+Thunderbird (GUI)
+*****************
+
+Thunderbird是Outlook的克隆版本,它很容易損壞文本,但也有一些方法強制修正。
+
+在完成修改後(包括安裝擴展),您需要重新啓動Thunderbird。
+
+- 允許使用外部編輯器:
+
+ 使用Thunderbird發補丁最簡單的方法是使用擴展來打開您最喜歡的外部編輯器。
+
+ 下面是一些能夠做到這一點的擴展樣例。
+
+ - “External Editor Revived”
+
+ https://github.com/Frederick888/external-editor-revived
+
+ https://addons.thunderbird.net/en-GB/thunderbird/addon/external-editor-revived/
+
+ 它需要安裝“本地消息主機(native messaging host)”。
+ 參見以下文檔:
+ https://github.com/Frederick888/external-editor-revived/wiki
+
+ - “External Editor”
+
+ https://github.com/exteditor/exteditor
+
+ 下載並安裝此擴展,然後打開 :menuselection:`新建消息` 窗口, 用
+ :menuselection:`查看-->工具欄-->自定義...` 給它增加一個按鈕,直接點擊此
+ 按鈕即可使用外置編輯器。
+
+ 請注意,“External Editor”要求你的編輯器不能fork,換句話說,編輯器必須在
+ 關閉前不返回。你可能需要傳遞額外的參數或修改編輯器設置。最值得注意的是,
+ 如果您使用的是gvim,那麼您必須將 :menuselection:`external editor` 設置的
+ 編輯器字段設置爲 ``/usr/bin/gvim --nofork"`` (假設可執行文件在
+ ``/usr/bin`` ),以傳遞 ``-f`` 參數。如果您正在使用其他編輯器,請閱讀其
+ 手冊瞭解如何處理。
+
+若要修正內部編輯器,請執行以下操作:
+
+- 修改你的Thunderbird設置,不要使用 ``format=flowed`` !
+ 回到主窗口,按照
+ :menuselection:`主菜單-->首選項-->常規-->配置編輯器...`
+ 打開Thunderbird的配置編輯器。
+
+ - 將 ``mailnews.send_plaintext_flowed`` 設爲 ``false``
+
+ - 將 ``mailnews.wraplength`` 從 ``72`` 改爲 ``0``
+
+- 不要寫HTML郵件!
+ 回到主窗口,打開
+ :menuselection:`主菜單-->賬戶設置-->你的@郵件.地址-->通訊錄/編寫&地址簿` ,
+ 關掉 ``以HTML格式編寫消息`` 。
+
+- 只用純文本格式查看郵件!
+ 回到主窗口, :menuselection:`主菜單-->查看-->消息體爲-->純文本` !
+
+TkRat (GUI)
+***********
+
+可以使用它。使用"Insert file..."或者外部的編輯器。
+
+Gmail (Web GUI)
+***************
+
+不要使用它發送補丁。
+
+Gmail網頁客戶端自動地把製表符轉換爲空格。
+
+雖然製表符轉換爲空格問題可以被外部編輯器解決,但它同時還會使用回車換行把每行
+拆分爲78個字符。
+
+另一個問題是Gmail還會把任何含有非ASCII的字符的消息改用base64編碼,如歐洲人的
+名字。
+
+
diff --git a/Documentation/translations/zh_TW/process/embargoed-hardware-issues.rst b/Documentation/translations/zh_TW/process/embargoed-hardware-issues.rst
new file mode 100644
index 000000000000..3cce7db2ab7e
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/embargoed-hardware-issues.rst
@@ -0,0 +1,232 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/embargoed-hardware-issues.rst <embargoed_hardware_issues>`
+:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+ Hu Haowen <2023002089@link.tyut.edu.cn>
+
+被限制的硬件問題
+================
+
+範圍
+----
+
+導致安全問題的硬件問題與隻影響Linux內核的純軟件錯誤是不同的安全錯誤類別。
+
+必須區別對待諸如熔燬(Meltdown)、Spectre、L1TF等硬件問題,因爲它們通常會影響
+所有操作系統(“OS”),因此需要在不同的OS供應商、發行版、硬件供應商和其他各方
+之間進行協調。對於某些問題,軟件緩解可能依賴於微碼或固件更新,這需要進一步的
+協調。
+
+.. _tw_Contact:
+
+接觸
+----
+
+Linux內核硬件安全小組獨立於普通的Linux內核安全小組。
+
+該小組只負責協調被限制的硬件安全問題。Linux內核中純軟件安全漏洞的報告不由該
+小組處理,報告者將被引導至常規Linux內核安全小組(:ref:`Documentation/admin-guide/
+<securitybugs>`)聯繫。
+
+可以通過電子郵件 <hardware-security@kernel.org> 與小組聯繫。這是一份私密的安全
+官名單,他們將幫助您根據我們的文檔化流程協調問題。
+
+郵件列表是加密的,發送到列表的電子郵件可以通過PGP或S/MIME加密,並且必須使用報告
+者的PGP密鑰或S/MIME證書籤名。該列表的PGP密鑰和S/MIME證書可從
+https://www.kernel.org/.... 獲得。
+
+雖然硬件安全問題通常由受影響的硬件供應商處理,但我們歡迎發現潛在硬件缺陷的研究
+人員或個人與我們聯繫。
+
+硬件安全官
+^^^^^^^^^^
+
+目前的硬件安全官小組:
+
+ - Linus Torvalds(Linux基金會院士)
+ - Greg Kroah Hartman(Linux基金會院士)
+ - Thomas Gleixner(Linux基金會院士)
+
+郵件列表的操作
+^^^^^^^^^^^^^^
+
+處理流程中使用的加密郵件列表託管在Linux Foundation的IT基礎設施上。通過提供這項
+服務,Linux基金會的IT基礎設施安全總監在技術上有能力訪問被限制的信息,但根據他
+的僱傭合同,他必須保密。Linux基金會的IT基礎設施安全總監還負責 kernel.org 基礎
+設施。
+
+Linux基金會目前的IT基礎設施安全總監是 Konstantin Ryabitsev。
+
+保密協議
+--------
+
+Linux內核硬件安全小組不是正式的機構,因此無法簽訂任何保密協議。核心社區意識到
+這些問題的敏感性,並提供了一份諒解備忘錄。
+
+諒解備忘錄
+----------
+
+Linux內核社區深刻理解在不同操作系統供應商、發行商、硬件供應商和其他各方之間
+進行協調時,保持硬件安全問題處於限制狀態的要求。
+
+Linux內核社區在過去已經成功地處理了硬件安全問題,並且有必要的機制允許在限制
+限制下進行符合社區的開發。
+
+Linux內核社區有一個專門的硬件安全小組負責初始聯繫,並監督在限制規則下處理
+此類問題的過程。
+
+硬件安全小組確定開發人員(領域專家),他們將組成特定問題的初始響應小組。最初
+的響應小組可以引入更多的開發人員(領域專家)以最佳的技術方式解決這個問題。
+
+所有相關開發商承諾遵守限制規定,並對收到的信息保密。違反承諾將導致立即從當前
+問題中排除,並從所有相關郵件列表中刪除。此外,硬件安全小組還將把違反者排除在
+未來的問題之外。這一後果的影響在我們社區是一種非常有效的威懾。如果發生違規
+情況,硬件安全小組將立即通知相關方。如果您或任何人發現潛在的違規行爲,請立即
+向硬件安全人員報告。
+
+流程
+^^^^
+
+由於Linux內核開發的全球分佈式特性,面對面的會議幾乎不可能解決硬件安全問題。
+由於時區和其他因素,電話會議很難協調,只能在絕對必要時使用。加密電子郵件已被
+證明是解決此類問題的最有效和最安全的通信方法。
+
+開始披露
+""""""""
+
+披露內容首先通過電子郵件聯繫Linux內核硬件安全小組。此初始聯繫人應包含問題的
+描述和任何已知受影響硬件的列表。如果您的組織製造或分發受影響的硬件,我們建議
+您也考慮哪些其他硬件可能會受到影響。
+
+硬件安全小組將提供一個特定於事件的加密郵件列表,用於與報告者進行初步討論、
+進一步披露和協調。
+
+硬件安全小組將向披露方提供一份開發人員(領域專家)名單,在與開發人員確認他們
+將遵守本諒解備忘錄和文件化流程後,應首先告知開發人員有關該問題的信息。這些開發
+人員組成初始響應小組,並在初始接觸後負責處理問題。硬件安全小組支持響應小組,
+但不一定參與緩解開發過程。
+
+雖然個別開發人員可能通過其僱主受到保密協議的保護,但他們不能以Linux內核開發
+人員的身份簽訂個別保密協議。但是,他們將同意遵守這一書面程序和諒解備忘錄。
+
+披露方應提供已經或應該被告知該問題的所有其他實體的聯繫人名單。這有幾個目的:
+
+ - 披露的實體列表允許跨行業通信,例如其他操作系統供應商、硬件供應商等。
+
+ - 可聯繫已披露的實體,指定應參與緩解措施開發的專家。
+
+ - 如果需要處理某一問題的專家受僱於某一上市實體或某一上市實體的成員,則響應
+ 小組可要求該實體披露該專家。這確保專家也是實體反應小組的一部分。
+
+披露
+""""
+
+披露方通過特定的加密郵件列表向初始響應小組提供詳細信息。
+
+根據我們的經驗,這些問題的技術文檔通常是一個足夠的起點,最好通過電子郵件進行
+進一步的技術澄清。
+
+緩解開發
+""""""""
+
+初始響應小組設置加密郵件列表,或在適當的情況下重新修改現有郵件列表。
+
+使用郵件列表接近於正常的Linux開發過程,並且在過去已經成功地用於爲各種硬件安全
+問題開發緩解措施。
+
+郵件列表的操作方式與正常的Linux開發相同。發佈、討論和審查修補程序,如果同意,
+則應用於非公共git存儲庫,參與開發人員只能通過安全連接訪問該存儲庫。存儲庫包含
+針對主線內核的主開發分支,並根據需要爲穩定的內核版本提供向後移植分支。
+
+最初的響應小組將根據需要從Linux內核開發人員社區中確定更多的專家。引進專家可以
+在開發過程中的任何時候發生,需要及時處理。
+
+如果專家受僱於披露方提供的披露清單上的實體或其成員,則相關實體將要求其參與。
+
+否則,披露方將被告知專家參與的情況。諒解備忘錄涵蓋了專家,要求披露方確認參與。
+如果披露方有令人信服的理由提出異議,則必須在五個工作日內提出異議,並立即與事件
+小組解決。如果披露方在五個工作日內未作出回應,則視爲默許。
+
+在確認或解決異議後,專家由事件小組披露,並進入開發過程。
+
+協調發布
+""""""""
+
+有關各方將協商限制結束的日期和時間。此時,準備好的緩解措施集成到相關的內核樹中
+併發布。
+
+雖然我們理解硬件安全問題需要協調限制時間,但限制時間應限制在所有有關各方制定、
+測試和準備緩解措施所需的最短時間內。人爲地延長限制時間以滿足會議討論日期或其他
+非技術原因,會給相關的開發人員和響應小組帶來了更多的工作和負擔,因爲補丁需要
+保持最新,以便跟蹤正在進行的上游內核開發,這可能會造成衝突的更改。
+
+CVE分配
+"""""""
+
+硬件安全小組和初始響應小組都不分配CVE,開發過程也不需要CVE。如果CVE是由披露方
+提供的,則可用於文檔中。
+
+流程專使
+--------
+
+爲了協助這一進程,我們在各組織設立了專使,他們可以回答有關報告流程和進一步處理
+的問題或提供指導。專使不參與特定問題的披露,除非響應小組或相關披露方提出要求。
+現任專使名單:
+
+ ============= ========================================================
+ ARM
+ AMD Tom Lendacky <thomas.lendacky@amd.com>
+ IBM
+ Intel Tony Luck <tony.luck@intel.com>
+ Qualcomm Trilok Soni <tsoni@codeaurora.org>
+
+ Microsoft Sasha Levin <sashal@kernel.org>
+ VMware
+ Xen Andrew Cooper <andrew.cooper3@citrix.com>
+
+ Canonical John Johansen <john.johansen@canonical.com>
+ Debian Ben Hutchings <ben@decadent.org.uk>
+ Oracle Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+ Red Hat Josh Poimboeuf <jpoimboe@redhat.com>
+ SUSE Jiri Kosina <jkosina@suse.cz>
+
+ Amazon
+ Google Kees Cook <keescook@chromium.org>
+ ============= ========================================================
+
+如果要將您的組織添加到專使名單中,請與硬件安全小組聯繫。被提名的專使必須完全
+理解和支持我們的過程,並且在Linux內核社區中很容易聯繫。
+
+加密郵件列表
+------------
+
+我們使用加密郵件列表進行通信。這些列表的工作原理是,發送到列表的電子郵件使用
+列表的PGP密鑰或列表的/MIME證書進行加密。郵件列表軟件對電子郵件進行解密,並
+使用訂閱者的PGP密鑰或S/MIME證書爲每個訂閱者分別對其進行重新加密。有關郵件列表
+軟件和用於確保列表安全和數據保護的設置的詳細信息,請訪問:
+https://www.kernel.org/....
+
+關鍵點
+^^^^^^
+
+初次接觸見 :ref:`zh_Contact`. 對於特定於事件的郵件列表,密鑰和S/MIME證書通過
+特定列表發送的電子郵件傳遞給訂閱者。
+
+訂閱事件特定列表
+^^^^^^^^^^^^^^^^
+
+訂閱由響應小組處理。希望參與通信的披露方將潛在訂戶的列表發送給響應組,以便
+響應組可以驗證訂閱請求。
+
+每個訂戶都需要通過電子郵件向響應小組發送訂閱請求。電子郵件必須使用訂閱服務器
+的PGP密鑰或S/MIME證書籤名。如果使用PGP密鑰,則必須從公鑰服務器獲得該密鑰,
+並且理想情況下該密鑰連接到Linux內核的PGP信任網。另請參見:
+https://www.kernel.org/signature.html.
+
+響應小組驗證訂閱者,並將訂閱者添加到列表中。訂閱後,訂閱者將收到來自郵件列表
+的電子郵件,該郵件列表使用列表的PGP密鑰或列表的/MIME證書籤名。訂閱者的電子郵件
+客戶端可以從簽名中提取PGP密鑰或S/MIME證書,以便訂閱者可以向列表發送加密電子
+郵件。
+
diff --git a/Documentation/translations/zh_TW/process/howto.rst b/Documentation/translations/zh_TW/process/howto.rst
new file mode 100644
index 000000000000..80c416483e73
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/howto.rst
@@ -0,0 +1,499 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. _tw_process_howto:
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/howto.rst <process_howto>`
+
+譯者::
+
+ 英文版維護者: Greg Kroah-Hartman <greg@kroah.com>
+ 中文版維護者: 李陽 Li Yang <leoyang.li@nxp.com>
+ 中文版翻譯者: 李陽 Li Yang <leoyang.li@nxp.com>
+ 時奎亮 Alex Shi <alex.shi@linux.alibaba.com>
+ 中文版校譯者:
+ 鍾宇 TripleX Chung <xxx.phy@gmail.com>
+ 陳琦 Maggie Chen <chenqi@beyondsoft.com>
+ 王聰 Wang Cong <xiyou.wangcong@gmail.com>
+ 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+如何參與Linux內核開發
+=====================
+
+這是一篇將如何參與Linux內核開發的相關問題一網打盡的終極祕笈。它將指導你
+成爲一名Linux內核開發者,並且學會如何同Linux內核開發社區合作。它儘可能不
+包括任何關於內核編程的技術細節,但會給你指引一條獲得這些知識的正確途徑。
+
+如果這篇文章中的任何內容不再適用,請給文末列出的文件維護者發送補丁。
+
+
+入門
+----
+
+你想了解如何成爲一名Linux內核開發者?或者老闆吩咐你「給這個設備寫個Linux
+驅動程序」?這篇文章的目的就是教會你達成這些目標的全部訣竅,它將描述你需
+要經過的流程以及給出如何同內核社區合作的一些提示。它還將試圖解釋內核社區
+爲何這樣運作。
+
+Linux內核大部分是由C語言寫成的,一些體系結構相關的代碼用到了彙編語言。要
+參與內核開發,你必須精通C語言。除非你想爲某個架構開發底層代碼,否則你並
+不需要了解(任何體系結構的)彙編語言。下面列舉的書籍雖然不能替代紮實的C
+語言教育和多年的開發經驗,但如果需要的話,做爲參考還是不錯的:
+
+ - "The C Programming Language" by Kernighan and Ritchie [Prentice Hall]
+ 《C程序設計語言(第2版·新版)》(徐寶文 李志 譯)[機械工業出版社]
+ - "Practical C Programming" by Steve Oualline [O'Reilly]
+ 《實用C語言編程(第三版)》(郭大海 譯)[中國電力出版社]
+ - "C: A Reference Manual" by Harbison and Steele [Prentice Hall]
+ 《C語言參考手冊(原書第5版)》(邱仲潘 等譯)[機械工業出版社]
+
+Linux內核使用GNU C和GNU工具鏈開發。雖然它遵循ISO C11標準,但也用到了一些
+標準中沒有定義的擴展。內核是自給自足的C環境,不依賴於標準C庫的支持,所以
+並不支持C標準中的部分定義。比如long long類型的大數除法和浮點運算就不允許
+使用。有時候確實很難弄清楚內核對工具鏈的要求和它所使用的擴展,不幸的是目
+前還沒有明確的參考資料可以解釋它們。請查閱gcc信息頁(使用「info gcc」命令
+顯示)獲得一些這方面信息。
+
+請記住你是在學習怎麼和已經存在的開發社區打交道。它由一羣形形色色的人組成,
+他們對代碼、風格和過程有著很高的標準。這些標準是在長期實踐中總結出來的,
+適應於地理上分散的大型開發團隊。它們已經被很好得整理成檔,建議你在開發
+之前儘可能多的學習這些標準,而不要期望別人來適應你或者你公司的行爲方式。
+
+
+法律問題
+--------
+
+Linux內核原始碼都是在GPL(通用公共許可證)的保護下發布的。要了解這種許可
+的細節請查看原始碼主目錄下的COPYING文件。Linux內核許可準則和如何使用
+`SPDX <https://spdx.org/>` 標誌符說明在這個文件中
+:ref:`Documentation/translations/zh_TW/process/license-rules.rst <tw_kernel_licensing>`
+如果你對它還有更深入問題請聯繫律師,而不要在Linux內核郵件組上提問。因爲
+郵件組裡的人並不是律師,不要期望他們的話有法律效力。
+
+對於GPL的常見問題和解答,請訪問以下連結:
+ https://www.gnu.org/licenses/gpl-faq.html
+
+
+文檔
+----
+
+Linux內核代碼中包含有大量的文檔。這些文檔對於學習如何與內核社區互動有著
+不可估量的價值。當一個新的功能被加入內核,最好把解釋如何使用這個功能的文
+檔也放進內核。當內核的改動導致面向用戶空間的接口發生變化時,最好將相關信
+息或手冊頁(manpages)的補丁發到mtk.manpages@gmail.com,以向手冊頁(manpages)
+的維護者解釋這些變化。
+
+以下是內核代碼中需要閱讀的文檔:
+ :ref:`Documentation/admin-guide/README.rst <readme>`
+ 文件簡要介紹了Linux內核的背景,並且描述了如何配置和編譯內核。內核的
+ 新用戶應該從這裡開始。
+
+
+ :ref:`Documentation/process/changes.rst <changes>`
+ 文件給出了用來編譯和使用內核所需要的最小軟體包列表。
+
+ :ref:`Documentation/translations/zh_TW/process/coding-style.rst <tw_codingstyle>`
+ 描述Linux內核的代碼風格和理由。所有新代碼需要遵守這篇文檔中定義的規
+ 范。大多數維護者只會接收符合規定的補丁,很多人也只會幫忙檢查符合風格
+ 的代碼。
+
+ :ref:`Documentation/translations/zh_TW/process/submitting-patches.rst <tw_submittingpatches>`
+
+ 這兩份文檔明確描述如何創建和發送補丁,其中包括(但不僅限於):
+ - 郵件內容
+ - 郵件格式
+ - 選擇收件人
+
+ 遵守這些規定並不能保證提交成功(因爲所有補丁需要通過嚴格的內容和風格
+ 審查),但是忽視他們幾乎就意味著失敗。
+
+ 其他關於如何正確地生成補丁的優秀文檔包括:
+ "The Perfect Patch"
+
+ https://www.ozlabs.org/~akpm/stuff/tpp.txt
+
+ "Linux kernel patch submission format"
+
+ https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html
+
+ :ref:`Documentation/translations/zh_TW/process/stable-api-nonsense.rst <tw_stable_api_nonsense>`
+ 論證內核爲什麼特意不包括穩定的內核內部API,也就是說不包括像這樣的特
+ 性:
+
+ - 子系統中間層(爲了兼容性?)
+ - 在不同作業系統間易於移植的驅動程序
+ - 減緩(甚至阻止)內核代碼的快速變化
+
+ 這篇文檔對於理解Linux的開發哲學至關重要。對於將開發平台從其他操作系
+ 統轉移到Linux的人來說也很重要。
+
+ :ref:`Documentation/process/security-bugs.rst <securitybugs>`
+ 如果你認爲自己發現了Linux內核的安全性問題,請根據這篇文檔中的步驟來
+ 提醒其他內核開發者並幫助解決這個問題。
+
+ :ref:`Documentation/translations/zh_TW/process/management-style.rst <tw_managementstyle>`
+
+ 描述內核維護者的工作方法及其共有特點。這對於剛剛接觸內核開發(或者對
+ 它感到好奇)的人來說很重要,因爲它解釋了很多對於內核維護者獨特行爲的
+ 普遍誤解與迷惑。
+
+ :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
+ 解釋了穩定版內核發布的規則,以及如何將改動放入這些版本的步驟。
+
+ :ref:`Documentation/process/kernel-docs.rst <kernel_docs>`
+ 有助於內核開發的外部文檔列表。如果你在內核自帶的文檔中沒有找到你想找
+ 的內容,可以查看這些文檔。
+
+ :ref:`Documentation/process/applying-patches.rst <applying_patches>`
+ 關於補丁是什麼以及如何將它打在不同內核開發分支上的好介紹
+
+內核還擁有大量從代碼自動生成或者從 ReStructuredText(ReST) 標記生成的文檔,
+比如這個文檔,它包含內核內部API的全面介紹以及如何妥善處理加鎖的規則。所有
+這些文檔都可以通過運行以下命令從內核代碼中生成爲PDF或HTML文檔::
+
+ make pdfdocs
+ make htmldocs
+
+ReST格式的文檔會生成在 Documentation/output. 目錄中。
+它們也可以用下列命令生成 LaTeX 和 ePub 格式文檔::
+
+ make latexdocs
+ make epubdocs
+
+如何成爲內核開發者
+------------------
+如果你對Linux內核開發一無所知,你應該訪問「Linux內核新手」計劃:
+
+ https://kernelnewbies.org
+
+它擁有一個可以問各種最基本的內核開發問題的郵件列表(在提問之前一定要記得
+查找已往的郵件,確認是否有人已經回答過相同的問題)。它還擁有一個可以獲得
+實時反饋的IRC聊天頻道,以及大量對於學習Linux內核開發相當有幫助的文檔。
+
+網站簡要介紹了原始碼組織結構、子系統劃分以及目前正在進行的項目(包括內核
+中的和單獨維護的)。它還提供了一些基本的幫助信息,比如如何編譯內核和打補
+丁。
+
+如果你想加入內核開發社區並協助完成一些任務,卻找不到從哪裡開始,可以訪問
+「Linux內核房管員」計劃:
+
+ https://kernelnewbies.org/KernelJanitors
+
+這是極佳的起點。它提供一個相對簡單的任務列表,列出內核代碼中需要被重新
+整理或者改正的地方。通過和負責這個計劃的開發者們一同工作,你會學到將補丁
+集成進內核的基本原理。如果還沒有決定下一步要做什麼的話,你還可能會得到方
+向性的指點。
+
+在真正動手修改內核代碼之前,理解要修改的代碼如何運作是必需的。要達到這個
+目的,沒什麼辦法比直接讀代碼更有效了(大多數花招都會有相應的注釋),而且
+一些特製的工具還可以提供幫助。例如,「Linux代碼交叉引用」項目就是一個值得
+特別推薦的幫助工具,它將原始碼顯示在有編目和索引的網頁上。其中一個更新及
+時的內核源碼庫,可以通過以下地址訪問:
+
+ https://elixir.bootlin.com/
+
+
+開發流程
+--------
+
+目前Linux內核開發流程包括幾個「主內核分支」和很多子系統相關的內核分支。這
+些分支包括:
+
+ - Linus 的內核源碼樹
+ - 多個主要版本的穩定版內核樹
+ - 子系統相關的內核樹
+ - linux-next 集成測試樹
+
+
+主線樹
+------
+主線樹是由Linus Torvalds 維護的。你可以在https://kernel.org 網站或者代碼
+庫中下找到它。它的開發遵循以下步驟:
+
+ - 每當一個新版本的內核被發布,爲期兩周的集成窗口將被打開。在這段時間裡
+ 維護者可以向Linus提交大段的修改,通常這些修改已經被放到-mm內核中幾個
+ 星期了。提交大量修改的首選方式是使用git工具(內核的代碼版本管理工具
+ ,更多的信息可以在 https://git-scm.com/ 獲取),不過使用普通補丁也是
+ 可以的。
+ - 兩個星期以後-rc1版本內核發布。之後只有不包含可能影響整個內核穩定性的
+ 新功能的補丁才可能被接受。請注意一個全新的驅動程序(或者文件系統)有
+ 可能在-rc1後被接受是因爲這樣的修改完全獨立,不會影響其他的代碼,所以
+ 沒有造成內核退步的風險。在-rc1以後也可以用git向Linus提交補丁,不過所
+ 有的補丁需要同時被發送到相應的公衆郵件列表以徵詢意見。
+ - 當Linus認爲當前的git源碼樹已經達到一個合理健全的狀態足以發布供人測試
+ 時,一個新的-rc版本就會被發布。計劃是每周都發布新的-rc版本。
+ - 這個過程一直持續下去直到內核被認爲達到足夠穩定的狀態,持續時間大概是
+ 6個星期。
+
+關於內核發布,值得一提的是Andrew Morton在linux-kernel郵件列表中如是說:
+ 「沒有人知道新內核何時會被發布,因爲發布是根據已知bug的情況來決定
+ 的,而不是根據一個事先制定好的時間表。」
+
+子系統特定樹
+------------
+
+各種內核子系統的維護者——以及許多內核子系統開發人員——在原始碼庫中公開了他們
+當前的開發狀態。這樣,其他人就可以看到內核的不同區域發生了什麼。在開發速度
+很快的領域,可能會要求開發人員將提交的內容建立在這樣的子系統內核樹上,這樣
+就避免了提交與其他已經進行的工作之間的衝突。
+
+這些存儲庫中的大多數都是Git樹,但是也有其他的scm在使用,或者補丁隊列被發布
+爲Quilt系列。這些子系統存儲庫的地址列在MAINTAINERS文件中。其中許多可以在
+https://git.kernel.org/上瀏覽。
+
+在將一個建議的補丁提交到這樣的子系統樹之前,需要對它進行審查,審查主要發生
+在郵件列表上(請參見下面相應的部分)。對於幾個內核子系統,這個審查過程是通
+過工具補丁跟蹤的。Patchwork提供了一個Web界面,顯示補丁發布、對補丁的任何評
+論或修訂,維護人員可以將補丁標記爲正在審查、接受或拒絕。大多數補丁網站都列
+在 https://patchwork.kernel.org/
+
+Linux-next 集成測試樹
+---------------------
+
+在將子系統樹的更新合併到主線樹之前,需要對它們進行集成測試。爲此,存在一個
+特殊的測試存儲庫,其中幾乎每天都會提取所有子系統樹:
+
+ https://git.kernel.org/?p=linux/kernel/git/next/linux-next.git
+
+通過這種方式,Linux-next 對下一個合併階段將進入主線內核的內容給出了一個概要
+展望。非常歡冒險的測試者運行測試Linux-next。
+
+多個主要版本的穩定版內核樹
+-----------------------------------
+由3個數字組成的內核版本號說明此內核是-stable版本。它們包含內核的相對較小且
+至關重要的修補,這些修補針對安全性問題或者嚴重的內核退步。
+
+這種版本的內核適用於那些期望獲得最新的穩定版內核並且不想參與測試開發版或
+者實驗版的用戶。
+
+穩定版內核樹版本由「穩定版」小組(郵件地址<stable@vger.kernel.org>)維護,一般
+隔周發布新版本。
+
+內核源碼中的 :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
+文件具體描述了可被穩定版內核接受的修改類型以及發布的流程。
+
+
+報告bug
+-------
+
+bugzilla.kernel.org是Linux內核開發者們用來跟蹤內核Bug的網站。我們鼓勵用
+戶在這個工具中報告找到的所有bug。如何使用內核bugzilla的細節請訪問:
+
+ http://test.kernel.org/bugzilla/faq.html
+
+內核源碼主目錄中的:ref:`admin-guide/reporting-bugs.rst <reportingbugs>`
+文件里有一個很好的模板。它指導用戶如何報告可能的內核bug以及需要提供哪些信息
+來幫助內核開發者們找到問題的根源。
+
+
+利用bug報告
+-----------
+
+練習內核開發技能的最好辦法就是修改其他人報告的bug。你不光可以幫助內核變
+得更加穩定,還可以學會如何解決實際問題從而提高自己的技能,並且讓其他開發
+者感受到你的存在。修改bug是贏得其他開發者讚譽的最好辦法,因爲並不是很多
+人都喜歡浪費時間去修改別人報告的bug。
+
+要嘗試修改已知的bug,請訪問 http://bugzilla.kernel.org 網址。
+
+
+郵件列表
+--------
+
+正如上面的文檔所描述,大多數的骨幹內核開發者都加入了Linux Kernel郵件列
+表。如何訂閱和退訂列表的細節可以在這裡找到:
+
+ http://vger.kernel.org/vger-lists.html#linux-kernel
+
+網上很多地方都有這個郵件列表的存檔(archive)。可以使用搜尋引擎來找到這些
+存檔。比如:
+
+ https://lore.kernel.org/lkml/
+
+在發信之前,我們強烈建議你先在存檔中搜索你想要討論的問題。很多已經被詳細
+討論過的問題只在郵件列表的存檔中可以找到。
+
+大多數內核子系統也有自己獨立的郵件列表來協調各自的開發工作。從
+MAINTAINERS文件中可以找到不同話題對應的郵件列表。
+
+很多郵件列表架設在kernel.org伺服器上。這些列表的信息可以在這裡找到:
+
+ http://vger.kernel.org/vger-lists.html
+
+在使用這些郵件列表時,請記住保持良好的行爲習慣。下面的連結提供了與這些列
+表(或任何其它郵件列表)交流的一些簡單規則,雖然內容有點濫竽充數。
+
+ http://www.albion.com/netiquette/
+
+當有很多人回覆你的郵件時,郵件的抄送列表會變得很長。請不要將任何人從抄送
+列表中刪除,除非你有足夠的理由這麼做。也不要只回復到郵件列表。請習慣於同
+一封郵件接收兩次(一封來自發送者一封來自郵件列表),而不要試圖通過添加一
+些奇特的郵件頭來解決這個問題,人們不會喜歡的。
+
+記住保留你所回復內容的上下文和源頭。在你回覆郵件的頂部保留「某某某說到……」
+這幾行。將你的評論加在被引用的段落之間而不要放在郵件的頂部。
+
+如果你在郵件中附帶補丁,請確認它們是可以直接閱讀的純文本(如
+:ref:`Documentation/translations/zh_TW/process/submitting-patches.rst <tw_submittingpatches>`
+文檔中所述)。內核開發者們不希望遇到附件或者被壓縮了的補丁。只有這樣才能
+保證他們可以直接評論你的每行代碼。請確保你使用的郵件發送程序不會修改空格
+和制表符。一個防範性的測試方法是先將郵件發送給自己,然後自己嘗試是否可以
+順利地打上收到的補丁。如果測試不成功,請調整或者更換你的郵件發送程序直到
+它正確工作爲止。
+
+總而言之,請尊重其他的郵件列表訂閱者。
+
+
+同內核社區合作
+----------------
+
+內核社區的目標就是提供盡善盡美的內核。所以當你提交補丁期望被接受進內核的
+時候,它的技術價值以及其他方面都將被評審。那麼你可能會得到什麼呢?
+
+ - 批評
+ - 評論
+ - 要求修改
+ - 要求證明修改的必要性
+ - 沉默
+
+要記住,這些是把補丁放進內核的正常情況。你必須學會聽取對補丁的批評和評論,
+從技術層面評估它們,然後要麼重寫你的補丁要麼簡明扼要地論證修改是不必要
+的。如果你發的郵件沒有得到任何回應,請過幾天後再試一次,因爲有時信件會湮
+沒在茫茫信海中。
+
+你不應該做的事情:
+
+ - 期望自己的補丁不受任何質疑就直接被接受
+ - 翻臉
+ - 忽略別人的評論
+ - 沒有按照別人的要求做任何修改就重新提交
+
+在一個努力追尋最好技術方案的社區里,對於一個補丁有多少好處總會有不同的見
+解。你必須要抱著合作的態度,願意改變自己的觀點來適應內核的風格。或者至少
+願意去證明你的想法是有價值的。記住,犯錯誤是允許的,只要你願意朝著正確的
+方案去努力。
+
+如果你的第一個補丁換來的是一堆修改建議,這是很正常的。這並不代表你的補丁
+不會被接受,也不意味著有人和你作對。你只需要改正所有提出的問題然後重新發
+送你的補丁。
+
+內核社區和公司文化的差異
+------------------------
+
+內核社區的工作模式同大多數傳統公司開發隊伍的工作模式並不相同。下面這些例
+子,可以幫助你避免某些可能發生問題:
+用這些話介紹你的修改提案會有好處:
+
+ - 它同時解決了多個問題
+ - 它刪除了2000行代碼
+ - 這是補丁,它已經解釋了我想要說明的
+ - 我在5種不同的體系結構上測試過它……
+ - 這是一系列小補丁用來……
+ - 這個修改提高了普通機器的性能……
+
+應該避免如下的說法:
+
+ - 我們在AIX/ptx/Solaris就是這麼做的,所以這麼做肯定是好的……
+ - 我做這行已經20年了,所以……
+ - 爲了我們公司賺錢考慮必須這麼做
+ - 這是我們的企業產品線所需要的
+ - 這裡是描述我觀點的1000頁設計文檔
+ - 這是一個5000行的補丁用來……
+ - 我重寫了現在亂七八糟的代碼,這就是……
+ - 我被規定了最後期限,所以這個補丁需要立刻被接受
+
+另外一個內核社區與大部分傳統公司的軟體開發隊伍不同的地方是無法面對面地交
+流。使用電子郵件和IRC聊天工具做爲主要溝通工具的一個好處是性別和種族歧視
+將會更少。Linux內核的工作環境更能接受婦女和少數族羣,因爲每個人在別人眼
+里只是一個郵件地址。國際化也幫助了公平的實現,因爲你無法通過姓名來判斷人
+的性別。男人有可能叫李麗,女人也有可能叫王剛。大多數在Linux內核上工作過
+並表達過看法的女性對在linux上工作的經歷都給出了正面的評價。
+
+對於一些不習慣使用英語的人來說,語言可能是一個引起問題的障礙。在郵件列表
+中要正確地表達想法必需良好地掌握語言,所以建議你在發送郵件之前最好檢查一
+下英文寫得是否正確。
+
+
+拆分修改
+--------
+
+Linux內核社區並不喜歡一下接收大段的代碼。修改需要被恰當地介紹、討論並且
+拆分成獨立的小段。這幾乎完全和公司中的習慣背道而馳。你的想法應該在開發最
+開始的階段就讓大家知道,這樣你就可以及時獲得對你正在進行的開發的反饋。這
+樣也會讓社區覺得你是在和他們協作,而不是僅僅把他們當作傾銷新功能的對象。
+無論如何,你不要一次性地向郵件列表發送50封信,你的補丁序列應該永遠用不到
+這麼多。
+
+將補丁拆開的原因如下:
+
+1) 小的補丁更有可能被接受,因爲它們不需要太多的時間和精力去驗證其正確性。
+ 一個5行的補丁,可能在維護者看了一眼以後就會被接受。而500行的補丁則
+ 需要數個小時來審查其正確性(所需時間隨補丁大小增加大約呈指數級增長)。
+
+ 當出了問題的時候,小的補丁也會讓調試變得非常容易。一個一個補丁地回溯
+ 將會比仔細剖析一個被打上的大補丁(這個補丁破壞了其他東西)容易得多。
+
+2)不光發送小的補丁很重要,在提交之前重新編排、化簡(或者僅僅重新排列)
+ 補丁也是很重要的。
+
+這裡有內核開發者Al Viro打的一個比方:
+ 「想像一個老師正在給學生批改數學作業。老師並不希望看到學生爲了得
+ 到正確解法所進行的嘗試和產生的錯誤。他希望看到的是最乾淨最優雅的
+ 解答。好學生了解這點,絕不會把最終解決之前的中間方案提交上去。」
+
+ 內核開發也是這樣。維護者和評審者不希望看到一個人在解決問題時的思
+ 考過程。他們只希望看到簡單和優雅的解決方案。
+
+直接給出一流的解決方案,和社區一起協作討論尚未完成的工作,這兩者之間似乎
+很難找到一個平衡點。所以最好儘早開始收集有利於你進行改進的反饋;同時也要
+保證修改分成很多小塊,這樣在整個項目都準備好被包含進內核之前,其中的一部
+分可能會先被接收。
+
+必須了解這樣做是不可接受的:試圖將未完成的工作提交進內核,然後再找時間修
+復。
+
+
+證明修改的必要性
+----------------
+除了將補丁拆成小塊,很重要的一點是讓Linux社區了解他們爲什麼需要這樣修改。
+你必須證明新功能是有人需要的並且是有用的。
+
+
+記錄修改
+--------
+
+當你發送補丁的時候,需要特別留意郵件正文的內容。因爲這裡的信息將會做爲補
+丁的修改記錄(ChangeLog),會被一直保留以備大家查閱。它需要完全地描述補丁,
+包括:
+
+ - 爲什麼需要這個修改
+ - 補丁的總體設計
+ - 實現細節
+ - 測試結果
+
+想了解它具體應該看起來像什麼,請查閱以下文檔中的「ChangeLog」章節:
+ 「The Perfect Patch」
+ https://www.ozlabs.org/~akpm/stuff/tpp.txt
+
+
+這些事情有時候做起來很難。要在任何方面都做到完美可能需要好幾年時間。這是
+一個持續提高的過程,它需要大量的耐心和決心。只要不放棄,你一定可以做到。
+很多人已經做到了,而他們都曾經和現在的你站在同樣的起點上。
+
+
+感謝
+----
+感謝Paolo Ciarrocchi允許「開發流程」部分基於他所寫的文章
+(http://www.kerneltravel.net/newbie/2.6-development_process),感謝Randy
+Dunlap和Gerrit Huizenga完善了應該說和不該說的列表。感謝Pat Mochel, Hanna
+Linder, Randy Dunlap, Kay Sievers, Vojtech Pavlik, Jan Kara, Josh Boyer,
+Kees Cook, Andrew Morton, Andi Kleen, Vadim Lobanov, Jesper Juhl, Adrian
+Bunk, Keri Harris, Frans Pop, David A. Wheeler, Junio Hamano, Michael
+Kerrisk和Alex Shepard的評審、建議和貢獻。沒有他們的幫助,這篇文檔是不可
+能完成的。
+
+
+
+英文版維護者: Greg Kroah-Hartman <greg@kroah.com>
+
diff --git a/Documentation/translations/zh_TW/process/index.rst b/Documentation/translations/zh_TW/process/index.rst
new file mode 100644
index 000000000000..65922d9faa20
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/index.rst
@@ -0,0 +1,67 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. raw:: latex
+
+ \renewcommand\thesection*
+ \renewcommand\thesubsection*
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/index.rst <process_index>`
+:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+ Hu Haowen <2023002089@link.tyut.edu.cn>
+
+.. _tw_process_index:
+
+========================
+與Linux 內核社區一起工作
+========================
+
+你想成爲Linux內核開發人員嗎?歡迎之至!在學習許多關於內核的技術知識的同時,
+瞭解我們社區的工作方式也很重要。閱讀這些文檔可以讓您以更輕鬆的、麻煩更少的
+方式將更改合併到內核。
+
+以下是每位開發人員都應閱讀的基本指南:
+
+.. toctree::
+ :maxdepth: 1
+
+ howto
+ code-of-conduct
+ code-of-conduct-interpretation
+ submitting-patches
+ programming-language
+ coding-style
+ development-process
+ email-clients
+ license-rules
+ kernel-enforcement-statement
+ kernel-driver-statement
+
+其它大多數開發人員感興趣的社區指南:
+
+
+.. toctree::
+ :maxdepth: 1
+
+ submit-checklist
+ stable-api-nonsense
+ stable-kernel-rules
+ management-style
+ embargoed-hardware-issues
+
+這些是一些總體性技術指南,由於不大好分類而放在這裏:
+
+.. toctree::
+ :maxdepth: 1
+
+ magic-number
+ volatile-considered-harmful
+
+.. only:: subproject and html
+
+ 目錄
+ ====
+
+ * :ref:`genindex`
+
diff --git a/Documentation/translations/zh_TW/process/kernel-driver-statement.rst b/Documentation/translations/zh_TW/process/kernel-driver-statement.rst
new file mode 100644
index 000000000000..23d5cae9685b
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/kernel-driver-statement.rst
@@ -0,0 +1,203 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. _tw_process_statement_driver:
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/kernel-driver-statement.rst <process_statement_driver>`
+:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+ Hu Haowen <2023002089@link.tyut.edu.cn>
+
+內核驅動聲明
+------------
+
+關於Linux內核模塊的立場聲明
+===========================
+
+我們,以下署名的Linux內核開發人員,認爲任何封閉源Linux內核模塊或驅動程序都是
+有害的和不可取的。我們已經一再發現它們對Linux用戶,企業和更大的Linux生態系統
+有害。這樣的模塊否定了Linux開發模型的開放性,穩定性,靈活性和可維護性,並使
+他們的用戶無法使用Linux社區的專業知識。提供閉源內核模塊的供應商迫使其客戶
+放棄Linux的主要優勢或選擇新的供應商。因此,爲了充分利用開源所提供的成本節省和
+共享支持優勢,我們敦促供應商採取措施,以開源內核代碼在Linux上爲其客戶提供支持。
+
+我們只爲自己說話,而不是我們今天可能會爲之工作,過去或將來會爲之工作的任何公司。
+
+ - Dave Airlie
+ - Nick Andrew
+ - Jens Axboe
+ - Ralf Baechle
+ - Felipe Balbi
+ - Ohad Ben-Cohen
+ - Muli Ben-Yehuda
+ - Jiri Benc
+ - Arnd Bergmann
+ - Thomas Bogendoerfer
+ - Vitaly Bordug
+ - James Bottomley
+ - Josh Boyer
+ - Neil Brown
+ - Mark Brown
+ - David Brownell
+ - Michael Buesch
+ - Franck Bui-Huu
+ - Adrian Bunk
+ - François Cami
+ - Ralph Campbell
+ - Luiz Fernando N. Capitulino
+ - Mauro Carvalho Chehab
+ - Denis Cheng
+ - Jonathan Corbet
+ - Glauber Costa
+ - Alan Cox
+ - Magnus Damm
+ - Ahmed S. Darwish
+ - Robert P. J. Day
+ - Hans de Goede
+ - Arnaldo Carvalho de Melo
+ - Helge Deller
+ - Jean Delvare
+ - Mathieu Desnoyers
+ - Sven-Thorsten Dietrich
+ - Alexey Dobriyan
+ - Daniel Drake
+ - Alex Dubov
+ - Randy Dunlap
+ - Michael Ellerman
+ - Pekka Enberg
+ - Jan Engelhardt
+ - Mark Fasheh
+ - J. Bruce Fields
+ - Larry Finger
+ - Jeremy Fitzhardinge
+ - Mike Frysinger
+ - Kumar Gala
+ - Robin Getz
+ - Liam Girdwood
+ - Jan-Benedict Glaw
+ - Thomas Gleixner
+ - Brice Goglin
+ - Cyrill Gorcunov
+ - Andy Gospodarek
+ - Thomas Graf
+ - Krzysztof Halasa
+ - Harvey Harrison
+ - Stephen Hemminger
+ - Michael Hennerich
+ - Tejun Heo
+ - Benjamin Herrenschmidt
+ - Kristian Høgsberg
+ - Henrique de Moraes Holschuh
+ - Marcel Holtmann
+ - Mike Isely
+ - Takashi Iwai
+ - Olof Johansson
+ - Dave Jones
+ - Jesper Juhl
+ - Matthias Kaehlcke
+ - Kenji Kaneshige
+ - Jan Kara
+ - Jeremy Kerr
+ - Russell King
+ - Olaf Kirch
+ - Roel Kluin
+ - Hans-Jürgen Koch
+ - Auke Kok
+ - Peter Korsgaard
+ - Jiri Kosina
+ - Aaro Koskinen
+ - Mariusz Kozlowski
+ - Greg Kroah-Hartman
+ - Michael Krufky
+ - Aneesh Kumar
+ - Clemens Ladisch
+ - Christoph Lameter
+ - Gunnar Larisch
+ - Anders Larsen
+ - Grant Likely
+ - John W. Linville
+ - Yinghai Lu
+ - Tony Luck
+ - Pavel Machek
+ - Matt Mackall
+ - Paul Mackerras
+ - Roland McGrath
+ - Patrick McHardy
+ - Kyle McMartin
+ - Paul Menage
+ - Thierry Merle
+ - Eric Miao
+ - Akinobu Mita
+ - Ingo Molnar
+ - James Morris
+ - Andrew Morton
+ - Paul Mundt
+ - Oleg Nesterov
+ - Luca Olivetti
+ - S.Çağlar Onur
+ - Pierre Ossman
+ - Keith Owens
+ - Venkatesh Pallipadi
+ - Nick Piggin
+ - Nicolas Pitre
+ - Evgeniy Polyakov
+ - Richard Purdie
+ - Mike Rapoport
+ - Sam Ravnborg
+ - Gerrit Renker
+ - Stefan Richter
+ - David Rientjes
+ - Luis R. Rodriguez
+ - Stefan Roese
+ - Francois Romieu
+ - Rami Rosen
+ - Stephen Rothwell
+ - Maciej W. Rozycki
+ - Mark Salyzyn
+ - Yoshinori Sato
+ - Deepak Saxena
+ - Holger Schurig
+ - Amit Shah
+ - Yoshihiro Shimoda
+ - Sergei Shtylyov
+ - Kay Sievers
+ - Sebastian Siewior
+ - Rik Snel
+ - Jes Sorensen
+ - Alexey Starikovskiy
+ - Alan Stern
+ - Timur Tabi
+ - Hirokazu Takata
+ - Eliezer Tamir
+ - Eugene Teo
+ - Doug Thompson
+ - FUJITA Tomonori
+ - Dmitry Torokhov
+ - Marcelo Tosatti
+ - Steven Toth
+ - Theodore Tso
+ - Matthias Urlichs
+ - Geert Uytterhoeven
+ - Arjan van de Ven
+ - Ivo van Doorn
+ - Rik van Riel
+ - Wim Van Sebroeck
+ - Hans Verkuil
+ - Horst H. von Brand
+ - Dmitri Vorobiev
+ - Anton Vorontsov
+ - Daniel Walker
+ - Johannes Weiner
+ - Harald Welte
+ - Matthew Wilcox
+ - Dan J. Williams
+ - Darrick J. Wong
+ - David Woodhouse
+ - Chris Wright
+ - Bryan Wu
+ - Rafael J. Wysocki
+ - Herbert Xu
+ - Vlad Yasevich
+ - Peter Zijlstra
+ - Bartlomiej Zolnierkiewicz
+
diff --git a/Documentation/translations/zh_TW/process/kernel-enforcement-statement.rst b/Documentation/translations/zh_TW/process/kernel-enforcement-statement.rst
new file mode 100644
index 000000000000..524eb4ac26cc
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/kernel-enforcement-statement.rst
@@ -0,0 +1,155 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. _tw_process_statement_kernel:
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/kernel-enforcement-statement.rst <process_statement_kernel>`
+:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+ Hu Haowen <2023002089@link.tyut.edu.cn>
+
+Linux 內核執行聲明
+------------------
+
+作爲Linux內核的開發人員,我們對如何使用我們的軟體以及如何實施軟體許可證有著
+濃厚的興趣。遵守GPL-2.0的互惠共享義務對我們軟體和社區的長期可持續性至關重要。
+
+雖然有權強制執行對我們社區的貢獻中的單獨版權權益,但我們有共同的利益,即確保
+個人強制執行行動的方式有利於我們的社區,不會對我們軟體生態系統的健康和增長
+產生意外的負面影響。爲了阻止無益的執法行動,我們同意代表我們自己和我們版權
+利益的任何繼承人對Linux內核用戶作出以下符合我們開發社區最大利益的承諾:
+
+ 儘管有GPL-2.0的終止條款,我們同意,採用以下GPL-3.0條款作爲我們許可證下的
+ 附加許可,作爲任何對許可證下權利的非防禦性主張,這符合我們開發社區的最佳
+ 利益。
+
+ 但是,如果您停止所有違反本許可證的行爲,則您從特定版權持有人處獲得的
+ 許可證將被恢復:(a)暫時恢復,除非版權持有人明確並最終終止您的許可證;
+ 以及(b)永久恢復, 如果版權持有人未能在你終止違反後60天內以合理方式
+ 通知您違反本許可證的行爲,則永久恢復您的許可證。
+
+ 此外,如果版權所有者以某種合理的方式通知您違反了本許可,這是您第一次
+ 從該版權所有者處收到違反本許可的通知(對於任何作品),並且您在收到通知
+ 後的30天內糾正違規行爲。則您從特定版權所有者處獲得的許可將永久恢復.
+
+我們提供這些保證的目的是鼓勵更多地使用該軟體。我們希望公司和個人使用、修改和
+分發此軟體。我們希望以公開和透明的方式與用戶合作,以消除我們對法規遵從性或強制
+執行的任何不確定性,這些不確定性可能會限制我們軟體的採用。我們將法律行動視爲
+最後手段,只有在其他社區努力未能解決這一問題時才採取行動。
+
+最後,一旦一個不合規問題得到解決,我們希望用戶會感到歡迎,加入我們爲之努力的
+這個項目。共同努力,我們會更強大。
+
+除了下面提到的以外,我們只爲自己說話,而不是爲今天、過去或將來可能爲之工作的
+任何公司說話。
+
+ - Laura Abbott
+ - Bjorn Andersson (Linaro)
+ - Andrea Arcangeli
+ - Neil Armstrong
+ - Jens Axboe
+ - Pablo Neira Ayuso
+ - Khalid Aziz
+ - Ralf Baechle
+ - Felipe Balbi
+ - Arnd Bergmann
+ - Ard Biesheuvel
+ - Tim Bird
+ - Paolo Bonzini
+ - Christian Borntraeger
+ - Mark Brown (Linaro)
+ - Paul Burton
+ - Javier Martinez Canillas
+ - Rob Clark
+ - Kees Cook (Google)
+ - Jonathan Corbet
+ - Dennis Dalessandro
+ - Vivien Didelot (Savoir-faire Linux)
+ - Hans de Goede
+ - Mel Gorman (SUSE)
+ - Sven Eckelmann
+ - Alex Elder (Linaro)
+ - Fabio Estevam
+ - Larry Finger
+ - Bhumika Goyal
+ - Andy Gross
+ - Juergen Gross
+ - Shawn Guo
+ - Ulf Hansson
+ - Stephen Hemminger (Microsoft)
+ - Tejun Heo
+ - Rob Herring
+ - Masami Hiramatsu
+ - Michal Hocko
+ - Simon Horman
+ - Johan Hovold (Hovold Consulting AB)
+ - Christophe JAILLET
+ - Olof Johansson
+ - Lee Jones (Linaro)
+ - Heiner Kallweit
+ - Srinivas Kandagatla
+ - Jan Kara
+ - Shuah Khan (Samsung)
+ - David Kershner
+ - Jaegeuk Kim
+ - Namhyung Kim
+ - Colin Ian King
+ - Jeff Kirsher
+ - Greg Kroah-Hartman (Linux Foundation)
+ - Christian König
+ - Vinod Koul
+ - Krzysztof Kozlowski
+ - Viresh Kumar
+ - Aneesh Kumar K.V
+ - Julia Lawall
+ - Doug Ledford
+ - Chuck Lever (Oracle)
+ - Daniel Lezcano
+ - Shaohua Li
+ - Xin Long
+ - Tony Luck
+ - Catalin Marinas (Arm Ltd)
+ - Mike Marshall
+ - Chris Mason
+ - Paul E. McKenney
+ - Arnaldo Carvalho de Melo
+ - David S. Miller
+ - Ingo Molnar
+ - Kuninori Morimoto
+ - Trond Myklebust
+ - Martin K. Petersen (Oracle)
+ - Borislav Petkov
+ - Jiri Pirko
+ - Josh Poimboeuf
+ - Sebastian Reichel (Collabora)
+ - Guenter Roeck
+ - Joerg Roedel
+ - Leon Romanovsky
+ - Steven Rostedt (VMware)
+ - Frank Rowand
+ - Ivan Safonov
+ - Anna Schumaker
+ - Jes Sorensen
+ - K.Y. Srinivasan
+ - David Sterba (SUSE)
+ - Heiko Stuebner
+ - Jiri Kosina (SUSE)
+ - Willy Tarreau
+ - Dmitry Torokhov
+ - Linus Torvalds
+ - Thierry Reding
+ - Rik van Riel
+ - Luis R. Rodriguez
+ - Geert Uytterhoeven (Glider bvba)
+ - Eduardo Valentin (Amazon.com)
+ - Daniel Vetter
+ - Linus Walleij
+ - Richard Weinberger
+ - Dan Williams
+ - Rafael J. Wysocki
+ - Arvind Yadav
+ - Masahiro Yamada
+ - Wei Yongjun
+ - Lv Zheng
+ - Marc Zyngier (Arm Ltd)
+
diff --git a/Documentation/translations/zh_TW/process/license-rules.rst b/Documentation/translations/zh_TW/process/license-rules.rst
new file mode 100644
index 000000000000..594255856b68
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/license-rules.rst
@@ -0,0 +1,372 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/license-rules.rst <kernel_licensing>`
+:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+ Hu Haowen <2023002089@link.tyut.edu.cn>
+
+.. _tw_kernel_licensing:
+
+Linux內核許可規則
+=================
+
+Linux內核根據LICENSES/preferred/GPL-2.0中提供的GNU通用公共許可證版本2
+(GPL-2.0)的條款提供,並在LICENSES/exceptions/Linux-syscall-note中顯式
+描述了例外的系統調用,如COPYING文件中所述。
+
+此文檔文件提供瞭如何對每個源文件進行註釋以使其許可證清晰明確的說明。
+它不會取代內核的許可證。
+
+內核源代碼作爲一個整體適用於COPYING文件中描述的許可證,但是單個源文件可以
+具有不同的與GPL-20兼容的許可證::
+
+ GPL-1.0+ : GNU通用公共許可證v1.0或更高版本
+ GPL-2.0+ : GNU通用公共許可證v2.0或更高版本
+ LGPL-2.0 : 僅限GNU庫通用公共許可證v2
+ LGPL-2.0+: GNU 庫通用公共許可證v2或更高版本
+ LGPL-2.1 : 僅限GNU寬通用公共許可證v2.1
+ LGPL-2.1+: GNU寬通用公共許可證v2.1或更高版本
+
+除此之外,個人文件可以在雙重許可下提供,例如一個兼容的GPL變體,或者BSD,
+MIT等許可。
+
+用戶空間API(UAPI)頭文件描述了用戶空間程序與內核的接口,這是一種特殊情況。
+根據內核COPYING文件中的註釋,syscall接口是一個明確的邊界,它不會將GPL要求
+擴展到任何使用它與內核通信的軟件。由於UAPI頭文件必須包含在創建在Linux內核
+上運行的可執行文件的任何源文件中,因此此例外必須記錄在特別的許可證表述中。
+
+表達源文件許可證的常用方法是將匹配的樣板文本添加到文件的頂部註釋中。由於
+格式,拼寫錯誤等,這些“樣板”很難通過那些在上下文中使用的驗證許可證合規性
+的工具。
+
+樣板文本的替代方法是在每個源文件中使用軟件包數據交換(SPDX)許可證標識符。
+SPDX許可證標識符是機器可解析的,並且是用於提供文件內容的許可證的精確縮寫。
+SPDX許可證標識符由Linux 基金會的SPDX 工作組管理,並得到了整個行業,工具
+供應商和法律團隊的合作伙伴的一致同意。有關詳細信息,請參閱
+https://spdx.org/
+
+Linux內核需要所有源文件中的精確SPDX標識符。內核中使用的有效標識符在
+`許可標識符`_ 一節中進行了解釋,並且已可以在
+https://spdx.org/licenses/ 上的官方SPDX許可證列表中檢索,並附帶許可證
+文本。
+
+許可標識符語法
+--------------
+
+1.安置:
+
+   內核文件中的SPDX許可證標識符應添加到可包含註釋的文件中的第一行。對於大多
+ 數文件,這是第一行,除了那些在第一行中需要'#!PATH_TO_INTERPRETER'的腳本。
+ 對於這些腳本,SPDX標識符進入第二行。
+
+|
+
+2. 風格:
+
+ SPDX許可證標識符以註釋的形式添加。註釋樣式取決於文件類型::
+
+ C source: // SPDX-License-Identifier: <SPDX License Expression>
+ C header: /* SPDX-License-Identifier: <SPDX License Expression> */
+ ASM: /* SPDX-License-Identifier: <SPDX License Expression> */
+ scripts: # SPDX-License-Identifier: <SPDX License Expression>
+ .rst: .. SPDX-License-Identifier: <SPDX License Expression>
+ .dts{i}: // SPDX-License-Identifier: <SPDX License Expression>
+
+ 如果特定工具無法處理標準註釋樣式,則應使用工具接受的相應註釋機制。這是在
+ C 頭文件中使用“/\*\*/”樣式註釋的原因。過去在使用生成的.lds文件中觀察到
+ 構建被破壞,其中'ld'無法解析C++註釋。現在已經解決了這個問題,但仍然有較
+ 舊的彙編程序工具無法處理C++樣式的註釋。
+
+|
+
+3. 句法:
+
+ <SPDX許可證表達式>是SPDX許可證列表中的SPDX短格式許可證標識符,或者在許可
+ 證例外適用時由“WITH”分隔的兩個SPDX短格式許可證標識符的組合。當應用多個許
+ 可證時,表達式由分隔子表達式的關鍵字“AND”,“OR”組成,並由“(”,“)”包圍。
+
+ 帶有“或更高”選項的[L]GPL等許可證的許可證標識符通過使用“+”來表示“或更高”
+ 選項來構建。::
+
+ // SPDX-License-Identifier: GPL-2.0+
+ // SPDX-License-Identifier: LGPL-2.1+
+
+ 當需要修正的許可證時,應使用WITH。 例如,linux內核UAPI文件使用表達式::
+
+ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+ // SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note
+
+ 其它在內核中使用WITH例外的事例如下::
+
+ // SPDX-License-Identifier: GPL-2.0 WITH mif-exception
+ // SPDX-License-Identifier: GPL-2.0+ WITH GCC-exception-2.0
+
+ 例外只能與特定的許可證標識符一起使用。有效的許可證標識符列在異常文本文件
+ 的標記中。有關詳細信息,請參閱 `許可標識符`_ 一章中的 `例外`_ 。
+
+ 如果文件是雙重許可且只選擇一個許可證,則應使用OR。例如,一些dtsi文件在雙
+ 許可下可用::
+
+ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+
+ 內核中雙許可文件中許可表達式的示例::
+
+ // SPDX-License-Identifier: GPL-2.0 OR MIT
+ // SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+ // SPDX-License-Identifier: GPL-2.0 OR Apache-2.0
+ // SPDX-License-Identifier: GPL-2.0 OR MPL-1.1
+ // SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR MIT
+ // SPDX-License-Identifier: GPL-1.0+ OR BSD-3-Clause OR OpenSSL
+
+ 如果文件具有多個許可證,其條款全部適用於使用該文件,則應使用AND。例如,
+ 如果代碼是從另一個項目繼承的,並且已經授予了將其放入內核的權限,但原始
+ 許可條款需要保持有效::
+
+ // SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) AND MIT
+
+ 另一個需要遵守兩套許可條款的例子是::
+
+ // SPDX-License-Identifier: GPL-1.0+ AND LGPL-2.1+
+
+許可標識符
+----------
+
+當前使用的許可證以及添加到內核的代碼許可證可以分解爲:
+
+1. _`優先許可`:
+
+ 應儘可能使用這些許可證,因爲它們已知完全兼容並廣泛使用。這些許可證在內核
+ 目錄::
+
+ LICENSES/preferred/
+
+ 此目錄中的文件包含完整的許可證文本和 `元標記`_ 。文件名與SPDX許可證標識
+ 符相同,後者應用於源文件中的許可證。
+
+ 例如::
+
+ LICENSES/preferred/GPL-2.0
+
+ 包含GPLv2許可證文本和所需的元標籤::
+
+ LICENSES/preferred/MIT
+
+ 包含MIT許可證文本和所需的元標記
+
+ _`元標記`:
+
+ 許可證文件中必須包含以下元標記:
+
+ - Valid-License-Identifier:
+
+   一行或多行, 聲明那些許可標識符在項目內有效, 以引用此特定許可的文本。通
+ 常這是一個有效的標識符,但是例如對於帶有'或更高'選項的許可證,兩個標識
+ 符都有效。
+
+ - SPDX-URL:
+
+ SPDX頁面的URL,其中包含與許可證相關的其他信息.
+
+ - Usage-Guidance:
+
+ 使用建議的自由格式文本。該文本必須包含SPDX許可證標識符的正確示例,因爲
+ 它們應根據 `許可標識符語法`_ 指南放入源文件中。
+
+ - License-Text:
+
+ 此標記之後的所有文本都被視爲原始許可文本
+
+ 文件格式示例::
+
+ Valid-License-Identifier: GPL-2.0
+ Valid-License-Identifier: GPL-2.0+
+ SPDX-URL: https://spdx.org/licenses/GPL-2.0.html
+ Usage-Guide:
+ To use this license in source code, put one of the following SPDX
+ tag/value pairs into a comment according to the placement
+ guidelines in the licensing rules documentation.
+ For 'GNU General Public License (GPL) version 2 only' use:
+ SPDX-License-Identifier: GPL-2.0
+ For 'GNU General Public License (GPL) version 2 or any later version' use:
+ SPDX-License-Identifier: GPL-2.0+
+ License-Text:
+ Full license text
+
+ ::
+
+ SPDX-License-Identifier: MIT
+ SPDX-URL: https://spdx.org/licenses/MIT.html
+ Usage-Guide:
+ To use this license in source code, put the following SPDX
+ tag/value pair into a comment according to the placement
+ guidelines in the licensing rules documentation.
+ SPDX-License-Identifier: MIT
+ License-Text:
+ Full license text
+
+|
+
+2. 不推薦的許可證:
+
+ 這些許可證只應用於現有代碼或從其他項目導入代碼。這些許可證在內核目錄::
+
+ LICENSES/other/
+
+ 此目錄中的文件包含完整的許可證文本和 `元標記`_ 。文件名與SPDX許可證標識
+ 符相同,後者應用於源文件中的許可證。
+
+ 例如::
+
+ LICENSES/other/ISC
+
+ 包含國際系統聯合許可文本和所需的元標籤::
+
+ LICENSES/other/ZLib
+
+ 包含ZLIB許可文本和所需的元標籤.
+
+ 元標籤:
+
+ “其他”許可證的元標籤要求與 `優先許可`_ 的要求相同。
+
+ 文件格式示例::
+
+ Valid-License-Identifier: ISC
+ SPDX-URL: https://spdx.org/licenses/ISC.html
+ Usage-Guide:
+ Usage of this license in the kernel for new code is discouraged
+ and it should solely be used for importing code from an already
+ existing project.
+ To use this license in source code, put the following SPDX
+ tag/value pair into a comment according to the placement
+ guidelines in the licensing rules documentation.
+ SPDX-License-Identifier: ISC
+ License-Text:
+ Full license text
+
+|
+
+3. _`例外`:
+
+ 某些許可證可以修改,並允許原始許可證不具有的某些例外權利。這些例外在
+ 內核目錄::
+
+ LICENSES/exceptions/
+
+ 此目錄中的文件包含完整的例外文本和所需的 `例外元標記`_ 。
+
+ 例如::
+
+ LICENSES/exceptions/Linux-syscall-note
+
+ 包含Linux內核的COPYING文件中記錄的Linux系統調用例外,該文件用於UAPI
+ 頭文件。例如::
+
+ LICENSES/exceptions/GCC-exception-2.0
+
+ 包含GCC'鏈接例外',它允許獨立於其許可證的任何二進制文件與標記有此例外的
+ 文件的編譯版本鏈接。這是從GPL不兼容源代碼創建可運行的可執行文件所必需的。
+
+ _`例外元標記`:
+
+ 以下元標記必須在例外文件中可用:
+
+ - SPDX-Exception-Identifier:
+
+   一個可與SPDX許可證標識符一起使用的例外標識符。
+
+ - SPDX-URL:
+
+ SPDX頁面的URL,其中包含與例外相關的其他信息。
+
+ - SPDX-Licenses:
+
+   以逗號分隔的例外可用的SPDX許可證標識符列表。
+
+ - Usage-Guidance:
+
+ 使用建議的自由格式文本。必須在文本後面加上SPDX許可證標識符的正確示例,
+ 因爲它們應根據 `許可標識符語法`_ 指南放入源文件中。
+
+ - Exception-Text:
+
+ 此標記之後的所有文本都被視爲原始異常文本
+
+ 文件格式示例::
+
+ SPDX-Exception-Identifier: Linux-syscall-note
+ SPDX-URL: https://spdx.org/licenses/Linux-syscall-note.html
+ SPDX-Licenses: GPL-2.0, GPL-2.0+, GPL-1.0+, LGPL-2.0, LGPL-2.0+, LGPL-2.1, LGPL-2.1+
+ Usage-Guidance:
+ This exception is used together with one of the above SPDX-Licenses
+ to mark user-space API (uapi) header files so they can be included
+ into non GPL compliant user-space application code.
+ To use this exception add it with the keyword WITH to one of the
+ identifiers in the SPDX-Licenses tag:
+ SPDX-License-Identifier: <SPDX-License> WITH Linux-syscall-note
+ Exception-Text:
+ Full exception text
+
+ ::
+
+ SPDX-Exception-Identifier: GCC-exception-2.0
+ SPDX-URL: https://spdx.org/licenses/GCC-exception-2.0.html
+ SPDX-Licenses: GPL-2.0, GPL-2.0+
+ Usage-Guidance:
+ The "GCC Runtime Library exception 2.0" is used together with one
+ of the above SPDX-Licenses for code imported from the GCC runtime
+ library.
+ To use this exception add it with the keyword WITH to one of the
+ identifiers in the SPDX-Licenses tag:
+ SPDX-License-Identifier: <SPDX-License> WITH GCC-exception-2.0
+ Exception-Text:
+ Full exception text
+
+
+所有SPDX許可證標識符和例外都必須在LICENSES子目錄中具有相應的文件。這是允許
+工具驗證(例如checkpatch.pl)以及準備好從源讀取和提取許可證所必需的, 這是
+各種FOSS組織推薦的,例如 `FSFE REUSE initiative <https://reuse.software/>`_.
+
+_`模塊許可`
+-----------------
+
+ 可加載內核模塊還需要MODULE_LICENSE()標記。此標記既不替代正確的源代碼
+ 許可證信息(SPDX-License-Identifier),也不以任何方式表示或確定提供模塊
+ 源代碼的確切許可證。
+
+ 此標記的唯一目的是提供足夠的信息,該模塊是否是自由軟件或者是內核模塊加
+ 載器和用戶空間工具的專有模塊。
+
+ MODULE_LICENSE()的有效許可證字符串是:
+
+ ============================= =============================================
+ "GPL" 模塊是根據GPL版本2許可的。這並不表示僅限於
+ GPL-2.0或GPL-2.0或更高版本之間的任何區別。
+ 最正確許可證信息只能通過相應源文件中的許可證
+ 信息來確定
+
+ "GPL v2" 和"GPL"相同,它的存在是因爲歷史原因。
+
+ "GPL and additional rights" 表示模塊源在GPL v2變體和MIT許可下雙重許可的
+ 歷史變體。請不要在新代碼中使用。
+
+ "Dual MIT/GPL" 表達該模塊在GPL v2變體或MIT許可證選擇下雙重
+ 許可的正確方式。
+
+ "Dual BSD/GPL" 該模塊根據GPL v2變體或BSD許可證選擇進行雙重
+ 許可。 BSD許可證的確切變體只能通過相應源文件
+ 中的許可證信息來確定。
+
+ "Dual MPL/GPL" 該模塊根據GPL v2變體或Mozilla Public License
+ (MPL)選項進行雙重許可。 MPL許可證的確切變體
+ 只能通過相應的源文件中的許可證信息來確定。
+
+ "Proprietary" 該模塊屬於專有許可。此字符串僅用於專有的第三
+ 方模塊,不能用於在內核樹中具有源代碼的模塊。
+ 以這種方式標記的模塊在加載時會使用'P'標記污
+ 染內核,並且內核模塊加載器拒絕將這些模塊鏈接
+ 到使用EXPORT_SYMBOL_GPL()導出的符號。
+ ============================= =============================================
+
+
diff --git a/Documentation/translations/zh_TW/process/magic-number.rst b/Documentation/translations/zh_TW/process/magic-number.rst
new file mode 100644
index 000000000000..199cd5d63973
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/magic-number.rst
@@ -0,0 +1,76 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. _tw_magicnumbers:
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/magic-number.rst <magicnumbers>`
+
+如果想評論或更新本文的內容,請直接發信到LKML。如果你使用英文交流有困難的話,也可
+以向中文版維護者求助。如果本翻譯更新不及時或者翻譯存在問題,請聯繫中文版維護者::
+
+ 中文版維護者: 賈威威 Jia Wei Wei <harryxiyou@gmail.com>
+ 中文版翻譯者: 賈威威 Jia Wei Wei <harryxiyou@gmail.com>
+ 中文版校譯者: 賈威威 Jia Wei Wei <harryxiyou@gmail.com>
+ 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+Linux 魔術數
+============
+
+這個文件是有關當前使用的魔術值註冊表。當你給一個結構添加了一個魔術值,你也應該把這個魔術值添加到這個文件,因爲我們最好把用於各種結構的魔術值統一起來。
+
+使用魔術值來保護內核數據結構是一個非常好的主意。這就允許你在運行期檢查(a)一個結構是否已經被攻擊,或者(b)你已經給一個例行程序通過了一個錯誤的結構。後一種情況特別地有用---特別是當你通過一個空指針指向結構體的時候。tty源碼,例如,經常通過特定驅動使用這種方法並且反覆地排列特定方面的結構。
+
+使用魔術值的方法是在結構的開始處聲明的,如下::
+
+ struct tty_ldisc {
+ int magic;
+ ...
+ };
+
+當你以後給內核添加增強功能的時候,請遵守這條規則!這樣就會節省數不清的調試時間,特別是一些古怪的情況,例如,數組超出範圍並且重新寫了超出部分。遵守這個規則,這些情況可以被快速地,安全地避免。
+
+ Theodore Ts'o
+ 31 Mar 94
+
+給當前的Linux 2.1.55添加魔術表。
+
+ Michael Chastain
+ <mailto:mec@shout.net>
+ 22 Sep 1997
+
+現在應該最新的Linux 2.1.112.因爲在特性凍結期間,不能在2.2.x前改變任何東西。這些條目被數域所排序。
+
+ Krzysztof G.Baranowski
+ <mailto: kgb@knm.org.pl>
+ 29 Jul 1998
+
+更新魔術表到Linux 2.5.45。剛好越過特性凍結,但是有可能還會有一些新的魔術值在2.6.x之前融入到內核中。
+
+ Petr Baudis
+ <pasky@ucw.cz>
+ 03 Nov 2002
+
+更新魔術表到Linux 2.5.74。
+
+ Fabian Frederick
+ <ffrederick@users.sourceforge.net>
+ 09 Jul 2003
+
+===================== ================ ======================== ==========================================
+魔術數名 數字 結構 文件
+===================== ================ ======================== ==========================================
+PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/pg.h``
+APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
+FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
+SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
+BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c``
+HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
+KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``
+CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h``
+YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c``
+CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c``
+QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c``
+QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c``
+NMI_MAGIC 0x48414d4d455201 nmi_s ``arch/mips/include/asm/sn/nmi.h``
+===================== ================ ======================== ==========================================
diff --git a/Documentation/translations/zh_TW/process/management-style.rst b/Documentation/translations/zh_TW/process/management-style.rst
new file mode 100644
index 000000000000..7cb912e89032
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/management-style.rst
@@ -0,0 +1,211 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/management-style.rst <managementstyle>`
+:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+ Hu Haowen <2023002089@link.tyut.edu.cn>
+
+.. _tw_managementstyle:
+
+Linux內核管理風格
+=================
+
+這是一個簡短的文檔,描述了Linux內核首選的(或胡編的,取決於您問誰)管理風格。
+它的目的是在某種程度上參照 :ref:`process/coding-style.rst <codingstyle>`
+主要是爲了避免反覆回答 [#cnf1]_ 相同(或類似)的問題。
+
+管理風格是非常個人化的,比簡單的編碼風格規則更難以量化,因此本文檔可能與實
+際情況有關,也可能與實際情況無關。起初它是一個玩笑,但這並不意味着它可能不
+是真的。你得自己決定。
+
+順便說一句,在談到“核心管理者”時,主要是技術負責人,而不是在公司內部進行傳
+統管理的人。如果你簽署了採購訂單或者對你的團隊的預算有任何瞭解,你幾乎肯定
+不是一個核心管理者。這些建議可能適用於您,也可能不適用於您。
+
+首先,我建議你購買“高效人的七個習慣”,而不是閱讀它。燒了它,這是一個偉大的
+象徵性姿態。
+
+.. [#cnf1] 本文件並不是通過回答問題,而是通過讓提問者痛苦地明白,我們不知道
+ 答案是什麼。
+
+不管怎樣,這裏是:
+
+.. _tw_decisions:
+
+1)決策
+-------
+
+每個人都認爲管理者做決定,而且決策很重要。決定越大越痛苦,管理者就必須越高級。
+這很明顯,但事實並非如此。
+
+最重要的是 **避免** 做出決定。尤其是,如果有人告訴你“選擇(a)或(b),
+我們真的需要你來做決定”,你就是陷入麻煩的管理者。你管理的人比你更瞭解細節,
+所以如果他們來找你做技術決策,你完蛋了。你顯然沒有能力爲他們做這個決定。
+
+(推論:如果你管理的人不比你更瞭解細節,你也會被搞砸,儘管原因完全不同。
+也就是說,你的工作是錯的,他們應該管理你的才智)
+
+所以最重要的是 **避免** 做出決定,至少是那些大而痛苦的決定。做一些小的
+和非結果性的決定是很好的,並且使您看起來好像知道自己在做什麼,所以內核管理者
+需要做的是將那些大的和痛苦的決定變成那些沒有人真正關心的小事情。
+
+這有助於認識到一個大的決定和一個小的決定之間的關鍵區別是你是否可以在事後修正
+你的決定。任何決定都可以通過始終確保如果你錯了(而且你一定會錯),你以後總是
+可以通過回溯來彌補損失。突然間,你就要做兩個無關緊要的決定,一個是錯誤的,另
+一個是正確的。
+
+人們甚至會認爲這是真正的領導能力(咳,胡說,咳)。
+
+因此,避免重大決策的關鍵在於避免做那些無法挽回的事情。不要被引導到一個你無法
+逃離的角落。走投無路的老鼠可能很危險——走投無路的管理者真可憐。
+
+事實證明,由於沒有人會愚蠢到讓內核管理者承擔巨大的財政責任,所以通常很容易
+回溯。既然你不可能浪費掉你無法償還的鉅額資金,你唯一可以回溯的就是技術決策,
+而回溯很容易:只要告訴大家你是個不稱職的傻瓜,說對不起,然後撤銷你去年讓別
+人所做的毫無價值的工作。突然間,你一年前做的決定不在是一個重大的決定,因爲
+它很容易被推翻。
+
+事實證明,有些人對接受這種方法有困難,原因有兩個:
+
+ - 承認你是個白癡比看起來更難。我們都喜歡保持形象,在公共場合說你錯了有時
+ 確實很難。
+ - 如果有人告訴你,你去年所做的工作終究是不值得的,那麼對那些可憐的低級工
+ 程師來說也是很困難的,雖然實際的 **工作** 很容易刪除,但你可能已經不可
+ 挽回地失去了工程師的信任。記住:“不可撤銷”是我們一開始就試圖避免的,
+ 而你的決定終究是一個重大的決定。
+
+令人欣慰的是,這兩個原因都可以通過預先承認你沒有任何線索,提前告訴人們你的
+決定完全是初步的,而且可能是錯誤的事情來有效地緩解。你應該始終保留改變主意
+的權利,並讓人們 **意識** 到這一點。當你 **還沒有** 做過真正愚蠢的事情的時
+候,承認自己是愚蠢的要容易得多。
+
+然後,當它真的被證明是愚蠢的時候,人們就轉動他們的眼珠說“哎呀,下次不要了”。
+
+這種對不稱職的先發制人的承認,也可能使真正做這項工作的人也會三思是否值得做。
+畢竟,如果他們不確定這是否是一個好主意,你肯定不應該通過向他們保證他們所做
+的工作將會進入(內核)鼓勵他們。在他們開始一項巨大的努力之前,至少讓他們三
+思而後行。
+
+記住:他們最好比你更瞭解細節,而且他們通常認爲他們對每件事都有答案。作爲一
+個管理者,你能做的最好的事情不是灌輸自信,而是對他們所做的事情進行健康的批
+判性思考。
+
+順便說一句,另一種避免做出決定的方法是看起來很可憐的抱怨 “我們不能兩者兼
+得嗎?” 相信我,它是有效的。如果不清楚哪種方法更好,他們最終會弄清楚的。
+最終的答案可能是兩個團隊都會因爲這種情況而感到沮喪,以至於他們放棄了。
+
+這聽起來像是一個失敗,但這通常是一個跡象,表明兩個項目都有問題,而參與其中
+的人不能做決定的原因是他們都是錯誤的。你最終會聞到玫瑰的味道,你避免了另一
+個你本可以搞砸的決定。
+
+2)人
+-----
+
+大多數人都是白癡,做一名管理者意味着你必須處理好這件事,也許更重要的是,
+**他們** 必須處理好你。
+
+事實證明,雖然很容易糾正技術錯誤,但不容易糾正人格障礙。你只能和他們的和
+你的(人格障礙)共處。
+
+但是,爲了做好作爲內核管理者的準備,最好記住不要燒掉任何橋樑,不要轟炸任何
+無辜的村民,也不要疏遠太多的內核開發人員。事實證明,疏遠人是相當容易的,而
+親近一個疏遠的人是很難的。因此,“疏遠”立即屬於“不可逆”的範疇,並根據
+:ref:`tw_decisions` 成爲絕不可以做的事情。
+
+這裏只有幾個簡單的規則:
+
+ (1) 不要叫人笨蛋(至少不要在公共場合)
+ (2) 學習如何在忘記規則(1)時道歉
+
+問題在於 #1 很容易去做,因爲你可以用數百萬種不同的方式說“你是一個笨蛋” [#cnf2]_
+有時甚至沒有意識到,而且幾乎總是帶着一種白熱化的信念,認爲你是對的。
+
+你越確信自己是對的(讓我們面對現實吧,你可以把幾乎所有人都稱爲壞人,而且你
+經常是對的),事後道歉就越難。
+
+要解決此問題,您實際上只有兩個選項:
+
+ - 非常擅長道歉
+ - 把“愛”均勻地散開,沒有人會真正感覺到自己被不公平地瞄準了。讓它有足夠的
+ 創造性,他們甚至可能會覺得好笑。
+
+選擇永遠保持禮貌是不存在的。沒有人會相信一個如此明顯地隱藏了他們真實性格的人。
+
+.. [#cnf2] 保羅·西蒙演唱了“離開愛人的50種方法”,因爲坦率地說,“告訴開發者
+ 他們是D*CKHEAD" 的100萬種方法都無法確認。但我確信他已經這麼想了。
+
+3)人2 - 好人
+-------------
+
+雖然大多數人都是白癡,但不幸的是,據此推論你也是白癡,儘管我們都自我感覺良
+好,我們比普通人更好(讓我們面對現實吧,沒有人相信他們是普通人或低於普通人),
+我們也應該承認我們不是最鋒利的刀,而且會有其他人比你更不像白癡。
+
+有些人對聰明人反應不好。其他人利用它們。
+
+作爲內核維護人員,確保您在第二組中。接受他們,因爲他們會讓你的工作更容易。
+特別是,他們能夠爲你做決定,這就是遊戲的全部內容。
+
+所以當你發現一個比你聰明的人時,就順其自然吧。你的管理職責在很大程度上變成
+了“聽起來像是個好主意——去嘗試吧”,或者“聽起來不錯,但是XXX呢?”“。第二個版
+本尤其是一個很好的方法,要麼學習一些關於“XXX”的新東西,要麼通過指出一些聰明
+人沒有想到的東西來顯得更具管理性。無論哪種情況,你都會贏。
+
+要注意的一件事是認識到一個領域的偉大不一定會轉化爲其他領域。所以你可能會向
+特定的方向刺激人們,但讓我們面對現實吧,他們可能擅長他們所做的事情,而且對
+其他事情都很差勁。好消息是,人們往往會自然而然地重拾他們擅長的東西,所以當
+你向某個方向刺激他們時,你並不是在做不可逆轉的事情,只是不要用力推。
+
+4)責備
+-------
+
+事情會出問題的,人們希望去責備人。貼標籤,你就是受責備的人。
+
+事實上,接受責備並不難,尤其是當人們意識到這不 **全是** 你的過錯時。這讓我
+們找到了承擔責任的最佳方式:爲別人承擔這件事。你會感覺很好,他們會感覺很好,
+沒有受到指責. 那誰,失去了他們的全部36GB色情收藏的人,因爲你的無能將勉強承
+認,你至少沒有試圖逃避責任。
+
+然後讓真正搞砸了的開發人員(如果你能找到他們)私下知道他們搞砸了。不僅是爲
+了將來可以避免,而且爲了讓他們知道他們欠你一個人情。而且,也許更重要的是,
+他們也可能是能夠解決問題的人。因爲,讓我們面對現實吧,肯定不是你。
+
+承擔責任也是你首先成爲管理者的原因。這是讓人們信任你,讓你獲得潛在的榮耀的
+一部分,因爲你就是那個會說“我搞砸了”的人。如果你已經遵循了以前的規則,你現
+在已經很擅長說了。
+
+5)應避免的事情
+---------------
+
+有一件事人們甚至比被稱爲“笨蛋”更討厭,那就是在一個神聖的聲音中被稱爲“笨蛋”。
+第一個你可以道歉,第二個你不會真正得到機會。即使你做得很好,他們也可能不再
+傾聽。
+
+我們都認爲自己比別人強,這意味着當別人裝腔作勢時,這會讓我們很惱火。你也許
+在道德和智力上比你周圍的每個人都優越,但不要試圖太明顯,除非你真的打算激怒
+某人 [#cnf3]_
+
+同樣,不要對事情太客氣或太微妙。禮貌很容易落得落花流水,把問題隱藏起來,
+正如他們所說,“在互聯網上,沒人能聽到你的含蓄。”用一個鈍器把這一點錘進去,
+因爲你不能真的依靠別人來獲得你的觀點。
+
+一些幽默可以幫助緩和直率和道德化。過度到荒謬的地步,可以灌輸一個觀點,而不
+會讓接受者感到痛苦,他們只是認爲你是愚蠢的。因此,它可以幫助我們擺脫對批評
+的個人心理障礙。
+
+.. [#cnf3] 提示:與你的工作沒有直接關係的網絡新聞組是消除你對他人不滿的好
+ 方法。偶爾寫些侮辱性的帖子,打個噴嚏,讓你的情緒得到淨化。別把牢騷帶回家
+
+6)爲什麼是我?
+---------------
+
+既然你的主要責任似乎是爲別人的錯誤承擔責任,並且讓別人痛苦地明白你是不稱職
+的,那麼顯而易見的問題之一就變成了爲什麼首先要這樣做。
+
+首先,雖然你可能會或可能不會聽到十幾歲女孩(或男孩,讓我們不要在這裏評判或
+性別歧視)敲你的更衣室門,你會得到一個巨大的個人成就感爲“負責”。別介意你真
+的在領導別人,你要跟上別人,儘可能快地追趕他們。每個人都會認爲你是負責人。
+
+如果你可以做到這個, 這是個偉大的工作!
+
diff --git a/Documentation/translations/zh_TW/process/programming-language.rst b/Documentation/translations/zh_TW/process/programming-language.rst
new file mode 100644
index 000000000000..d2c64a5599e8
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/programming-language.rst
@@ -0,0 +1,75 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/programming-language.rst <programming_language>`
+:Translator: Alex Shi <alex.shi@linux.alibaba.com>
+ Hu Haowen <2023002089@link.tyut.edu.cn>
+
+.. _tw_programming_language:
+
+程序設計語言
+============
+
+內核是用C語言 :ref:`c-language <tw_c-language>` 編寫的。更準確地說,內核通常是用 :ref:`gcc <tw_gcc>`
+在 ``-std=gnu11`` :ref:`gcc-c-dialect-options <tw_gcc-c-dialect-options>` 下編譯的:ISO C11的 GNU 方言
+
+這種方言包含對語言 :ref:`gnu-extensions <tw_gnu-extensions>` 的許多擴展,當然,它們許多都在內核中使用。
+
+對於一些體系結構,有一些使用 :ref:`clang <tw_clang>` 和 :ref:`icc <tw_icc>` 編譯內核
+的支持,儘管在編寫此文檔時還沒有完成,仍需要第三方補丁。
+
+屬性
+----
+
+在整個內核中使用的一個常見擴展是屬性(attributes) :ref:`gcc-attribute-syntax <tw_gcc-attribute-syntax>`
+屬性允許將實現定義的語義引入語言實體(如變量、函數或類型),而無需對語言進行
+重大的語法更改(例如添加新關鍵字) :ref:`n2049 <tw_n2049>`
+
+在某些情況下,屬性是可選的(即不支持這些屬性的編譯器仍然應該生成正確的代碼,
+即使其速度較慢或執行的編譯時檢查/診斷次數不夠)
+
+內核定義了僞關鍵字(例如, ``pure`` ),而不是直接使用GNU屬性語法(例如,
+``__attribute__((__pure__))`` ),以檢測可以使用哪些關鍵字和/或縮短代碼, 具體
+請參閱 ``include/linux/compiler_attributes.h``
+
+.. _tw_c-language:
+
+c-language
+ http://www.open-std.org/jtc1/sc22/wg14/www/standards
+
+.. _tw_gcc:
+
+gcc
+ https://gcc.gnu.org
+
+.. _tw_clang:
+
+clang
+ https://clang.llvm.org
+
+.. _tw_icc:
+
+icc
+ https://software.intel.com/en-us/c-compilers
+
+.. _tw_gcc-c-dialect-options:
+
+c-dialect-options
+ https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html
+
+.. _tw_gnu-extensions:
+
+gnu-extensions
+ https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html
+
+.. _tw_gcc-attribute-syntax:
+
+gcc-attribute-syntax
+ https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html
+
+.. _tw_n2049:
+
+n2049
+ http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2049.pdf
+
diff --git a/Documentation/translations/zh_TW/process/stable-api-nonsense.rst b/Documentation/translations/zh_TW/process/stable-api-nonsense.rst
new file mode 100644
index 000000000000..4b8597fed5ae
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/stable-api-nonsense.rst
@@ -0,0 +1,159 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. _tw_stable_api_nonsense:
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/stable-api-nonsense.rst
+ <stable_api_nonsense>`
+
+譯者::
+
+ 中文版維護者: 鍾宇 TripleX Chung <xxx.phy@gmail.com>
+ 中文版翻譯者: 鍾宇 TripleX Chung <xxx.phy@gmail.com>
+ 中文版校譯者: 李陽 Li Yang <leoyang.li@nxp.com>
+ 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+Linux 內核驅動接口
+==================
+
+寫作本文檔的目的,是爲了解釋爲什麼Linux既沒有二進制內核接口,也沒有穩定
+的內核接口。這裏所說的內核接口,是指內核裏的接口,而不是內核和用戶空間
+的接口。內核到用戶空間的接口,是提供給應用程序使用的系統調用,系統調用
+在歷史上幾乎沒有過變化,將來也不會有變化。我有一些老應用程序是在0.9版本
+或者更早版本的內核上編譯的,在使用2.6版本內核的Linux發佈上依然用得很好
+。用戶和應用程序作者可以將這個接口看成是穩定的。
+
+
+執行綱要
+--------
+
+你也許以爲自己想要穩定的內核接口,但是你不清楚你要的實際上不是它。你需
+要的其實是穩定的驅動程序,而你只有將驅動程序放到公版內核的源代碼樹裏,
+纔有可能達到這個目的。而且這樣做還有很多其它好處,正是因爲這些好處使得
+Linux能成爲強壯,穩定,成熟的操作系統,這也是你最開始選擇Linux的原因。
+
+
+入門
+-----
+
+只有那些寫驅動程序的“怪人”纔會擔心內核接口的改變,對廣大用戶來說,既
+看不到內核接口,也不需要去關心它。
+
+首先,我不打算討論關於任何非GPL許可的內核驅動的法律問題,這些非GPL許可
+的驅動程序包括不公開源代碼,隱藏源代碼,二進制或者是用源代碼包裝,或者
+是其它任何形式的不能以GPL許可公開源代碼的驅動程序。如果有法律問題,請諮
+詢律師,我只是一個程序員,所以我只打算探討技術問題(不是小看法律問題,
+法律問題很實際,並且需要一直關注)。
+
+既然只談技術問題,我們就有了下面兩個主題:二進制內核接口和穩定的內核源
+代碼接口。這兩個問題是互相關聯的,讓我們先解決掉二進制接口的問題。
+
+
+二進制內核接口
+--------------
+假如我們有一個穩定的內核源代碼接口,那麼自然而然的,我們就擁有了穩定的
+二進制接口,是這樣的嗎?錯。讓我們看看關於Linux內核的幾點事實:
+
+ - 取決於所用的C編譯器的版本,不同的內核數據結構裏的結構體的對齊方
+ 式會有差別,代碼中不同函數的表現形式也不一樣(函數是不是被inline
+ 編譯取決於編譯器行爲)。不同的函數的表現形式並不重要,但是數據
+ 結構內部的對齊方式很關鍵。
+
+ - 取決於內核的配置選項,不同的選項會讓內核的很多東西發生改變:
+
+ - 同一個結構體可能包含不同的成員變量
+ - 有的函數可能根本不會被實現(比如編譯的時候沒有選擇SMP支持
+ 一些鎖函數就會被定義成空函數)。
+ - 內核使用的內存會以不同的方式對齊,這取決於不同的內核配置選
+ 項。
+
+ - Linux可以在很多的不同體系結構的處理器上運行。在某個體系結構上編
+ 譯好的二進制驅動程序,不可能在另外一個體繫結構上正確的運行。
+
+對於一個特定的內核,滿足這些條件並不難,使用同一個C編譯器和同樣的內核配
+置選項來編譯驅動程序模塊就可以了。這對於給一個特定Linux發佈的特定版本提
+供驅動程序,是完全可以滿足需求的。但是如果你要給不同發佈的不同版本都發
+佈一個驅動程序,就需要在每個發佈上用不同的內核設置參數都編譯一次內核,
+這簡直跟噩夢一樣。而且還要注意到,每個Linux發佈還提供不同的Linux內核,
+這些內核都針對不同的硬件類型進行了優化(有很多種不同的處理器,還有不同
+的內核設置選項)。所以每發佈一次驅動程序,都需要提供很多不同版本的內核
+模塊。
+
+相信我,如果你真的要採取這種發佈方式,一定會慢慢瘋掉,我很久以前就有過
+深刻的教訓...
+
+
+穩定的內核源代碼接口
+--------------------
+
+如果有人不將他的內核驅動程序,放入公版內核的源代碼樹,而又想讓驅動程序
+一直保持在最新的內核中可用,那麼這個話題將會變得沒完沒了。
+內核開發是持續而且快節奏的,從來都不會慢下來。內核開發人員在當前接口中
+找到bug,或者找到更好的實現方式。一旦發現這些,他們就很快會去修改當前的
+接口。修改接口意味着,函數名可能會改變,結構體可能被擴充或者刪減,函數
+的參數也可能發生改變。一旦接口被修改,內核中使用這些接口的地方需要同時
+修正,這樣才能保證所有的東西繼續工作。
+
+舉一個例子,內核的USB驅動程序接口在USB子系統的整個生命週期中,至少經歷
+了三次重寫。這些重寫解決以下問題:
+
+ - 把數據流從同步模式改成非同步模式,這個改動減少了一些驅動程序的
+ 複雜度,提高了所有USB驅動程序的吞吐率,這樣幾乎所有的USB設備都
+ 能以最大速率工作了。
+ - 修改了USB核心代碼中爲USB驅動分配數據包內存的方式,所有的驅動都
+ 需要提供更多的參數給USB核心,以修正了很多已經被記錄在案的死鎖。
+
+這和一些封閉源代碼的操作系統形成鮮明的對比,在那些操作系統上,不得不額
+外的維護舊的USB接口。這導致了一個可能性,新的開發者依然會不小心使用舊的
+接口,以不恰當的方式編寫代碼,進而影響到操作系統的穩定性。
+在上面的例子中,所有的開發者都同意這些重要的改動,在這樣的情況下修改代
+價很低。如果Linux保持一個穩定的內核源代碼接口,那麼就得創建一個新的接口
+;舊的,有問題的接口必須一直維護,給Linux USB開發者帶來額外的工作。既然
+所有的Linux USB驅動的作者都是利用自己的時間工作,那麼要求他們去做毫無意
+義的免費額外工作,是不可能的。
+安全問題對Linux來說十分重要。一個安全問題被發現,就會在短時間內得到修
+正。在很多情況下,這將導致Linux內核中的一些接口被重寫,以從根本上避免安
+全問題。一旦接口被重寫,所有使用這些接口的驅動程序,必須同時得到修正,
+以確定安全問題已經得到修復並且不可能在未來還有同樣的安全問題。如果內核
+內部接口不允許改變,那麼就不可能修復這樣的安全問題,也不可能確認這樣的
+安全問題以後不會發生。
+開發者一直在清理內核接口。如果一個接口沒有人在使用了,它就會被刪除。這
+樣可以確保內核儘可能的小,而且所有潛在的接口都會得到儘可能完整的測試
+(沒有人使用的接口是不可能得到良好的測試的)。
+
+
+要做什麼
+--------
+
+如果你寫了一個Linux內核驅動,但是它還不在Linux源代碼樹裏,作爲一個開發
+者,你應該怎麼做?爲每個發佈的每個版本提供一個二進制驅動,那簡直是一個
+噩夢,要跟上永遠處於變化之中的內核接口,也是一件辛苦活。
+很簡單,讓你的驅動進入內核源代碼樹(要記得我們在談論的是以GPL許可發行
+的驅動,如果你的代碼不符合GPL,那麼祝你好運,你只能自己解決這個問題了,
+你這個吸血鬼<把Andrew和Linus對吸血鬼的定義鏈接到這裏>)。當你的代碼加入
+公版內核源代碼樹之後,如果一個內核接口改變,你的驅動會直接被修改接口的
+那個人修改。保證你的驅動永遠都可以編譯通過,並且一直工作,你幾乎不需要
+做什麼事情。
+
+把驅動放到內核源代碼樹裏會有很多的好處:
+
+ - 驅動的質量會提升,而維護成本(對原始作者來說)會下降。
+ - 其他人會給驅動添加新特性。
+ - 其他人會找到驅動中的bug並修復。
+ - 其他人會在驅動中找到性能優化的機會。
+ - 當外部的接口的改變需要修改驅動程序的時候,其他人會修改驅動程序
+ - 不需要聯繫任何發行商,這個驅動會自動的隨着所有的Linux發佈一起發
+ 布。
+
+和別的操作系統相比,Linux爲更多不同的設備提供現成的驅動,而且能在更多不
+同體繫結構的處理器上支持這些設備。這個經過考驗的開發模式,必然是錯不了
+的 :)
+
+感謝
+----
+感謝 Randy Dunlap, Andrew Morton, David Brownell, Hanna Linder,
+Robert Love, and Nishanth Aravamudan 對於本文檔早期版本的評審和建議。
+
+英文版維護者: Greg Kroah-Hartman <greg@kroah.com>
+
diff --git a/Documentation/translations/zh_TW/process/stable-kernel-rules.rst b/Documentation/translations/zh_TW/process/stable-kernel-rules.rst
new file mode 100644
index 000000000000..2f8f064f8629
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/stable-kernel-rules.rst
@@ -0,0 +1,68 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. _tw_stable_kernel_rules:
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
+
+如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
+交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻
+譯存在問題,請聯繫中文版維護者::
+
+ 中文版維護者: 鍾宇 TripleX Chung <xxx.phy@gmail.com>
+ 中文版翻譯者: 鍾宇 TripleX Chung <xxx.phy@gmail.com>
+ 中文版校譯者:
+ - 李陽 Li Yang <leoyang.li@nxp.com>
+ - Kangkai Yin <e12051@motorola.com>
+ - 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+所有你想知道的事情 - 關於linux穩定版發佈
+========================================
+
+關於Linux 2.6穩定版發佈,所有你想知道的事情。
+
+關於哪些類型的補丁可以被接收進入穩定版代碼樹,哪些不可以的規則:
+----------------------------------------------------------------
+
+ - 必須是顯而易見的正確,並且經過測試的。
+ - 連同上下文,不能大於100行。
+ - 必須只修正一件事情。
+ - 必須修正了一個給大家帶來麻煩的真正的bug(不是“這也許是一個問題...”
+ 那樣的東西)。
+ - 必須修正帶來如下後果的問題:編譯錯誤(對被標記爲CONFIG_BROKEN的例外),
+ 內核崩潰,掛起,數據損壞,真正的安全問題,或者一些類似“哦,這不
+ 好”的問題。簡短的說,就是一些致命的問題。
+ - 沒有“理論上的競爭條件”,除非能給出競爭條件如何被利用的解釋。
+ - 不能存在任何的“瑣碎的”修正(拼寫修正,去掉多餘空格之類的)。
+ - 必須被相關子系統的維護者接受。
+ - 必須遵循Documentation/translations/zh_CN/process/submitting-patches.rst裏的規則。
+
+向穩定版代碼樹提交補丁的過程:
+------------------------------
+
+ - 在確認了補丁符合以上的規則後,將補丁發送到stable@vger.kernel.org。
+ - 如果補丁被接受到隊列裏,發送者會收到一個ACK回覆,如果沒有被接受,收
+ 到的是NAK回覆。回覆需要幾天的時間,這取決於開發者的時間安排。
+ - 被接受的補丁會被加到穩定版本隊列裏,等待其他開發者的審查。
+ - 安全方面的補丁不要發到這個列表,應該發送到security@kernel.org。
+
+審查週期:
+----------
+
+ - 當穩定版的維護者決定開始一個審查週期,補丁將被髮送到審查委員會,以
+ 及被補丁影響的領域的維護者(除非提交者就是該領域的維護者)並且抄送
+ 到linux-kernel郵件列表。
+ - 審查委員會有48小時的時間,用來決定給該補丁回覆ACK還是NAK。
+ - 如果委員會中有成員拒絕這個補丁,或者linux-kernel列表上有人反對這個
+ 補丁,並提出維護者和審查委員會之前沒有意識到的問題,補丁會從隊列中
+ 丟棄。
+ - 在審查週期結束的時候,那些得到ACK回應的補丁將會被加入到最新的穩定版
+ 發佈中,一個新的穩定版發佈就此產生。
+ - 安全性補丁將從內核安全小組那裏直接接收到穩定版代碼樹中,而不是通過
+ 通常的審查週期。請聯繫內核安全小組以獲得關於這個過程的更多細節。
+
+審查委員會:
+------------
+ - 由一些自願承擔這項任務的內核開發者,和幾個非志願的組成。
+
diff --git a/Documentation/translations/zh_TW/process/submit-checklist.rst b/Documentation/translations/zh_TW/process/submit-checklist.rst
new file mode 100644
index 000000000000..43f2e3c5b514
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/submit-checklist.rst
@@ -0,0 +1,114 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/process/submit-checklist.rst
+:Translator:
+ - Alex Shi <alexs@kernel.org>
+ - Wu XiangCheng <bobwxc@email.cn>
+ - Hu Haowen <2023002089@link.tyut.edu.cn>
+
+.. _tw_submitchecklist:
+
+Linux內核補丁提交檢查單
+~~~~~~~~~~~~~~~~~~~~~~~
+
+如果開發人員希望看到他們的內核補丁提交更快地被接受,那麼他們應該做一些基本
+的事情。
+
+這些都是在 Documentation/translations/zh_CN/process/submitting-patches.rst
+和其他有關提交Linux內核補丁的文檔中提供的。
+
+1) 如果使用工具,則包括定義/聲明該工具的文件。不要依賴其他頭文件來引入您使用
+ 的頭文件。
+
+2) 乾淨的編譯:
+
+ a) 使用合適的 ``CONFIG`` 選項 ``=y``、``=m`` 和 ``=n`` 。沒有 ``gcc``
+ 警告/錯誤,沒有鏈接器警告/錯誤。
+
+ b) 通過 ``allnoconfig`` 、 ``allmodconfig``
+
+ c) 使用 ``O=builddir`` 時可以成功編譯
+
+ d) 任何 Doucmentation/ 下的變更都能成功構建且不引入新警告/錯誤。
+ 用 ``make htmldocs`` 或 ``make pdfdocs`` 檢驗構建情況並修復問題。
+
+3) 通過使用本地交叉編譯工具或其他一些構建設施在多個CPU體系結構上構建。
+
+4) PPC64是一種很好的交叉編譯檢查體系結構,因爲它傾向於對64位的數使用無符號
+ 長整型。
+
+5) 按 Documentation/translations/zh_CN/process/coding-style.rst 所述檢查您的
+ 補丁是否爲常規樣式。在提交之前使用補丁樣式檢查器 ``scripts/checkpatch.pl``
+ 檢查是否有輕微的衝突。您應該能夠處理您的補丁中存在的所有
+ 違規行爲。
+
+6) 任何新的或修改過的 ``CONFIG`` 選項都不應搞亂配置菜單,並默認爲關閉,除非
+ 它們符合 ``Documentation/kbuild/kconfig-language.rst`` 菜單屬性:默認值中
+ 記錄的例外條件。
+
+7) 所有新的 ``kconfig`` 選項都有幫助文本。
+
+8) 已仔細審查了相關的 ``Kconfig`` 組合。這很難用測試來糾正——腦力在這裏是有
+ 回報的。
+
+9) 通過 sparse 清查。
+ (參見 Documentation/translations/zh_CN/dev-tools/sparse.rst )
+
+10) 使用 ``make checkstack`` 並修復他們發現的任何問題。
+
+ .. note::
+
+ ``checkstack`` 並不會明確指出問題,但是任何一個在堆棧上使用超過512
+ 字節的函數都可以進行更改。
+
+11) 包括 :ref:`kernel-doc <kernel_doc_zh>` 內核文檔以記錄全局內核API。(靜態
+ 函數不需要,但也可以。)使用 ``make htmldocs`` 或 ``make pdfdocs`` 檢查
+ :ref:`kernel-doc <kernel_doc_zh>` 並修復任何問題。
+
+12) 通過以下選項同時啓用的測試: ``CONFIG_PREEMPT``, ``CONFIG_DEBUG_PREEMPT``,
+ ``CONFIG_DEBUG_SLAB``, ``CONFIG_DEBUG_PAGEALLOC``, ``CONFIG_DEBUG_MUTEXES``,
+ ``CONFIG_DEBUG_SPINLOCK``, ``CONFIG_DEBUG_ATOMIC_SLEEP``,
+ ``CONFIG_PROVE_RCU`` 和 ``CONFIG_DEBUG_OBJECTS_RCU_HEAD`` 。
+
+13) 在 ``CONFIG_SMP``, ``CONFIG_PREEMPT`` 開啓和關閉的情況下都進行構建和運行
+ 時測試。
+
+14) 所有代碼路徑都已在啓用所有死鎖檢測(lockdep)功能的情況下運行。
+
+15) 所有新的 ``/proc`` 條目都記錄在 ``Documentation/``
+
+16) 所有新的內核引導參數都記錄在
+ Documentation/admin-guide/kernel-parameters.rst 中。
+
+17) 所有新的模塊參數都記錄在 ``MODULE_PARM_DESC()``
+
+18) 所有新的用戶空間接口都記錄在 ``Documentation/ABI/`` 中。有關詳細信息,
+ 請參閱 ``Documentation/ABI/README`` 。更改用戶空間接口的補丁應該抄送
+ linux-api@vger.kernel.org。
+
+19) 已通過至少注入slab和page分配失敗進行檢查。請參閱 ``Documentation/fault-injection/`` 。
+ 如果新代碼是實質性的,那麼添加子系統特定的故障注入可能是合適的。
+
+20) 新添加的代碼已經用 ``gcc -W`` 編譯(使用 ``make EXTRA-CFLAGS=-W`` )。這
+ 將產生大量噪聲,但對於查找諸如“警告:有符號和無符號之間的比較”之類的錯誤
+ 很有用。
+
+21) 在它被合併到-mm補丁集中之後進行測試,以確保它仍然與所有其他排隊的補丁以
+ 及VM、VFS和其他子系統中的各種更改一起工作。
+
+22) 所有內存屏障(例如 ``barrier()``, ``rmb()``, ``wmb()`` )都需要源代碼注
+ 釋來解釋它們正在執行的操作及其原因的邏輯。
+
+23) 如果補丁添加了任何ioctl,那麼也要更新
+ ``Documentation/userspace-api/ioctl/ioctl-number.rst`` 。
+
+24) 如果修改後的源代碼依賴或使用與以下 ``Kconfig`` 符號相關的任何內核API或
+ 功能,則在禁用相關 ``Kconfig`` 符號和/或 ``=m`` (如果該選項可用)的情況
+ 下測試以下多個構建[並非所有這些都同時存在,只是它們的各種/隨機組合]:
+
+ ``CONFIG_SMP``, ``CONFIG_SYSFS``, ``CONFIG_PROC_FS``, ``CONFIG_INPUT``,
+ ``CONFIG_PCI``, ``CONFIG_BLOCK``, ``CONFIG_PM``, ``CONFIG_MAGIC_SYSRQ``,
+ ``CONFIG_NET``, ``CONFIG_INET=n`` (但是最後一個需要 ``CONFIG_NET=y`` )。
+
diff --git a/Documentation/translations/zh_TW/process/submitting-patches.rst b/Documentation/translations/zh_TW/process/submitting-patches.rst
new file mode 100644
index 000000000000..99fa0f2fe6f4
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/submitting-patches.rst
@@ -0,0 +1,659 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+.. include:: ../disclaimer-zh_TW.rst
+
+.. _tw_submittingpatches:
+
+:Original: Documentation/process/submitting-patches.rst
+
+:譯者:
+ - 鍾宇 TripleX Chung <xxx.phy@gmail.com>
+ - 時奎亮 Alex Shi <alexs@kernel.org>
+ - 吳想成 Wu XiangCheng <bobwxc@email.cn>
+
+:校譯:
+ - 李陽 Li Yang <leoyang.li@nxp.com>
+ - 王聰 Wang Cong <xiyou.wangcong@gmail.com>
+ - 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+
+提交補丁:如何讓你的改動進入內核
+================================
+
+對於想要將改動提交到 Linux 內核的個人或者公司來說,如果不熟悉“規矩”,
+提交的流程會讓人畏懼。本文檔包含了一系列建議,可以大大提高你
+的改動被接受的機會.
+
+本文檔以較爲簡潔的行文給出了大量建議。關於內核開發流程如何進行的詳細信息,
+參見: Documentation/translations/zh_CN/process/development-process.rst 。
+Documentation/translations/zh_CN/process/submit-checklist.rst 給出了一系列
+提交補丁之前要檢查的事項。設備樹相關的補丁,請參閱
+Documentation/devicetree/bindings/submitting-patches.rst 。
+
+本文檔假設您正在使用 ``git`` 準備你的補丁。如果您不熟悉 ``git`` ,最好學習
+如何使用它,這將使您作爲內核開發人員的生活變得更加輕鬆。
+
+部分子系統和維護人員的樹有一些關於其工作流程和要求的額外信息,請參閱
+Documentation/process/maintainer-handbooks.rst 。
+
+獲取當前源碼樹
+--------------
+
+如果您手頭沒有當前內核源代碼的存儲庫,請使用 ``git`` 獲取一份。您需要先獲取
+主線存儲庫,它可以通過以下命令拉取::
+
+ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
+
+但是,請注意,您可能不想直接針對主線樹進行開發。大多數子系統維護人員運
+行自己的樹,並希望看到針對這些樹準備的補丁。請參見MAINTAINERS文件中子系
+統的 **T:** 項以查找該樹,或者直接詢問維護者該樹是否未在其中列出。
+
+.. _tw_describe_changes:
+
+描述你的改動
+------------
+
+描述你的問題。無論您的補丁是一行錯誤修復還是5000行新功能,都必須有一個潛在
+的問題激勵您完成這項工作。說服審閱者相信有一個問題值得解決,讓他們讀完第一段
+後就能明白這一點。
+
+描述用戶可見的影響。直接崩潰和鎖定是相當有說服力的,但並不是所有的錯誤都那麼
+明目張膽。即使在代碼審閱期間發現了這個問題,也要描述一下您認爲它可能對用戶產
+生的影響。請記住,大多數Linux安裝運行的內核來自二級穩定樹或特定於供應商/產品
+的樹,只從上游精選特定的補丁,因此請包含任何可以幫助您將更改定位到下游的內容:
+觸發的場景、DMESG的摘錄、崩潰描述、性能迴歸、延遲尖峯、鎖定等。
+
+質量優化和權衡。如果您聲稱在性能、內存消耗、堆棧佔用空間或二進制大小方面有所
+改進,請包括支持它們的數據。但也要描述不明顯的成本。優化通常不是零成本的,而是
+在CPU、內存和可讀性之間進行權衡;或者,做探索性的工作,在不同的工作負載之間進
+行權衡。請描述優化的預期缺點,以便審閱者可以權衡成本和收益。
+
+提出問題之後,就要詳細地描述一下您實際在做的技術細節。對於審閱者來說,用簡練的
+英語描述代碼的變化是很重要的,以驗證代碼的行爲是否符合您的意圖。
+
+如果您將補丁描述寫成“標準格式”,可以很容易地作爲“提交日誌”放入Linux的源代
+碼管理系統 ``git`` 中,那麼維護人員將非常感謝您。
+參見 :ref:`zh_the_canonical_patch_format` 。
+
+每個補丁只解決一個問題。如果你的描述開始變長,這就表明你可能需要拆分你的補丁。
+請見 :ref:`zh_split_changes` 。
+
+提交或重新提交補丁或補丁系列時,請包括完整的補丁說明和理由。不要
+只說這是補丁(系列)的第幾版。不要期望子系統維護人員引用更早的補丁版本或引用
+URL來查找補丁描述並將其放入補丁中。也就是說,補丁(系列)及其描述應該是獨立的。
+這對維護人員和審閱者都有好處。一些審閱者可能甚至沒有收到補丁的早期版本。
+
+用祈使句描述你的變更,例如“make xyzzy do frotz”而不是“[This patch]make
+xyzzy do frotz”或“[I]changed xyzzy to do frotz”,就好像你在命令代碼庫改變
+它的行爲一樣。
+
+如果您想要引用一個特定的提交,不要只引用提交的SHA-1 ID。還請包括提交的一行
+摘要,以便於審閱者瞭解它是關於什麼的。例如::
+
+ Commit e21d2170f36602ae2708 ("video: remove unnecessary
+ platform_set_drvdata()") removed the unnecessary
+ platform_set_drvdata(), but left the variable "dev" unused,
+ delete it.
+
+您還應該確保至少使用前12位SHA-1 ID。內核存儲庫包含 *許多* 對象,使較短的ID
+發生衝突的可能性很大。記住,即使現在不會與您的六個字符ID發生衝突,這種情況
+也可能在五年後改變。
+
+如果該變更的相關討論或背景信息可以在網上查閱,請加上“Link:”標籤指向它。例如
+你的補丁修復了一個缺陷,需要添加一個帶有URL的標籤指向郵件列表存檔或缺陷跟蹤器
+的相關報告;如果該補丁是由一些早先郵件列表討論或網絡上的記錄引起的,請指向它。
+
+當鏈接到郵件列表存檔時,請首選lore.kernel.org郵件存檔服務。用郵件中的
+``Message-ID`` 頭(去掉尖括號)可以創建鏈接URL。例如::
+
+ Link: https://lore.kernel.org/r/30th.anniversary.repost@klaava.Helsinki.FI/
+
+請檢查該鏈接以確保可用且指向正確的郵件。
+
+不過,在沒有外部資源的情況下,也要儘量讓你的解釋可理解。除了提供郵件列表存檔或
+缺陷的URL之外,還要需要總結該補丁的相關討論要點。
+
+如果補丁修復了特定提交中的錯誤,例如使用 ``git bisct`` 發現了一個問題,請使用
+帶有前12個字符SHA-1 ID的“Fixes:”標籤和單行摘要。爲了簡化解析腳本,不要將該
+標籤拆分爲多行,標籤不受“75列換行”規則的限制。例如::
+
+ Fixes: 54a4f0239f2e ("KVM: MMU: make kvm_mmu_zap_page() return the number of pages it actually freed")
+
+下列 ``git config`` 設置可以讓 ``git log``, ``git show`` 增加上述風格的顯示格式::
+
+ [core]
+ abbrev = 12
+ [pretty]
+ fixes = Fixes: %h (\"%s\")
+
+使用示例::
+
+ $ git log -1 --pretty=fixes 54a4f0239f2e
+ Fixes: 54a4f0239f2e ("KVM: MMU: make kvm_mmu_zap_page() return the number of pages it actually freed")
+
+.. _tw_split_changes:
+
+拆分你的改動
+------------
+
+將每個 **邏輯更改** 拆分成一個單獨的補丁。
+
+例如,如果你的改動裏同時有bug修正和性能優化,那麼把這些改動拆分到兩個或
+者更多的補丁文件中。如果你的改動包含對API的修改,並且增加了一個使用該新API
+的驅動,那麼把這些修改分成兩個補丁。
+
+另一方面,如果你將一個單獨的改動做成多個補丁文件,那麼將它們合併成一個
+單獨的補丁文件。這樣一個邏輯上單獨的改動只被包含在一個補丁文件裏。
+
+需要記住的一點是,每個補丁的更改都應易於理解,以便審閱者驗證。每個補丁都應該
+對其價值進行闡述。
+
+如果有一個補丁依賴另外一個補丁來完成它的改動,那沒問題。直接在你的補
+丁描述裏指出 **“這個補丁依賴某補丁”** 就好了。
+
+在將您的更改劃分爲一系列補丁時,要特別注意確保內核在應用系列中的每個補丁之後
+都能正常構建和運行。使用 ``git bisect`` 來追蹤問題的開發者可能會在任何地方分
+割你的補丁系列;如果你在中間引入錯誤,他們不會感謝你。
+
+如果你不能將補丁系列濃縮得更小,那麼每次大約發送出15個補丁,然後等待審閱
+和集成。
+
+檢查你的更改風格
+----------------
+
+檢查您的補丁是否違反了基本樣式規定,詳細信息參見
+Documentation/translations/zh_CN/process/coding-style.rst
+中找到。如果不這樣做,只會浪費審閱者的時間,並且會導致你的補丁被拒絕,甚至
+可能沒有被閱讀。
+
+一個重要的例外是在將代碼從一個文件移動到另一個文件時——在這種情況下,您不應
+該在移動代碼的同一個補丁中修改移動的代碼。這清楚地描述了移動代碼和您的更改
+的行爲。這大大有助於審閱實際差異,並允許工具更好地跟蹤代碼本身的歷史。
+
+在提交之前,使用補丁樣式檢查程序檢查補丁(scripts/check patch.pl)。不過,
+請注意,樣式檢查程序應該被視爲一個指南,而不是作爲人類判斷的替代品。如果您
+的代碼看起來更好,但有違規行爲,那麼最好別管它。
+
+檢查者報告三個級別:
+
+ - ERROR:很可能出錯的事情
+ - WARNING:需要仔細審閱的事項
+ - CHECK:需要思考的事情
+
+您應該能夠判斷您的補丁中存在的所有違規行爲。
+
+選擇補丁收件人
+--------------
+
+您應該總是知會任何補丁相應代碼的子系統維護人員;查看
+維護人員文件和源代碼修訂歷史記錄,以瞭解這些維護人員是誰。腳本
+scripts/get_maintainer.pl在這個步驟中非常有用。如果您找不到正在工作的子系統
+的維護人員,那麼Andrew Morton(akpm@linux-foundation.org)將充當最後的維護
+人員。
+
+您通常還應該選擇至少一個郵件列表來接收補丁集的副本。linux-kernel@vger.kernel.org
+是所有補丁的默認列表,但是這個列表的流量已經導致了許多開發人員不再看它。
+在MAINTAINERS文件中查找子系統特定的列表;您的補丁可能會在那裏得到更多的關注。
+不過,請不要發送垃圾郵件到無關的列表。
+
+許多與內核相關的列表託管在vger.kernel.org上;您可以在
+http://vger.kernel.org/vger-lists.html 上找到它們的列表。不過,也有與內核相關
+的列表託管在其他地方。
+
+不要一次發送超過15個補丁到vger郵件列表!!!!
+
+Linus Torvalds是決定改動能否進入 Linux 內核的最終裁決者。他的郵件地址是
+torvalds@linux-foundation.org 。他收到的郵件很多,所以一般來說最好 **別**
+給他發郵件。
+
+如果您有修復可利用安全漏洞的補丁,請將該補丁發送到 security@kernel.org 。對於
+嚴重的bug,可以考慮短期禁令以允許分銷商(有時間)向用戶發佈補丁;在這種情況下,
+顯然不應將補丁發送到任何公共列表。
+參見 Documentation/translations/zh_CN/admin-guide/security-bugs.rst 。
+
+修復已發佈內核中嚴重錯誤的補丁程序應該抄送給穩定版維護人員,方法是把以下列行
+放進補丁的籤準區(注意,不是電子郵件收件人)::
+
+ Cc: stable@vger.kernel.org
+
+除了本文件之外,您還應該閱讀
+Documentation/translations/zh_CN/process/stable-kernel-rules.rst 。
+
+如果更改影響到用戶側內核接口,請向手冊頁維護人員(如維護人員文件中所列)發送
+手冊頁補丁,或至少發送更改通知,以便一些信息進入手冊頁。還應將用戶空間API
+更改抄送到 linux-api@vger.kernel.org 。
+
+
+不要MIME編碼,不要鏈接,不要壓縮,不要附件,只要純文本
+------------------------------------------------------
+
+Linus 和其他的內核開發者需要閱讀和評論你提交的改動。對於內核開發者來說
+,可以“引用”你的改動很重要,使用一般的郵件工具,他們就可以在你的
+代碼的任何位置添加評論。
+
+因爲這個原因,所有的提交的補丁都是郵件中“內嵌”的。最簡單(和推薦)的方法就
+是使用 ``git send-email`` 。https://git-send-email.io 有 ``git send-email``
+的交互式教程。
+
+如果你選擇不用 ``git send-email`` :
+
+.. warning::
+
+ 如果你使用剪切-粘貼你的補丁,小心你的編輯器的自動換行功能破壞你的補丁
+
+不要將補丁作爲MIME編碼的附件,不管是否壓縮。很多流行的郵件軟件不
+是任何時候都將MIME編碼的附件當作純文本發送的,這會使得別人無法在你的
+代碼中加評論。另外,MIME編碼的附件會讓Linus多花一點時間來處理,這就
+降低了你的改動被接受的可能性。
+
+例外:如果你的郵路損壞了補丁,那麼有人可能會要求你使用MIME重新發送補丁。
+
+請參閱 Documentation/translations/zh_CN/process/email-clients.rst
+以獲取有關配置電子郵件客戶端以使其不受影響地發送補丁的提示。
+
+回覆審閱意見
+------------
+
+你的補丁幾乎肯定會得到審閱者對補丁改進方法的評論(以回覆郵件的形式)。您必須
+對這些評論作出回應;讓補丁被忽略的一個好辦法就是忽略審閱者的意見。直接回復郵
+件來回應意見即可。不會導致代碼更改的意見或問題幾乎肯定會帶來註釋或變更日誌的
+改變,以便下一個審閱者更好地瞭解正在發生的事情。
+
+一定要告訴審閱者你在做什麼改變,並感謝他們的時間。代碼審閱是一個累人且耗時的
+過程,審閱者有時會變得暴躁。即使在這種情況下,也要禮貌地回應並解決他們指出的
+問題。當發送下一版時,在封面郵件或獨立補丁里加上 ``patch changelog`` 說明與
+前一版本的不同之處(參見 :ref:`zh_the_canonical_patch_format` )。
+
+.. _tw_resend_reminders:
+
+不要泄氣或不耐煩
+----------------
+
+提交更改後,請耐心等待。審閱者是大忙人,可能無法立即審閱您的補丁。
+
+曾幾何時,補丁曾在沒收到評論的情況下消失在虛空中,但現在開發過程應該更加順利了。
+您應該在一週左右的時間內收到評論;如果沒有收到評論,請確保您已將補丁發送
+到正確的位置。在重新提交或聯繫審閱者之前至少等待一週——在諸如合併窗口之類的
+繁忙時間可能更長。
+
+在等了幾個星期後,用帶RESEND的主題重發補丁也是可以的::
+
+ [PATCH Vx RESEND] sub/sys: Condensed patch summary
+
+當你發佈補丁(系列)修改版的時候,不要加上“RESEND”——“RESEND”只適用於重
+新提交之前未經修改的補丁(系列)。
+
+主題中包含 PATCH
+----------------
+
+由於到Linus和linux-kernel的電子郵件流量很高,通常會在主題行前面加上[PATCH]
+前綴。這使Linus和其他內核開發人員更容易將補丁與其他電子郵件討論區分開。
+
+``git send-email`` 會自動爲你加上。
+
+簽署你的作品——開發者來源認證
+------------------------------
+
+爲了加強對誰做了何事的追蹤,尤其是對那些透過好幾層維護者才最終到達的補丁,我
+們在通過郵件發送的補丁上引入了“簽署(sign-off)”流程。
+
+“簽署”是在補丁註釋最後的一行簡單文字,認證你編寫了它或者其他
+人有權力將它作爲開放源代碼的補丁傳遞。規則很簡單:如果你能認證如下信息:
+
+開發者來源認證 1.1
+^^^^^^^^^^^^^^^^^^
+
+對於本項目的貢獻,我認證如下信息:
+
+ (a) 這些貢獻是完全或者部分的由我創建,我有權利以文件中指出
+ 的開放源代碼許可證提交它;或者
+
+ (b) 這些貢獻基於以前的工作,據我所知,這些以前的工作受恰當的開放
+ 源代碼許可證保護,而且,根據文件中指出的許可證,我有權提交修改後的貢獻,
+ 無論是完全還是部分由我創造,這些貢獻都使用同一個開放源代碼許可證
+ (除非我被允許用其它的許可證);或者
+
+ (c) 這些貢獻由認證(a),(b)或者(c)的人直接提供給我,而
+ 且我沒有修改它。
+
+ (d) 我理解並同意這個項目和貢獻是公開的,貢獻的記錄(包括我
+ 一起提交的個人記錄,包括sign-off)被永久維護並且可以和這個項目
+ 或者開放源代碼的許可證同步地再發行。
+
+那麼加入這樣一行::
+
+ Signed-off-by: Random J Developer <random@developer.example.org>
+
+使用你的真名(抱歉,不能使用假名或者匿名。)如果使用 ``git commit -s`` 的話
+將會自動完成。撤銷也應當包含“Signed-off-by”, ``git revert -s`` 會幫你搞定。
+
+有些人會在最後加上額外的標籤。現在這些東西會被忽略,但是你可以這樣做,來標記
+公司內部的過程,或者只是指出關於簽署的一些特殊細節。
+
+作者簽署之後的任何其他簽署(Signed-off-by:'s)均來自處理和傳遞補丁的人員,但
+未參與其開發。簽署鏈應當反映補丁傳播到維護者並最終傳播到Linus所經過的 **真實**
+路徑,首個簽署指明單個作者的主要作者身份。
+
+何時使用Acked-by:,CC:,和Co-Developed by:
+------------------------------------------
+
+Singed-off-by: 標籤表示簽名者參與了補丁的開發,或者他/她在補丁的傳遞路徑中。
+
+如果一個人沒有直接參與補丁的準備或處理,但希望表示並記錄他們對補丁的批准/贊成,
+那麼他們可以要求在補丁的變更日誌中添加一個Acked-by:。
+
+Acked-by: 通常由受影響代碼的維護者使用,當該維護者既沒有貢獻也沒有轉發補丁時。
+
+Acked-by: 不像簽署那樣正式。這是一個記錄,確認人至少審閱了補丁,並表示接受。
+因此,補丁合併有時會手動將Acker的“Yep,looks good to me”轉換爲 Acked-By:(但
+請注意,通常最好要求一個明確的Ack)。
+
+Acked-by:不一定表示對整個補丁的確認。例如,如果一個補丁影響多個子系統,並且
+有一個來自某個子系統維護者的Acked-By:,那麼這通常表示只確認影響維護者代碼的部
+分。這裏應該仔細判斷。如有疑問,應參考郵件列表存檔中的原始討論。
+
+如果某人本應有機會對補丁進行評論,但沒有提供此類評論,您可以選擇在補丁中添加
+``Cc:`` 這是唯一可以在沒有被該人明確同意的情況下添加的標籤——但它應該表明
+這個人是在補丁上抄送的。此標籤記錄了討論中包含的潛在利益相關方。
+
+Co-developed-by: 聲明補丁是由多個開發人員共同創建的;當幾個人在一個補丁上工
+作時,它用於給出共同作者(除了From:所給出的作者之外)。因爲Co-developed-by:
+表示作者身份,所以每個Co-developed-by:必須緊跟在相關合作作者的簽署之後。標準
+簽署程序要求Singed-off-by:標籤的順序應儘可能反映補丁的時間歷史,無論作者是通
+過From:還是Co-developed-by:表明。值得注意的是,最後一個Singed-off-by:必須是
+提交補丁的開發人員。
+
+注意,如果From:作者也是電子郵件標題的From:行中列出的人,則From:標籤是可選的。
+
+被From:作者提交的補丁示例::
+
+ <changelog>
+
+ Co-developed-by: First Co-Author <first@coauthor.example.org>
+ Signed-off-by: First Co-Author <first@coauthor.example.org>
+ Co-developed-by: Second Co-Author <second@coauthor.example.org>
+ Signed-off-by: Second Co-Author <second@coauthor.example.org>
+ Signed-off-by: From Author <from@author.example.org>
+
+被合作開發者提交的補丁示例::
+
+ From: From Author <from@author.example.org>
+
+ <changelog>
+
+ Co-developed-by: Random Co-Author <random@coauthor.example.org>
+ Signed-off-by: Random Co-Author <random@coauthor.example.org>
+ Signed-off-by: From Author <from@author.example.org>
+ Co-developed-by: Submitting Co-Author <sub@coauthor.example.org>
+ Signed-off-by: Submitting Co-Author <sub@coauthor.example.org>
+
+
+使用Reported-by:、Tested-by:、Reviewed-by:、Suggested-by:和Fixes:
+-----------------------------------------------------------------
+
+Reported-by: 給那些發現錯誤並報告錯誤的人致謝,它希望激勵他們在將來再次幫助
+我們。請注意,如果bug是以私有方式報告的,那麼在使用Reported-by標籤之前,請
+先請求許可。此標籤是爲Bug設計的;請不要將其用於感謝功能請求。
+
+Tested-by: 標籤表示補丁已由指定的人(在某些環境中)成功測試。這個標籤通知
+維護人員已經執行了一些測試,爲將來的補丁提供了一種定位測試人員的方法,並彰顯測試人員的功勞。
+
+Reviewed-by:根據審閱者的監督聲明,表明該補丁已被審閱並被認爲是可接受的:
+
+
+審閱者的監督聲明
+^^^^^^^^^^^^^^^^
+
+通過提供我的Reviewed-by:標籤,我聲明:
+
+ (a) 我已經對這個補丁進行了一次技術審閱,以評估它是否適合被包含到
+ 主線內核中。
+
+ (b) 與補丁相關的任何問題、顧慮或問題都已反饋給提交者。我對提交者對
+ 我的評論的回應感到滿意。
+
+ (c) 雖然這一提交可能仍可被改進,但我相信,此時,(1)對內核
+ 進行了有價值的修改,(2)沒有包含爭論中涉及的已知問題。
+
+ (d) 雖然我已經審閱了補丁並認爲它是健全的,但我不會(除非另有明確
+ 說明)作出任何保證或擔保它會在任何給定情況下實現其規定的目的
+ 或正常運行。
+
+Reviewed-by是一種觀點聲明,即補丁是對內核的適當修改,沒有任何遺留的嚴重技術
+問題。任何感興趣的審閱者(完成工作的人)都可以爲一個補丁提供一個Reviewed-by
+標籤。此標籤用於向審閱者提供致謝,並通知維護者補丁的審閱進度。
+當Reviewed-by:標籤由已知了解主題區域並執行徹底檢查的審閱者提供時,通常會增加
+補丁進入內核的可能性。
+
+一旦從測試人員或審閱者的“Tested-by”和“Reviewed-by”標籤出現在郵件列表中,
+作者應在發送下一個版本時將其添加到適用的補丁中。但是,如果補丁在以下版本中發
+生了實質性更改,這些標籤可能不再適用,因此應該刪除。通常,在補丁更改日誌中
+(在 ``---`` 分隔符之後)應該提到刪除某人的測試者或審閱者標籤。
+
+Suggested-by: 表示補丁的想法是由指定的人提出的,並確保將此想法歸功於指定的
+人。請注意,未經許可,不得添加此標籤,特別是如果該想法未在公共論壇上發佈。
+也就是說,如果我們勤快地致謝創意提供者,他們將受到鼓舞,很有希望在未來再次
+幫助我們。
+
+Fixes: 指示補丁修復了之前提交的一個問題。它可以便於確定錯誤的來源,這有助於
+檢查錯誤修復。這個標籤還幫助穩定內核團隊確定應該接收修復的穩定內核版本。這是
+指示補丁修復的錯誤的首選方法。請參閱 :ref:`zh_describe_changes` 瞭解更多信息。
+
+.. note::
+
+ 附加Fixes:標籤不會改變穩定內核規則流程,也不改變所有穩定版補丁抄送
+ stable@vger.kernel.org的要求。有關更多信息,請閱讀
+ Documentation/translations/zh_CN/process/stable-kernel-rules.rst 。
+
+.. _tw_the_canonical_patch_format:
+
+標準補丁格式
+------------
+
+本節描述如何格式化補丁本身。請注意,如果您的補丁存儲在 ``Git`` 存儲庫中,則
+可以使用 ``git format-patch`` 進行正確的補丁格式化。但是,這些工具無法創建
+必要的文本,因此請務必閱讀下面的說明。
+
+標準的補丁標題行是::
+
+ Subject: [PATCH 001/123] 子系統:一句話概述
+
+標準補丁的信體包含如下部分:
+
+ - 一個 ``from`` 行指出補丁作者。後跟空行(僅當發送補丁的人不是作者時才需要)。
+
+ - 說明文字,每行最長75列,這將被複制到永久變更日誌來描述這個補丁。
+
+ - 一個空行
+
+ - 上述的 ``Signed-off-by:`` 行,也將出現在更改日誌中。
+
+ - 只包含 ``---`` 的標記線。
+
+ - 任何其他不適合放在變更日誌的註釋。
+
+ - 實際補丁( ``diff`` 輸出)。
+
+標題行的格式,使得對標題行按字母序排序非常的容易——很多郵件客戶端都
+可以支持——因爲序列號是用零填充的,所以按數字排序和按字母排序是一樣的。
+
+郵件標題中的“子系統”標識哪個內核子系統將被打補丁。
+
+郵件標題中的“一句話概述”扼要的描述郵件中的補丁。“一句話概述”
+不應該是一個文件名。對於一個補丁系列(“補丁系列”指一系列的多個相關補
+丁),不要對每個補丁都使用同樣的“一句話概述”。
+
+記住郵件的“一句話概述”會成爲該補丁的全局唯一標識。它會進入 ``git``
+的改動記錄裏。然後“一句話概述”會被用在開發者的討論裏,用來指代這個補
+丁。用戶將希望通過搜索引擎搜索“一句話概述”來找到那些討論這個補丁的文
+章。當人們在兩三個月後使用諸如 ``gitk`` 或 ``git log --oneline`` 之類
+的工具查看數千個補丁時,也會很快看到它。
+
+出於這些原因,概述必須不超過70-75個字符,並且必須描述補丁的更改以及爲
+什麼需要補丁。既要簡潔又要描述性很有挑戰性,但寫得好的概述應該這樣。
+
+概述的前綴可以用方括號括起來:“Subject: [PATCH <tag>...] <概述>”。標記
+不被視爲概述的一部分,而是描述應該如何處理補丁。如果補丁的多個版本已發
+送出來以響應評審(即“v1,v2,v3”)則必須包含版本號,或包含“RFC”以指示
+評審請求。如果一個補丁系列中有四個補丁,那麼各個補丁可以這樣編號:1/4、2/4、
+3/4、4/4。這可以確保開發人員瞭解補丁應用的順序,且
+已經查看或應用了補丁系列中的所有補丁。
+
+一些標題的例子::
+
+ Subject: [patch 2/5] ext2: improve scalability of bitmap searching
+ Subject: [PATCHv2 001/207] x86: fix eflags tracking
+
+``From`` 行是信體裏的最上面一行,具有如下格式::
+
+ From: Patch Author <author@example.com>
+
+``From`` 行指明在永久改動日誌裏,誰會被確認爲作者。如果沒有 ``From`` 行,那
+麼郵件頭裏的 ``From:`` 行會被用來決定改動日誌中的作者。
+
+說明文字將會被提交到永久的源代碼改動日誌裏,因此應針對那些早已經不記得和這
+個補丁相關的討論細節的讀者。包括補丁處理的故障症狀(內核日誌消息、oops消息
+等),這對於可能正在搜索提交日誌以查找適用補丁的人特別有用。文本應該寫得如
+此詳細,以便在數週、數月甚至數年後閱讀時,能夠爲讀者提供所需的細節信息,以
+掌握創建補丁的 **原因** 。
+
+如果一個補丁修復了一個編譯失敗,那麼可能不需要包含 *所有* 編譯失敗;
+只要足夠讓搜索補丁的人能夠找到它就行了。與概述一樣,既要簡潔又要描述性。
+
+``---`` 標記行對於補丁處理工具要找到哪裏是改動日誌信息的結束,是不可缺少
+的。
+
+對於 ``---`` 標記之後的額外註解,一個好的用途就是用來寫 ``diffstat`` ,用來顯
+示修改了什麼文件和每個文件都增加和刪除了多少行。 ``diffstat`` 對於比較大的補
+丁特別有用。
+使用 ``diffstat`` 的選項 ``-p 1 -w 70`` 這樣文件名就會從內核源代碼樹的目錄開始
+,不會佔用太寬的空間(很容易適合80列的寬度,也許會有一些縮進。)
+( ``git`` 默認會生成合適的diffstat。)
+
+其餘那些只適用於當時或者與維護者相關的註解,不合適放到永久的改動日誌裏的,也
+應該放這裏。較好的例子就是 ``補丁更改記錄`` ,記錄了v1和v2版本補丁之間的差異。
+
+請將此信息放在將變更日誌與補丁的其餘部分分隔開的 ``---`` 行 **之後** 。版本
+信息不是提交到git樹的變更日誌的一部分。只是供審閱人員使用的附加信息。如果將
+其放置在提交標記上方,則需要手動交互才能將其刪除。如果它位於分隔線以下,則在
+應用補丁時會自動剝離::
+
+ <commit message>
+ ...
+ Signed-off-by: Author <author@mail>
+ ---
+ V2 -> V3: Removed redundant helper function
+ V1 -> V2: Cleaned up coding style and addressed review comments
+
+ path/to/file | 5+++--
+ ...
+
+在後面的參考資料中能看到正確補丁格式的更多細節。
+
+.. _tw_backtraces:
+
+提交消息中的回溯(Backtraces)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+回溯有助於記錄導致問題的調用鏈。然而,並非所有回溯都有幫助。例如,早期引導調
+用鏈是獨特而明顯的。而逐字複製完整的dmesg輸出則會增加時間戳、模塊列表、寄存
+器和堆棧轉儲等分散注意力的信息。
+
+因此,最有用的回溯應該從轉儲中提取相關信息,以更容易集中在真實問題上。下面是
+一個剪裁良好的回溯示例::
+
+ unchecked MSR access error: WRMSR to 0xd51 (tried to write 0x0000000000000064)
+ at rIP: 0xffffffffae059994 (native_write_msr+0x4/0x20)
+ Call Trace:
+ mba_wrmsr
+ update_domains
+ rdtgroup_mkdir
+
+.. _tw_explicit_in_reply_to:
+
+明確回覆郵件頭(In-Reply-To)
+-----------------------------
+
+手動添加回復補丁的的郵件頭(In-Reply_To:)是有用的(例如,使用 ``git send-email`` ),
+可以將補丁與以前的相關討論關聯起來,例如,將bug補丁鏈接到電子郵件和bug報告。
+但是,對於多補丁系列,最好避免在回覆時使用鏈接到該系列的舊版本。這樣,
+補丁的多個版本就不會成爲電子郵件客戶端中無法管理的引用樹。如果鏈接有用,
+可以使用 https://lore.kernel.org/ 重定向器(例如,在封面電子郵件文本中)
+鏈接到補丁系列的早期版本。
+
+給出基礎樹信息
+--------------
+
+當其他開發人員收到您的補丁並開始審閱時,知道應該將您的工作放到代碼樹歷史記錄
+中的什麼位置通常很有用。這對於自動化持續集成流水(CI)特別有用,這些流水線試
+圖運行一系列測試,以便在維護人員開始審閱之前確定提交的質量。
+
+如果您使用 ``git format-patch`` 生成補丁,則可以通過 ``--base`` 標誌在提交中
+自動包含基礎樹信息。使用此選項最簡單、最方便的方法是配合主題分支::
+
+ $ git checkout -t -b my-topical-branch master
+ Branch 'my-topical-branch' set up to track local branch 'master'.
+ Switched to a new branch 'my-topical-branch'
+
+ [perform your edits and commits]
+
+ $ git format-patch --base=auto --cover-letter -o outgoing/ master
+ outgoing/0000-cover-letter.patch
+ outgoing/0001-First-Commit.patch
+ outgoing/...
+
+當你編輯 ``outgoing/0000-cover-letter.patch`` 時,您會注意到在它的最底部有一
+行 ``base-commit:`` 尾註,它爲審閱者和CI工具提供了足夠的信息以正確執行
+``git am`` 而不必擔心衝突::
+
+ $ git checkout -b patch-review [base-commit-id]
+ Switched to a new branch 'patch-review'
+ $ git am patches.mbox
+ Applying: First Commit
+ Applying: ...
+
+有關此選項的更多信息,請參閱 ``man git-format-patch`` 。
+
+.. note::
+
+ ``--base`` 功能是在2.9.0版git中引入的。
+
+如果您不使用git格式化補丁,仍然可以包含相同的 ``base-commit`` 尾註,以指示您
+的工作所基於的樹的提交哈希。你應該在封面郵件或系列的第一個補丁中添加它,它應
+該放在 ``---`` 行的下面或所有其他內容之後,即只在你的電子郵件簽名之前。
+
+參考文獻
+--------
+
+Andrew Morton,“完美的補丁”(tpp)
+ <https://www.ozlabs.org/~akpm/stuff/tpp.txt>
+
+Jeff Garzik,“Linux內核補丁提交格式”
+ <https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html>
+
+Greg Kroah-Hartman,“如何惹惱內核子系統維護人員”
+ <http://www.kroah.com/log/linux/maintainer.html>
+
+ <http://www.kroah.com/log/linux/maintainer-02.html>
+
+ <http://www.kroah.com/log/linux/maintainer-03.html>
+
+ <http://www.kroah.com/log/linux/maintainer-04.html>
+
+ <http://www.kroah.com/log/linux/maintainer-05.html>
+
+ <http://www.kroah.com/log/linux/maintainer-06.html>
+
+不!!!別再發巨型補丁炸彈給linux-kernel@vger.kernel.org的人們了!
+ <https://lore.kernel.org/r/20050711.125305.08322243.davem@davemloft.net>
+
+內核 Documentation/translations/zh_CN/process/coding-style.rst
+
+Linus Torvalds關於標準補丁格式的郵件
+ <https://lore.kernel.org/r/Pine.LNX.4.58.0504071023190.28951@ppc970.osdl.org>
+
+Andi Kleen,“提交補丁之路”
+ 一些幫助合入困難或有爭議的變更的策略。
+
+ http://halobates.de/on-submitting-patches.pdf
+
diff --git a/Documentation/translations/zh_TW/process/volatile-considered-harmful.rst b/Documentation/translations/zh_TW/process/volatile-considered-harmful.rst
new file mode 100644
index 000000000000..e2723f3cbbb0
--- /dev/null
+++ b/Documentation/translations/zh_TW/process/volatile-considered-harmful.rst
@@ -0,0 +1,110 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. _tw_volatile_considered_harmful:
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/process/volatile-considered-harmful.rst
+ <volatile_considered_harmful>`
+
+如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
+交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻
+譯存在問題,請聯繫中文版維護者::
+
+ 英文版維護者: Jonathan Corbet <corbet@lwn.net>
+ 中文版維護者: 伍鵬 Bryan Wu <bryan.wu@analog.com>
+ 中文版翻譯者: 伍鵬 Bryan Wu <bryan.wu@analog.com>
+ 中文版校譯者: 張漢輝 Eugene Teo <eugeneteo@kernel.sg>
+ 楊瑞 Dave Young <hidave.darkstar@gmail.com>
+ 時奎亮 Alex Shi <alex.shi@linux.alibaba.com>
+ 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn>
+
+爲什麼不應該使用“volatile”類型
+==============================
+
+C程序員通常認爲volatile表示某個變量可以在當前執行的線程之外被改變;因此,在內核
+中用到共享數據結構時,常常會有C程序員喜歡使用volatile這類變量。換句話說,他們經
+常會把volatile類型看成某種簡易的原子變量,當然它們不是。在內核中使用volatile幾
+乎總是錯誤的;本文檔將解釋爲什麼這樣。
+
+理解volatile的關鍵是知道它的目的是用來消除優化,實際上很少有人真正需要這樣的應
+用。在內核中,程序員必須防止意外的併發訪問破壞共享的數據結構,這其實是一個完全
+不同的任務。用來防止意外併發訪問的保護措施,可以更加高效的避免大多數優化相關的
+問題。
+
+像volatile一樣,內核提供了很多原語來保證併發訪問時的數據安全(自旋鎖, 互斥量,內
+存屏障等等),同樣可以防止意外的優化。如果可以正確使用這些內核原語,那麼就沒有
+必要再使用volatile。如果仍然必須使用volatile,那麼幾乎可以肯定在代碼的某處有一
+個bug。在正確設計的內核代碼中,volatile能帶來的僅僅是使事情變慢。
+
+思考一下這段典型的內核代碼::
+
+ spin_lock(&the_lock);
+ do_something_on(&shared_data);
+ do_something_else_with(&shared_data);
+ spin_unlock(&the_lock);
+
+如果所有的代碼都遵循加鎖規則,當持有the_lock的時候,不可能意外的改變shared_data的
+值。任何可能訪問該數據的其他代碼都會在這個鎖上等待。自旋鎖原語跟內存屏障一樣—— 它
+們顯式的用來書寫成這樣 —— 意味着數據訪問不會跨越它們而被優化。所以本來編譯器認爲
+它知道在shared_data裏面將有什麼,但是因爲spin_lock()調用跟內存屏障一樣,會強制編
+譯器忘記它所知道的一切。那麼在訪問這些數據時不會有優化的問題。
+
+如果shared_data被聲名爲volatile,鎖操作將仍然是必須的。就算我們知道沒有其他人正在
+使用它,編譯器也將被阻止優化對臨界區內shared_data的訪問。在鎖有效的同時,
+shared_data不是volatile的。在處理共享數據的時候,適當的鎖操作可以不再需要
+volatile —— 並且是有潛在危害的。
+
+volatile的存儲類型最初是爲那些內存映射的I/O寄存器而定義。在內核裏,寄存器訪問也應
+該被鎖保護,但是人們也不希望編譯器“優化”臨界區內的寄存器訪問。內核裏I/O的內存訪問
+是通過訪問函數完成的;不贊成通過指針對I/O內存的直接訪問,並且不是在所有體系架構上
+都能工作。那些訪問函數正是爲了防止意外優化而寫的,因此,再說一次,volatile類型不
+是必需的。
+
+另一種引起用戶可能使用volatile的情況是當處理器正忙着等待一個變量的值。正確執行一
+個忙等待的方法是::
+
+ while (my_variable != what_i_want)
+ cpu_relax();
+
+cpu_relax()調用會降低CPU的能量消耗或者讓位於超線程雙處理器;它也作爲內存屏障一樣出
+現,所以,再一次,volatile不是必需的。當然,忙等待一開始就是一種反常規的做法。
+
+在內核中,一些稀少的情況下volatile仍然是有意義的:
+
+ - 在一些體系架構的系統上,允許直接的I/0內存訪問,那麼前面提到的訪問函數可以使用
+ volatile。基本上,每一個訪問函數調用它自己都是一個小的臨界區域並且保證了按照
+ 程序員期望的那樣發生訪問操作。
+
+ - 某些會改變內存的內聯彙編代碼雖然沒有什麼其他明顯的附作用,但是有被GCC刪除的可
+ 能性。在彙編聲明中加上volatile關鍵字可以防止這種刪除操作。
+
+ - Jiffies變量是一種特殊情況,雖然每次引用它的時候都可以有不同的值,但讀jiffies
+ 變量時不需要任何特殊的加鎖保護。所以jiffies變量可以使用volatile,但是不贊成
+ 其他跟jiffies相同類型變量使用volatile。Jiffies被認爲是一種“愚蠢的遺留物"
+ (Linus的話)因爲解決這個問題比保持現狀要麻煩的多。
+
+ - 由於某些I/0設備可能會修改連續一致的內存,所以有時,指向連續一致內存的數據結構
+ 的指針需要正確的使用volatile。網絡適配器使用的環狀緩存區正是這類情形的一個例
+ 子,其中適配器用改變指針來表示哪些描述符已經處理過了。
+
+對於大多代碼,上述幾種可以使用volatile的情況都不適用。所以,使用volatile是一種
+bug並且需要對這樣的代碼額外仔細檢查。那些試圖使用volatile的開發人員需要退一步想想
+他們真正想實現的是什麼。
+
+非常歡迎刪除volatile變量的補丁 - 只要證明這些補丁完整的考慮了併發問題。
+
+註釋
+----
+
+[1] https://lwn.net/Articles/233481/
+[2] https://lwn.net/Articles/233482/
+
+致謝
+----
+
+最初由Randy Dunlap推動並作初步研究
+由Jonathan Corbet撰寫
+參考Satyam Sharma,Johannes Stezenbach,Jesper Juhl,Heikki Orsila,
+H. Peter Anvin,Philipp Hahn和Stefan Richter的意見改善了本檔。
+