diff --git a/Documentation/.gitignore b/Documentation/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e74fec8693b29ce52094c0f5a055200db18e8570 --- /dev/null +++ b/Documentation/.gitignore @@ -0,0 +1,2 @@ +output +*.pyc diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index d70f9b68174e8bc388dc4bec617b28596b903cc4..496d4295ec38e5a7b9c0d6d1927ac2be009193fd 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -33,10 +33,6 @@ PDF_METHOD = $(prefer-db2x) PS_METHOD = $(prefer-db2x) -### -# The targets that may be used. -PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs - targets += $(DOCBOOKS) BOOKS := $(addprefix $(obj)/,$(DOCBOOKS)) xmldocs: $(BOOKS) @@ -63,6 +59,9 @@ installmandocs: mandocs sort -k 2 -k 1 | uniq -f 1 | sed -e 's: :/:' | \ xargs install -m 644 -t /usr/local/man/man9/ +# no-op for the DocBook toolchain +epubdocs: + ### #External programs used KERNELDOCXMLREF = $(srctree)/scripts/kernel-doc-xml-ref @@ -219,7 +218,7 @@ silent_gen_xml = : ### # Help targets as used by the top-level makefile dochelp: - @echo ' Linux kernel internal documentation in different formats:' + @echo ' Linux kernel internal documentation in different formats (DocBook):' @echo ' htmldocs - HTML' @echo ' pdfdocs - PDF' @echo ' psdocs - Postscript' @@ -228,7 +227,7 @@ dochelp: @echo ' installmandocs - install man pages generated by mandocs' @echo ' cleandocs - clean all generated DocBook files' @echo - @echo 'make DOCBOOKS="s1.xml s2.xml" [target] Generate only docs s1.xml s2.xml' + @echo ' make DOCBOOKS="s1.xml s2.xml" [target] Generate only docs s1.xml s2.xml' @echo ' valid values for DOCBOOKS are: $(DOCBOOKS)' diff --git a/Documentation/Makefile.sphinx b/Documentation/Makefile.sphinx new file mode 100644 index 0000000000000000000000000000000000000000..810c11f0d37f486cb35fb65133c70616a005b035 --- /dev/null +++ b/Documentation/Makefile.sphinx @@ -0,0 +1,71 @@ +# -*- makefile -*- +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXBUILD = sphinx-build +SPHINXOPTS = +PAPER = +BUILDDIR = $(obj)/output + +# User-friendly check for sphinx-build +HAVE_SPHINX := $(shell if which $(SPHINXBUILD) >/dev/null 2>&1; then echo 1; else echo 0; fi) + +ifeq ($(HAVE_SPHINX),0) + +.DEFAULT: + $(warning The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed and in PATH, or set the SPHINXBUILD make variable to point to the full path of the '$(SPHINXBUILD)' executable.) + @echo " SKIP Sphinx $@ target." + +else # HAVE_SPHINX + +# User-friendly check for rst2pdf +HAVE_RST2PDF := $(shell if python -c "import rst2pdf" >/dev/null 2>&1; then echo 1; else echo 0; fi) + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +KERNELDOC = $(srctree)/scripts/kernel-doc +KERNELDOC_CONF = -D kerneldoc_srctree=$(srctree) -D kerneldoc_bin=$(KERNELDOC) +ALLSPHINXOPTS = -D version=$(KERNELVERSION) -D release=$(KERNELRELEASE) -d $(BUILDDIR)/.doctrees $(KERNELDOC_CONF) $(PAPEROPT_$(PAPER)) -c $(srctree)/$(src) $(SPHINXOPTS) $(srctree)/$(src) +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +quiet_cmd_sphinx = SPHINX $@ + cmd_sphinx = $(SPHINXBUILD) -b $2 $(ALLSPHINXOPTS) $(BUILDDIR)/$2 + +htmldocs: + $(call cmd,sphinx,html) + +pdfdocs: +ifeq ($(HAVE_RST2PDF),0) + $(warning The Python 'rst2pdf' module was not found. Make sure you have the module installed to produce PDF output.) + @echo " SKIP Sphinx $@ target." +else # HAVE_RST2PDF + $(call cmd,sphinx,pdf) +endif # HAVE_RST2PDF + +epubdocs: + $(call cmd,sphinx,epub) + +xmldocs: + $(call cmd,sphinx,xml) + +# no-ops for the Sphinx toolchain +sgmldocs: +psdocs: +mandocs: +installmandocs: + +cleandocs: + $(Q)rm -rf $(BUILDDIR) + +dochelp: + @echo ' Linux kernel internal documentation in different formats (Sphinx):' + @echo ' htmldocs - HTML' + @echo ' pdfdocs - PDF' + @echo ' epubdocs - EPUB' + @echo ' xmldocs - XML' + @echo ' cleandocs - clean all generated files' + +endif # HAVE_SPHINX diff --git a/Documentation/bcache.txt b/Documentation/bcache.txt index 32b6c3189d9826a53875ae6dc51ce62e9b86778b..a9259b562d5c8b188576f22cfd9ed532ad522d79 100644 --- a/Documentation/bcache.txt +++ b/Documentation/bcache.txt @@ -1,4 +1,4 @@ -Say you've got a big slow raid 6, and an X-25E or three. Wouldn't it be +Say you've got a big slow raid 6, and an ssd or three. Wouldn't it be nice if you could use them as cache... Hence bcache. Wiki and git repositories are at: @@ -8,7 +8,7 @@ Wiki and git repositories are at: It's designed around the performance characteristics of SSDs - it only allocates in erase block sized buckets, and it uses a hybrid btree/log to track cached -extants (which can be anywhere from a single sector to the bucket size). It's +extents (which can be anywhere from a single sector to the bucket size). It's designed to avoid random writes at all costs; it fills up an erase block sequentially, then issues a discard before reusing it. @@ -55,7 +55,10 @@ immediately. Without udev, you can manually register devices like this: Registering the backing device makes the bcache device show up in /dev; you can now format it and use it as normal. But the first time using a new bcache device, it'll be running in passthrough mode until you attach it to a cache. -See the section on attaching. +If you are thinking about using bcache later, it is recommended to setup all your +slow devices as bcache backing devices without a cache, and you can choose to add +a caching device later. +See 'ATTACHING' section below. The devices show up as: @@ -72,12 +75,14 @@ To get started: mount /dev/bcache0 /mnt You can control bcache devices through sysfs at /sys/block/bcache<N>/bcache . +You can also control them through /sys/fs//bcache/<cset-uuid>/ . Cache devices are managed as sets; multiple caches per set isn't supported yet but will allow for mirroring of metadata and dirty data in the future. Your new cache set shows up as /sys/fs/bcache/<UUID> -ATTACHING: +ATTACHING +--------- After your cache device and backing device are registered, the backing device must be attached to your cache set to enable caching. Attaching a backing @@ -105,7 +110,8 @@ but all the cached data will be invalidated. If there was dirty data in the cache, don't expect the filesystem to be recoverable - you will have massive filesystem corruption, though ext4's fsck does work miracles. -ERROR HANDLING: +ERROR HANDLING +-------------- Bcache tries to transparently handle IO errors to/from the cache device without affecting normal operation; if it sees too many errors (the threshold is @@ -127,12 +133,181 @@ the backing devices to passthrough mode. writeback mode). It currently doesn't do anything intelligent if it fails to read some of the dirty data, though. -TROUBLESHOOTING PERFORMANCE: + +HOWTO/COOKBOOK +-------------- + +A) Starting a bcache with a missing caching device + +If registering the backing device doesn't help, it's already there, you just need +to force it to run without the cache: + host:~# echo /dev/sdb1 > /sys/fs/bcache/register + [ 119.844831] bcache: register_bcache() error opening /dev/sdb1: device already registered + +Next, you try to register your caching device if it's present. However +if it's absent, or registration fails for some reason, you can still +start your bcache without its cache, like so: + host:/sys/block/sdb/sdb1/bcache# echo 1 > running + +Note that this may cause data loss if you were running in writeback mode. + + +B) Bcache does not find its cache + + host:/sys/block/md5/bcache# echo 0226553a-37cf-41d5-b3ce-8b1e944543a8 > attach + [ 1933.455082] bcache: bch_cached_dev_attach() Couldn't find uuid for md5 in set + [ 1933.478179] bcache: __cached_dev_store() Can't attach 0226553a-37cf-41d5-b3ce-8b1e944543a8 + [ 1933.478179] : cache set not found + +In this case, the caching device was simply not registered at boot +or disappeared and came back, and needs to be (re-)registered: + host:/sys/block/md5/bcache# echo /dev/sdh2 > /sys/fs/bcache/register + + +C) Corrupt bcache crashes the kernel at device registration time: + +This should never happen. If it does happen, then you have found a bug! +Please report it to the bcache development list: linux-bcache@vger.kernel.org + +Be sure to provide as much information that you can including kernel dmesg +output if available so that we may assist. + + +D) Recovering data without bcache: + +If bcache is not available in the kernel, a filesystem on the backing +device is still available at an 8KiB offset. So either via a loopdev +of the backing device created with --offset 8K, or any value defined by +--data-offset when you originally formatted bcache with `make-bcache`. + +For example: + losetup -o 8192 /dev/loop0 /dev/your_bcache_backing_dev + +This should present your unmodified backing device data in /dev/loop0 + +If your cache is in writethrough mode, then you can safely discard the +cache device without loosing data. + + +E) Wiping a cache device + +host:~# wipefs -a /dev/sdh2 +16 bytes were erased at offset 0x1018 (bcache) +they were: c6 85 73 f6 4e 1a 45 ca 82 65 f5 7f 48 ba 6d 81 + +After you boot back with bcache enabled, you recreate the cache and attach it: +host:~# make-bcache -C /dev/sdh2 +UUID: 7be7e175-8f4c-4f99-94b2-9c904d227045 +Set UUID: 5bc072a8-ab17-446d-9744-e247949913c1 +version: 0 +nbuckets: 106874 +block_size: 1 +bucket_size: 1024 +nr_in_set: 1 +nr_this_dev: 0 +first_bucket: 1 +[ 650.511912] bcache: run_cache_set() invalidating existing data +[ 650.549228] bcache: register_cache() registered cache device sdh2 + +start backing device with missing cache: +host:/sys/block/md5/bcache# echo 1 > running + +attach new cache: +host:/sys/block/md5/bcache# echo 5bc072a8-ab17-446d-9744-e247949913c1 > attach +[ 865.276616] bcache: bch_cached_dev_attach() Caching md5 as bcache0 on set 5bc072a8-ab17-446d-9744-e247949913c1 + + +F) Remove or replace a caching device + + host:/sys/block/sda/sda7/bcache# echo 1 > detach + [ 695.872542] bcache: cached_dev_detach_finish() Caching disabled for sda7 + + host:~# wipefs -a /dev/nvme0n1p4 + wipefs: error: /dev/nvme0n1p4: probing initialization failed: Device or resource busy + Ooops, it's disabled, but not unregistered, so it's still protected + +We need to go and unregister it: + host:/sys/fs/bcache/b7ba27a1-2398-4649-8ae3-0959f57ba128# ls -l cache0 + lrwxrwxrwx 1 root root 0 Feb 25 18:33 cache0 -> ../../../devices/pci0000:00/0000:00:1d.0/0000:70:00.0/nvme/nvme0/nvme0n1/nvme0n1p4/bcache/ + host:/sys/fs/bcache/b7ba27a1-2398-4649-8ae3-0959f57ba128# echo 1 > stop + kernel: [ 917.041908] bcache: cache_set_free() Cache set b7ba27a1-2398-4649-8ae3-0959f57ba128 unregistered + +Now we can wipe it: + host:~# wipefs -a /dev/nvme0n1p4 + /dev/nvme0n1p4: 16 bytes were erased at offset 0x00001018 (bcache): c6 85 73 f6 4e 1a 45 ca 82 65 f5 7f 48 ba 6d 81 + + +G) dm-crypt and bcache + +First setup bcache unencrypted and then install dmcrypt on top of +/dev/bcache<N> This will work faster than if you dmcrypt both the backing +and caching devices and then install bcache on top. [benchmarks?] + + +H) Stop/free a registered bcache to wipe and/or recreate it + +Suppose that you need to free up all bcache references so that you can +fdisk run and re-register a changed partition table, which won't work +if there are any active backing or caching devices left on it: + +1) Is it present in /dev/bcache* ? (there are times where it won't be) + +If so, it's easy: + host:/sys/block/bcache0/bcache# echo 1 > stop + +2) But if your backing device is gone, this won't work: + host:/sys/block/bcache0# cd bcache + bash: cd: bcache: No such file or directory + +In this case, you may have to unregister the dmcrypt block device that +references this bcache to free it up: + host:~# dmsetup remove oldds1 + bcache: bcache_device_free() bcache0 stopped + bcache: cache_set_free() Cache set 5bc072a8-ab17-446d-9744-e247949913c1 unregistered + +This causes the backing bcache to be removed from /sys/fs/bcache and +then it can be reused. This would be true of any block device stacking +where bcache is a lower device. + +3) In other cases, you can also look in /sys/fs/bcache/: + +host:/sys/fs/bcache# ls -l */{cache?,bdev?} +lrwxrwxrwx 1 root root 0 Mar 5 09:39 0226553a-37cf-41d5-b3ce-8b1e944543a8/bdev1 -> ../../../devices/virtual/block/dm-1/bcache/ +lrwxrwxrwx 1 root root 0 Mar 5 09:39 0226553a-37cf-41d5-b3ce-8b1e944543a8/cache0 -> ../../../devices/virtual/block/dm-4/bcache/ +lrwxrwxrwx 1 root root 0 Mar 5 09:39 5bc072a8-ab17-446d-9744-e247949913c1/cache0 -> ../../../devices/pci0000:00/0000:00:01.0/0000:01:00.0/ata10/host9/target9:0:0/9:0:0:0/block/sdl/sdl2/bcache/ + +The device names will show which UUID is relevant, cd in that directory +and stop the cache: + host:/sys/fs/bcache/5bc072a8-ab17-446d-9744-e247949913c1# echo 1 > stop + +This will free up bcache references and let you reuse the partition for +other purposes. + + + +TROUBLESHOOTING PERFORMANCE +--------------------------- Bcache has a bunch of config options and tunables. The defaults are intended to be reasonable for typical desktop and server workloads, but they're not what you want for getting the best possible numbers when benchmarking. + - Backing device alignment + + The default metadata size in bcache is 8k. If your backing device is + RAID based, then be sure to align this by a multiple of your stride + width using `make-bcache --data-offset`. If you intend to expand your + disk array in the future, then multiply a series of primes by your + raid stripe size to get the disk multiples that you would like. + + For example: If you have a 64k stripe size, then the following offset + would provide alignment for many common RAID5 data spindle counts: + 64k * 2*2*2*3*3*5*7 bytes = 161280k + + That space is wasted, but for only 157.5MB you can grow your RAID 5 + volume to the following data-spindle counts without re-aligning: + 3,4,5,6,7,8,9,10,12,14,15,18,20,21 ... + - Bad write performance If write performance is not what you expected, you probably wanted to be @@ -140,7 +315,7 @@ want for getting the best possible numbers when benchmarking. maturity, but simply because in writeback mode you'll lose data if something happens to your SSD) - # echo writeback > /sys/block/bcache0/cache_mode + # echo writeback > /sys/block/bcache0/bcache/cache_mode - Bad performance, or traffic not going to the SSD that you'd expect @@ -193,7 +368,9 @@ want for getting the best possible numbers when benchmarking. Solution: warm the cache by doing writes, or use the testing branch (there's a fix for the issue there). -SYSFS - BACKING DEVICE: + +SYSFS - BACKING DEVICE +---------------------- Available at /sys/block/<bdev>/bcache, /sys/block/bcache*/bcache and (if attached) /sys/fs/bcache/<cset-uuid>/bdev* @@ -238,7 +415,7 @@ sequential_merge against all new requests to determine which new requests are sequential continuations of previous requests for the purpose of determining sequential cutoff. This is necessary if the sequential cutoff value is greater than the - maximum acceptable sequential size for any single request. + maximum acceptable sequential size for any single request. state The backing device can be in one of four different states: @@ -325,7 +502,7 @@ bucket_size Size of buckets cache<0..n> - Symlink to each of the cache devices comprising this cache set. + Symlink to each of the cache devices comprising this cache set. cache_available_percent Percentage of cache device which doesn't contain dirty data, and could diff --git a/Documentation/conf.py b/Documentation/conf.py new file mode 100644 index 0000000000000000000000000000000000000000..792b6338ef197e2f0e26347673a4e3ae54247492 --- /dev/null +++ b/Documentation/conf.py @@ -0,0 +1,414 @@ +# -*- coding: utf-8 -*- +# +# The Linux Kernel documentation build configuration file, created by +# sphinx-quickstart on Fri Feb 12 13:51:46 2016. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('sphinx')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['kernel-doc', 'rstFlatTable'] + +# Gracefully handle missing rst2pdf. +try: + import rst2pdf + extensions += ['rst2pdf.pdfbuilder'] +except ImportError: + pass + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'The Linux Kernel' +copyright = '2016, The kernel development community' +author = 'The kernel development community' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# In a normal build, version and release are are set to KERNELVERSION and +# KERNELRELEASE, respectively, from the Makefile via Sphinx command line +# arguments. +# +# The following code tries to extract the information by reading the Makefile, +# when Sphinx is run directly (e.g. by Read the Docs). +try: + makefile_version = None + makefile_patchlevel = None + for line in open('../Makefile'): + key, val = [x.strip() for x in line.split('=', 2)] + if key == 'VERSION': + makefile_version = val + elif key == 'PATCHLEVEL': + makefile_patchlevel = val + if makefile_version and makefile_patchlevel: + break +except: + pass +finally: + if makefile_version and makefile_patchlevel: + version = release = makefile_version + '.' + makefile_patchlevel + else: + sys.stderr.write('Warning: Could not extract kernel version\n') + version = release = "unknown version" + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['output'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + +primary_domain = 'C' +highlight_language = 'C' + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. + +# The Read the Docs theme is available from +# - https://github.com/snide/sphinx_rtd_theme +# - https://pypi.python.org/pypi/sphinx_rtd_theme +# - python-sphinx-rtd-theme package (on Debian) +try: + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] +except ImportError: + sys.stderr.write('Warning: The Sphinx \'sphinx_rtd_theme\' HTML theme was not found. Make sure you have the theme installed to produce pretty HTML output. Falling back to the default theme.\n') + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# "<project> v<release> documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +#html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'TheLinuxKerneldoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'TheLinuxKernel.tex', 'The Linux Kernel Documentation', + 'The kernel development community', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'thelinuxkernel', 'The Linux Kernel Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'TheLinuxKernel', 'The Linux Kernel Documentation', + author, 'TheLinuxKernel', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + + +# -- Options for Epub output ---------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project +epub_author = author +epub_publisher = author +epub_copyright = copyright + +# The basename for the epub file. It defaults to the project name. +#epub_basename = project + +# The HTML theme for the epub output. Since the default themes are not +# optimized for small screen space, using the same theme for HTML and epub +# output is usually not wise. This defaults to 'epub', a theme designed to save +# visual space. +#epub_theme = 'epub' + +# The language of the text. It defaults to the language option +# or 'en' if the language is not set. +#epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +#epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +#epub_identifier = '' + +# A unique identification for the text. +#epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +#epub_cover = () + +# A sequence of (type, uri, title) tuples for the guide element of content.opf. +#epub_guide = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_pre_files = [] + +# HTML files that should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_post_files = [] + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] + +# The depth of the table of contents in toc.ncx. +#epub_tocdepth = 3 + +# Allow duplicate toc entries. +#epub_tocdup = True + +# Choose between 'default' and 'includehidden'. +#epub_tocscope = 'default' + +# Fix unsupported image types using the Pillow. +#epub_fix_images = False + +# Scale large images. +#epub_max_image_width = 0 + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#epub_show_urls = 'inline' + +# If false, no index is generated. +#epub_use_index = True + +#======= +# rst2pdf +# +# Grouping the document tree into PDF files. List of tuples +# (source start file, target name, title, author, options). +# +# See the Sphinx chapter of http://ralsina.me/static/manual.pdf +# +# FIXME: Do not add the index file here; the result will be too big. Adding +# multiple PDF files here actually tries to get the cross-referencing right +# *between* PDF files. +pdf_documents = [ + ('index', u'Kernel', u'Kernel', u'J. Random Bozo'), +] + +# kernel-doc extension configuration for running Sphinx directly (e.g. by Read +# the Docs). In a normal build, these are supplied from the Makefile via command +# line arguments. +kerneldoc_bin = '../scripts/kernel-doc' +kerneldoc_srctree = '..' diff --git a/Documentation/dmaengine/provider.txt b/Documentation/dmaengine/provider.txt index 122b7f4876bb637bf4023826703a12936bd326c7..91ce82d5f0c4f6bb951c4b406792144a7fc374ca 100644 --- a/Documentation/dmaengine/provider.txt +++ b/Documentation/dmaengine/provider.txt @@ -323,7 +323,7 @@ supported. * device_resume - Resumes a transfer on the channel - This command should operate synchronously on the channel, - pausing right away the work of the given channel + resuming right away the work of the given channel * device_terminate_all - Aborts all the pending and ongoing transfers on the channel diff --git a/Documentation/index.rst b/Documentation/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..f92854f01773fe46f9ba23900c4d217725827ba8 --- /dev/null +++ b/Documentation/index.rst @@ -0,0 +1,22 @@ +.. The Linux Kernel documentation master file, created by + sphinx-quickstart on Fri Feb 12 13:51:46 2016. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to The Linux Kernel's documentation! +============================================ + +Nothing for you to see here *yet*. Please move along. + +Contents: + +.. toctree:: + :maxdepth: 2 + + kernel-documentation + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`search` diff --git a/Documentation/kernel-documentation.rst b/Documentation/kernel-documentation.rst new file mode 100644 index 0000000000000000000000000000000000000000..391decc66a18fd3da282cc009d6f239441de4a8d --- /dev/null +++ b/Documentation/kernel-documentation.rst @@ -0,0 +1,648 @@ +========================== +Linux Kernel Documentation +========================== + +Introduction +============ + +The Linux kernel uses `Sphinx`_ to generate pretty documentation from +`reStructuredText`_ files under ``Documentation``. To build the documentation in +HTML or PDF formats, use ``make htmldocs`` or ``make pdfdocs``. The generated +documentation is placed in ``Documentation/output``. + +.. _Sphinx: http://www.sphinx-doc.org/ +.. _reStructuredText: http://docutils.sourceforge.net/rst.html + +The reStructuredText files may contain directives to include structured +documentation comments, or kernel-doc comments, from source files. Usually these +are used to describe the functions and types and design of the code. The +kernel-doc comments have some special structure and formatting, but beyond that +they are also treated as reStructuredText. + +There is also the deprecated DocBook toolchain to generate documentation from +DocBook XML template files under ``Documentation/DocBook``. The DocBook files +are to be converted to reStructuredText, and the toolchain is slated to be +removed. + +Finally, there are thousands of plain text documentation files scattered around +``Documentation``. Some of these will likely be converted to reStructuredText +over time, but the bulk of them will remain in plain text. + +Sphinx Build +============ + +The usual way to generate the documentation is to run ``make htmldocs`` or +``make pdfdocs``. There are also other formats available, see the documentation +section of ``make help``. The generated documentation is placed in +format-specific subdirectories under ``Documentation/output``. + +To generate documentation, Sphinx (``sphinx-build``) must obviously be +installed. For prettier HTML output, the Read the Docs Sphinx theme +(``sphinx_rtd_theme``) is used if available. For PDF output, ``rst2pdf`` is also +needed. All of these are widely available and packaged in distributions. + +To pass extra options to Sphinx, you can use the ``SPHINXOPTS`` make +variable. For example, use ``make SPHINXOPTS=-v htmldocs`` to get more verbose +output. + +To remove the generated documentation, run ``make cleandocs``. + +Writing Documentation +===================== + +Adding new documentation can be as simple as: + +1. Add a new ``.rst`` file somewhere under ``Documentation``. +2. Refer to it from the Sphinx main `TOC tree`_ in ``Documentation/index.rst``. + +.. _TOC tree: http://www.sphinx-doc.org/en/stable/markup/toctree.html + +This is usually good enough for simple documentation (like the one you're +reading right now), but for larger documents it may be advisable to create a +subdirectory (or use an existing one). For example, the graphics subsystem +documentation is under ``Documentation/gpu``, split to several ``.rst`` files, +and has a separate ``index.rst`` (with a ``toctree`` of its own) referenced from +the main index. + +See the documentation for `Sphinx`_ and `reStructuredText`_ on what you can do +with them. In particular, the Sphinx `reStructuredText Primer`_ is a good place +to get started with reStructuredText. There are also some `Sphinx specific +markup constructs`_. + +.. _reStructuredText Primer: http://www.sphinx-doc.org/en/stable/rest.html +.. _Sphinx specific markup constructs: http://www.sphinx-doc.org/en/stable/markup/index.html + +Specific guidelines for the kernel documentation +------------------------------------------------ + +Here are some specific guidelines for the kernel documentation: + +* Please don't go overboard with reStructuredText markup. Keep it simple. + +* Please stick to this order of heading adornments: + + 1. ``=`` with overline for document title:: + + ============== + Document title + ============== + + 2. ``=`` for chapters:: + + Chapters + ======== + + 3. ``-`` for sections:: + + Section + ------- + + 4. ``~`` for subsections:: + + Subsection + ~~~~~~~~~~ + + Although RST doesn't mandate a specific order ("Rather than imposing a fixed + number and order of section title adornment styles, the order enforced will be + the order as encountered."), having the higher levels the same overall makes + it easier to follow the documents. + +list tables +----------- + +We recommend the use of *list table* formats. The *list table* formats are +double-stage lists. Compared to the ASCII-art they might not be as +comfortable for +readers of the text files. Their advantage is that they are easy to +create or modify and that the diff of a modification is much more meaningful, +because it is limited to the modified content. + +The ``flat-table`` is a double-stage list similar to the ``list-table`` with +some additional features: + +* column-span: with the role ``cspan`` a cell can be extended through + additional columns + +* row-span: with the role ``rspan`` a cell can be extended through + additional rows + +* auto span rightmost cell of a table row over the missing cells on the right + side of that table-row. With Option ``:fill-cells:`` this behavior can + changed from *auto span* to *auto fill*, which automatically inserts (empty) + cells instead of spanning the last cell. + +options: + +* ``:header-rows:`` [int] count of header rows +* ``:stub-columns:`` [int] count of stub columns +* ``:widths:`` [[int] [int] ... ] widths of columns +* ``:fill-cells:`` instead of auto-spanning missing cells, insert missing cells + +roles: + +* ``:cspan:`` [int] additional columns (*morecols*) +* ``:rspan:`` [int] additional rows (*morerows*) + +The example below shows how to use this markup. The first level of the staged +list is the *table-row*. In the *table-row* there is only one markup allowed, +the list of the cells in this *table-row*. Exceptions are *comments* ( ``..`` ) +and *targets* (e.g. a ref to ``:ref:`last row <last row>``` / :ref:`last row +<last row>`). + +.. code-block:: rst + + .. flat-table:: table title + :widths: 2 1 1 3 + + * - head col 1 + - head col 2 + - head col 3 + - head col 4 + + * - column 1 + - field 1.1 + - field 1.2 with autospan + + * - column 2 + - field 2.1 + - :rspan:`1` :cspan:`1` field 2.2 - 3.3 + + * .. _`last row`: + + - column 3 + +Rendered as: + + .. flat-table:: table title + :widths: 2 1 1 3 + + * - head col 1 + - head col 2 + - head col 3 + - head col 4 + + * - column 1 + - field 1.1 + - field 1.2 with autospan + + * - column 2 + - field 2.1 + - :rspan:`1` :cspan:`1` field 2.2 - 3.3 + + * .. _`last row`: + + - column 3 + + +Including kernel-doc comments +============================= + +The Linux kernel source files may contain structured documentation comments, or +kernel-doc comments to describe the functions and types and design of the +code. The documentation comments may be included to any of the reStructuredText +documents using a dedicated kernel-doc Sphinx directive extension. + +The kernel-doc directive is of the format:: + + .. kernel-doc:: source + :option: + +The *source* is the path to a source file, relative to the kernel source +tree. The following directive options are supported: + +export: *[source-pattern ...]* + Include documentation for all functions in *source* that have been exported + using ``EXPORT_SYMBOL`` or ``EXPORT_SYMBOL_GPL`` either in *source* or in any + of the files specified by *source-pattern*. + + The *source-pattern* is useful when the kernel-doc comments have been placed + in header files, while ``EXPORT_SYMBOL`` and ``EXPORT_SYMBOL_GPL`` are next to + the function definitions. + + Examples:: + + .. kernel-doc:: lib/bitmap.c + :export: + + .. kernel-doc:: include/net/mac80211.h + :export: net/mac80211/*.c + +internal: *[source-pattern ...]* + Include documentation for all functions and types in *source* that have + **not** been exported using ``EXPORT_SYMBOL`` or ``EXPORT_SYMBOL_GPL`` either + in *source* or in any of the files specified by *source-pattern*. + + Example:: + + .. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c + :internal: + +doc: *title* + Include documentation for the ``DOC:`` paragraph identified by *title* in + *source*. Spaces are allowed in *title*; do not quote the *title*. The *title* + is only used as an identifier for the paragraph, and is not included in the + output. Please make sure to have an appropriate heading in the enclosing + reStructuredText document. + + Example:: + + .. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c + :doc: High Definition Audio over HDMI and Display Port + +functions: *function* *[...]* + Include documentation for each *function* in *source*. + + Example:: + + .. kernel-doc:: lib/bitmap.c + :functions: bitmap_parselist bitmap_parselist_user + +Without options, the kernel-doc directive includes all documentation comments +from the source file. + +The kernel-doc extension is included in the kernel source tree, at +``Documentation/sphinx/kernel-doc.py``. Internally, it uses the +``scripts/kernel-doc`` script to extract the documentation comments from the +source. + +Writing kernel-doc comments +=========================== + +In order to provide embedded, "C" friendly, easy to maintain, but consistent and +extractable overview, function and type documentation, the Linux kernel has +adopted a consistent style for documentation comments. The format for this +documentation is called the kernel-doc format, described below. This style +embeds the documentation within the source files, using a few simple conventions +for adding documentation paragraphs and documenting functions and their +parameters, structures and unions and their members, enumerations, and typedefs. + +.. note:: The kernel-doc format is deceptively similar to gtk-doc or Doxygen, + yet distinctively different, for historical reasons. The kernel source + contains tens of thousands of kernel-doc comments. Please stick to the style + described here. + +The ``scripts/kernel-doc`` script is used by the Sphinx kernel-doc extension in +the documentation build to extract this embedded documentation into the various +HTML, PDF, and other format documents. + +In order to provide good documentation of kernel functions and data structures, +please use the following conventions to format your kernel-doc comments in the +Linux kernel source. + +How to format kernel-doc comments +--------------------------------- + +The opening comment mark ``/**`` is reserved for kernel-doc comments. Only +comments so marked will be considered by the ``kernel-doc`` tool. Use it only +for comment blocks that contain kernel-doc formatted comments. The usual ``*/`` +should be used as the closing comment marker. The lines in between should be +prefixed by `` * `` (space star space). + +The function and type kernel-doc comments should be placed just before the +function or type being described. The overview kernel-doc comments may be freely +placed at the top indentation level. + +Example kernel-doc function comment:: + + /** + * foobar() - Brief description of foobar. + * @arg: Description of argument of foobar. + * + * Longer description of foobar. + * + * Return: Description of return value of foobar. + */ + int foobar(int arg) + +The format is similar for documentation for structures, enums, paragraphs, +etc. See the sections below for details. + +The kernel-doc structure is extracted from the comments, and proper `Sphinx C +Domain`_ function and type descriptions with anchors are generated for them. The +descriptions are filtered for special kernel-doc highlights and +cross-references. See below for details. + +.. _Sphinx C Domain: http://www.sphinx-doc.org/en/stable/domains.html + +Highlights and cross-references +------------------------------- + +The following special patterns are recognized in the kernel-doc comment +descriptive text and converted to proper reStructuredText markup and `Sphinx C +Domain`_ references. + +.. attention:: The below are **only** recognized within kernel-doc comments, + **not** within normal reStructuredText documents. + +``funcname()`` + Function reference. + +``@parameter`` + Name of a function parameter. (No cross-referencing, just formatting.) + +``%CONST`` + Name of a constant. (No cross-referencing, just formatting.) + +``$ENVVAR`` + Name of an environment variable. (No cross-referencing, just formatting.) + +``&struct name`` + Structure reference. + +``&enum name`` + Enum reference. + +``&typedef name`` + Typedef reference. + +``&struct_name->member`` or ``&struct_name.member`` + Structure or union member reference. The cross-reference will be to the struct + or union definition, not the member directly. + +``&name`` + A generic type reference. Prefer using the full reference described above + instead. This is mostly for legacy comments. + +Cross-referencing from reStructuredText +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To cross-reference the functions and types defined in the kernel-doc comments +from reStructuredText documents, please use the `Sphinx C Domain`_ +references. For example:: + + See function :c:func:`foo` and struct/union/enum/typedef :c:type:`bar`. + +While the type reference works with just the type name, without the +struct/union/enum/typedef part in front, you may want to use:: + + See :c:type:`struct foo <foo>`. + See :c:type:`union bar <bar>`. + See :c:type:`enum baz <baz>`. + See :c:type:`typedef meh <meh>`. + +This will produce prettier links, and is in line with how kernel-doc does the +cross-references. + +For further details, please refer to the `Sphinx C Domain`_ documentation. + +Function documentation +---------------------- + +The general format of a function and function-like macro kernel-doc comment is:: + + /** + * function_name() - Brief description of function. + * @arg1: Describe the first argument. + * @arg2: Describe the second argument. + * One can provide multiple line descriptions + * for arguments. + * + * A longer description, with more discussion of the function function_name() + * that might be useful to those using or modifying it. Begins with an + * empty comment line, and may include additional embedded empty + * comment lines. + * + * The longer description may have multiple paragraphs. + * + * Return: Describe the return value of foobar. + * + * The return value description can also have multiple paragraphs, and should + * be placed at the end of the comment block. + */ + +The brief description following the function name may span multiple lines, and +ends with an ``@argument:`` description, a blank comment line, or the end of the +comment block. + +The kernel-doc function comments describe each parameter to the function, in +order, with the ``@argument:`` descriptions. The ``@argument:`` descriptions +must begin on the very next line following the opening brief function +description line, with no intervening blank comment lines. The ``@argument:`` +descriptions may span multiple lines. The continuation lines may contain +indentation. If a function parameter is ``...`` (varargs), it should be listed +in kernel-doc notation as: ``@...:``. + +The return value, if any, should be described in a dedicated section at the end +of the comment starting with "Return:". + +Structure, union, and enumeration documentation +----------------------------------------------- + +The general format of a struct, union, and enum kernel-doc comment is:: + + /** + * struct struct_name - Brief description. + * @member_name: Description of member member_name. + * + * Description of the structure. + */ + +Below, "struct" is used to mean structs, unions and enums, and "member" is used +to mean struct and union members as well as enumerations in an enum. + +The brief description following the structure name may span multiple lines, and +ends with a ``@member:`` description, a blank comment line, or the end of the +comment block. + +The kernel-doc data structure comments describe each member of the structure, in +order, with the ``@member:`` descriptions. The ``@member:`` descriptions must +begin on the very next line following the opening brief function description +line, with no intervening blank comment lines. The ``@member:`` descriptions may +span multiple lines. The continuation lines may contain indentation. + +In-line member documentation comments +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The structure members may also be documented in-line within the definition:: + + /** + * struct foo - Brief description. + * @foo: The Foo member. + */ + struct foo { + int foo; + /** + * @bar: The Bar member. + */ + int bar; + /** + * @baz: The Baz member. + * + * Here, the member description may contain several paragraphs. + */ + int baz; + } + +Private members +~~~~~~~~~~~~~~~ + +Inside a struct description, you can use the "private:" and "public:" comment +tags. Structure fields that are inside a "private:" area are not listed in the +generated output documentation. The "private:" and "public:" tags must begin +immediately following a ``/*`` comment marker. They may optionally include +comments between the ``:`` and the ending ``*/`` marker. + +Example:: + + /** + * struct my_struct - short description + * @a: first member + * @b: second member + * + * Longer description + */ + struct my_struct { + int a; + int b; + /* private: internal use only */ + int c; + }; + + +Typedef documentation +--------------------- + +The general format of a typedef kernel-doc comment is:: + + /** + * typedef type_name - Brief description. + * + * Description of the type. + */ + +Overview documentation comments +------------------------------- + +To facilitate having source code and comments close together, you can include +kernel-doc documentation blocks that are free-form comments instead of being +kernel-doc for functions, structures, unions, enums, or typedefs. This could be +used for something like a theory of operation for a driver or library code, for +example. + +This is done by using a ``DOC:`` section keyword with a section title. + +The general format of an overview or high-level documentation comment is:: + + /** + * 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). + */ + +The title following ``DOC:`` acts as a heading within the source file, but also +as an identifier for extracting the documentation comment. Thus, the title must +be unique within the file. + +Recommendations +--------------- + +We definitely need kernel-doc formatted documentation for functions that are +exported to loadable modules using ``EXPORT_SYMBOL`` or ``EXPORT_SYMBOL_GPL``. + +We also look to provide kernel-doc formatted documentation for functions +externally visible to other kernel files (not marked "static"). + +We also recommend providing kernel-doc formatted documentation for private (file +"static") routines, for consistency of kernel source code layout. But this is +lower priority and at the discretion of the MAINTAINER of that kernel source +file. + +Data structures visible in kernel include files should also be documented using +kernel-doc formatted comments. + +DocBook XML [DEPRECATED] +======================== + +.. attention:: + + This section describes the deprecated DocBook XML toolchain. Please do not + create new DocBook XML template files. Please consider converting existing + DocBook XML templates files to Sphinx/reStructuredText. + +Converting DocBook to Sphinx +---------------------------- + +Over time, we expect all of the documents under ``Documentation/DocBook`` to be +converted to Sphinx and reStructuredText. For most DocBook XML documents, a good +enough solution is to use the simple ``Documentation/sphinx/tmplcvt`` script, +which uses ``pandoc`` under the hood. For example:: + + $ cd Documentation/sphinx + $ ./tmplcvt ../DocBook/in.tmpl ../out.rst + +Then edit the resulting rst files to fix any remaining issues, and add the +document in the ``toctree`` in ``Documentation/index.rst``. + +Components of the kernel-doc system +----------------------------------- + +Many places in the source tree have extractable documentation in the form of +block comments above functions. The components of this system are: + +- ``scripts/kernel-doc`` + + This is a perl script that hunts for the block comments and can mark them up + directly into reStructuredText, DocBook, man, text, and HTML. (No, not + texinfo.) + +- ``Documentation/DocBook/*.tmpl`` + + These are XML template files, which are normal XML files with special + place-holders for where the extracted documentation should go. + +- ``scripts/docproc.c`` + + This is a program for converting XML template files into XML files. When a + file is referenced it is searched for symbols exported (EXPORT_SYMBOL), to be + able to distinguish between internal and external functions. + + It invokes kernel-doc, giving it the list of functions that are to be + documented. + + Additionally it is used to scan the XML template files to locate all the files + referenced herein. This is used to generate dependency information as used by + make. + +- ``Makefile`` + + The targets 'xmldocs', 'psdocs', 'pdfdocs', and 'htmldocs' are used to build + DocBook XML files, PostScript files, PDF files, and html files in + Documentation/DocBook. The older target 'sgmldocs' is equivalent to 'xmldocs'. + +- ``Documentation/DocBook/Makefile`` + + This is where C files are associated with SGML templates. + +How to use kernel-doc comments in DocBook XML template files +------------------------------------------------------------ + +DocBook XML template files (\*.tmpl) are like normal XML files, except that they +can contain escape sequences where extracted documentation should be inserted. + +``!E<filename>`` is replaced by the documentation, in ``<filename>``, for +functions that are exported using ``EXPORT_SYMBOL``: the function list is +collected from files listed in ``Documentation/DocBook/Makefile``. + +``!I<filename>`` is replaced by the documentation for functions that are **not** +exported using ``EXPORT_SYMBOL``. + +``!D<filename>`` is used to name additional files to search for functions +exported using ``EXPORT_SYMBOL``. + +``!F<filename> <function [functions...]>`` is replaced by the documentation, in +``<filename>``, for the functions listed. + +``!P<filename> <section title>`` is replaced by the contents of the ``DOC:`` +section titled ``<section title>`` from ``<filename>``. Spaces are allowed in +``<section title>``; do not quote the ``<section title>``. + +``!C<filename>`` is replaced by nothing, but makes the tools check that all DOC: +sections and documented functions, symbols, etc. are used. This makes sense to +use when you use ``!F`` or ``!P`` only and want to verify that all documentation +is included. diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 82b42c958d1c7def4eac5c9931a0e8a6f9aab6c6..a2a662d4da8373e1061950209e1fc9ddf687ecce 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -3992,8 +3992,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. trace_event=[event-list] [FTRACE] Set and start specified trace events in order - to facilitate early boot debugging. - See also Documentation/trace/events.txt + to facilitate early boot debugging. The event-list is a + comma separated list of trace events to enable. See + also Documentation/trace/events.txt trace_options=[option-list] [FTRACE] Enable or disable tracer options at boot. diff --git a/Documentation/md.txt b/Documentation/md.txt index 1a2ada46aaedae5162499886ec7c532d80c84b82..d6e2fcf273375b8513955cb8024627e63805aa8b 100644 --- a/Documentation/md.txt +++ b/Documentation/md.txt @@ -602,7 +602,7 @@ These currently include stripe_cache_size (currently raid5 only) number of entries in the stripe cache. This is writable, but - there are upper and lower limits (32768, 16). Default is 128. + there are upper and lower limits (32768, 17). Default is 256. strip_cache_active (currently raid5 only) number of active entries in the stripe cache preread_bypass_threshold (currently raid5 only) diff --git a/Documentation/mic/mpssd/mpssd.c b/Documentation/mic/mpssd/mpssd.c index 30fb842a976d3ed3b9b9e1cb0bf5e1f64640dcc4..49db1def1721cdedc09b6a4e459b1cd41f82a749 100644 --- a/Documentation/mic/mpssd/mpssd.c +++ b/Documentation/mic/mpssd/mpssd.c @@ -1538,9 +1538,9 @@ set_cmdline(struct mic_info *mic) len = snprintf(buffer, PATH_MAX, "clocksource=tsc highres=off nohz=off "); - len += snprintf(buffer + len, PATH_MAX, + len += snprintf(buffer + len, PATH_MAX - len, "cpufreq_on;corec6_off;pc3_off;pc6_off "); - len += snprintf(buffer + len, PATH_MAX, + len += snprintf(buffer + len, PATH_MAX - len, "ifcfg=static;address,172.31.%d.1;netmask,255.255.255.0", mic->id + 1); diff --git a/Documentation/security/self-protection.txt b/Documentation/security/self-protection.txt index babd6378ec05730a0dd26af3ffadecc295883746..3010576c9fca047af63b668a926e6bd9f923563d 100644 --- a/Documentation/security/self-protection.txt +++ b/Documentation/security/self-protection.txt @@ -183,8 +183,9 @@ provide meaningful defenses. ### Canaries, blinding, and other secrets It should be noted that things like the stack canary discussed earlier -are technically statistical defenses, since they rely on a (leakable) -secret value. +are technically statistical defenses, since they rely on a secret value, +and such values may become discoverable through an information exposure +flaw. Blinding literal values for things like JITs, where the executable contents may be partially under the control of userspace, need a similar @@ -199,8 +200,8 @@ working?) in order to maximize their success. Since the location of kernel memory is almost always instrumental in mounting a successful attack, making the location non-deterministic raises the difficulty of an exploit. (Note that this in turn makes -the value of leaks higher, since they may be used to discover desired -memory locations.) +the value of information exposures higher, since they may be used to +discover desired memory locations.) #### Text and module base @@ -222,14 +223,21 @@ become more difficult to locate. Much of the kernel's dynamic memory (e.g. kmalloc, vmalloc, etc) ends up being relatively deterministic in layout due to the order of early-boot initializations. If the base address of these areas is not the same -between boots, targeting them is frustrated, requiring a leak specific -to the region. +between boots, targeting them is frustrated, requiring an information +exposure specific to the region. + +#### Structure layout + +By performing a per-build randomization of the layout of sensitive +structures, attacks must either be tuned to known kernel builds or expose +enough kernel memory to determine structure layouts before manipulating +them. -## Preventing Leaks +## Preventing Information Exposures Since the locations of sensitive structures are the primary target for -attacks, it is important to defend against leaks of both kernel memory +attacks, it is important to defend against exposure of both kernel memory addresses and kernel memory contents (since they may contain kernel addresses or other sensitive things like canary values). @@ -250,8 +258,8 @@ sure structure holes are cleared. When releasing memory, it is best to poison the contents (clear stack on syscall return, wipe heap memory on a free), to avoid reuse attacks that rely on the old contents of memory. This frustrates many uninitialized -variable attacks, stack info leaks, heap info leaks, and use-after-free -attacks. +variable attacks, stack content exposures, heap content exposures, and +use-after-free attacks. ### Destination tracking diff --git a/Documentation/sphinx/convert_template.sed b/Documentation/sphinx/convert_template.sed new file mode 100644 index 0000000000000000000000000000000000000000..c1503fcca4ecac1c10ff6196952947e9ee196798 --- /dev/null +++ b/Documentation/sphinx/convert_template.sed @@ -0,0 +1,18 @@ +# +# Pandoc doesn't grok <function> or <structname>, so convert them +# ahead of time. +# +# Use the following escapes to pass through pandoc: +# $bq = "`" +# $lt = "<" +# $gt = ">" +# +s%<function>\([^<(]\+\)()</function>%:c:func:$bq\1()$bq%g +s%<function>\([^<(]\+\)</function>%:c:func:$bq\1()$bq%g +s%<structname>struct *\([^<]\+\)</structname>%:c:type:$bqstruct \1 $lt\1$gt$bq%g +s%struct <structname>\([^<]\+\)</structname>%:c:type:$bqstruct \1 $lt\1$gt$bq%g +s%<structname>\([^<]\+\)</structname>%:c:type:$bqstruct \1 $lt\1$gt$bq%g +# +# Wrap docproc directives in para and code blocks. +# +s%^\(!.*\)$%<para><code>DOCPROC: \1</code></para>% diff --git a/Documentation/sphinx/kernel-doc.py b/Documentation/sphinx/kernel-doc.py new file mode 100644 index 0000000000000000000000000000000000000000..dedb24e3bb7ab4035f4f324bfc55d5c060c898b2 --- /dev/null +++ b/Documentation/sphinx/kernel-doc.py @@ -0,0 +1,135 @@ +# coding=utf-8 +# +# Copyright © 2016 Intel Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. +# +# Authors: +# Jani Nikula <jani.nikula@intel.com> +# +# Please make sure this works on both python2 and python3. +# + +import os +import subprocess +import sys +import re +import glob + +from docutils import nodes, statemachine +from docutils.statemachine import ViewList +from docutils.parsers.rst import directives +from sphinx.util.compat import Directive + +class KernelDocDirective(Directive): + """Extract kernel-doc comments from the specified file""" + required_argument = 1 + optional_arguments = 4 + option_spec = { + 'doc': directives.unchanged_required, + 'functions': directives.unchanged_required, + 'export': directives.unchanged, + 'internal': directives.unchanged, + } + has_content = False + + def run(self): + env = self.state.document.settings.env + cmd = [env.config.kerneldoc_bin, '-rst', '-enable-lineno'] + + filename = env.config.kerneldoc_srctree + '/' + self.arguments[0] + export_file_patterns = [] + + # Tell sphinx of the dependency + env.note_dependency(os.path.abspath(filename)) + + tab_width = self.options.get('tab-width', self.state.document.settings.tab_width) + + # FIXME: make this nicer and more robust against errors + if 'export' in self.options: + cmd += ['-export'] + export_file_patterns = str(self.options.get('export')).split() + elif 'internal' in self.options: + cmd += ['-internal'] + export_file_patterns = str(self.options.get('internal')).split() + elif 'doc' in self.options: + cmd += ['-function', str(self.options.get('doc'))] + elif 'functions' in self.options: + for f in str(self.options.get('functions')).split(): + cmd += ['-function', f] + + for pattern in export_file_patterns: + for f in glob.glob(env.config.kerneldoc_srctree + '/' + pattern): + env.note_dependency(os.path.abspath(f)) + cmd += ['-export-file', f] + + cmd += [filename] + + try: + env.app.verbose('calling kernel-doc \'%s\'' % (" ".join(cmd))) + + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) + out, err = p.communicate() + + # python2 needs conversion to unicode. + # python3 with universal_newlines=True returns strings. + if sys.version_info.major < 3: + out, err = unicode(out, 'utf-8'), unicode(err, 'utf-8') + + if p.returncode != 0: + sys.stderr.write(err) + + env.app.warn('kernel-doc \'%s\' failed with return code %d' % (" ".join(cmd), p.returncode)) + return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))] + elif env.config.kerneldoc_verbosity > 0: + sys.stderr.write(err) + + lines = statemachine.string2lines(out, tab_width, convert_whitespace=True) + result = ViewList() + + lineoffset = 0; + line_regex = re.compile("^#define LINENO ([0-9]+)$") + for line in lines: + match = line_regex.search(line) + if match: + # sphinx counts lines from 0 + lineoffset = int(match.group(1)) - 1 + # we must eat our comments since the upset the markup + else: + result.append(line, filename, lineoffset) + lineoffset += 1 + + node = nodes.section() + node.document = self.state.document + self.state.nested_parse(result, self.content_offset, node) + + return node.children + + except Exception as e: + env.app.warn('kernel-doc \'%s\' processing failed with: %s' % + (" ".join(cmd), str(e))) + return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))] + +def setup(app): + app.add_config_value('kerneldoc_bin', None, 'env') + app.add_config_value('kerneldoc_srctree', None, 'env') + app.add_config_value('kerneldoc_verbosity', 1, 'env') + + app.add_directive('kernel-doc', KernelDocDirective) diff --git a/Documentation/sphinx/post_convert.sed b/Documentation/sphinx/post_convert.sed new file mode 100644 index 0000000000000000000000000000000000000000..392770bac53b79ac0814c02fde26d61fc2935fcb --- /dev/null +++ b/Documentation/sphinx/post_convert.sed @@ -0,0 +1,23 @@ +# +# Unescape. +# +s/$bq/`/g +s/$lt/</g +s/$gt/>/g +# +# pandoc thinks that both "_" needs to be escaped. Remove the extra +# backslashes. +# +s/\\_/_/g +# +# Unwrap docproc directives. +# +s/^``DOCPROC: !E\(.*\)``$/.. kernel-doc:: \1\n :export:/ +s/^``DOCPROC: !I\(.*\)``$/.. kernel-doc:: \1\n :internal:/ +s/^``DOCPROC: !F\([^ ]*\) \(.*\)``$/.. kernel-doc:: \1\n :functions: \2/ +s/^``DOCPROC: !P\([^ ]*\) \(.*\)``$/.. kernel-doc:: \1\n :doc: \2/ +s/^``DOCPROC: \(!.*\)``$/.. WARNING: DOCPROC directive not supported: \1/ +# +# Trim trailing whitespace. +# +s/[[:space:]]*$// diff --git a/Documentation/sphinx/rstFlatTable.py b/Documentation/sphinx/rstFlatTable.py new file mode 100644 index 0000000000000000000000000000000000000000..26db852e3c745ed9b4e134198b3ea716552633f6 --- /dev/null +++ b/Documentation/sphinx/rstFlatTable.py @@ -0,0 +1,365 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8; mode: python -*- +# pylint: disable=C0330, R0903, R0912 + +u""" + flat-table + ~~~~~~~~~~ + + Implementation of the ``flat-table`` reST-directive. + + :copyright: Copyright (C) 2016 Markus Heiser + :license: GPL Version 2, June 1991 see linux/COPYING for details. + + The ``flat-table`` (:py:class:`FlatTable`) is a double-stage list similar to + the ``list-table`` with some additional features: + + * *column-span*: with the role ``cspan`` a cell can be extended through + additional columns + + * *row-span*: with the role ``rspan`` a cell can be extended through + additional rows + + * *auto span* rightmost cell of a table row over the missing cells on the + right side of that table-row. With Option ``:fill-cells:`` this behavior + can changed from *auto span* to *auto fill*, which automaticly inserts + (empty) cells instead of spanning the last cell. + + Options: + + * header-rows: [int] count of header rows + * stub-columns: [int] count of stub columns + * widths: [[int] [int] ... ] widths of columns + * fill-cells: instead of autospann missing cells, insert missing cells + + roles: + + * cspan: [int] additionale columns (*morecols*) + * rspan: [int] additionale rows (*morerows*) +""" + +# ============================================================================== +# imports +# ============================================================================== + +import sys + +from docutils import nodes +from docutils.parsers.rst import directives, roles +from docutils.parsers.rst.directives.tables import Table +from docutils.utils import SystemMessagePropagation + +# ============================================================================== +# common globals +# ============================================================================== + +# The version numbering follows numbering of the specification +# (Documentation/books/kernel-doc-HOWTO). +__version__ = '1.0' + +PY3 = sys.version_info[0] == 3 +PY2 = sys.version_info[0] == 2 + +if PY3: + # pylint: disable=C0103, W0622 + unicode = str + basestring = str + +# ============================================================================== +def setup(app): +# ============================================================================== + + app.add_directive("flat-table", FlatTable) + roles.register_local_role('cspan', c_span) + roles.register_local_role('rspan', r_span) + +# ============================================================================== +def c_span(name, rawtext, text, lineno, inliner, options=None, content=None): +# ============================================================================== + # pylint: disable=W0613 + + options = options if options is not None else {} + content = content if content is not None else [] + nodelist = [colSpan(span=int(text))] + msglist = [] + return nodelist, msglist + +# ============================================================================== +def r_span(name, rawtext, text, lineno, inliner, options=None, content=None): +# ============================================================================== + # pylint: disable=W0613 + + options = options if options is not None else {} + content = content if content is not None else [] + nodelist = [rowSpan(span=int(text))] + msglist = [] + return nodelist, msglist + + +# ============================================================================== +class rowSpan(nodes.General, nodes.Element): pass # pylint: disable=C0103,C0321 +class colSpan(nodes.General, nodes.Element): pass # pylint: disable=C0103,C0321 +# ============================================================================== + +# ============================================================================== +class FlatTable(Table): +# ============================================================================== + + u"""FlatTable (``flat-table``) directive""" + + option_spec = { + 'name': directives.unchanged + , 'class': directives.class_option + , 'header-rows': directives.nonnegative_int + , 'stub-columns': directives.nonnegative_int + , 'widths': directives.positive_int_list + , 'fill-cells' : directives.flag } + + def run(self): + + if not self.content: + error = self.state_machine.reporter.error( + 'The "%s" directive is empty; content required.' % self.name, + nodes.literal_block(self.block_text, self.block_text), + line=self.lineno) + return [error] + + title, messages = self.make_title() + node = nodes.Element() # anonymous container for parsing + self.state.nested_parse(self.content, self.content_offset, node) + + tableBuilder = ListTableBuilder(self) + tableBuilder.parseFlatTableNode(node) + tableNode = tableBuilder.buildTableNode() + # SDK.CONSOLE() # print --> tableNode.asdom().toprettyxml() + if title: + tableNode.insert(0, title) + return [tableNode] + messages + + +# ============================================================================== +class ListTableBuilder(object): +# ============================================================================== + + u"""Builds a table from a double-stage list""" + + def __init__(self, directive): + self.directive = directive + self.rows = [] + self.max_cols = 0 + + def buildTableNode(self): + + colwidths = self.directive.get_column_widths(self.max_cols) + stub_columns = self.directive.options.get('stub-columns', 0) + header_rows = self.directive.options.get('header-rows', 0) + + table = nodes.table() + tgroup = nodes.tgroup(cols=len(colwidths)) + table += tgroup + + + for colwidth in colwidths: + colspec = nodes.colspec(colwidth=colwidth) + # FIXME: It seems, that the stub method only works well in the + # absence of rowspan (observed by the html buidler, the docutils-xml + # build seems OK). This is not extraordinary, because there exists + # no table directive (except *this* flat-table) which allows to + # define coexistent of rowspan and stubs (there was no use-case + # before flat-table). This should be reviewed (later). + if stub_columns: + colspec.attributes['stub'] = 1 + stub_columns -= 1 + tgroup += colspec + stub_columns = self.directive.options.get('stub-columns', 0) + + if header_rows: + thead = nodes.thead() + tgroup += thead + for row in self.rows[:header_rows]: + thead += self.buildTableRowNode(row) + + tbody = nodes.tbody() + tgroup += tbody + + for row in self.rows[header_rows:]: + tbody += self.buildTableRowNode(row) + return table + + def buildTableRowNode(self, row_data, classes=None): + classes = [] if classes is None else classes + row = nodes.row() + for cell in row_data: + if cell is None: + continue + cspan, rspan, cellElements = cell + + attributes = {"classes" : classes} + if rspan: + attributes['morerows'] = rspan + if cspan: + attributes['morecols'] = cspan + entry = nodes.entry(**attributes) + entry.extend(cellElements) + row += entry + return row + + def raiseError(self, msg): + error = self.directive.state_machine.reporter.error( + msg + , nodes.literal_block(self.directive.block_text + , self.directive.block_text) + , line = self.directive.lineno ) + raise SystemMessagePropagation(error) + + def parseFlatTableNode(self, node): + u"""parses the node from a :py:class:`FlatTable` directive's body""" + + if len(node) != 1 or not isinstance(node[0], nodes.bullet_list): + self.raiseError( + 'Error parsing content block for the "%s" directive: ' + 'exactly one bullet list expected.' % self.directive.name ) + + for rowNum, rowItem in enumerate(node[0]): + row = self.parseRowItem(rowItem, rowNum) + self.rows.append(row) + self.roundOffTableDefinition() + + def roundOffTableDefinition(self): + u"""Round off the table definition. + + This method rounds off the table definition in :py:member:`rows`. + + * This method inserts the needed ``None`` values for the missing cells + arising from spanning cells over rows and/or columns. + + * recount the :py:member:`max_cols` + + * Autospan or fill (option ``fill-cells``) missing cells on the right + side of the table-row + """ + + y = 0 + while y < len(self.rows): + x = 0 + + while x < len(self.rows[y]): + cell = self.rows[y][x] + if cell is None: + x += 1 + continue + cspan, rspan = cell[:2] + # handle colspan in current row + for c in range(cspan): + try: + self.rows[y].insert(x+c+1, None) + except: # pylint: disable=W0702 + # the user sets ambiguous rowspans + pass # SDK.CONSOLE() + # handle colspan in spanned rows + for r in range(rspan): + for c in range(cspan + 1): + try: + self.rows[y+r+1].insert(x+c, None) + except: # pylint: disable=W0702 + # the user sets ambiguous rowspans + pass # SDK.CONSOLE() + x += 1 + y += 1 + + # Insert the missing cells on the right side. For this, first + # re-calculate the max columns. + + for row in self.rows: + if self.max_cols < len(row): + self.max_cols = len(row) + + # fill with empty cells or cellspan? + + fill_cells = False + if 'fill-cells' in self.directive.options: + fill_cells = True + + for row in self.rows: + x = self.max_cols - len(row) + if x and not fill_cells: + if row[-1] is None: + row.append( ( x - 1, 0, []) ) + else: + cspan, rspan, content = row[-1] + row[-1] = (cspan + x, rspan, content) + elif x and fill_cells: + for i in range(x): + row.append( (0, 0, nodes.comment()) ) + + def pprint(self): + # for debugging + retVal = "[ " + for row in self.rows: + retVal += "[ " + for col in row: + if col is None: + retVal += ('%r' % col) + retVal += "\n , " + else: + content = col[2][0].astext() + if len (content) > 30: + content = content[:30] + "..." + retVal += ('(cspan=%s, rspan=%s, %r)' + % (col[0], col[1], content)) + retVal += "]\n , " + retVal = retVal[:-2] + retVal += "]\n , " + retVal = retVal[:-2] + return retVal + "]" + + def parseRowItem(self, rowItem, rowNum): + row = [] + childNo = 0 + error = False + cell = None + target = None + + for child in rowItem: + if (isinstance(child , nodes.comment) + or isinstance(child, nodes.system_message)): + pass + elif isinstance(child , nodes.target): + target = child + elif isinstance(child, nodes.bullet_list): + childNo += 1 + cell = child + else: + error = True + break + + if childNo != 1 or error: + self.raiseError( + 'Error parsing content block for the "%s" directive: ' + 'two-level bullet list expected, but row %s does not ' + 'contain a second-level bullet list.' + % (self.directive.name, rowNum + 1)) + + for cellItem in cell: + cspan, rspan, cellElements = self.parseCellItem(cellItem) + if target is not None: + cellElements.insert(0, target) + row.append( (cspan, rspan, cellElements) ) + return row + + def parseCellItem(self, cellItem): + # search and remove cspan, rspan colspec from the first element in + # this listItem (field). + cspan = rspan = 0 + if not len(cellItem): + return cspan, rspan, [] + for elem in cellItem[0]: + if isinstance(elem, colSpan): + cspan = elem.get("span") + elem.parent.remove(elem) + continue + if isinstance(elem, rowSpan): + rspan = elem.get("span") + elem.parent.remove(elem) + continue + return cspan, rspan, cellItem[:] diff --git a/Documentation/sphinx/tmplcvt b/Documentation/sphinx/tmplcvt new file mode 100755 index 0000000000000000000000000000000000000000..909a73065e0a5b9c0b4d680b94d2e738698f606c --- /dev/null +++ b/Documentation/sphinx/tmplcvt @@ -0,0 +1,19 @@ +#!/bin/bash +# +# Convert a template file into something like RST +# +# fix <function> +# feed to pandoc +# fix \_ +# title line? +# + +in=$1 +rst=$2 +tmp=$rst.tmp + +cp $in $tmp +sed --in-place -f convert_template.sed $tmp +pandoc -s -S -f docbook -t rst -o $rst $tmp +sed --in-place -f post_convert.sed $rst +rm $tmp diff --git a/Documentation/sync_file.txt b/Documentation/sync_file.txt index eaf8297dbca23cfeeeeb7b21b97385715246f451..e8e2ebafe5fa0ea350af12b5103788e3d04de268 100644 --- a/Documentation/sync_file.txt +++ b/Documentation/sync_file.txt @@ -6,8 +6,8 @@ This document serves as a guide for device drivers writers on what the sync_file API is, and how drivers can support it. Sync file is the carrier of -the fences(struct fence) that needs to synchronized between drivers or across -process boundaries. +the fences(struct fence) that are needed to synchronize between drivers or +across process boundaries. The sync_file API is meant to be used to send and receive fence information to/from userspace. It enables userspace to do explicit fencing, where instead @@ -32,7 +32,7 @@ in-fences and out-fences Sync files can go either to or from userspace. When a sync_file is sent from the driver to userspace we call the fences it contains 'out-fences'. They are related to a buffer that the driver is processing or is going to process, so -the driver an create out-fence to be able to notify, through fence_signal(), +the driver creates an out-fence to be able to notify, through fence_signal(), when it has finished using (or processing) that buffer. Out-fences are fences that the driver creates. diff --git a/Documentation/thermal/intel_powerclamp.txt b/Documentation/thermal/intel_powerclamp.txt index 332de4a39b5a6443b9347f8354e03177b735e2d3..60073dc9f7489c8eba82b6f4910f08c5176f1062 100644 --- a/Documentation/thermal/intel_powerclamp.txt +++ b/Documentation/thermal/intel_powerclamp.txt @@ -121,7 +121,7 @@ time is considered largely as a non-causal system where its behavior cannot be based on the past or current input. Therefore, the intel_powerclamp driver attempts to enforce the desired idle time instantly as given input (target idle ratio). After injection, -powerclamp moniors the actual idle for a given time window and adjust +powerclamp monitors the actual idle for a given time window and adjust the next injection accordingly to avoid over/under correction. When used in a causal control system, such as a temperature control, diff --git a/Documentation/usb/gadget_multi.txt b/Documentation/usb/gadget_multi.txt index 5faf514047e9f8f9c52d5a1549221cccc0090a45..b3146dd7aa4362dd0ce3337ef4c29d04be5a3e32 100644 --- a/Documentation/usb/gadget_multi.txt +++ b/Documentation/usb/gadget_multi.txt @@ -36,7 +36,7 @@ configuration with CDC ECM which should work better under Linux. ** Windows host drivers -For the gadget two work under Windows two conditions have to be met: +For the gadget to work under Windows two conditions have to be met: *** Detecting as composite gadget diff --git a/Documentation/zh_CN/CodingStyle b/Documentation/zh_CN/CodingStyle index 654afd72eb24762e926440656355352c5253eaba..bbb9d6ae05ca1ea688bedc854ea9ff7652eb6295 100644 --- a/Documentation/zh_CN/CodingStyle +++ b/Documentation/zh_CN/CodingStyle @@ -24,34 +24,33 @@ Documentation/CodingStyleçš„ä¸æ–‡ç¿»è¯‘ Linuxå†…æ ¸ä»£ç é£Žæ ¼ -这是一个简çŸçš„文档,æ述了linuxå†…æ ¸çš„é¦–é€‰ä»£ç é£Žæ ¼ã€‚ä»£ç é£Žæ ¼æ˜¯å› äººè€Œå¼‚çš„ï¼Œè€Œä¸”æˆ‘ -ä¸æ„¿æ„æŠŠæˆ‘çš„è§‚ç‚¹å¼ºåŠ ç»™ä»»ä½•äººï¼Œä¸è¿‡è¿™é‡Œæ‰€è®²è¿°çš„是我必须è¦ç»´æŠ¤çš„代ç 所éµå®ˆçš„é£Žæ ¼ï¼Œ -并且我也希望ç»å¤§å¤šæ•°å…¶ä»–代ç 也能éµå®ˆè¿™ä¸ªé£Žæ ¼ã€‚请在写代ç 时至少考虑一下本文所述的 -é£Žæ ¼ã€‚ +这是一个简çŸçš„文档,æ述了 linux å†…æ ¸çš„é¦–é€‰ä»£ç é£Žæ ¼ã€‚ä»£ç é£Žæ ¼æ˜¯å› äººè€Œå¼‚çš„ï¼Œè€Œä¸”æˆ‘ +ä¸æ„¿æ„æŠŠè‡ªå·±çš„è§‚ç‚¹å¼ºåŠ ç»™ä»»ä½•äººï¼Œä½†è¿™å°±åƒæˆ‘去åšä»»ä½•äº‹æƒ…都必须éµå¾ªçš„åŽŸåˆ™é‚£æ ·ï¼Œæˆ‘ä¹Ÿ +希望在ç»å¤§å¤šæ•°äº‹ä¸Šä¿æŒè¿™ç§çš„æ€åº¦ã€‚请(在写代ç 时)至少考虑一下这里的代ç é£Žæ ¼ã€‚ -é¦–å…ˆï¼Œæˆ‘å»ºè®®ä½ æ‰“å°ä¸€ä»½GNU代ç 规范,然åŽä¸è¦è¯»å®ƒã€‚烧了它,这是一个具有é‡å¤§è±¡å¾æ€§ -æ„义的动作。 +é¦–å…ˆï¼Œæˆ‘å»ºè®®ä½ æ‰“å°ä¸€ä»½ GNU 代ç 规范,然åŽä¸è¦è¯»ã€‚烧了它,这是一个具有é‡å¤§è±¡å¾æ€§æ„义 +的动作。 ä¸ç®¡æ€Žæ ·ï¼ŒçŽ°åœ¨æˆ‘们开始: - ç¬¬ä¸€ç« ï¼šç¼©è¿› + ç¬¬ä¸€ç« ï¼šç¼©è¿› -制表符是8个å—符,所以缩进也是8个å—符。有些异端è¿åŠ¨è¯•å›¾å°†ç¼©è¿›å˜ä¸º4(乃至2)个å—符 -æ·±ï¼Œè¿™å‡ ä¹Žç›¸å½“äºŽå°è¯•å°†åœ†å‘¨çŽ‡çš„值定义为3。 +制表符是 8 个å—符,所以缩进也是 8 个å—符。有些异端è¿åŠ¨è¯•å›¾å°†ç¼©è¿›å˜ä¸º 4(甚至 2ï¼ï¼‰ +个å—ç¬¦æ·±ï¼Œè¿™å‡ ä¹Žç›¸å½“äºŽå°è¯•å°†åœ†å‘¨çŽ‡çš„值定义为 3。 ç†ç”±ï¼šç¼©è¿›çš„全部æ„义就在于清楚的定义一个控制å—èµ·æ¢äºŽä½•å¤„ã€‚å°¤å…¶æ˜¯å½“ä½ ç›¯ç€ä½ çš„å±å¹• -è¿žç»çœ‹äº†20å°æ—¶ä¹‹åŽï¼Œä½ 将会å‘çŽ°å¤§ä¸€ç‚¹çš„ç¼©è¿›ä¼šä½¿ä½ æ›´å®¹æ˜“åˆ†è¾¨ç¼©è¿›ã€‚ +è¿žç»çœ‹äº† 20 å°æ—¶ä¹‹åŽï¼Œä½ 将会å‘çŽ°å¤§ä¸€ç‚¹çš„ç¼©è¿›ä¼šä½¿ä½ æ›´å®¹æ˜“åˆ†è¾¨ç¼©è¿›ã€‚ -现在,有些人会抱怨8个å—符的缩进会使代ç å‘å³è¾¹ç§»åŠ¨çš„太远,在80个å—符的终端å±å¹•ä¸Š -å°±å¾ˆéš¾è¯»è¿™æ ·çš„ä»£ç 。这个问题的ç”æ¡ˆæ˜¯ï¼Œå¦‚æžœä½ éœ€è¦3级以上的缩进,ä¸ç®¡ç”¨ä½•ç§æ–¹å¼ä½ +现在,有些人会抱怨 8 个å—符的缩进会使代ç å‘å³è¾¹ç§»åŠ¨çš„太远,在 80 个å—符的终端å±å¹•ä¸Š +å°±å¾ˆéš¾è¯»è¿™æ ·çš„ä»£ç 。这个问题的ç”æ¡ˆæ˜¯ï¼Œå¦‚æžœä½ éœ€è¦ 3 级以上的缩进,ä¸ç®¡ç”¨ä½•ç§æ–¹å¼ä½ 的代ç å·²ç»æœ‰é—®é¢˜äº†ï¼Œåº”该修æ£ä½ 的程åºã€‚ -简而言之,8个å—符的缩进å¯ä»¥è®©ä»£ç æ›´å®¹æ˜“é˜…è¯»ï¼Œè¿˜æœ‰ä¸€ä¸ªå¥½å¤„æ˜¯å½“ä½ çš„å‡½æ•°åµŒå¥—å¤ªæ·±çš„ +简而言之,8 个å—符的缩进å¯ä»¥è®©ä»£ç æ›´å®¹æ˜“é˜…è¯»ï¼Œè¿˜æœ‰ä¸€ä¸ªå¥½å¤„æ˜¯å½“ä½ çš„å‡½æ•°åµŒå¥—å¤ªæ·±çš„ 时候å¯ä»¥ç»™ä½ è¦å‘Šã€‚留心这个è¦å‘Šã€‚ -在switchè¯å¥ä¸æ¶ˆé™¤å¤šçº§ç¼©è¿›çš„首选的方å¼æ˜¯è®©â€œswitchâ€å’Œä»Žå±žäºŽå®ƒçš„“caseâ€æ ‡ç¾å¯¹é½äºŽåŒ -一列,而ä¸è¦â€œä¸¤æ¬¡ç¼©è¿›â€â€œcaseâ€æ ‡ç¾ã€‚比如: +在 switch è¯å¥ä¸æ¶ˆé™¤å¤šçº§ç¼©è¿›çš„首选的方å¼æ˜¯è®© “switch†和从属于它的 “caseâ€ æ ‡ç¾ +对é½äºŽåŒä¸€åˆ—,而ä¸è¦ “两次缩进†“caseâ€ æ ‡ç¾ã€‚比如: switch (suffix) { case 'G': @@ -70,7 +69,6 @@ Documentation/CodingStyleçš„ä¸æ–‡ç¿»è¯‘ break; } - ä¸è¦æŠŠå¤šä¸ªè¯å¥æ”¾åœ¨ä¸€è¡Œé‡Œï¼Œé™¤éžä½ 有什么东西è¦éšè—: if (condition) do_this; @@ -79,7 +77,7 @@ Documentation/CodingStyleçš„ä¸æ–‡ç¿»è¯‘ 也ä¸è¦åœ¨ä¸€è¡Œé‡Œæ”¾å¤šä¸ªèµ‹å€¼è¯å¥ã€‚å†…æ ¸ä»£ç é£Žæ ¼è¶…çº§ç®€å•ã€‚就是é¿å…å¯èƒ½å¯¼è‡´åˆ«äººè¯¯è¯»çš„表 è¾¾å¼ã€‚ -除了注释ã€æ–‡æ¡£å’ŒKconfig之外,ä¸è¦ä½¿ç”¨ç©ºæ ¼æ¥ç¼©è¿›ï¼Œå‰é¢çš„例å是例外,是有æ„为之。 +除了注释ã€æ–‡æ¡£å’Œ Kconfig 之外,ä¸è¦ä½¿ç”¨ç©ºæ ¼æ¥ç¼©è¿›ï¼Œå‰é¢çš„例å是例外,是有æ„为之。 选用一个好的编辑器,ä¸è¦åœ¨è¡Œå°¾ç•™ç©ºæ ¼ã€‚ @@ -88,27 +86,18 @@ Documentation/CodingStyleçš„ä¸æ–‡ç¿»è¯‘ 代ç é£Žæ ¼çš„æ„义就在于使用平常使用的工具æ¥ç»´æŒä»£ç çš„å¯è¯»æ€§å’Œå¯ç»´æŠ¤æ€§ã€‚ -æ¯ä¸€è¡Œçš„长度的é™åˆ¶æ˜¯80列,我们强烈建议您éµå®ˆè¿™ä¸ªæƒ¯ä¾‹ã€‚ +æ¯ä¸€è¡Œçš„长度的é™åˆ¶æ˜¯ 80 列,我们强烈建议您éµå®ˆè¿™ä¸ªæƒ¯ä¾‹ã€‚ -长于80列的è¯å¥è¦æ‰“æ•£æˆæœ‰æ„义的片段。æ¯ä¸ªç‰‡æ®µè¦æ˜Žæ˜¾çŸäºŽåŽŸæ¥çš„è¯å¥ï¼Œè€Œä¸”放置的ä½ç½® -也明显的é å³ã€‚åŒæ ·çš„规则也适用于有很长å‚数列表的函数头。长å—符串也è¦æ‰“æ•£æˆè¾ƒçŸçš„ -å—符串。唯一的例外是超过80列å¯ä»¥å¤§å¹…度æ高å¯è¯»æ€§å¹¶ä¸”ä¸ä¼šéšè—ä¿¡æ¯çš„情况。 - -void fun(int a, int b, int c) -{ - if (condition) - printk(KERN_WARNING "Warning this is a long printk with " - "3 parameters a: %u b: %u " - "c: %u \n", a, b, c); - else - next_statement; -} +长于 80 列的è¯å¥è¦æ‰“æ•£æˆæœ‰æ„义的片段。除éžè¶…过 80 åˆ—èƒ½æ˜¾è‘—å¢žåŠ å¯è¯»æ€§ï¼Œå¹¶ä¸”ä¸ä¼šéšè— +ä¿¡æ¯ã€‚å片段è¦æ˜Žæ˜¾çŸäºŽæ¯ç‰‡æ®µï¼Œå¹¶æ˜Žæ˜¾é å³ã€‚è¿™åŒæ ·é€‚用于有ç€å¾ˆé•¿å‚数列表的函数头。 +然而,ç»å¯¹ä¸è¦æ‰“散对用户å¯è§çš„å—符串,例如 printk ä¿¡æ¯ï¼Œå› ä¸ºè¿™å°†å¯¼è‡´æ— æ³• grep 这些 +ä¿¡æ¯ã€‚ ç¬¬ä¸‰ç« ï¼šå¤§æ‹¬å·å’Œç©ºæ ¼çš„放置 Cè¯è¨€é£Žæ ¼ä¸å¦å¤–一个常è§é—®é¢˜æ˜¯å¤§æ‹¬å·çš„放置。和缩进大å°ä¸åŒï¼Œé€‰æ‹©æˆ–弃用æŸç§æ”¾ç½®ç– -ç•¥å¹¶æ²¡æœ‰å¤šå°‘æŠ€æœ¯ä¸Šçš„åŽŸå› ï¼Œä¸è¿‡é¦–选的方å¼ï¼Œå°±åƒKernighanå’ŒRitchie展示给我们的,是 -把起始大括å·æ”¾åœ¨è¡Œå°¾ï¼Œè€ŒæŠŠç»“æŸå¤§æ‹¬å·æ”¾åœ¨è¡Œé¦–,所以: +ç•¥å¹¶æ²¡æœ‰å¤šå°‘æŠ€æœ¯ä¸Šçš„åŽŸå› ï¼Œä¸è¿‡é¦–选的方å¼ï¼Œå°±åƒ Kernighan å’Œ Ritchie 展示给我们的, +是把起始大括å·æ”¾åœ¨è¡Œå°¾ï¼Œè€ŒæŠŠç»“æŸå¤§æ‹¬å·æ”¾åœ¨è¡Œé¦–,所以: if (x is true) { we do y @@ -134,12 +123,12 @@ Cè¯è¨€é£Žæ ¼ä¸å¦å¤–一个常è§é—®é¢˜æ˜¯å¤§æ‹¬å·çš„æ”¾ç½®ã€‚å’Œç¼©è¿›å¤§å° body of function } -全世界的异端å¯èƒ½ä¼šæŠ±æ€¨è¿™ä¸ªä¸ä¸€è‡´æ€§æ˜¯â€¦â€¦å‘ƒâ€¦â€¦ä¸ä¸€è‡´çš„,ä¸è¿‡æ‰€æœ‰æ€ç»´å¥å…¨çš„人都知é“( -a)K&R是_æ£ç¡®çš„_,并且(b)K&R是æ£ç¡®çš„。æ¤å¤–,ä¸ç®¡æ€Žæ ·å‡½æ•°éƒ½æ˜¯ç‰¹æ®Šçš„(在Cè¯è¨€ä¸ -,函数是ä¸èƒ½åµŒå¥—的)。 +全世界的异端å¯èƒ½ä¼šæŠ±æ€¨è¿™ä¸ªä¸ä¸€è‡´æ€§æ˜¯â€¦â€¦å‘ƒâ€¦â€¦ä¸ä¸€è‡´çš„,ä¸è¿‡æ‰€æœ‰æ€ç»´å¥å…¨çš„äººéƒ½çŸ¥é“ +(a) K&R 是 _æ£ç¡®çš„_,并且 (b) K&R 是æ£ç¡®çš„。æ¤å¤–,ä¸ç®¡æ€Žæ ·å‡½æ•°éƒ½æ˜¯ç‰¹æ®Šçš„(C +函数是ä¸èƒ½åµŒå¥—的)。 -注æ„结æŸå¤§æ‹¬å·ç‹¬è‡ªå æ®ä¸€è¡Œï¼Œé™¤éžå®ƒåŽé¢è·Ÿç€åŒä¸€ä¸ªè¯å¥çš„剩余部分,也就是doè¯å¥ä¸çš„ -“whileâ€æˆ–者ifè¯å¥ä¸çš„“elseâ€ï¼Œåƒè¿™æ ·ï¼š +注æ„结æŸå¤§æ‹¬å·ç‹¬è‡ªå æ®ä¸€è¡Œï¼Œé™¤éžå®ƒåŽé¢è·Ÿç€åŒä¸€ä¸ªè¯å¥çš„剩余部分,也就是 do è¯å¥ä¸çš„ +“while†或者 if è¯å¥ä¸çš„ “elseâ€ï¼Œåƒè¿™æ ·ï¼š do { body of do-loop @@ -158,41 +147,50 @@ a)K&R是_æ£ç¡®çš„_,并且(b)K&R是æ£ç¡®çš„。æ¤å¤–,ä¸ç®¡æ€Žæ ·å‡½ ç†ç”±ï¼šK&R。 也请注æ„è¿™ç§å¤§æ‹¬å·çš„放置方å¼ä¹Ÿèƒ½ä½¿ç©ºï¼ˆæˆ–者差ä¸å¤šç©ºçš„)行的数é‡æœ€å°åŒ–,åŒæ—¶ä¸å¤±å¯ -è¯»æ€§ã€‚å› æ¤ï¼Œç”±äºŽä½ çš„å±å¹•ä¸Šçš„新行是ä¸å¯å†ç”Ÿèµ„æºï¼ˆæƒ³æƒ³25行的终端å±å¹•ï¼‰ï¼Œä½ 将会有更 +è¯»æ€§ã€‚å› æ¤ï¼Œç”±äºŽä½ çš„å±å¹•ä¸Šçš„新行是ä¸å¯å†ç”Ÿèµ„æºï¼ˆæƒ³æƒ³ 25 行的终端å±å¹•ï¼‰ï¼Œä½ 将会有更 多的空行æ¥æ”¾ç½®æ³¨é‡Šã€‚ 当åªæœ‰ä¸€ä¸ªå•ç‹¬çš„è¯å¥çš„时候,ä¸ç”¨åŠ ä¸å¿…è¦çš„大括å·ã€‚ -if (condition) - action(); + if (condition) + action(); + +å’Œ + + if (condition) + do_this(); + else + do_that(); -这点ä¸é€‚用于本身为æŸä¸ªæ¡ä»¶è¯å¥çš„一个分支的å•ç‹¬è¯å¥ã€‚这时需è¦åœ¨ä¸¤ä¸ªåˆ†æ”¯é‡Œéƒ½ä½¿ç”¨å¤§ -括å·ã€‚ +这并ä¸é€‚用于åªæœ‰ä¸€ä¸ªæ¡ä»¶åˆ†æ”¯æ˜¯å•è¯å¥çš„情况;这时所有分支都è¦ä½¿ç”¨å¤§æ‹¬å·ï¼š -if (condition) { - do_this(); - do_that(); -} else { - otherwise(); -} + if (condition) { + do_this(); + do_that(); + } else { + otherwise(); + } 3.1ï¼šç©ºæ ¼ -Linuxå†…æ ¸çš„ç©ºæ ¼ä½¿ç”¨æ–¹å¼ï¼ˆä¸»è¦ï¼‰å–决于它是用于函数还是关键å—。(大多数)关键å—åŽ -è¦åŠ ä¸€ä¸ªç©ºæ ¼ã€‚å€¼å¾—æ³¨æ„的例外是sizeofã€typeofã€alignofå’Œ__attribute__ï¼Œè¿™äº›å…³é”®å— -æŸäº›ç¨‹åº¦ä¸Šçœ‹èµ·æ¥æ›´åƒå‡½æ•°ï¼ˆå®ƒä»¬åœ¨Linux里也常常伴éšå°æ‹¬å·è€Œä½¿ç”¨ï¼Œå°½ç®¡åœ¨Cè¯è¨€é‡Œè¿™æ · -çš„å°æ‹¬å·ä¸æ˜¯å¿…需的,就åƒâ€œstruct fileinfo infoâ€å£°æ˜Žè¿‡åŽçš„“sizeof infoâ€ï¼‰ã€‚ +Linux å†…æ ¸çš„ç©ºæ ¼ä½¿ç”¨æ–¹å¼ï¼ˆä¸»è¦ï¼‰å–决于它是用于函数还是关键å—。(大多数)关键å—åŽ +è¦åŠ ä¸€ä¸ªç©ºæ ¼ã€‚å€¼å¾—æ³¨æ„的例外是 sizeofã€typeofã€alignof å’Œ __attribute__,这些 +关键å—æŸäº›ç¨‹åº¦ä¸Šçœ‹èµ·æ¥æ›´åƒå‡½æ•°ï¼ˆå®ƒä»¬åœ¨ Linux 里也常常伴éšå°æ‹¬å·è€Œä½¿ç”¨ï¼Œå°½ç®¡åœ¨ C 里 +è¿™æ ·çš„å°æ‹¬å·ä¸æ˜¯å¿…éœ€çš„ï¼Œå°±åƒ â€œstruct fileinfo info†声明过åŽçš„ “sizeof infoâ€ï¼‰ã€‚ 所以在这些关键å—之åŽæ”¾ä¸€ä¸ªç©ºæ ¼ï¼š + if, switch, case, for, do, while -但是ä¸è¦åœ¨sizeofã€typeofã€alignof或者__attribute__这些关键å—之åŽæ”¾ç©ºæ ¼ã€‚例如, + +但是ä¸è¦åœ¨ sizeofã€typeofã€alignof 或者 __attribute__ 这些关键å—之åŽæ”¾ç©ºæ ¼ã€‚例如, + s = sizeof(struct file); ä¸è¦åœ¨å°æ‹¬å·é‡Œçš„表达å¼ä¸¤ä¾§åŠ ç©ºæ ¼ã€‚è¿™æ˜¯ä¸€ä¸ªå例: s = sizeof( struct file ); -当声明指针类型或者返回指针类型的函数时,“*â€çš„首选使用方å¼æ˜¯ä½¿ä¹‹é è¿‘å˜é‡å或者函 +当声明指针类型或者返回指针类型的函数时,“*†的首选使用方å¼æ˜¯ä½¿ä¹‹é è¿‘å˜é‡å或者函 æ•°å,而ä¸æ˜¯é 近类型å。例å: char *linux_banner; @@ -204,15 +202,18 @@ Linuxå†…æ ¸çš„ç©ºæ ¼ä½¿ç”¨æ–¹å¼ï¼ˆä¸»è¦ï¼‰å–决于它是用于函数还是关 = + - < > * / % | & ^ <= >= == != ? : 但是一元æ“作符åŽä¸è¦åŠ ç©ºæ ¼ï¼š + & * + - ~ ! sizeof typeof alignof __attribute__ defined åŽç¼€è‡ªåŠ 和自å‡ä¸€å…ƒæ“作符å‰ä¸åŠ ç©ºæ ¼ï¼š + ++ -- å‰ç¼€è‡ªåŠ 和自å‡ä¸€å…ƒæ“作符åŽä¸åŠ ç©ºæ ¼ï¼š + ++ -- -“.â€å’Œâ€œ->â€ç»“构体æˆå‘˜æ“作符å‰åŽä¸åŠ ç©ºæ ¼ã€‚ +‘.’ å’Œ “->†结构体æˆå‘˜æ“作符å‰åŽä¸åŠ ç©ºæ ¼ã€‚ ä¸è¦åœ¨è¡Œå°¾ç•™ç©ºç™½ã€‚有些å¯ä»¥è‡ªåŠ¨ç¼©è¿›çš„ç¼–è¾‘å™¨ä¼šåœ¨æ–°è¡Œçš„è¡Œé¦–åŠ å…¥é€‚é‡çš„空白,然åŽä½ å°±å¯ä»¥ç›´æŽ¥åœ¨é‚£ä¸€è¡Œè¾“入代ç 。ä¸è¿‡å‡å¦‚ä½ æœ€åŽæ²¡æœ‰åœ¨é‚£ä¸€è¡Œè¾“入代ç ï¼Œæœ‰äº›ç¼–è¾‘å™¨å°±ä¸ @@ -225,23 +226,23 @@ Linuxå†…æ ¸çš„ç©ºæ ¼ä½¿ç”¨æ–¹å¼ï¼ˆä¸»è¦ï¼‰å–决于它是用于函数还是关 ç¬¬å››ç« ï¼šå‘½å -C是一个简朴的è¯è¨€ï¼Œä½ 的命åä¹Ÿåº”è¯¥è¿™æ ·ã€‚å’ŒModula-2å’ŒPascal程åºå‘˜ä¸åŒï¼ŒC程åºå‘˜ä¸ä½¿ -用类似ThisVariableIsATemporaryCounterè¿™æ ·åŽä¸½çš„åå—。C程åºå‘˜ä¼šç§°é‚£ä¸ªå˜é‡ä¸ºâ€œtmp†-ï¼Œè¿™æ ·å†™èµ·æ¥ä¼šæ›´å®¹æ˜“,而且至少ä¸ä¼šä»¤å…¶éš¾äºŽç†è§£ã€‚ +C是一个简朴的è¯è¨€ï¼Œä½ 的命åä¹Ÿåº”è¯¥è¿™æ ·ã€‚å’Œ Modula-2 å’Œ Pascal 程åºå‘˜ä¸åŒï¼ŒC 程åºå‘˜ +ä¸ä½¿ç”¨ç±»ä¼¼ ThisVariableIsATemporaryCounter è¿™æ ·åŽä¸½çš„åå—。C 程åºå‘˜ä¼šç§°é‚£ä¸ªå˜é‡ +为 “tmpâ€ï¼Œè¿™æ ·å†™èµ·æ¥ä¼šæ›´å®¹æ˜“,而且至少ä¸ä¼šä»¤å…¶éš¾äºŽç†è§£ã€‚ ä¸è¿‡ï¼Œè™½ç„¶æ··ç”¨å¤§å°å†™çš„åå—是ä¸æ倡使用的,但是全局å˜é‡è¿˜æ˜¯éœ€è¦ä¸€ä¸ªå…·æ述性的åå— -。称一个全局函数为“fooâ€æ˜¯ä¸€ä¸ªéš¾ä»¥é¥¶æ•çš„错误。 +。称一个全局函数为 “foo†是一个难以饶æ•çš„错误。 全局å˜é‡ï¼ˆåªæœ‰å½“ä½ çœŸæ£éœ€è¦å®ƒä»¬çš„时候å†ç”¨å®ƒï¼‰éœ€è¦æœ‰ä¸€ä¸ªå…·æ述性的åå—,就åƒå…¨å±€å‡½ -æ•°ã€‚å¦‚æžœä½ æœ‰ä¸€ä¸ªå¯ä»¥è®¡ç®—活动用户数é‡çš„å‡½æ•°ï¼Œä½ åº”è¯¥å«å®ƒâ€œcount_active_users()â€æˆ–者 -类似的åå—ï¼Œä½ ä¸åº”该å«å®ƒâ€œcntuser()â€ã€‚ +æ•°ã€‚å¦‚æžœä½ æœ‰ä¸€ä¸ªå¯ä»¥è®¡ç®—活动用户数é‡çš„å‡½æ•°ï¼Œä½ åº”è¯¥å«å®ƒ “count_active_users()†+或者类似的åå—ï¼Œä½ ä¸åº”该å«å®ƒ “cntuser()â€ã€‚ 在函数åä¸åŒ…å«å‡½æ•°ç±»åž‹ï¼ˆæ‰€è°“的匈牙利命å法)是脑å出了问题——编译器知é“那些类型而 ä¸”èƒ½å¤Ÿæ£€æŸ¥é‚£äº›ç±»åž‹ï¼Œè¿™æ ·åšåªèƒ½æŠŠç¨‹åºå‘˜å¼„ç³Šæ¶‚äº†ã€‚éš¾æ€ªå¾®è½¯æ€»æ˜¯åˆ¶é€ å‡ºæœ‰é—®é¢˜çš„ç¨‹åºã€‚ 本地å˜é‡å应该简çŸï¼Œè€Œä¸”能够表达相关的å«ä¹‰ã€‚å¦‚æžœä½ æœ‰ä¸€äº›éšæœºçš„整数型的循环计数器 -,它应该被称为“iâ€ã€‚å«å®ƒâ€œloop_counterâ€å¹¶æ— 益处,如果它没有被误解的å¯èƒ½çš„è¯ã€‚类似 -的,“tmpâ€å¯ä»¥ç”¨æ¥ç§°å‘¼ä»»æ„类型的临时å˜é‡ã€‚ +,它应该被称为 “iâ€ã€‚å«å®ƒ “loop_counterâ€ å¹¶æ— ç›Šå¤„ï¼Œå¦‚æžœå®ƒæ²¡æœ‰è¢«è¯¯è§£çš„å¯èƒ½çš„è¯ã€‚ +类似的,“tmp†å¯ä»¥ç”¨æ¥ç§°å‘¼ä»»æ„类型的临时å˜é‡ã€‚ å¦‚æžœä½ æ€•æ··æ·†äº†ä½ çš„æœ¬åœ°å˜é‡åï¼Œä½ å°±é‡åˆ°å¦ä¸€ä¸ªé—®é¢˜äº†ï¼Œå«åšå‡½æ•°å¢žé•¿è·å°”蒙失衡综åˆç—‡ 。请看第å…ç« ï¼ˆå‡½æ•°ï¼‰ã€‚ @@ -249,9 +250,9 @@ C是一个简朴的è¯è¨€ï¼Œä½ 的命åä¹Ÿåº”è¯¥è¿™æ ·ã€‚å’ŒModula-2å’ŒPascal ç¬¬äº”ç« ï¼šTypedef -ä¸è¦ä½¿ç”¨ç±»ä¼¼â€œvps_tâ€ä¹‹ç±»çš„东西。 +ä¸è¦ä½¿ç”¨ç±»ä¼¼ “vps_t†之类的东西。 -对结构体和指针使用typedefæ˜¯ä¸€ä¸ªé”™è¯¯ã€‚å½“ä½ åœ¨ä»£ç 里看到: +对结构体和指针使用 typedef æ˜¯ä¸€ä¸ªé”™è¯¯ã€‚å½“ä½ åœ¨ä»£ç 里看到: vps_t a; @@ -261,91 +262,91 @@ C是一个简朴的è¯è¨€ï¼Œä½ 的命åä¹Ÿåº”è¯¥è¿™æ ·ã€‚å’ŒModula-2å’ŒPascal struct virtual_container *a; -ä½ å°±çŸ¥é““aâ€æ˜¯ä»€ä¹ˆäº†ã€‚ +ä½ å°±çŸ¥é“ â€œa†是什么了。 -很多人认为typedef“能æ高å¯è¯»æ€§â€ã€‚实际ä¸æ˜¯è¿™æ ·çš„。它们åªåœ¨ä¸‹åˆ—情况下有用: +很多人认为 typedef “能æ高å¯è¯»æ€§â€ã€‚实际ä¸æ˜¯è¿™æ ·çš„。它们åªåœ¨ä¸‹åˆ—情况下有用: - (a) 完全ä¸é€æ˜Žçš„对象(这ç§æƒ…况下è¦ä¸»åŠ¨ä½¿ç”¨typedefæ¥éšè—这个对象实际上是什么)。 + (a) 完全ä¸é€æ˜Žçš„对象(这ç§æƒ…况下è¦ä¸»åŠ¨ä½¿ç”¨ typedef æ¥éšè—这个对象实际上是什么)。 - 例如:“pte_tâ€ç‰ä¸é€æ˜Žå¯¹è±¡ï¼Œä½ åªèƒ½ç”¨åˆé€‚的访问函数æ¥è®¿é—®å®ƒä»¬ã€‚ + 例如:“pte_t†ç‰ä¸é€æ˜Žå¯¹è±¡ï¼Œä½ åªèƒ½ç”¨åˆé€‚的访问函数æ¥è®¿é—®å®ƒä»¬ã€‚ - 注æ„ï¼ä¸é€æ˜Žæ€§å’Œâ€œè®¿é—®å‡½æ•°â€æœ¬èº«æ˜¯ä¸å¥½çš„。我们使用pte_tç‰ç±»åž‹çš„åŽŸå› åœ¨äºŽçœŸçš„æ˜¯ + 注æ„ï¼ä¸é€æ˜Žæ€§å’Œâ€œè®¿é—®å‡½æ•°â€æœ¬èº«æ˜¯ä¸å¥½çš„。我们使用 pte_t ç‰ç±»åž‹çš„åŽŸå› åœ¨äºŽçœŸçš„æ˜¯ 完全没有任何共用的å¯è®¿é—®ä¿¡æ¯ã€‚ - (b) 清楚的整数类型,如æ¤ï¼Œè¿™å±‚抽象就å¯ä»¥å¸®åŠ©æ¶ˆé™¤åˆ°åº•æ˜¯â€œintâ€è¿˜æ˜¯â€œlongâ€çš„混淆。 + (b) 清楚的整数类型,如æ¤ï¼Œè¿™å±‚抽象就å¯ä»¥å¸®åŠ©æ¶ˆé™¤åˆ°åº•æ˜¯ “int†还是 “long†的混淆。 - u8/u16/u32是完全没有问题的typedef,ä¸è¿‡å®ƒä»¬æ›´ç¬¦åˆç±»åˆ«(d)而ä¸æ˜¯è¿™é‡Œã€‚ + u8/u16/u32 是完全没有问题的 typedef,ä¸è¿‡å®ƒä»¬æ›´ç¬¦åˆç±»åˆ« (d) 而ä¸æ˜¯è¿™é‡Œã€‚ - å†æ¬¡æ³¨æ„ï¼è¦è¿™æ ·åšï¼Œå¿…é¡»äº‹å‡ºæœ‰å› ã€‚å¦‚æžœæŸä¸ªå˜é‡æ˜¯â€œunsigned longâ€œï¼Œé‚£ä¹ˆæ²¡æœ‰å¿…è¦ + å†æ¬¡æ³¨æ„ï¼è¦è¿™æ ·åšï¼Œå¿…é¡»äº‹å‡ºæœ‰å› ã€‚å¦‚æžœæŸä¸ªå˜é‡æ˜¯ “unsigned longâ€œï¼Œé‚£ä¹ˆæ²¡æœ‰å¿…è¦ typedef unsigned long myflags_t; - ä¸è¿‡å¦‚æžœæœ‰ä¸€ä¸ªæ˜Žç¡®çš„åŽŸå› ï¼Œæ¯”å¦‚å®ƒåœ¨æŸç§æƒ…况下å¯èƒ½ä¼šæ˜¯ä¸€ä¸ªâ€œunsigned intâ€è€Œåœ¨ - 其他情况下å¯èƒ½ä¸ºâ€œunsigned longâ€ï¼Œé‚£ä¹ˆå°±ä¸è¦çŠ¹è±«ï¼Œè¯·åŠ¡å¿…使用typedef。 + ä¸è¿‡å¦‚æžœæœ‰ä¸€ä¸ªæ˜Žç¡®çš„åŽŸå› ï¼Œæ¯”å¦‚å®ƒåœ¨æŸç§æƒ…况下å¯èƒ½ä¼šæ˜¯ä¸€ä¸ª “unsigned int†而在 + 其他情况下å¯èƒ½ä¸º “unsigned longâ€ï¼Œé‚£ä¹ˆå°±ä¸è¦çŠ¹è±«ï¼Œè¯·åŠ¡å¿…使用 typedef。 (c) å½“ä½ ä½¿ç”¨sparse按å—é¢çš„创建一个新类型æ¥åšç±»åž‹æ£€æŸ¥çš„时候。 (d) å’Œæ ‡å‡†C99类型相åŒçš„类型,在æŸäº›ä¾‹å¤–的情况下。 - 虽然让眼ç›å’Œè„‘ç‹æ¥é€‚åº”æ–°çš„æ ‡å‡†ç±»åž‹æ¯”å¦‚â€œuint32_tâ€ä¸éœ€è¦èŠ±å¾ˆå¤šæ—¶é—´ï¼Œå¯æ˜¯æœ‰äº› + 虽然让眼ç›å’Œè„‘ç‹æ¥é€‚åº”æ–°çš„æ ‡å‡†ç±»åž‹æ¯”å¦‚ “uint32_t†ä¸éœ€è¦èŠ±å¾ˆå¤šæ—¶é—´ï¼Œå¯æ˜¯æœ‰äº› 人ä»ç„¶æ‹’ç»ä½¿ç”¨å®ƒä»¬ã€‚ - å› æ¤ï¼ŒLinux特有的ç‰åŒäºŽæ ‡å‡†ç±»åž‹çš„“u8/u16/u32/u64â€ç±»åž‹å’Œå®ƒä»¬çš„有符å·ç±»åž‹æ˜¯è¢« + å› æ¤ï¼ŒLinux 特有的ç‰åŒäºŽæ ‡å‡†ç±»åž‹çš„ “u8/u16/u32/u64†类型和它们的有符å·ç±»åž‹æ˜¯è¢« å…è®¸çš„â€”â€”å°½ç®¡åœ¨ä½ è‡ªå·±çš„æ–°ä»£ç ä¸ï¼Œå®ƒä»¬ä¸æ˜¯å¼ºåˆ¶è¦æ±‚è¦ä½¿ç”¨çš„。 当编辑已ç»ä½¿ç”¨äº†æŸä¸ªç±»åž‹é›†çš„已有代ç æ—¶ï¼Œä½ åº”è¯¥éµå¾ªé‚£äº›ä»£ç ä¸å·²ç»åšå‡ºçš„选择。 (e) å¯ä»¥åœ¨ç”¨æˆ·ç©ºé—´å®‰å…¨ä½¿ç”¨çš„类型。 - 在æŸäº›ç”¨æˆ·ç©ºé—´å¯è§çš„结构体里,我们ä¸èƒ½è¦æ±‚C99类型而且ä¸èƒ½ç”¨ä¸Šé¢æ到的“u32†- ç±»åž‹ã€‚å› æ¤ï¼Œæˆ‘们在与用户空间共享的所有结构体ä¸ä½¿ç”¨__u32和类似的类型。 + 在æŸäº›ç”¨æˆ·ç©ºé—´å¯è§çš„结构体里,我们ä¸èƒ½è¦æ±‚C99类型而且ä¸èƒ½ç”¨ä¸Šé¢æ到的 “u32†+ ç±»åž‹ã€‚å› æ¤ï¼Œæˆ‘们在与用户空间共享的所有结构体ä¸ä½¿ç”¨ __u32 和类似的类型。 -å¯èƒ½è¿˜æœ‰å…¶ä»–的情况,ä¸è¿‡åŸºæœ¬çš„规则是永远ä¸è¦ä½¿ç”¨typedef,除éžä½ å¯ä»¥æ˜Žç¡®çš„应用上 +å¯èƒ½è¿˜æœ‰å…¶ä»–的情况,ä¸è¿‡åŸºæœ¬çš„规则是永远ä¸è¦ä½¿ç”¨ typedef,除éžä½ å¯ä»¥æ˜Žç¡®çš„应用上 è¿°æŸä¸ªè§„则ä¸çš„一个。 总的æ¥è¯´ï¼Œå¦‚æžœä¸€ä¸ªæŒ‡é’ˆæˆ–è€…ä¸€ä¸ªç»“æž„ä½“é‡Œçš„å…ƒç´ å¯ä»¥åˆç†çš„è¢«ç›´æŽ¥è®¿é—®åˆ°ï¼Œé‚£ä¹ˆå®ƒä»¬å°±ä¸ -应该是一个typedef。 +应该是一个 typedef。 第å…ç« ï¼šå‡½æ•° 函数应该简çŸè€Œæ¼‚亮,并且åªå®Œæˆä¸€ä»¶äº‹æƒ…。函数应该å¯ä»¥ä¸€å±æˆ–者两å±æ˜¾ç¤ºå®Œï¼ˆæˆ‘们都知 -é“ISO/ANSIå±å¹•å¤§å°æ˜¯80x24),åªåšä¸€ä»¶äº‹æƒ…,而且把它åšå¥½ã€‚ +é“ ISO/ANSI å±å¹•å¤§å°æ˜¯ 80x24),åªåšä¸€ä»¶äº‹æƒ…,而且把它åšå¥½ã€‚ 一个函数的最大长度是和该函数的å¤æ‚度和缩进级数æˆåæ¯”çš„ã€‚æ‰€ä»¥ï¼Œå¦‚æžœä½ æœ‰ä¸€ä¸ªç†è®ºä¸Š -很简å•çš„åªæœ‰ä¸€ä¸ªå¾ˆé•¿ï¼ˆä½†æ˜¯ç®€å•ï¼‰çš„caseè¯å¥çš„å‡½æ•°ï¼Œè€Œä¸”ä½ éœ€è¦åœ¨æ¯ä¸ªcase里åšå¾ˆå¤šå¾ˆ -å°çš„äº‹æƒ…ï¼Œè¿™æ ·çš„å‡½æ•°å°½ç®¡å¾ˆé•¿ï¼Œä½†ä¹Ÿæ˜¯å¯ä»¥çš„。 +很简å•çš„åªæœ‰ä¸€ä¸ªå¾ˆé•¿ï¼ˆä½†æ˜¯ç®€å•ï¼‰çš„ case è¯å¥çš„å‡½æ•°ï¼Œè€Œä¸”ä½ éœ€è¦åœ¨æ¯ä¸ª case é‡Œåš +很多很å°çš„äº‹æƒ…ï¼Œè¿™æ ·çš„å‡½æ•°å°½ç®¡å¾ˆé•¿ï¼Œä½†ä¹Ÿæ˜¯å¯ä»¥çš„。 ä¸è¿‡ï¼Œå¦‚æžœä½ æœ‰ä¸€ä¸ªå¤æ‚çš„å‡½æ•°ï¼Œè€Œä¸”ä½ æ€€ç–‘ä¸€ä¸ªå¤©åˆ†ä¸æ˜¯å¾ˆé«˜çš„高ä¸ä¸€å¹´çº§å¦ç”Ÿå¯èƒ½ç”šè‡³ æžä¸æ¸…æ¥šè¿™ä¸ªå‡½æ•°çš„ç›®çš„ï¼Œä½ åº”è¯¥ä¸¥æ ¼çš„éµå®ˆå‰é¢æ到的长度é™åˆ¶ã€‚使用辅助函数,并为之 å–个具æ述性的åå—ï¼ˆå¦‚æžœä½ è§‰å¾—å®ƒä»¬çš„æ€§èƒ½å¾ˆé‡è¦çš„è¯ï¼Œå¯ä»¥è®©ç¼–译器内è”å®ƒä»¬ï¼Œè¿™æ ·çš„ æ•ˆæžœå¾€å¾€ä¼šæ¯”ä½ å†™ä¸€ä¸ªå¤æ‚函数的效果è¦å¥½ã€‚) -函数的å¦å¤–一个衡é‡æ ‡å‡†æ˜¯æœ¬åœ°å˜é‡çš„æ•°é‡ã€‚æ¤æ•°é‡ä¸åº”超过5ï¼10个,å¦åˆ™ä½ 的函数就有 +函数的å¦å¤–一个衡é‡æ ‡å‡†æ˜¯æœ¬åœ°å˜é‡çš„æ•°é‡ã€‚æ¤æ•°é‡ä¸åº”超过 5ï¼10 个,å¦åˆ™ä½ 的函数就有 问题了。é‡æ–°è€ƒè™‘ä¸€ä¸‹ä½ çš„å‡½æ•°ï¼ŒæŠŠå®ƒåˆ†æ‹†æˆæ›´å°çš„函数。人的大脑一般å¯ä»¥è½»æ¾çš„åŒæ—¶è·Ÿ -踪7个ä¸åŒçš„事物,如果å†å¢žå¤šçš„è¯ï¼Œå°±ä¼šç³Šæ¶‚了。å³ä¾¿ä½ èªé¢–è¿‡äººï¼Œä½ ä¹Ÿå¯èƒ½ä¼šè®°ä¸æ¸…ä½ 2 -个星期å‰åšè¿‡çš„事情。 +踪 7 个ä¸åŒçš„事物,如果å†å¢žå¤šçš„è¯ï¼Œå°±ä¼šç³Šæ¶‚了。å³ä¾¿ä½ èªé¢–è¿‡äººï¼Œä½ ä¹Ÿå¯èƒ½ä¼šè®°ä¸æ¸…ä½ +2 个星期å‰åšè¿‡çš„事情。 -在æºæ–‡ä»¶é‡Œï¼Œä½¿ç”¨ç©ºè¡Œéš”å¼€ä¸åŒçš„函数。如果该函数需è¦è¢«å¯¼å‡ºï¼Œå®ƒçš„EXPORT*å®åº”该紧贴 +在æºæ–‡ä»¶é‡Œï¼Œä½¿ç”¨ç©ºè¡Œéš”å¼€ä¸åŒçš„函数。如果该函数需è¦è¢«å¯¼å‡ºï¼Œå®ƒçš„ EXPORT* å®åº”该紧贴 在它的结æŸå¤§æ‹¬å·ä¹‹ä¸‹ã€‚比如: -int system_is_up(void) -{ - return system_state == SYSTEM_RUNNING; -} -EXPORT_SYMBOL(system_is_up); + int system_is_up(void) + { + return system_state == SYSTEM_RUNNING; + } + EXPORT_SYMBOL(system_is_up); -在函数原型ä¸ï¼ŒåŒ…å«å‡½æ•°å和它们的数æ®ç±»åž‹ã€‚虽然Cè¯è¨€é‡Œæ²¡æœ‰è¿™æ ·çš„è¦æ±‚,在Linux里这 +在函数原型ä¸ï¼ŒåŒ…å«å‡½æ•°å和它们的数æ®ç±»åž‹ã€‚虽然Cè¯è¨€é‡Œæ²¡æœ‰è¿™æ ·çš„è¦æ±‚,在 Linux 里这 是æ倡的åšæ³•ï¼Œå› ä¸ºè¿™æ ·å¯ä»¥å¾ˆç®€å•çš„给读者æ供更多的有价值的信æ¯ã€‚ ç¬¬ä¸ƒç« ï¼šé›†ä¸çš„函数退出途径 -虽然被æŸäº›äººå£°ç§°å·²ç»è¿‡æ—¶ï¼Œä½†æ˜¯gotoè¯å¥çš„ç‰ä»·ç‰©è¿˜æ˜¯ç»å¸¸è¢«ç¼–译器所使用,具体形å¼æ˜¯ +虽然被æŸäº›äººå£°ç§°å·²ç»è¿‡æ—¶ï¼Œä½†æ˜¯ goto è¯å¥çš„ç‰ä»·ç‰©è¿˜æ˜¯ç»å¸¸è¢«ç¼–译器所使用,具体形å¼æ˜¯ æ— æ¡ä»¶è·³è½¬æŒ‡ä»¤ã€‚ -当一个函数从多个ä½ç½®é€€å‡ºå¹¶ä¸”需è¦åšä¸€äº›é€šç”¨çš„清ç†å·¥ä½œçš„时候,gotoçš„å¥½å¤„å°±æ˜¾çŽ°å‡ºæ¥ -了。 +当一个函数从多个ä½ç½®é€€å‡ºï¼Œå¹¶ä¸”需è¦åšä¸€äº›ç±»ä¼¼æ¸…ç†çš„常è§æ“作时,goto è¯å¥å°±å¾ˆæ–¹ä¾¿äº†ã€‚ +如果并ä¸éœ€è¦æ¸…ç†æ“作,那么直接 return å³å¯ã€‚ ç†ç”±æ˜¯ï¼š @@ -354,26 +355,37 @@ EXPORT_SYMBOL(system_is_up); - å¯ä»¥é¿å…由于修改时忘记更新æŸä¸ªå•ç‹¬çš„退出点而导致的错误 - å‡è½»äº†ç¼–è¯‘å™¨çš„å·¥ä½œï¼Œæ— éœ€åˆ é™¤å†—ä½™ä»£ç ;) -int fun(int a) -{ - int result = 0; - char *buffer = kmalloc(SIZE); - - if (buffer == NULL) - return -ENOMEM; - - if (condition1) { - while (loop1) { - ... + 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_buffer; } - result = 1; - goto out; + ... + out_buffer: + kfree(buffer); + return result; } - ... -out: - kfree(buffer); - return result; -} + +一个需è¦æ³¨æ„的常è§é”™è¯¯æ˜¯â€œä¸€ä¸ª err 错误â€ï¼Œå°±åƒè¿™æ ·ï¼š + + err: + kfree(foo->bar); + kfree(foo); + return ret; + +这段代ç 的错误是,在æŸäº›é€€å‡ºè·¯å¾„上 “foo†是 NULL。通常情况下,通过把它分离æˆä¸¤ä¸ª +é”™è¯¯æ ‡ç¾ â€œerr_bar:†和 “err_foo:†æ¥ä¿®å¤è¿™ä¸ªé”™è¯¯ã€‚ ç¬¬å…«ç« ï¼šæ³¨é‡Š @@ -386,10 +398,10 @@ out: åŠ å¤ªå¤šã€‚ä½ åº”è¯¥åšçš„,是把注释放在函数的头部,告诉人们它åšäº†ä»€ä¹ˆï¼Œä¹Ÿå¯ä»¥åŠ 上它åšè¿™ äº›äº‹æƒ…çš„åŽŸå› ã€‚ -å½“æ³¨é‡Šå†…æ ¸API函数时,请使用kernel-docæ ¼å¼ã€‚请看 -Documentation/kernel-doc-nano-HOWTO.txtå’Œscripts/kernel-doc以获得详细信æ¯ã€‚ +å½“æ³¨é‡Šå†…æ ¸API函数时,请使用 kernel-doc æ ¼å¼ã€‚请看 +Documentation/kernel-doc-nano-HOWTO.txtå’Œscripts/kernel-doc 以获得详细信æ¯ã€‚ -Linuxçš„æ³¨é‡Šé£Žæ ¼æ˜¯C89“/* ... */â€é£Žæ ¼ã€‚ä¸è¦ä½¿ç”¨C99é£Žæ ¼â€œ// ...â€æ³¨é‡Šã€‚ +Linuxçš„æ³¨é‡Šé£Žæ ¼æ˜¯ C89 “/* ... */â€ é£Žæ ¼ã€‚ä¸è¦ä½¿ç”¨ C99 é£Žæ ¼ “// ...†注释。 é•¿ï¼ˆå¤šè¡Œï¼‰çš„é¦–é€‰æ³¨é‡Šé£Žæ ¼æ˜¯ï¼š @@ -402,6 +414,15 @@ Linuxçš„æ³¨é‡Šé£Žæ ¼æ˜¯C89“/* ... */â€é£Žæ ¼ã€‚ä¸è¦ä½¿ç”¨C99é£Žæ ¼â€œ// ... * with beginning and ending almost-blank lines. */ +对于在 net/ å’Œ drivers/net/ çš„æ–‡ä»¶ï¼Œé¦–é€‰çš„é•¿ï¼ˆå¤šè¡Œï¼‰æ³¨é‡Šé£Žæ ¼æœ‰äº›ä¸åŒã€‚ + + /* 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. + */ + 注释数æ®ä¹Ÿæ˜¯å¾ˆé‡è¦çš„,ä¸ç®¡æ˜¯åŸºæœ¬ç±»åž‹è¿˜æ˜¯è¡ç”Ÿç±»åž‹ã€‚为了方便实现这一点,æ¯ä¸€è¡Œåº”åª å£°æ˜Žä¸€ä¸ªæ•°æ®ï¼ˆä¸è¦ä½¿ç”¨é€—å·æ¥ä¸€æ¬¡å£°æ˜Žå¤šä¸ªæ•°æ®ï¼‰ã€‚è¿™æ ·ä½ å°±æœ‰ç©ºé—´æ¥ä¸ºæ¯ä¸ªæ•°æ®å†™ä¸€æ®µ å°æ³¨é‡Šæ¥è§£é‡Šå®ƒä»¬çš„用途了。 @@ -409,49 +430,63 @@ Linuxçš„æ³¨é‡Šé£Žæ ¼æ˜¯C89“/* ... */â€é£Žæ ¼ã€‚ä¸è¦ä½¿ç”¨C99é£Žæ ¼â€œ// ... 第ä¹ç« ï¼šä½ å·²ç»æŠŠäº‹æƒ…弄糟了 -è¿™æ²¡ä»€ä¹ˆï¼Œæˆ‘ä»¬éƒ½æ˜¯è¿™æ ·ã€‚å¯èƒ½ä½ 的使用了很长时间Unix的朋å‹å·²ç»å‘Šè¯‰ä½ “GNU emacsâ€èƒ½ -è‡ªåŠ¨å¸®ä½ æ ¼å¼åŒ–Cæºä»£ç ï¼Œè€Œä¸”ä½ ä¹Ÿæ³¨æ„åˆ°äº†ï¼Œç¡®å®žæ˜¯è¿™æ ·ï¼Œä¸è¿‡å®ƒæ‰€ä½¿ç”¨çš„默认值和我们 -想è¦çš„相去甚远(实际上,甚至比éšæœºæ‰“的还è¦å·®â€”â€”æ— æ•°ä¸ªçŒ´å在GNU emacs里打å—æ°¸è¿œä¸ -ä¼šåˆ›é€ å‡ºä¸€ä¸ªå¥½ç¨‹åºï¼‰ï¼ˆè¯‘注:请å‚考Infinite Monkey Theorem) - -æ‰€ä»¥ä½ è¦ä¹ˆæ”¾å¼ƒGNU emacs,è¦ä¹ˆæ”¹å˜å®ƒè®©å®ƒä½¿ç”¨æ›´åˆç†çš„设定。è¦é‡‡ç”¨åŽä¸€ä¸ªæ–¹æ¡ˆï¼Œä½ å¯ -以把下é¢è¿™æ®µç²˜è´´åˆ°ä½ çš„.emacs文件里。 - -(defun linux-c-mode () - "C mode with adjusted defaults for use with the Linux kernel." - (interactive) - (c-mode) - (c-set-style "K&R") - (setq tab-width 8) - (setq indent-tabs-mode t) - (setq c-basic-offset 8)) - -è¿™æ ·å°±å®šä¹‰äº†M-x linux-c-modeå‘½ä»¤ã€‚å½“ä½ hack一个模å—çš„æ—¶å€™ï¼Œå¦‚æžœä½ æŠŠå—符串 --*- linux-c -*-放在头两行的æŸä¸ªä½ç½®ï¼Œè¿™ä¸ªæ¨¡å¼å°†ä¼šè¢«è‡ªåŠ¨è°ƒç”¨ã€‚å¦‚æžœä½ å¸Œæœ›åœ¨ä½ ä¿®æ”¹ -/usr/src/linux里的文件时é”术般自动打开linux-c-modeçš„è¯ï¼Œä½ 也å¯èƒ½éœ€è¦æ·»åŠ - -(setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.[ch]$" . linux-c-mode) - auto-mode-alist)) - -åˆ°ä½ çš„.emacs文件里。 - -ä¸è¿‡å°±ç®—ä½ å°è¯•è®©emacsæ£ç¡®çš„æ ¼å¼åŒ–代ç 失败了,也并ä¸æ„味ç€ä½ 失去了一切:还å¯ä»¥ç”¨â€œ -indentâ€ã€‚ - -ä¸è¿‡ï¼ŒGNU indent也有和GNU emacsä¸€æ ·æœ‰é—®é¢˜çš„è®¾å®šï¼Œæ‰€ä»¥ä½ éœ€è¦ç»™å®ƒä¸€äº›å‘½ä»¤é€‰é¡¹ã€‚ä¸ -过,这还ä¸ç®—å¤ªç³Ÿç³•ï¼Œå› ä¸ºå°±ç®—æ˜¯GNU indent的作者也认åŒK&Rçš„æƒå¨æ€§ï¼ˆGNU的人并ä¸æ˜¯å -人,他们åªæ˜¯åœ¨è¿™ä¸ªé—®é¢˜ä¸Šè¢«ä¸¥é‡çš„è¯¯å¯¼äº†ï¼‰ï¼Œæ‰€ä»¥ä½ åªè¦ç»™indent指定选项“-kr -i8†-(代表“K&R,8个å—符缩进â€ï¼‰ï¼Œæˆ–者使用“scripts/Lindentâ€ï¼Œè¿™æ ·å°±å¯ä»¥ä»¥æœ€æ—¶é«¦çš„æ–¹å¼ +è¿™æ²¡ä»€ä¹ˆï¼Œæˆ‘ä»¬éƒ½æ˜¯è¿™æ ·ã€‚å¯èƒ½ä½ 的使用了很长时间 Unix 的朋å‹å·²ç»å‘Šè¯‰ä½ “GNU emacs†能 +è‡ªåŠ¨å¸®ä½ æ ¼å¼åŒ– C æºä»£ç ï¼Œè€Œä¸”ä½ ä¹Ÿæ³¨æ„åˆ°äº†ï¼Œç¡®å®žæ˜¯è¿™æ ·ï¼Œä¸è¿‡å®ƒæ‰€ä½¿ç”¨çš„默认值和我们 +想è¦çš„相去甚远(实际上,甚至比éšæœºæ‰“的还è¦å·®â€”â€”æ— æ•°ä¸ªçŒ´å在 GNU emacs 里打å—æ°¸è¿œä¸ +ä¼šåˆ›é€ å‡ºä¸€ä¸ªå¥½ç¨‹åºï¼‰ï¼ˆè¯‘注:请å‚考 Infinite Monkey Theorem) + +æ‰€ä»¥ä½ è¦ä¹ˆæ”¾å¼ƒ GNU emacs,è¦ä¹ˆæ”¹å˜å®ƒè®©å®ƒä½¿ç”¨æ›´åˆç†çš„设定。è¦é‡‡ç”¨åŽä¸€ä¸ªæ–¹æ¡ˆï¼Œä½ å¯ +以把下é¢è¿™æ®µç²˜è´´åˆ°ä½ çš„ .emacs 文件里。 + +(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))) + +(add-hook 'c-mode-common-hook + (lambda () + ;; Add kernel style + (c-add-style + "linux-tabs-only" + '("linux" (c-offsets-alist + (arglist-cont-nonempty + c-lineup-gcc-asm-reg + c-lineup-arglist-tabs-only)))))) + +(add-hook 'c-mode-hook + (lambda () + (let ((filename (buffer-file-name))) + ;; Enable kernel mode for the appropriate files + (when (and filename + (string-match (expand-file-name "~/src/linux-trees") + filename)) + (setq indent-tabs-mode t) + (setq show-trailing-whitespace t) + (c-set-style "linux-tabs-only"))))) + +这会让 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â€ä¸èƒ½ä¿®æ£åçš„ç¼–ç¨‹ä¹ æƒ¯ã€‚ +“indent†有很多选项,特别是é‡æ–°æ ¼å¼åŒ–æ³¨é‡Šçš„æ—¶å€™ï¼Œä½ å¯èƒ½éœ€è¦çœ‹ä¸€ä¸‹å®ƒçš„手册页。ä¸è¿‡ +è®°ä½ï¼šâ€œindent†ä¸èƒ½ä¿®æ£åçš„ç¼–ç¨‹ä¹ æƒ¯ã€‚ - 第åç« ï¼šKconfigé…置文件 + 第åç« ï¼šKconfig é…置文件 -对于é布æºç æ ‘çš„æ‰€æœ‰Kconfig*é…置文件æ¥è¯´ï¼Œå®ƒä»¬ç¼©è¿›æ–¹å¼ä¸ŽC代ç 相比有所ä¸åŒã€‚紧挨 -在“configâ€å®šä¹‰ä¸‹é¢çš„行缩进一个制表符,帮助信æ¯åˆ™å†å¤šç¼©è¿›2ä¸ªç©ºæ ¼ã€‚æ¯”å¦‚ï¼š +对于é布æºç æ ‘çš„æ‰€æœ‰ Kconfig* é…置文件æ¥è¯´ï¼Œå®ƒä»¬ç¼©è¿›æ–¹å¼ä¸Ž C 代ç 相比有所ä¸åŒã€‚紧挨 +在 “config†定义下é¢çš„行缩进一个制表符,帮助信æ¯åˆ™å†å¤šç¼©è¿› 2 ä¸ªç©ºæ ¼ã€‚æ¯”å¦‚ï¼š config AUDIT bool "Auditing support" @@ -470,7 +505,7 @@ config ADFS_FS_RW depends on ADFS_FS ... -è¦æŸ¥çœ‹é…置文件的完整文档,请看Documentation/kbuild/kconfig-language.txt。 +è¦æŸ¥çœ‹é…置文件的完整文档,请看 Documentation/kbuild/kconfig-language.txt。 第åä¸€ç« ï¼šæ•°æ®ç»“æž„ @@ -489,11 +524,11 @@ config ADFS_FS_RW 很多数æ®ç»“构实际上有2级引用计数,它们通常有ä¸åŒâ€œç±»â€çš„用户。å类计数器统计å类用 户的数é‡ï¼Œæ¯å½“å类计数器å‡è‡³é›¶æ—¶ï¼Œå…¨å±€è®¡æ•°å™¨å‡ä¸€ã€‚ -è¿™ç§â€œå¤šçº§å¼•ç”¨è®¡æ•°â€çš„例åå¯ä»¥åœ¨å†…å˜ç®¡ç†ï¼ˆâ€œstruct mm_structâ€ï¼šmm_userså’Œmm_count) +è¿™ç§â€œå¤šçº§å¼•ç”¨è®¡æ•°â€çš„例åå¯ä»¥åœ¨å†…å˜ç®¡ç†ï¼ˆâ€œstruct mm_structâ€ï¼šmm_users å’Œ mm_count) 和文件系统(“struct super_blockâ€ï¼šs_countå’Œs_active)ä¸æ‰¾åˆ°ã€‚ è®°ä½ï¼šå¦‚æžœå¦ä¸€ä¸ªæ‰§è¡Œçº¿ç´¢å¯ä»¥æ‰¾åˆ°ä½ çš„æ•°æ®ç»“构,但是这个数æ®ç»“构没有引用计数器,这 -é‡Œå‡ ä¹Žè‚¯å®šæ˜¯ä¸€ä¸ªbug。 +é‡Œå‡ ä¹Žè‚¯å®šæ˜¯ä¸€ä¸ª bug。 第åäºŒç« ï¼šå®ï¼Œæžšä¸¾å’ŒRTL @@ -508,102 +543,128 @@ config ADFS_FS_RW 一般的,如果能写æˆå†…è”函数就ä¸è¦å†™æˆåƒå‡½æ•°çš„å®ã€‚ -å«æœ‰å¤šä¸ªè¯å¥çš„å®åº”该被包å«åœ¨ä¸€ä¸ªdo-while代ç å—里: +å«æœ‰å¤šä¸ªè¯å¥çš„å®åº”该被包å«åœ¨ä¸€ä¸ª do-while 代ç å—里: -#define macrofun(a, b, c) \ - do { \ - if (a == 5) \ - do_this(b, c); \ - } while (0) + #define macrofun(a, b, c) \ + do { \ + if (a == 5) \ + do_this(b, c); \ + } while (0) 使用å®çš„时候应é¿å…的事情: 1) å½±å“控制æµç¨‹çš„å®ï¼š -#define FOO(x) \ - do { \ - if (blah(x) < 0) \ - return -EBUGGERED; \ - } while(0) + #define FOO(x) \ + do { \ + if (blah(x) < 0) \ + return -EBUGGERED; \ + } while (0) éžå¸¸ä¸å¥½ã€‚它看起æ¥åƒä¸€ä¸ªå‡½æ•°ï¼Œä¸è¿‡å´èƒ½å¯¼è‡´â€œè°ƒç”¨â€å®ƒçš„函数退出;ä¸è¦æ‰“乱读者大脑里 çš„è¯æ³•åˆ†æžå™¨ã€‚ 2) ä¾èµ–于一个固定åå—的本地å˜é‡çš„å®ï¼š -#define FOO(val) bar(index, val) + #define FOO(val) bar(index, val) å¯èƒ½çœ‹èµ·æ¥åƒæ˜¯ä¸ªä¸é”™çš„东西,ä¸è¿‡å®ƒéžå¸¸å®¹æ˜“把读代ç 的人æžç³Šæ¶‚ï¼Œè€Œä¸”å®¹æ˜“å¯¼è‡´çœ‹èµ·æ¥ ä¸ç›¸å…³çš„改动带æ¥é”™è¯¯ã€‚ -3) 作为左值的带å‚æ•°çš„å®ï¼š FOO(x) = y;如果有人把FOOå˜æˆä¸€ä¸ªå†…è”函数的è¯ï¼Œè¿™ç§ç”¨ +3) 作为左值的带å‚æ•°çš„å®ï¼š FOO(x) = y;如果有人把 FOO å˜æˆä¸€ä¸ªå†…è”函数的è¯ï¼Œè¿™ç§ç”¨ 法就会出错了。 4) 忘记了优先级:使用表达å¼å®šä¹‰å¸¸é‡çš„å®å¿…须将表达å¼ç½®äºŽä¸€å¯¹å°æ‹¬å·ä¹‹å†…。带å‚æ•°çš„ å®ä¹Ÿè¦æ³¨æ„æ¤ç±»é—®é¢˜ã€‚ -#define CONSTANT 0x4000 -#define CONSTEXP (CONSTANT | 3) + #define CONSTANT 0x4000 + #define CONSTEXP (CONSTANT | 3) + +5) 在å®é‡Œå®šä¹‰ç±»ä¼¼å‡½æ•°çš„本地å˜é‡æ—¶å‘½å冲çªï¼š -cpp手册对å®çš„讲解很详细。Gcc internals手册也详细讲解了RTL(译注:register + #define FOO(x) \ + ({ \ + typeof(x) ret; \ + ret = calc_ret(x); \ + (ret); \ + }) + +ret 是本地å˜é‡çš„通用åå— - __foo_ret æ›´ä¸å®¹æ˜“与一个已å˜åœ¨çš„å˜é‡å†²çªã€‚ + +cpp 手册对å®çš„讲解很详细。gcc internals 手册也详细讲解了 RTL(译注:register transfer languageï¼‰ï¼Œå†…æ ¸é‡Œçš„æ±‡ç¼–è¯è¨€ç»å¸¸ç”¨åˆ°å®ƒã€‚ 第åä¸‰ç« ï¼šæ‰“å°å†…æ ¸æ¶ˆæ¯ å†…æ ¸å¼€å‘者应该是å—过良好教育的。请一定注æ„å†…æ ¸ä¿¡æ¯çš„拼写,以给人以好的å°è±¡ã€‚ä¸è¦ -用ä¸è§„范的å•è¯æ¯”如“dontâ€ï¼Œè€Œè¦ç”¨â€œdo notâ€æˆ–者“don'tâ€ã€‚ä¿è¯è¿™äº›ä¿¡æ¯ç®€å•ã€æ˜Žäº†ã€æ— -æ§ä¹‰ã€‚ +用ä¸è§„范的å•è¯æ¯”如 “dontâ€ï¼Œè€Œè¦ç”¨ “do notâ€æˆ–者 “don'tâ€ã€‚ä¿è¯è¿™äº›ä¿¡æ¯ç®€å•ã€æ˜Žäº†ã€ +æ— æ§ä¹‰ã€‚ å†…æ ¸ä¿¡æ¯ä¸å¿…以å¥å·ï¼ˆè¯‘注:英文å¥å·ï¼Œå³ç‚¹ï¼‰ç»“æŸã€‚ -在å°æ‹¬å·é‡Œæ‰“å°æ•°å—(%d)没有任何价值,应该é¿å…è¿™æ ·åšã€‚ +在å°æ‹¬å·é‡Œæ‰“å°æ•°å— (%d) 没有任何价值,应该é¿å…è¿™æ ·åšã€‚ -<linux/device.h>里有一些驱动模型诊æ–å®ï¼Œä½ 应该使用它们,以确ä¿ä¿¡æ¯å¯¹åº”于æ£ç¡®çš„ -è®¾å¤‡å’Œé©±åŠ¨ï¼Œå¹¶ä¸”è¢«æ ‡è®°äº†æ£ç¡®çš„消æ¯çº§åˆ«ã€‚这些å®æœ‰ï¼šdev_err(), dev_warn(), -dev_info()ç‰ç‰ã€‚对于那些ä¸å’ŒæŸä¸ªç‰¹å®šè®¾å¤‡ç›¸å…³è¿žçš„ä¿¡æ¯ï¼Œ<linux/kernel.h>定义了 -pr_debug()å’Œpr_info()。 +<linux/device.h> 里有一些驱动模型诊æ–å®ï¼Œä½ 应该使用它们,以确ä¿ä¿¡æ¯å¯¹åº”于æ£ç¡®çš„ +è®¾å¤‡å’Œé©±åŠ¨ï¼Œå¹¶ä¸”è¢«æ ‡è®°äº†æ£ç¡®çš„消æ¯çº§åˆ«ã€‚这些å®æœ‰ï¼šdev_err(),dev_warn(), +dev_info() ç‰ç‰ã€‚对于那些ä¸å’ŒæŸä¸ªç‰¹å®šè®¾å¤‡ç›¸å…³è¿žçš„ä¿¡æ¯ï¼Œ<linux/printk.h> 定义了 +pr_notice(),pr_info(),pr_warn(),pr_err() 和其他。 -写出好的调试信æ¯å¯ä»¥æ˜¯ä¸€ä¸ªå¾ˆå¤§çš„æŒ‘æˆ˜ï¼›å½“ä½ å†™å‡ºæ¥ä¹‹åŽï¼Œè¿™äº›ä¿¡æ¯åœ¨è¿œç¨‹é™¤é”™çš„时候 -就会æˆä¸ºæžå¤§çš„帮助。当DEBUG符å·æ²¡æœ‰è¢«å®šä¹‰çš„时候,这些信æ¯ä¸åº”è¯¥è¢«ç¼–è¯‘è¿›å†…æ ¸é‡Œ -(也就是说,默认地,它们ä¸åº”该被包å«åœ¨å†…ï¼‰ã€‚å¦‚æžœä½ ä½¿ç”¨dev_dbg()或者pr_debug(), -就能自动达到这个效果。很多å系统拥有Kconfig选项æ¥å¯ç”¨-DDEBUG。还有一个相关的惯例 -是使用VERBOSE_DEBUGæ¥æ·»åŠ dev_vdbg()消æ¯åˆ°é‚£äº›å·²ç»ç”±DEBUGå¯ç”¨çš„消æ¯ä¹‹ä¸Šã€‚ +写出好的调试信æ¯å¯ä»¥æ˜¯ä¸€ä¸ªå¾ˆå¤§çš„æŒ‘æˆ˜ï¼›ä¸€æ—¦ä½ å†™å‡ºåŽï¼Œè¿™äº›ä¿¡æ¯åœ¨è¿œç¨‹é™¤é”™æ—¶èƒ½æä¾›æžå¤§ +的帮助。然而打å°è°ƒè¯•ä¿¡æ¯çš„处ç†æ–¹å¼åŒæ‰“å°éžè°ƒè¯•ä¿¡æ¯ä¸åŒã€‚其他 pr_XXX() å‡½æ•°èƒ½æ— æ¡ä»¶åœ° +打å°ï¼Œpr_debug() å´ä¸ï¼›é»˜è®¤æƒ…况下它ä¸ä¼šè¢«ç¼–译,除éžå®šä¹‰äº† DEBUG 或设定了 +CONFIG_DYNAMIC_DEBUG。实际这åŒæ ·æ˜¯ä¸ºäº† dev_dbg(),一个相关约定是在一个已ç»å¼€å¯äº† +DEBUG 时,使用 VERBOSE_DEBUG æ¥æ·»åŠ dev_vdbg()。 + +许多å系统拥有 Kconfig 调试选项æ¥å¼€å¯ -DDEBUG 在对应的 Makefile 里é¢ï¼›åœ¨å…¶ä»– +情况下,特殊文件使用 #define DEBUG。当一æ¡è°ƒè¯•ä¿¡æ¯éœ€è¦è¢«æ— æ¡ä»¶æ‰“å°æ—¶ï¼Œä¾‹å¦‚,如果 +å·²ç»åŒ…å«ä¸€ä¸ªè°ƒè¯•ç›¸å…³çš„ #ifdef æ¡ä»¶ï¼Œprintk(KERN_DEBUG ...) å°±å¯è¢«ä½¿ç”¨ã€‚ 第åå››ç« ï¼šåˆ†é…å†…å˜ -å†…æ ¸æ供了下é¢çš„一般用途的内å˜åˆ†é…函数:kmalloc(),kzalloc(),kcalloc()å’Œ -vmalloc()。请å‚考API文档以获å–有关它们的详细信æ¯ã€‚ +å†…æ ¸æ供了下é¢çš„一般用途的内å˜åˆ†é…函数: +kmalloc(),kzalloc(),kmalloc_array(),kcalloc(),vmalloc() å’Œ vzalloc()。 +请å‚考 API 文档以获å–有关它们的详细信æ¯ã€‚ ä¼ é€’ç»“æž„ä½“å¤§å°çš„首选形å¼æ˜¯è¿™æ ·çš„: p = kmalloc(sizeof(*p), ...); -å¦å¤–一ç§ä¼ 递方å¼ä¸ï¼Œsizeofçš„æ“作数是结构体的åå—ï¼Œè¿™æ ·ä¼šé™ä½Žå¯è¯»æ€§ï¼Œå¹¶ä¸”å¯èƒ½ä¼šå¼• -å…¥bug。有å¯èƒ½æŒ‡é’ˆå˜é‡ç±»åž‹è¢«æ”¹å˜æ—¶ï¼Œè€Œå¯¹åº”çš„ä¼ é€’ç»™å†…å˜åˆ†é…函数的sizeof的结果ä¸å˜ã€‚ +å¦å¤–一ç§ä¼ 递方å¼ä¸ï¼Œsizeof çš„æ“作数是结构体的åå—ï¼Œè¿™æ ·ä¼šé™ä½Žå¯è¯»æ€§ï¼Œå¹¶ä¸”å¯èƒ½ä¼šå¼• +å…¥ bug。有å¯èƒ½æŒ‡é’ˆå˜é‡ç±»åž‹è¢«æ”¹å˜æ—¶ï¼Œè€Œå¯¹åº”çš„ä¼ é€’ç»™å†…å˜åˆ†é…函数的 sizeof 的结果ä¸å˜ã€‚ -强制转æ¢ä¸€ä¸ªvoid指针返回值是多余的。Cè¯è¨€æœ¬èº«ä¿è¯äº†ä»Žvoid指针到其他任何指针类型 +强制转æ¢ä¸€ä¸ª void 指针返回值是多余的。C è¯è¨€æœ¬èº«ä¿è¯äº†ä»Ž void 指针到其他任何指针类型 的转æ¢æ˜¯æ²¡æœ‰é—®é¢˜çš„。 +分é…一个数组的首选形å¼æ˜¯è¿™æ ·çš„: + + p = kmalloc_array(n, sizeof(...), ...); + +分é…一个零长数组的首选形å¼æ˜¯è¿™æ ·çš„: + + p = kcalloc(n, sizeof(...), ...); + +两ç§å½¢å¼æ£€æŸ¥åˆ†é…å¤§å° n * sizeof(...) 的溢出,如果溢出返回 NULL。 + 第åäº”ç« ï¼šå†…è”弊病 -有一个常è§çš„误解是内è”函数是gccæ供的å¯ä»¥è®©ä»£ç è¿è¡Œæ›´å¿«çš„ä¸€ä¸ªé€‰é¡¹ã€‚è™½ç„¶ä½¿ç”¨å†…è” +有一个常è§çš„误解是内è”函数是 gcc æ供的å¯ä»¥è®©ä»£ç è¿è¡Œæ›´å¿«çš„ä¸€ä¸ªé€‰é¡¹ã€‚è™½ç„¶ä½¿ç”¨å†…è” å‡½æ•°æœ‰æ—¶å€™æ˜¯æ°å½“的(比如作为一ç§æ›¿ä»£å®çš„æ–¹å¼ï¼Œè¯·çœ‹ç¬¬åäºŒç« ï¼‰ï¼Œä¸è¿‡å¾ˆå¤šæƒ…况下ä¸æ˜¯ -è¿™æ ·ã€‚inline关键å—çš„è¿‡åº¦ä½¿ç”¨ä¼šä½¿å†…æ ¸å˜å¤§ï¼Œä»Žè€Œä½¿æ•´ä¸ªç³»ç»Ÿè¿è¡Œé€Ÿåº¦å˜æ…¢ã€‚å› ä¸ºå¤§å†…æ ¸ +è¿™æ ·ã€‚inline 关键å—çš„è¿‡åº¦ä½¿ç”¨ä¼šä½¿å†…æ ¸å˜å¤§ï¼Œä»Žè€Œä½¿æ•´ä¸ªç³»ç»Ÿè¿è¡Œé€Ÿåº¦å˜æ…¢ã€‚å› ä¸ºå¤§å†…æ ¸ 会å 用更多的指令高速缓å˜ï¼ˆè¯‘注:一级缓å˜é€šå¸¸æ˜¯æŒ‡ä»¤ç¼“å˜å’Œæ•°æ®ç¼“å˜åˆ†å¼€çš„)而且会导 -致pagecacheçš„å¯ç”¨å†…å˜å‡å°‘。想象一下,一次pagecache未命ä¸å°±ä¼šå¯¼è‡´ä¸€æ¬¡ç£ç›˜å¯»å€ï¼Œå°† -耗时5毫秒。5毫秒的时间内CPU能执行很多很多指令。 +致 pagecache çš„å¯ç”¨å†…å˜å‡å°‘。想象一下,一次pagecache未命ä¸å°±ä¼šå¯¼è‡´ä¸€æ¬¡ç£ç›˜å¯»å€ï¼Œ +将耗时 5 毫秒。5 毫秒的时间内 CPU 能执行很多很多指令。 -一个基本的原则是如果一个函数有3行以上,就ä¸è¦æŠŠå®ƒå˜æˆå†…è”函数。这个原则的一个例 +一个基本的原则是如果一个函数有 3 行以上,就ä¸è¦æŠŠå®ƒå˜æˆå†…è”函数。这个原则的一个例 å¤–æ˜¯ï¼Œå¦‚æžœä½ çŸ¥é“æŸä¸ªå‚数是一个编译时常é‡ï¼Œè€Œä¸”å› ä¸ºè¿™ä¸ªå¸¸é‡ä½ 确定编译器在编译时能 -ä¼˜åŒ–æŽ‰ä½ çš„å‡½æ•°çš„å¤§éƒ¨åˆ†ä»£ç ,那ä»ç„¶å¯ä»¥ç»™å®ƒåŠ 上inline关键å—。kmalloc()内è”函数就 +ä¼˜åŒ–æŽ‰ä½ çš„å‡½æ•°çš„å¤§éƒ¨åˆ†ä»£ç ,那ä»ç„¶å¯ä»¥ç»™å®ƒåŠ 上 inline 关键å—。kmalloc() 内è”函数就 是一个很好的例å。 -人们ç»å¸¸ä¸»å¼ ç»™static的而且åªç”¨äº†ä¸€æ¬¡çš„å‡½æ•°åŠ ä¸Šinline,如æ¤ä¸ä¼šæœ‰ä»»ä½•æŸå¤±ï¼Œå› 为没 -有什么好æƒè¡¡çš„。虽然从技术上说这是æ£ç¡®çš„,但是实际上这ç§æƒ…况下å³ä½¿ä¸åŠ inline gcc -也å¯ä»¥è‡ªåŠ¨ä½¿å…¶å†…è”。而且其他用户å¯èƒ½ä¼šè¦æ±‚移除inline,由æ¤è€Œæ¥çš„争论会抵消inline +人们ç»å¸¸ä¸»å¼ ç»™ static 的而且åªç”¨äº†ä¸€æ¬¡çš„å‡½æ•°åŠ ä¸Š inline,如æ¤ä¸ä¼šæœ‰ä»»ä½•æŸå¤±ï¼Œå› 为没 +有什么好æƒè¡¡çš„。虽然从技术上说这是æ£ç¡®çš„,但是实际上这ç§æƒ…况下å³ä½¿ä¸åŠ inline gcc +也å¯ä»¥è‡ªåŠ¨ä½¿å…¶å†…è”。而且其他用户å¯èƒ½ä¼šè¦æ±‚移除 inline,由æ¤è€Œæ¥çš„争论会抵消 inline 自身的潜在价值,得ä¸å¿å¤±ã€‚ @@ -613,37 +674,37 @@ vmalloc()。请å‚考API文档以获å–有关它们的详细信æ¯ã€‚ 的一个值å¯ä»¥è¡¨ç¤ºä¸ºä¸€ä¸ªé”™è¯¯ä»£ç 整数(-Exxxï¼å¤±è´¥ï¼Œ0ï¼æˆåŠŸï¼‰æˆ–者一个“æˆåŠŸâ€å¸ƒå°”值( 0ï¼å¤±è´¥ï¼Œéž0ï¼æˆåŠŸï¼‰ã€‚ -æ··åˆä½¿ç”¨è¿™ä¸¤ç§è¡¨è¾¾æ–¹å¼æ˜¯éš¾äºŽå‘现的bugçš„æ¥æºã€‚如果Cè¯è¨€æœ¬èº«ä¸¥æ ¼åŒºåˆ†æ•´å½¢å’Œå¸ƒå°”åž‹å˜ -é‡ï¼Œé‚£ä¹ˆç¼–译器就能够帮我们å‘现这些错误……ä¸è¿‡Cè¯è¨€ä¸åŒºåˆ†ã€‚为了é¿å…产生这ç§bug,请 +æ··åˆä½¿ç”¨è¿™ä¸¤ç§è¡¨è¾¾æ–¹å¼æ˜¯éš¾äºŽå‘现的 bug çš„æ¥æºã€‚如果 C è¯è¨€æœ¬èº«ä¸¥æ ¼åŒºåˆ†æ•´å½¢å’Œå¸ƒå°”åž‹å˜ +é‡ï¼Œé‚£ä¹ˆç¼–译器就能够帮我们å‘现这些错误……ä¸è¿‡ C è¯è¨€ä¸åŒºåˆ†ã€‚为了é¿å…äº§ç”Ÿè¿™ç§ bug,请 éµå¾ªä¸‹é¢çš„惯例: 如果函数的åå—是一个动作或者强制性的命令,那么这个函数应该返回错误代ç æ•´ 数。如果是一个判æ–,那么函数应该返回一个“æˆåŠŸâ€å¸ƒå°”值。 -比如,“add workâ€æ˜¯ä¸€ä¸ªå‘½ä»¤ï¼Œæ‰€ä»¥add_work()函数在æˆåŠŸæ—¶è¿”回0,在失败时返回-EBUSY。 -ç±»ä¼¼çš„ï¼Œå› ä¸ºâ€œPCI device presentâ€æ˜¯ä¸€ä¸ªåˆ¤æ–,所以pci_dev_present()函数在æˆåŠŸæ‰¾åˆ° -一个匹é…的设备时应该返回1,如果找ä¸åˆ°æ—¶åº”该返回0。 +比如,“add work†是一个命令,所以 add_work() 函数在æˆåŠŸæ—¶è¿”回 0,在失败时返回 -EBUSY。 +ç±»ä¼¼çš„ï¼Œå› ä¸º “PCI device present†是一个判æ–,所以 pci_dev_present() 函数在æˆåŠŸæ‰¾åˆ° +一个匹é…的设备时应该返回 1,如果找ä¸åˆ°æ—¶åº”该返回 0。 所有导出(译注:EXPORT)的函数都必须éµå®ˆè¿™ä¸ªæƒ¯ä¾‹ï¼Œæ‰€æœ‰çš„公共函数也都应该如æ¤ã€‚ç§ æœ‰ï¼ˆstatic)函数ä¸éœ€è¦å¦‚æ¤ï¼Œä½†æ˜¯æˆ‘们也推èè¿™æ ·åšã€‚ 返回值是实际计算结果而ä¸æ˜¯è®¡ç®—是å¦æˆåŠŸçš„æ ‡å¿—çš„å‡½æ•°ä¸å—æ¤æƒ¯ä¾‹çš„é™åˆ¶ã€‚一般的,他们 通过返回一些æ£å¸¸å€¼èŒƒå›´ä¹‹å¤–的结果æ¥è¡¨ç¤ºå‡ºé”™ã€‚典型的例å是返回指针的函数,他们使用 -NULL或者ERR_PTR机制æ¥æŠ¥å‘Šé”™è¯¯ã€‚ +NULL 或者 ERR_PTR 机制æ¥æŠ¥å‘Šé”™è¯¯ã€‚ 第åä¸ƒç« ï¼šä¸è¦é‡æ–°å‘æ˜Žå†…æ ¸å® -头文件include/linux/kernel.h包å«äº†ä¸€äº›å®ï¼Œä½ 应该使用它们,而ä¸è¦è‡ªå·±å†™ä¸€äº›å®ƒä»¬çš„ +头文件 include/linux/kernel.h 包å«äº†ä¸€äº›å®ï¼Œä½ 应该使用它们,而ä¸è¦è‡ªå·±å†™ä¸€äº›å®ƒä»¬çš„ å˜ç§ã€‚æ¯”å¦‚ï¼Œå¦‚æžœä½ éœ€è¦è®¡ç®—ä¸€ä¸ªæ•°ç»„çš„é•¿åº¦ï¼Œä½¿ç”¨è¿™ä¸ªå® - #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) ç±»ä¼¼çš„ï¼Œå¦‚æžœä½ è¦è®¡ç®—æŸç»“构体æˆå‘˜çš„大å°ï¼Œä½¿ç”¨ - #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) + #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) -还有å¯ä»¥åšä¸¥æ ¼çš„类型检查的min()å’Œmax()å®ï¼Œå¦‚æžœä½ éœ€è¦å¯ä»¥ä½¿ç”¨å®ƒä»¬ã€‚ä½ å¯ä»¥è‡ªå·±çœ‹çœ‹ +还有å¯ä»¥åšä¸¥æ ¼çš„类型检查的 min() å’Œ max() å®ï¼Œå¦‚æžœä½ éœ€è¦å¯ä»¥ä½¿ç”¨å®ƒä»¬ã€‚ä½ å¯ä»¥è‡ªå·±çœ‹çœ‹ é‚£ä¸ªå¤´æ–‡ä»¶é‡Œè¿˜å®šä¹‰äº†ä»€ä¹ˆä½ å¯ä»¥æ‹¿æ¥ç”¨çš„东西,如果有定义的è¯ï¼Œä½ å°±ä¸åº”åœ¨ä½ çš„ä»£ç 里 自己é‡æ–°å®šä¹‰ã€‚ @@ -653,42 +714,100 @@ NULL或者ERR_PTR机制æ¥æŠ¥å‘Šé”™è¯¯ã€‚ 有一些编辑器å¯ä»¥è§£é‡ŠåµŒå…¥åœ¨æºæ–‡ä»¶é‡Œçš„ç”±ä¸€äº›ç‰¹æ®Šæ ‡è®°æ ‡æ˜Žçš„é…置信æ¯ã€‚比如,emacs èƒ½å¤Ÿè§£é‡Šè¢«æ ‡è®°æˆè¿™æ ·çš„行: --*- mode: c -*- + -*- mode: c -*- æˆ–è€…è¿™æ ·çš„ï¼š -/* -Local Variables: -compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c" -End: -*/ + /* + Local Variables: + compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c" + End: + */ -Vimèƒ½å¤Ÿè§£é‡Šè¿™æ ·çš„æ ‡è®°ï¼š +Vim èƒ½å¤Ÿè§£é‡Šè¿™æ ·çš„æ ‡è®°ï¼š -/* vim:set sw=8 noet */ + /* vim:set sw=8 noet */ ä¸è¦åœ¨æºä»£ç ä¸åŒ…å«ä»»ä½•è¿™æ ·çš„内容。æ¯ä¸ªäººéƒ½æœ‰ä»–自己的编辑器é…ç½®ï¼Œä½ çš„æºæ–‡ä»¶ä¸åº” 该覆盖别人的é…置。这包括有关缩进和模å¼é…ç½®çš„æ ‡è®°ã€‚äººä»¬å¯ä»¥ä½¿ç”¨ä»–们自己定制的模 å¼ï¼Œæˆ–者使用其他å¯ä»¥äº§ç”Ÿæ£ç¡®çš„缩进的巧妙方法。 + 第åä¹ç« :内è”汇编 + +在特定架构的代ç ä¸ï¼Œä½ 也许需è¦å†…è”汇编æ¥ä½¿ç”¨ CPU 接å£å’Œå¹³å°ç›¸å…³åŠŸèƒ½ã€‚åœ¨éœ€è¦ +这么åšæ—¶ï¼Œä¸è¦çŠ¹è±«ã€‚然而,当 C å¯ä»¥å®Œæˆå·¥ä½œæ—¶ï¼Œä¸è¦æ— 端地使用内è”汇编。如果 +å¯èƒ½ï¼Œä½ å¯ä»¥å¹¶ä¸”应该用 C 和硬件交互。 + +考虑去写通用一点的内è”汇编作为简明的辅助函数,而ä¸æ˜¯é‡å¤å†™ä¸‹å®ƒä»¬çš„ç»†èŠ‚ã€‚è®°ä½ +内è”汇编å¯ä»¥ä½¿ç”¨ C å‚数。 + +大而特殊的汇编函数应该放在 .S 文件ä¸ï¼Œå¯¹åº” C 的原型定义在 C 头文件ä¸ã€‚汇编 +函数的 C 原型应该使用 “asmlinkageâ€ã€‚ + +ä½ å¯èƒ½éœ€è¦å°†ä½ 的汇编è¯å¥æ ‡è®°ä¸º volatile,æ¥é˜»æ¢ GCC 在没å‘现任何副作用åŽå°± +ç§»é™¤äº†å®ƒã€‚ä½ ä¸å¿…æ€»æ˜¯è¿™æ ·åšï¼Œè™½ç„¶ï¼Œè¿™æ ·å¯ä»¥é™åˆ¶ä¸å¿…è¦çš„优化。 + +在写一个包å«å¤šæ¡æŒ‡ä»¤çš„å•ä¸ªå†…è”汇编è¯å¥æ—¶ï¼ŒæŠŠæ¯æ¡æŒ‡ä»¤ç”¨å¼•å·å—符串分离,并写在 +å•ç‹¬ä¸€è¡Œï¼Œåœ¨æ¯ä¸ªå—符串结尾,除了 \n\t 结尾之外,在汇编输出ä¸é€‚当地缩进下 +一æ¡æŒ‡ä»¤ï¼š + + asm ("magic %reg1, #42\n\t" + "more_magic %reg2, %reg3" + : /* outputs */ : /* inputs */ : /* clobbers */); + + + 第二åç« ï¼šæ¡ä»¶ç¼–译 + +åªè¦å¯èƒ½ï¼Œå°±ä¸è¦åœ¨ .c 文件里é¢ä½¿ç”¨é¢„处ç†æ¡ä»¶ï¼›è¿™æ ·åšè®©ä»£ç 更难阅读并且逻辑难以 +跟踪。替代方案是,在头文件定义函数在这些 .c 文件ä¸ä½¿ç”¨è¿™ç±»çš„æ¡ä»¶è¡¨è¾¾å¼ï¼Œæ供空 +æ“作的桩版本(译注:桩程åºï¼Œæ˜¯æŒ‡ç”¨æ¥æ›¿æ¢ä¸€éƒ¨åˆ†åŠŸèƒ½çš„程åºæ®µï¼‰åœ¨ #else 情况下, +å†ä»Ž .c 文件ä¸æ— æ¡ä»¶åœ°è°ƒç”¨è¿™äº›å‡½æ•°ã€‚编译器会é¿å…生æˆä»»ä½•æ¡©è°ƒç”¨çš„代ç ,产生一致 +çš„ç»“æžœï¼Œä½†é€»è¾‘å°†æ›´åŠ æ¸…æ™°ã€‚ + +å®å¯ç¼–译整个函数,而ä¸æ˜¯éƒ¨åˆ†å‡½æ•°æˆ–部分表达å¼ã€‚而ä¸æ˜¯åœ¨ä¸€ä¸ªè¡¨è¾¾å¼æ·»åŠ ifdef, +解æžéƒ¨åˆ†æˆ–全部表达å¼åˆ°ä¸€ä¸ªå•ç‹¬çš„辅助函数,并应用æ¡ä»¶åˆ°è¯¥å‡½æ•°å†…。 + +å¦‚æžœä½ æœ‰ä¸€ä¸ªåœ¨ç‰¹å®šé…ç½®ä¸å¯èƒ½æ˜¯æœªä½¿ç”¨çš„函数或å˜é‡ï¼Œç¼–译器将è¦å‘Šå®ƒå®šä¹‰äº†ä½†æœªä½¿ç”¨ï¼Œ +æ ‡è®°è¿™ä¸ªå®šä¹‰ä¸º __maybe_unused 而ä¸æ˜¯å°†å®ƒåŒ…å«åœ¨ä¸€ä¸ªé¢„处ç†æ¡ä»¶ä¸ã€‚(然而,如果 +一个函数或å˜é‡æ€»æ˜¯æœªä½¿ç”¨çš„ï¼Œå°±ç›´æŽ¥åˆ é™¤å®ƒã€‚ï¼‰ + +在代ç ä¸ï¼Œå¯èƒ½çš„情况下,使用 IS_ENABLED å®æ¥è½¬åŒ–æŸä¸ª Kconfig æ ‡è®°ä¸º C 的布尔 +表达å¼ï¼Œå¹¶åœ¨æ£å¸¸çš„ C æ¡ä»¶ä¸ä½¿ç”¨å®ƒï¼š + + if (IS_ENABLED(CONFIG_SOMETHING)) { + ... + } + +ç¼–è¯‘å™¨ä¼šæ— æ¡ä»¶åœ°åšå¸¸æ•°åˆå¹¶ï¼Œå°±åƒä½¿ç”¨ #ifdef é‚£æ ·ï¼ŒåŒ…å«æˆ–排除代ç å—,所以这ä¸ä¼š +带æ¥ä»»ä½•è¿è¡Œæ—¶å¼€é”€ã€‚然而,这ç§æ–¹æ³•ä¾æ—§å…许 C 编译器查看å—内的代ç ,并检查它的æ£ç¡® +性(è¯æ³•ï¼Œç±»åž‹ï¼Œç¬¦å·å¼•ç”¨ï¼Œç‰ç‰ï¼‰ã€‚å› æ¤ï¼Œå¦‚æžœæ¡ä»¶ä¸æ»¡è¶³ï¼Œä»£ç å—内的引用符å·å°†ä¸å˜åœ¨ï¼Œ +ä½ å¿…é¡»ç»§ç»ä½¿ç”¨ #ifdef。 + +在任何有æ„义的 #if 或 #ifdef å—çš„æœ«å°¾ï¼ˆè¶…è¿‡å‡ è¡Œï¼‰ï¼Œåœ¨ #endif åŒä¸€è¡Œçš„åŽé¢å†™ä¸‹ +注释,指出该æ¡ä»¶è¡¨è¾¾å¼è¢«ä½¿ç”¨ã€‚例如: + + #ifdef CONFIG_SOMETHING + ... + #endif /* CONFIG_SOMETHING */ + 附录 I:å‚考 -The C Programming Language, 第二版, 作者Brian W. Kernighanå’ŒDenni -M. Ritchie. Prentice Hall, Inc., 1988. ISBN 0-13-110362-8 (软皮), -0-13-110370-9 (硬皮). URL: http://cm.bell-labs.com/cm/cs/cbook/ +The C Programming Language, 第二版 +作者:Brian W. Kernighan å’Œ Denni M. Ritchie. +Prentice Hall, Inc., 1988. +ISBN 0-13-110362-8 (软皮), 0-13-110370-9 (硬皮). -The Practice of Programming 作者Brian W. Kernighanå’ŒRob Pike. Addison-Wesley, -Inc., 1999. ISBN 0-201-61586-X. URL: http://cm.bell-labs.com/cm/cs/tpop/ +The Practice of Programming +作者:Brian W. Kernighan å’Œ Rob Pike. +Addison-Wesley, Inc., 1999. +ISBN 0-201-61586-X. -cpp,gcc,gcc internalså’Œindentçš„GNU手册——和K&RåŠæœ¬æ–‡ç›¸ç¬¦åˆçš„部分,全部å¯ä»¥åœ¨ -http://www.gnu.org/manual/找到 +GNU 手册 - éµå¾ª K&R æ ‡å‡†å’Œæ¤æ–‡æœ¬ - cpp, gcc, gcc internals and indent, +都å¯ä»¥ä»Ž http://www.gnu.org/manual/ 找到 WG14是Cè¯è¨€çš„å›½é™…æ ‡å‡†åŒ–å·¥ä½œç»„ï¼ŒURL: http://www.open-std.org/JTC1/SC22/WG14/ -Kernel CodingStyle,作者greg@kroah.comå‘表于OLS 2002: +Kernel CodingStyle,作者 greg@kroah.com å‘表于OLS 2002: http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/ - --- -最åŽæ›´æ–°äºŽ2007å¹´7月13日。 diff --git a/Makefile b/Makefile index 0f70de63cfdb450c31e4a346d669047585c8063c..f7f393c4088627b6e4c129b3db68ae1928d4479f 100644 --- a/Makefile +++ b/Makefile @@ -1364,6 +1364,8 @@ help: @$(MAKE) $(build)=$(package-dir) help @echo '' @echo 'Documentation targets:' + @$(MAKE) -f $(srctree)/Documentation/Makefile.sphinx dochelp + @echo '' @$(MAKE) -f $(srctree)/Documentation/DocBook/Makefile dochelp @echo '' @echo 'Architecture specific targets ($(SRCARCH)):' @@ -1412,8 +1414,11 @@ $(help-board-dirs): help-%: # Documentation targets # --------------------------------------------------------------------------- -%docs: scripts_basic FORCE +DOC_TARGETS := xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs epubdocs cleandocs +PHONY += $(DOC_TARGETS) +$(DOC_TARGETS): scripts_basic FORCE $(Q)$(MAKE) $(build)=scripts build_docproc build_check-lc_ctype + $(Q)$(MAKE) $(build)=Documentation -f $(srctree)/Documentation/Makefile.sphinx $@ $(Q)$(MAKE) $(build)=Documentation/DocBook $@ else # KBUILD_EXTMOD diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 2fc8fad5195e8994a320013cd8c731a0d9469f63..932b3f34ff06384bdbd5cb41e467ba0659c3dc68 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -59,6 +59,12 @@ Output format selection (mutually exclusive): -text Output plain text format. Output selection (mutually exclusive): + -export Only output documentation for symbols that have been + exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL() + in any input FILE or -export-file FILE. + -internal Only output documentation for symbols that have NOT been + exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL() + in any input FILE or -export-file FILE. -function NAME Only output documentation for the given function(s) or DOC: section title(s). All other functions and DOC: sections are ignored. May be specified multiple times. @@ -68,6 +74,11 @@ Output selection (mutually exclusive): Output selection modifiers: -no-doc-sections Do not output DOC: sections. + -enable-lineno Enable output of #define LINENO lines. Only works with + reStructuredText format. + -export-file FILE Specify an additional FILE in which to look for + EXPORT_SYMBOL() and EXPORT_SYMBOL_GPL(). To be used with + -export or -internal. May be specified multiple times. Other parameters: -v Verbose output, more warnings and other information. @@ -206,6 +217,10 @@ my $type_struct_xml = '\\&((struct\s*)*[_\w]+)'; my $type_env = '(\$\w+)'; my $type_enum_full = '\&(enum)\s*([_\w]+)'; my $type_struct_full = '\&(struct)\s*([_\w]+)'; +my $type_typedef_full = '\&(typedef)\s*([_\w]+)'; +my $type_union_full = '\&(union)\s*([_\w]+)'; +my $type_member = '\&([_\w]+)((\.|->)[_\w]+)'; +my $type_member_func = $type_member . '\(\)'; # Output conversion substitutions. # One for each output format @@ -274,10 +289,16 @@ my $blankline_text = ""; # rst-mode my @highlights_rst = ( [$type_constant, "``\$1``"], - [$type_func, "\\:c\\:func\\:`\$1`"], + # Note: need to escape () to avoid func matching later + [$type_member_func, "\\:c\\:type\\:`\$1\$2\\\\(\\\\) <\$1>`"], + [$type_member, "\\:c\\:type\\:`\$1\$2 <\$1>`"], + [$type_func, "\\:c\\:func\\:`\$1()`"], [$type_struct_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], [$type_enum_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], - [$type_struct, "\\:c\\:type\\:`struct \$1 <\$1>`"], + [$type_typedef_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], + [$type_union_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], + # in rst this can refer to any type + [$type_struct, "\\:c\\:type\\:`\$1`"], [$type_param, "**\$1**"] ); my $blankline_rst = "\n"; @@ -303,12 +324,23 @@ my $verbose = 0; my $output_mode = "man"; my $output_preformatted = 0; my $no_doc_sections = 0; +my $enable_lineno = 0; my @highlights = @highlights_man; my $blankline = $blankline_man; my $modulename = "Kernel API"; -my $function_only = 0; + +use constant { + OUTPUT_ALL => 0, # output all symbols and doc sections + OUTPUT_INCLUDE => 1, # output only specified symbols + OUTPUT_EXCLUDE => 2, # output everything except specified symbols + OUTPUT_EXPORTED => 3, # output exported symbols + OUTPUT_INTERNAL => 4, # output non-exported symbols +}; +my $output_selection = OUTPUT_ALL; my $show_not_found = 0; +my @export_file_list; + my @build_time; if (defined($ENV{'KBUILD_BUILD_TIMESTAMP'}) && (my $seconds = `date -d"${ENV{'KBUILD_BUILD_TIMESTAMP'}}" +%s`) ne '') { @@ -327,6 +359,7 @@ my $man_date = ('January', 'February', 'March', 'April', 'May', 'June', # CAVEAT EMPTOR! Some of the others I localised may not want to be, which # could cause "use of undefined value" or other bugs. my ($function, %function_table, %parametertypes, $declaration_purpose); +my $declaration_start_line; my ($type, $declaration_name, $return_type); my ($newsection, $newcontents, $prototype, $brcount, %source_map); @@ -344,52 +377,62 @@ my $section_counter = 0; my $lineprefix=""; -# states -# 0 - normal code -# 1 - looking for function name -# 2 - scanning field start. -# 3 - scanning prototype. -# 4 - documentation block -# 5 - gathering documentation outside main block +# Parser states +use constant { + STATE_NORMAL => 0, # normal code + STATE_NAME => 1, # looking for function name + STATE_FIELD => 2, # scanning field start + STATE_PROTO => 3, # scanning prototype + STATE_DOCBLOCK => 4, # documentation block + STATE_INLINE => 5, # gathering documentation outside main block +}; my $state; my $in_doc_sect; -# Split Doc State -# 0 - Invalid (Before start or after finish) -# 1 - Is started (the /** was found inside a struct) -# 2 - The @parameter header was found, start accepting multi paragraph text. -# 3 - Finished (the */ was found) -# 4 - Error - Comment without header was found. Spit a warning as it's not -# proper kernel-doc and ignore the rest. -my $split_doc_state; +# Inline documentation state +use constant { + STATE_INLINE_NA => 0, # not applicable ($state != STATE_INLINE) + STATE_INLINE_NAME => 1, # looking for member name (@foo:) + STATE_INLINE_TEXT => 2, # looking for member documentation + STATE_INLINE_END => 3, # done + STATE_INLINE_ERROR => 4, # error - Comment without header was found. + # Spit a warning as it's not + # proper kernel-doc and ignore the rest. +}; +my $inline_doc_state; #declaration types: can be # 'function', 'struct', 'union', 'enum', 'typedef' my $decl_type; -my $doc_special = "\@\%\$\&"; - my $doc_start = '^/\*\*\s*$'; # Allow whitespace at end of comment start. my $doc_end = '\*/'; my $doc_com = '\s*\*\s*'; my $doc_com_body = '\s*\* ?'; my $doc_decl = $doc_com . '(\w+)'; -my $doc_sect = $doc_com . '([' . $doc_special . ']?[\w\s]+):(.*)'; +# @params and a strictly limited set of supported section names +my $doc_sect = $doc_com . + '\s*(\@\w+|description|context|returns?|notes?|examples?)\s*:(.*)'; my $doc_content = $doc_com_body . '(.*)'; my $doc_block = $doc_com . 'DOC:\s*(.*)?'; -my $doc_split_start = '^\s*/\*\*\s*$'; -my $doc_split_sect = '\s*\*\s*(@[\w\s]+):(.*)'; -my $doc_split_end = '^\s*\*/\s*$'; +my $doc_inline_start = '^\s*/\*\*\s*$'; +my $doc_inline_sect = '\s*\*\s*(@[\w\s]+):(.*)'; +my $doc_inline_end = '^\s*\*/\s*$'; +my $export_symbol = '^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*;'; -my %constants; my %parameterdescs; +my %parameterdesc_start_lines; my @parameterlist; my %sections; my @sectionlist; +my %section_start_lines; my $sectcheck; my $struct_actual; my $contents = ""; +my $new_start_line = 0; + +# the canonical section names. see also $doc_sect above. my $section_default = "Description"; # default section my $section_intro = "Introduction"; my $section = $section_default; @@ -437,19 +480,30 @@ while ($ARGV[0] =~ m/^-(.*)/) { } elsif ($cmd eq "-module") { # not needed for XML, inherits from calling document $modulename = shift @ARGV; } elsif ($cmd eq "-function") { # to only output specific functions - $function_only = 1; + $output_selection = OUTPUT_INCLUDE; $function = shift @ARGV; $function_table{$function} = 1; - } elsif ($cmd eq "-nofunction") { # to only output specific functions - $function_only = 2; + } elsif ($cmd eq "-nofunction") { # output all except specific functions + $output_selection = OUTPUT_EXCLUDE; $function = shift @ARGV; $function_table{$function} = 1; + } elsif ($cmd eq "-export") { # only exported symbols + $output_selection = OUTPUT_EXPORTED; + %function_table = (); + } elsif ($cmd eq "-internal") { # only non-exported symbols + $output_selection = OUTPUT_INTERNAL; + %function_table = (); + } elsif ($cmd eq "-export-file") { + my $file = shift @ARGV; + push(@export_file_list, $file); } elsif ($cmd eq "-v") { $verbose = 1; } elsif (($cmd eq "-h") || ($cmd eq "--help")) { usage(); } elsif ($cmd eq '-no-doc-sections') { $no_doc_sections = 1; + } elsif ($cmd eq '-enable-lineno') { + $enable_lineno = 1; } elsif ($cmd eq '-show-not-found') { $show_not_found = 1; } @@ -467,6 +521,13 @@ sub get_kernel_version() { return $version; } +# +sub print_lineno { + my $lineno = shift; + if ($enable_lineno && defined($lineno)) { + print "#define LINENO " . $lineno . "\n"; + } +} ## # dumps section contents to arrays/hashes intended for that purpose. # @@ -475,28 +536,32 @@ sub dump_section { my $name = shift; my $contents = join "\n", @_; - if ($name =~ m/$type_constant/) { - $name = $1; -# print STDERR "constant section '$1' = '$contents'\n"; - $constants{$name} = $contents; - } elsif ($name =~ m/$type_param/) { -# print STDERR "parameter def '$1' = '$contents'\n"; + if ($name =~ m/$type_param/) { $name = $1; $parameterdescs{$name} = $contents; $sectcheck = $sectcheck . $name . " "; + $parameterdesc_start_lines{$name} = $new_start_line; + $new_start_line = 0; } elsif ($name eq "@\.\.\.") { -# print STDERR "parameter def '...' = '$contents'\n"; $name = "..."; $parameterdescs{$name} = $contents; $sectcheck = $sectcheck . $name . " "; + $parameterdesc_start_lines{$name} = $new_start_line; + $new_start_line = 0; } else { -# print STDERR "other section '$name' = '$contents'\n"; if (defined($sections{$name}) && ($sections{$name} ne "")) { - print STDERR "${file}:$.: error: duplicate section name '$name'\n"; - ++$errors; + # Only warn on user specified duplicate section names. + if ($name ne $section_default) { + print STDERR "${file}:$.: warning: duplicate section name '$name'\n"; + ++$warnings; + } + $sections{$name} .= $contents; + } else { + $sections{$name} = $contents; + push @sectionlist, $name; + $section_start_lines{$name} = $new_start_line; + $new_start_line = 0; } - $sections{$name} = $contents; - push @sectionlist, $name; } } @@ -512,15 +577,17 @@ sub dump_doc_section { return; } - if (($function_only == 0) || - ( $function_only == 1 && defined($function_table{$name})) || - ( $function_only == 2 && !defined($function_table{$name}))) + if (($output_selection == OUTPUT_ALL) || + ($output_selection == OUTPUT_INCLUDE && + defined($function_table{$name})) || + ($output_selection == OUTPUT_EXCLUDE && + !defined($function_table{$name}))) { dump_section($file, $name, $contents); output_blockhead({'sectionlist' => \@sectionlist, 'sections' => \%sections, 'module' => $modulename, - 'content-only' => ($function_only != 0), }); + 'content-only' => ($output_selection != OUTPUT_ALL), }); } } @@ -1736,7 +1803,10 @@ sub output_blockhead_rst(%) { my ($parameter, $section); foreach $section (@{$args{'sectionlist'}}) { - print "**$section**\n\n"; + if ($output_selection != OUTPUT_INCLUDE) { + print "**$section**\n\n"; + } + print_lineno($section_start_lines{$section}); output_highlight_rst($args{'sections'}{$section}); print "\n"; } @@ -1753,19 +1823,14 @@ sub output_highlight_rst { die $@ if $@; foreach $line (split "\n", $contents) { - if ($line eq "") { - print $lineprefix, $blankline; - } else { - $line =~ s/\\\\\\/\&/g; - print $lineprefix, $line; - } - print "\n"; + print $lineprefix . $line . "\n"; } } sub output_function_rst(%) { my %args = %{$_[0]}; my ($parameter, $section); + my $oldprefix = $lineprefix; my $start; print ".. c:function:: "; @@ -1790,29 +1855,37 @@ sub output_function_rst(%) { print $type . " " . $parameter; } } - print ")\n\n " . $args{'purpose'} . "\n\n"; + print ")\n\n"; + print_lineno($declaration_start_line); + $lineprefix = " "; + output_highlight_rst($args{'purpose'}); + print "\n"; - print ":Parameters:\n\n"; + print "**Parameters**\n\n"; + $lineprefix = " "; foreach $parameter (@{$args{'parameterlist'}}) { my $parameter_name = $parameter; #$parameter_name =~ s/\[.*//; $type = $args{'parametertypes'}{$parameter}; if ($type ne "") { - print " ``$type $parameter``\n"; + print "``$type $parameter``\n"; } else { - print " ``$parameter``\n"; + print "``$parameter``\n"; } - if ($args{'parameterdescs'}{$parameter_name} ne $undescribed) { - my $oldprefix = $lineprefix; - $lineprefix = " "; + + print_lineno($parameterdesc_start_lines{$parameter_name}); + + if (defined($args{'parameterdescs'}{$parameter_name}) && + $args{'parameterdescs'}{$parameter_name} ne $undescribed) { output_highlight_rst($args{'parameterdescs'}{$parameter_name}); - $lineprefix = $oldprefix; } else { - print "\n _undescribed_\n"; + print " *undescribed*\n"; } print "\n"; } + + $lineprefix = $oldprefix; output_section_rst(@_); } @@ -1820,10 +1893,11 @@ sub output_section_rst(%) { my %args = %{$_[0]}; my $section; my $oldprefix = $lineprefix; - $lineprefix = " "; + $lineprefix = ""; foreach $section (@{$args{'sectionlist'}}) { - print ":$section:\n\n"; + print "**$section**\n\n"; + print_lineno($section_start_lines{$section}); output_highlight_rst($args{'sections'}{$section}); print "\n"; } @@ -1834,24 +1908,28 @@ sub output_section_rst(%) { sub output_enum_rst(%) { my %args = %{$_[0]}; my ($parameter); + my $oldprefix = $lineprefix; my $count; my $name = "enum " . $args{'enum'}; print "\n\n.. c:type:: " . $name . "\n\n"; - print " " . $args{'purpose'} . "\n\n"; + print_lineno($declaration_start_line); + $lineprefix = " "; + output_highlight_rst($args{'purpose'}); + print "\n"; - print "..\n\n:Constants:\n\n"; - my $oldprefix = $lineprefix; - $lineprefix = " "; + print "**Constants**\n\n"; + $lineprefix = " "; foreach $parameter (@{$args{'parameterlist'}}) { - print " `$parameter`\n"; + print "``$parameter``\n"; if ($args{'parameterdescs'}{$parameter} ne $undescribed) { output_highlight_rst($args{'parameterdescs'}{$parameter}); } else { - print " undescribed\n"; + print " *undescribed*\n"; } print "\n"; } + $lineprefix = $oldprefix; output_section_rst(@_); } @@ -1859,30 +1937,37 @@ sub output_enum_rst(%) { sub output_typedef_rst(%) { my %args = %{$_[0]}; my ($parameter); - my $count; + my $oldprefix = $lineprefix; my $name = "typedef " . $args{'typedef'}; - ### FIXME: should the name below contain "typedef" or not? print "\n\n.. c:type:: " . $name . "\n\n"; - print " " . $args{'purpose'} . "\n\n"; + print_lineno($declaration_start_line); + $lineprefix = " "; + output_highlight_rst($args{'purpose'}); + print "\n"; + $lineprefix = $oldprefix; output_section_rst(@_); } sub output_struct_rst(%) { my %args = %{$_[0]}; my ($parameter); + my $oldprefix = $lineprefix; my $name = $args{'type'} . " " . $args{'struct'}; print "\n\n.. c:type:: " . $name . "\n\n"; - print " " . $args{'purpose'} . "\n\n"; + print_lineno($declaration_start_line); + $lineprefix = " "; + output_highlight_rst($args{'purpose'}); + print "\n"; - print ":Definition:\n\n"; - print " ::\n\n"; + print "**Definition**\n\n"; + print "::\n\n"; print " " . $args{'type'} . " " . $args{'struct'} . " {\n"; foreach $parameter (@{$args{'parameterlist'}}) { if ($parameter =~ /^#/) { - print " " . "$parameter\n"; + print " " . "$parameter\n"; next; } @@ -1903,7 +1988,8 @@ sub output_struct_rst(%) { } print " };\n\n"; - print ":Members:\n\n"; + print "**Members**\n\n"; + $lineprefix = " "; foreach $parameter (@{$args{'parameterlist'}}) { ($parameter =~ /^#/) && next; @@ -1912,14 +1998,14 @@ sub output_struct_rst(%) { ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; $type = $args{'parametertypes'}{$parameter}; - print " `$type $parameter`" . "\n"; - my $oldprefix = $lineprefix; - $lineprefix = " "; + print_lineno($parameterdesc_start_lines{$parameter_name}); + print "``$type $parameter``\n"; output_highlight_rst($args{'parameterdescs'}{$parameter_name}); - $lineprefix = $oldprefix; print "\n"; } print "\n"; + + $lineprefix = $oldprefix; output_section_rst(@_); } @@ -1969,9 +2055,13 @@ sub output_declaration { my $name = shift; my $functype = shift; my $func = "output_${functype}_$output_mode"; - if (($function_only==0) || - ( $function_only == 1 && defined($function_table{$name})) || - ( $function_only == 2 && !($functype eq "function" && defined($function_table{$name})))) + if (($output_selection == OUTPUT_ALL) || + (($output_selection == OUTPUT_INCLUDE || + $output_selection == OUTPUT_EXPORTED) && + defined($function_table{$name})) || + (($output_selection == OUTPUT_EXCLUDE || + $output_selection == OUTPUT_INTERNAL) && + !($functype eq "function" && defined($function_table{$name})))) { &$func(@_); $section_counter++; @@ -2471,7 +2561,6 @@ sub dump_function($$) { sub reset_state { $function = ""; - %constants = (); %parameterdescs = (); %parametertypes = (); @parameterlist = (); @@ -2481,8 +2570,8 @@ sub reset_state { $struct_actual = ""; $prototype = ""; - $state = 0; - $split_doc_state = 0; + $state = STATE_NORMAL; + $inline_doc_state = STATE_INLINE_NA; } sub tracepoint_munge($) { @@ -2545,7 +2634,7 @@ sub syscall_munge() { } } -sub process_state3_function($$) { +sub process_proto_function($$) { my $x = shift; my $file = shift; @@ -2575,7 +2664,7 @@ sub process_state3_function($$) { } } -sub process_state3_type($$) { +sub process_proto_type($$) { my $x = shift; my $file = shift; @@ -2649,25 +2738,54 @@ sub local_unescape($) { return $text; } -sub process_file($) { +sub map_filename($) { my $file; - my $identifier; - my $func; - my $descr; - my $in_purpose = 0; - my $initial_section_counter = $section_counter; my ($orig_file) = @_; if (defined($ENV{'SRCTREE'})) { $file = "$ENV{'SRCTREE'}" . "/" . $orig_file; - } - else { + } else { $file = $orig_file; } + if (defined($source_map{$file})) { $file = $source_map{$file}; } + return $file; +} + +sub process_export_file($) { + my ($orig_file) = @_; + my $file = map_filename($orig_file); + + if (!open(IN,"<$file")) { + print STDERR "Error: Cannot open file $file\n"; + ++$errors; + return; + } + + while (<IN>) { + if (/$export_symbol/) { + $function_table{$2} = 1; + } + } + + close(IN); +} + +sub process_file($) { + my $file; + my $identifier; + my $func; + my $descr; + my $in_purpose = 0; + my $initial_section_counter = $section_counter; + my ($orig_file) = @_; + my $leading_space; + + $file = map_filename($orig_file); + if (!open(IN,"<$file")) { print STDERR "Error: Cannot open file $file\n"; ++$errors; @@ -2681,15 +2799,18 @@ sub process_file($) { while (s/\\\s*$//) { $_ .= <IN>; } - if ($state == 0) { + if ($state == STATE_NORMAL) { if (/$doc_start/o) { - $state = 1; # next line is always the function name + $state = STATE_NAME; # next line is always the function name $in_doc_sect = 0; + $declaration_start_line = $. + 1; } - } elsif ($state == 1) { # this line is the function name (always) + } elsif ($state == STATE_NAME) {# this line is the function name (always) if (/$doc_block/o) { - $state = 4; + $state = STATE_DOCBLOCK; $contents = ""; + $new_start_line = $. + 1; + if ( $1 eq "" ) { $section = $section_intro; } else { @@ -2702,7 +2823,12 @@ sub process_file($) { $identifier = $1; } - $state = 2; + $state = STATE_FIELD; + # if there's no @param blocks need to set up default section + # here + $contents = ""; + $section = $section_default; + $new_start_line = $. + 1; if (/-(.*)/) { # strip leading/trailing/multiple spaces $descr= $1; @@ -2740,13 +2866,25 @@ sub process_file($) { print STDERR "${file}:$.: warning: Cannot understand $_ on line $.", " - I thought it was a doc line\n"; ++$warnings; - $state = 0; + $state = STATE_NORMAL; } - } elsif ($state == 2) { # look for head: lines, and include content - if (/$doc_sect/o) { + } elsif ($state == STATE_FIELD) { # look for head: lines, and include content + if (/$doc_sect/i) { # case insensitive for supported section names $newsection = $1; $newcontents = $2; + # map the supported section names to the canonical names + if ($newsection =~ m/^description$/i) { + $newsection = $section_default; + } elsif ($newsection =~ m/^context$/i) { + $newsection = $section_context; + } elsif ($newsection =~ m/^returns?$/i) { + $newsection = $section_return; + } elsif ($newsection =~ m/^\@return$/) { + # special: @return is a section, not a param description + $newsection = $section_return; + } + if (($contents ne "") && ($contents ne "\n")) { if (!$in_doc_sect && $verbose) { print STDERR "${file}:$.: warning: contents before sections\n"; @@ -2759,14 +2897,16 @@ sub process_file($) { $in_doc_sect = 1; $in_purpose = 0; $contents = $newcontents; + $new_start_line = $.; + while ((substr($contents, 0, 1) eq " ") || + substr($contents, 0, 1) eq "\t") { + $contents = substr($contents, 1); + } if ($contents ne "") { - while ((substr($contents, 0, 1) eq " ") || - substr($contents, 0, 1) eq "\t") { - $contents = substr($contents, 1); - } $contents .= "\n"; } $section = $newsection; + $leading_space = undef; } elsif (/$doc_end/) { if (($contents ne "") && ($contents ne "\n")) { dump_section($file, $section, xml_escape($contents)); @@ -2780,7 +2920,7 @@ sub process_file($) { } $prototype = ""; - $state = 3; + $state = STATE_PROTO; $brcount = 0; # print STDERR "end of doc comment, looking for prototype\n"; } elsif (/$doc_content/) { @@ -2791,6 +2931,7 @@ sub process_file($) { dump_section($file, $section, xml_escape($contents)); $section = $section_default; $contents = ""; + $new_start_line = $.; } else { $contents .= "\n"; } @@ -2801,87 +2942,86 @@ sub process_file($) { $declaration_purpose .= " " . xml_escape($1); $declaration_purpose =~ s/\s+/ /g; } else { - $contents .= $1 . "\n"; + my $cont = $1; + if ($section =~ m/^@/ || $section eq $section_context) { + if (!defined $leading_space) { + if ($cont =~ m/^(\s+)/) { + $leading_space = $1; + } else { + $leading_space = ""; + } + } + + $cont =~ s/^$leading_space//; + } + $contents .= $cont . "\n"; } } else { # i dont know - bad line? ignore. print STDERR "${file}:$.: warning: bad line: $_"; ++$warnings; } - } elsif ($state == 5) { # scanning for split parameters + } elsif ($state == STATE_INLINE) { # scanning for inline parameters # First line (state 1) needs to be a @parameter - if ($split_doc_state == 1 && /$doc_split_sect/o) { + if ($inline_doc_state == STATE_INLINE_NAME && /$doc_inline_sect/o) { $section = $1; $contents = $2; + $new_start_line = $.; if ($contents ne "") { while ((substr($contents, 0, 1) eq " ") || substr($contents, 0, 1) eq "\t") { $contents = substr($contents, 1); } - $contents .= "\n"; + $contents .= "\n"; } - $split_doc_state = 2; + $inline_doc_state = STATE_INLINE_TEXT; # Documentation block end */ - } elsif (/$doc_split_end/) { + } elsif (/$doc_inline_end/) { if (($contents ne "") && ($contents ne "\n")) { dump_section($file, $section, xml_escape($contents)); $section = $section_default; $contents = ""; } - $state = 3; - $split_doc_state = 0; + $state = STATE_PROTO; + $inline_doc_state = STATE_INLINE_NA; # Regular text } elsif (/$doc_content/) { - if ($split_doc_state == 2) { + if ($inline_doc_state == STATE_INLINE_TEXT) { $contents .= $1 . "\n"; - } elsif ($split_doc_state == 1) { - $split_doc_state = 4; + # nuke leading blank lines + if ($contents =~ /^\s*$/) { + $contents = ""; + } + } elsif ($inline_doc_state == STATE_INLINE_NAME) { + $inline_doc_state = STATE_INLINE_ERROR; print STDERR "Warning(${file}:$.): "; print STDERR "Incorrect use of kernel-doc format: $_"; ++$warnings; } } - } elsif ($state == 3) { # scanning for function '{' (end of prototype) - if (/$doc_split_start/) { - $state = 5; - $split_doc_state = 1; + } elsif ($state == STATE_PROTO) { # scanning for function '{' (end of prototype) + if (/$doc_inline_start/) { + $state = STATE_INLINE; + $inline_doc_state = STATE_INLINE_NAME; } elsif ($decl_type eq 'function') { - process_state3_function($_, $file); + process_proto_function($_, $file); } else { - process_state3_type($_, $file); + process_proto_type($_, $file); } - } elsif ($state == 4) { - # Documentation block - if (/$doc_block/) { - dump_doc_section($file, $section, xml_escape($contents)); - $contents = ""; - $function = ""; - %constants = (); - %parameterdescs = (); - %parametertypes = (); - @parameterlist = (); - %sections = (); - @sectionlist = (); - $prototype = ""; - if ( $1 eq "" ) { - $section = $section_intro; - } else { - $section = $1; - } - } - elsif (/$doc_end/) + } elsif ($state == STATE_DOCBLOCK) { + if (/$doc_end/) { dump_doc_section($file, $section, xml_escape($contents)); + $section = $section_default; $contents = ""; $function = ""; - %constants = (); %parameterdescs = (); %parametertypes = (); @parameterlist = (); %sections = (); @sectionlist = (); $prototype = ""; - $state = 0; + $state = STATE_NORMAL; } elsif (/$doc_content/) { @@ -2898,7 +3038,7 @@ sub process_file($) { } if ($initial_section_counter == $section_counter) { print STDERR "${file}:1: warning: no structured comments found\n"; - if (($function_only == 1) && ($show_not_found == 1)) { + if (($output_selection == OUTPUT_INCLUDE) && ($show_not_found == 1)) { print STDERR " Was looking for '$_'.\n" for keys %function_table; } if ($output_mode eq "xml") { @@ -2957,6 +3097,17 @@ if (open(SOURCE_MAP, "<.tmp_filelist.txt")) { close(SOURCE_MAP); } +if ($output_selection == OUTPUT_EXPORTED || + $output_selection == OUTPUT_INTERNAL) { + + push(@export_file_list, @ARGV); + + foreach (@export_file_list) { + chomp; + process_export_file($_); + } +} + foreach (@ARGV) { chomp; process_file($_);