Global spinlock list and usage

			Rick Lindsley
			IBM Linux Technology Center
			nevdull@sequent.com
			nevdull@us.ibm.com
			rick@eaglet.rain.com
	    Current for 2.4.5; Rev 0.2; last revised 6/6/01

----------------------------REVIEWERS -- READ PLEASE---------------------------

The goal of the review process, though, is to insure accuracy while
minimizing the impact to any one developer. Many of you who have
volunteered have other irons in the fire, and I want to use your time
efficiently. So I emphasize that I'm not asking any one person to review
the entire document -- please review those locks that you believe you
understand already and verify that I've interpreted them correctly. Note
that the r/w locks are only half finished; although I believe there's
only a few more hours work there, I really wanted to get this out NOW
and avoid putting it off while working on "just one more thing."

The remaining uses of the Big Kernel Lock are especially enigmatic.
If anyone feels qualified to comment on any remaining, legitimate uses
for the BKL, please do elaborate. My default belief, right now, is that
all the current uses are either incorrect, unnecessary, or due to be
so very soon (although I've not inserted this opinion into the document
quite so succinctly.)

One more topic I encourage you to comment on is support. My original
intention was that this become a document submitted for inclusion in
usr/src/Documentation, and that it then be maintained on an ongoing basis
either by myself or another. (Yes I volunteer, initially.)  If you have
thoughts on format, enhancements, or support issues please do include
that in your comments.  Simply to provide a starting point, I'll take the
position right now that it be updated no more frequently than quarterly
and quite possibly less frequently. Updates will necessarily follow any
new release by a minimum of six weeks since I can't make the document
correct for any particular release until it is out and I have time to
go through it (or unless the release waits for me and I'm quite happy
to have Linus be the final gate on release thank you.) If you have other
thoughts or desires on support, by all means -- dissuade me. I'm fairly
open on this.

Thank you for your efforts. I encourage you to return comments by
6/22 but will accept them both sooner and later.

----------------------------REVIEWERS -- END READ ---------------------------

1. Introduction

One of the first steps in determining whether Linux scales in SMP
situations or not was to draw upon existing SMP experience and expertise
and investigate whether existing locking mechanisms were SMP-efficient
or not.  It would seem, however, that there is frequently neither external
documentation, nor internal documentation (comments) describing the
proper usage of most of the locks on the system, making this an
inexact task at best and frustrating one at worst.

2. Scope

This is an attempt to document both the existence and usage of the
spinlocks in the Linux 2.4.5 kernel. Since it is borne from the need
to understand how some of these global locks are properly utilized,
this first effort is restricted to the type spinlock_t and rwlock_t
and does not, for the most part, include semaphores, wait
queues, or any other kind of synchronization mechanism.  The thinking,
for this initial effort, is that the spinlocks most likely to be misused
are those whose scope extends outside the file of their declaration. For
this reason, this document does not (currently) include static spinlocks,
or spinlocks declared within a structure (which typically guard elements
of the structure). Ideally, all locks and semaphores would be clearly
documented as to their use, and this document may be extended in the
future (or patches to comments in the code) to provide that.

If, coincidentally, the usage of an excluded lock was examined as part
of determining the usage of a global lock, then that information was also
recorded in the last section, below, rather than discarding it. However,
static locks really ought to be conveniently documented in the file to
which they are static.  If they are not, they are (I hope) at least less
prone to misuse when they are only used within a single file.

You'll find that the document itself is more of a reference document
than a paper, but that's intentional at this point.  Once we establish
the "correct" use of the various locks in use in the system, we can then
spend time discussing incorrect or unnecessary usages. Before we agree on
"correct" usage, such discussions can become quite philosophical.

As mentioned, this document does not attempt to cover spinlocks which
may be part of global structures. Usually, these guard elements of
the structures in which they are declared, although this should not be
blindly assumed.  (Elaborating upon this class of locks would be another
nice addition to this document.)

In general, the information here describes what IS, not what SHOULD BE.
It is true, however, that seeing what IS in print may make some misusages
obvious. When those bugs are fixed, if the result changes the information
here, this document should be updated.

3. Format of Lock Descriptions

These are the fields used to describe each lock:

Lock		The name of the spinlock as it is declared. (Sometimes
		a lock's use is "hidden" by being part of a macro. When
		this is the case, it will be listed under its declared
		name, and the macros which use it will be mentioned in
		the Macros section.

Interrupts	The Interrupts field describes (in part) how the lock
		is acquired.  (Note, again, that this is NOT a commentary
		on how it SHOULD be acquired.)

		    Saved:	the lock is acquired by
				spin_lock_irqsave() or equivalent.
				Interrupt and flag state is saved and
				restored, and interrupts are blocked
				while holding this lock.
		    Blocked:	the lock is acquired by spin_lock_irq()
				or equivalent. Interrupts are blocked
				while holding this locked.
		    Blocked (bh): The lock is acquired by spin_lock_bh(),
				read_lock_bh(), or write_lock_bh(). Bottom
				half (software) interrupts are blocked
				while holding the lock in this manner,
				but hardware interrupts may occur. Found
				most commonly in network code.
		    Ignored:	the lock is acquired by spin_lock(), or
				read_lock() or write_lock() for rwlock_t's.
				Interrupts may occur while this lock
				is held.

Use		Describes under what conditions this lock is held. As
		described above, this is not necessarily a commentary
		on how it SHOULD be used, but an observation on how it
		appears to be currently used (or an indication that it
		is not obvious how it is to be used.)

Functions	When provided, indicates which functions access this
		spin lock directly.

Macros		Some spinlocks are only accessible via macros. When
		that is the case, they will be listed here, followed by
		the files in which those macros are utilized.

Notes		If some additional comments need to be made about a lock,
		they will be made here.

Architectures	Most locks are present on all architectures because they
		are used with data and code that is architecture
		independent (or present on every architecture). Some,
		however, are architecture-specific. This field, if
		present, indicates which architecture(s) it is used
		on. The absence of this field indicates the lock is used
		on all architectures.

4. Global spin locks

#
# kernel/
#
Lock:		task_capability_lock
Interrupts:	Ignored
Functions:	sys_capget()
Use:		Held while modifying the capabilities of a task.
Notes:		When tasklist_lock() is also needed, this one should be
		acquired first.

Lock:		dma_spin_lock
Interrupts:	Saved
Macros:         claim_dma_lock()
		    eata.c, u14-34f.c, floppy.c, xd.c, esp.c,
		    tpqic02.c, 3c505.c, ltpc.c, dmascc.c, lance.c,
		    ni65.c, tms380tr.c, cosa.c, z85230.c, znet.c,
		    parport_pc.c, NCR53c406a.c, wd7000.c, dmabuf.c,
		    sscape.c, irda_device.c;
		release_dma_lock()
		    eata.c, u14-34f.c, floppy.c, xd.c, esp.c,
		    tpqic02.c, 3c505.c, ltpc.c, dmascc.c, lance.c,
		    ni65.c, tms380tr.c, cosa.c, z85230.c, znet.c,
		    parport_pc.c, NCR53c406a.c, wd7000.c, dmabuf.c,
		    sscape.c, irda_device.c;
Use:            Held while changing DMA parameters such as (but not
		limited to) enabling or disabling a particular DMA
		channel.

Lock:		lastpid_lock
Interrupts:	Ignored
Functions:	get_pid()
Use:		Held while last_pid is incremented and checked for rollover.
Notes:		When tasklist_lock is also needed, this should be acquired
		first.

Lock:		console_lock
Interrupts:	Ignored, Blocked, and Saved
Functions:	nmi_watchdog_tick(), show(), do_con_write(),
		console_sorting(), con_flush_chars(), con_font_op(),
		vcs_read(), vcs_write(), vt_ioctl(), do_syslog(),
		printk(), console_print(), unblank_console(),
		register_console(), unregister_console()
Use:		Held while adding or removing a character from log_buf
		(the syslog console buffer), as well as modifying
		any of these variables: log_start, logged_chars,
		console_loglevel. Also held while writing a character
		to the console.  Apparently held while changing consoles
		as well.

Lock:		runqueue_lock
Interrupts:	Ignored, Blocked, and Saved
Functions:	release(), wake_up_process(),
		wake_up_process_synchronous(), __schedule_tail(),
		schedule(), setscheduler(), sys_sched_yield(),
		signal_wake_up()
Use:		Held to check or modify p->has_cpu.
		Held while forcing a reschedule on another cpu due to
		a signal being sent to a process running on that cpu.
		Held to test the condition of, traverse, or modify the
		runqueue (task_on_runqueue(), add_to_runqueue(),
		del_from_runqueue(), schedule()).
Notes:		The one case where interrupts are ignored is in
		signal_wake_up(), and a comment there remarks that it is
		expected that interrupts are already blocked by a previous
		lock acquisition. So for all intents and purposes,
		this lock is consistently held with interrupts blocked.

Lock:		global_bh_lock
Interrupts:	Ignored
Functions:	bh_action(), sync_timers()
Use:		Held while running a bottom half. (Only one bottom
		half may run at a time, even on SMP systems.)

Lock:		timerlist_lock
Interrupts:	Blocked and Saved
Functions:	add_timer(), mod_timer(), del_timer(), del_timer_sync(),
		run_timer_list()
Notes:		It appears this could be made static to timer.c.
Use:		Held while modifying or inspecting any of the timer_vec's
		(including tv1, a timer_vec_root).

Lock:		tqueue_lock
Interrupts:	Saved
Macros:		queue_task()
		    <many many files under drivers/>
		run_task_queue()
		    <many many files under drivers/>
Use:		Held while adding a bottom half "software interrupt"
		handler to ANY task queue.

# arch/alpha
Lock:		i8259_irq_lock
Interrupts:	Ignored
Functions:	i8259a_enable_irq(),i8259a_disable_irq(),
		i8259a_mask_and_ack_ireq()
Use:		Held when writing to the IO ports for the i8259a.
Notes:		It appears this could be made static to irq_i8259.c.

Lock:		global_irq_lock
Interrupts:	Ignored
Functions:	wait_on_irq(), get_irqlock(), release_irqlock(), irq_enter()
Notes:		This is declared differently on different
		architectures.	On an alpha and a Mips-64, it is a
		spinlock. On a i386 ia-64, and ppc it is simply an
		unsigned int. On an s390, it is an atomic_t, which is
		a signed int. The purpose of the lock, however, seems
		identical across all architectures since it is used in
		similar manners across all architectures.
Use:		It is difficult to tell. It appears to not guard any
		actual data, but instead seems to provide a means to
		serialize cpus when a global cli is desired. get_irqlock
		is only called in __global_cli(), and thus this seems
		to serve to serialize global cli requests.
Architectures:	alpha

Lock:		srm_irq_lock
Interrupts:	Ignored
Functions:	srm_enabled_irq(), srm_enabled_irq()
Use:		Held while writing to hardware registers.
Architectures:	alpha

Lock:		dp264_irq_lock
Interrupts:	Ignored
Functions:	dp264_enabled_irq(), dp264_enabled_irq(),
		clipper_enable_irq(), clipper_disable_irq(),
		dp264_set_affinity(), clipper_set_affinity()
Use:		Held while writing to hardware registers.
Architectures:	alpha

Lock:		rawhide_irq_lock
Interrupts:	Ignored
Functions:	rawhide_enabled_irq(), rawhide_enabled_irq()
Use:		Held while writing to hardware registers.
Architectures:	alpha

Lock:		sable_irq_lock
Interrupts:	Ignored
Functions:	sable_enabled_irq(), sable_enabled_irq(),
		sable_mask_and_ack_irq()
Use:		Held while writing to hardware registers.
Architectures:	alpha

Lock:		titan_irq_lock
Interrupts:	Ignored
Functions:	privateer_enabled_irq(), privateer_enabled_irq(),
		privateer_set_affinity()
Use:		Held while writing to hardware registers.
Architectures:	alpha

Lock:		wildfire_irq_lock
Interrupts:	Ignored
Functions:	wildfire_enabled_irq(), wildfire_enabled_irq(),
		wildfire_mask_and_ack_irq()
Use:		Held while writing to hardware registers.
Architectures:	alpha

Lock:		rtc_lock
Interrupts:	Ignored, Blocked, and Saved
Functions:	set_rtc_mmss(), nvram_read_byte(), nvram_write_byte(),
		nvram_check_checksum(), nvram_check_checksum(),
		nvram_read(), nvram_write(), nvram_ioctl(),
		nvram_read_proc(), pc_proc_infos(), rtc_interrupt(),
		rtc_read(), rtc_ioctl(), rtc_open(), rtc_release(),
		rtc_poll(), rtc_init(), rtc_exit(), rtc_dropped_irq(),
		rtc_proc_output(), rtc_is_updating(), get_rtc_time(),
		get_rtc_alm_time(), mask_rtc_irq_bit(), set_rtc_irq_bit()
Use:		Usage for all routines but the nvram_* routines (including
		set_rtc_mmss()) is explained nicely in rtc.c:
		    A very tiny interrupt handler. It runs with
		    SA_INTERRUPT set, but there is possibility of
		    conflicting with the set_rtc_mmss() call (the rtc
		    irq and the timer irq can easily run at the same
		    time in two different CPUs). So we need to serializes
		    accesses to the chip with the rtc_lock spinlock that
		    each architecture should implement in the timer code.
		By contrast, it's not clear why it is acquired in the
		nvram_* routines. The nvram_* routines are the only ones
		that do a save/restore on this lock.


# arch/arm
Lock:		gpio_lock
Interrupts:	Saved
Functions:	wb977_init_gpio(), cpld_init(), nw_hw_init(),
		netwinder_leds_event(), netwinder_lock(),
		netwinder_unlock(), netwinder_set_fan(), kick_open(),
		vnc_update_spkr_mute()
Use:		According to netwinder-hw.h, "This is a lock for
		accessing ports GP1_IO_BASE and GP2_IO_BASE."

Lock:		die_lock
Interrupts:	Blocked
Functions:	die()
Use:		Held while processing a trap to insure serialization
		for the die() routine (only one process is trying to
		die at a time!). (Not sure why this is global.)

# arch/i386
Lock:		i8259A_lock
Interrupts:	Saved, Ignored
Functions:	disable_8259A_irq(), enable_8259A_irq(),
		8259A_irq_pending(), mask_anc_ack_8259A(), init_8259A(),
		print_PIC(), do_slow_gettimeoffset(), do_timer_interrupt()
Use:		Held while writing to or reading from some device
		registers to guarantee that only one process is doing
		this at a time.
Architectures:	i386

Lock:		i8253_lock
Interrupts:	Saved, Ignored
Functions:	get_8254_timer_count(), do_slow_get_timeoffset(),
		timer_interrupt()
Use:		Held while writing to or reading from some device
		registers to guarantee that only one process is doing
		this at a time.
Architectures:	i386

# arch/ia64
Lock:		pci_lock
Interrupts:	Saved
Macros:		PCI_OP()
		    pci.c;
Use:		As described in pci.c, "This interrupt-safe spinlock
		protects all accesses to PCI configuration space."

Lock:		sal_lock
Interrupts:	Ignored
Macros:		SAL_CALL()
		    sal.h;
Use:		Not clear what this is used for. Appears to be IA64 related.
Architectures:	ia64

Lock:		ptcg_lock
Interrupts:	Ignored
Functions:	flush_tlb_no_ptcg(), flush_tlb_range()
Use:		Not clear what this is guarding.
Notes:		The comment at the top of flush_tlb_no_ptcg() appears to
		be incorrect. This lock probably could be made static.
Architectures:	ia64

Lock:		hcl_spinlock
Interrupts:	Never used
Notes:		initialized, but never used to guard anything.
Architectures:	ia64

Lock:		cpuprom_spinlock
Interrupts:	Ignored
Macros:		PROM_LOCK()
		    prominfo_add(), prominfo_get(), prominfo_nodeget()
		PROM_UNLOCK()
		    prominfo_add(), prominfo_get(), prominfo_nodeget()
Use:		Seems to guard cpuprom_head.
Notes:		This lock probably could be made static.
Architectures:	ia64

Lock:		hub_mask_lock
Interrupts:	Ignored
Functions:	mlreset(), per_hub_init()
Use:		Not clear how this is used.
Notes:		There are two instances of this lock, each called by
		a routine named the same (per_hub_init) but defined once
		each in two different files. Having one instance of this
		lock be static and another global is confusing at best
		and dangerous at worst. It appears that the two locks
		are intended for distinct purposes, so both should be
		made static and one renamed.
Architectures:	ia64, mips64

Lock:		intr_dev_targ_map_lock
Interrupts:	Ignored
Functions:	init_platform_nodepda(), do_intr_reserve_level()
Use:		Apparently guards intr_dev_targ_map.
Notes:		Could be made static.
Architectures:	ia64

Lock:		xbow_perf_lock
Interrupts:	Ignored
Functions:	xbow_enable_perf_counter(), xbow_update_perf_counters(),
		xbow_attach()
Use:		Seems to guard xbow_perf.
Notes:		Could be made static.
Architectures:	ia64

Lock:		xbow_bw_alloc_lock
Interrupts:	Ignored
Functions:	xbow_prio_bw_alloc(), xbow_attach()
Use:		Not clear what it guards.
Notes:		Could be made static.
Architectures:	ia64

Lock:		int_test_spin
Interrupts:	Saved, Blocked
Functions:	xbow_prio_bw_alloc(), xbow_attach()
Use:		Not clear what it guards.
Notes:		Grabbed, but never released.
Architectures:	ia64

Lock:		efivars_lock
Interrupts:	Ignored
Functions:	efivar_read(), efivar_write(), efivar_init(), efivar_exit()
Use:		Not clear what it guards.
Notes:		Could be made static.
Architectures:	ia64

# arch/mips64
Lock:		nmi_lock
Interrupts:	Ignored
Macros:		enter_panic_mode()
		    ip27-nmi.c;
Use:		Seems to be serializing NMI processing on a mips64
		architecture, allowing only one cpu to process a NMI
		at a time. This appears to be a prelude to purposefully
		crashing the machine.
Architectures:	mips64

#
# arch/parisc
#
Lock:		__atomic_hash
Interrupts:	Saved
Macros:		ATOMIC_HASH()
Use:		parisc doesn't have atomic operations, so they need
		very clever tricks to make atomic.h work. One is having a
		hashed list of spinlocks, and this lock guards that list.
Notes:		When CONFIG_SMP is not defined, this is an array of
		spinlocks of length 1. When it IS defined, the array is
		length ... one. Looks wrong to me somehow, but ...
Architectures:	parisc

Lock:		__atomic_lock
Interrupts:	Saved
Functions:	__xchg
Use:		Seems it might be used to guarantee the atomicity of a 64
		byte exchange operation. See above about lack of atomic
		operations.
Architectures:	parisc



# arch/ppc
Lock:		rtas_lock
Interrupts:	Saved
Functions:	call_rtas()
Use:		This is acquired before calling enter_rtas().
Notes:		I can't find the definition of enter_rtas() anywhere.
Architectures:	ppc

Lock:		i8259_lock
Interrupts:	Saved, Ignored
Functions:	i8259_irq(), i8259_mask_and_ack_irq(), i8259_mask_irq(),
		i8259_unmask_irq(), i8259_init()
Use:		Held when writing to the IO ports for the i8259.
Notes:		It appears this could be made static to i8259.c.
Architectures:	ppc

Lock:		pmac_pic_lock
Interrupts:	Saved
Functions:	pmac_mask_and_ack_irq(), pmac_set_irq_mask()
Use:		Not clear.
Notes:		It appears this could be made static to pmac-pic.c.
Architectures:	ppc

Lock:		oops_lock
Interrupts:	Blocked
Functions:	die()
Use:		Looks like it intends to serialize the die() routine.
Notes:		Every other architecture seems to call this the die_lock.
		For consistency, this lock should probably change its name.
Architectures:	ppc


# arch/s390x
# arch/s390
# arch/sh
# arch/m68k
Lock:		semaphore_wake_lock
Interrupts:	Saved
Functions:	wake_one_more(), wake_non_zero(), wake_non_zero_interruptible(),
		wake_non_zero_trylock()
Use:		This appears to be a global lock that guards all
		semaphores.  When fields of *any* semaphore is examined
		or modified, this lock is held.
Notes:		It's not clear why this is not a member of the individual
		semaphore structures rather than being made global. It
		also appears that the macros using this lock in
		semaphore-helper.h are not included anywhere.
Architectures:	s390, sh, arm, m68k, parisc, s390x

# arch/sparc
Lock:		sun4d_imsk_lock
Interrupts:	Saved
Functions:	sun4d_disable_irq(), sun4d_enable_irq(), smp4d_callin()
Use:		Acquired to serially mask interrupts on other processors.
Architectures:	sparc

Lock:		srmmu_nocache_spinlock
Interrupts:	Ignored
Functions:	__srmmu_get_nocache(), srmmu_free_nocache()
Use:		Apparently held while looking for uncached memory on a
		Sparc processor.
Architectures:	sparc

Lock:		prom_lock
Interrupts:	Saved
Functions:	prom_nbgetchar(), prom_nbputchar(),
		prom_query_input_device(), prom_query_output_device(),
		prom_mapio(), prom_unmapio(), prom_devopen(),
		prom_devclose(), prom_seek(), prom_seek(),
		prom_reboot(), prom_feval(), prom_cmdline(),
		prom_halt(), prom_startcpu(), prom_stopcpu(),
		prom_idlecpu(), prom_restartcpu(), prom_putsegment(),
		__prom_getchild(), __prom_getsibling(), prom_getproplen(),
		prom_getproperty(), __prom_nextprop(), prom_setprop(),
		prom_inst2pkg()
Use:		This lock is apparently used to serialize nearly every
		operation on the Sun prom, guarding against concurrent
		operations.
Architectures:	sparc


# arch/sparc64
Lock:		pci_controller_lock
Interrupts:	Saved
Functions:	pci_scan_each_controller_bus(), psycho_init()
Use:		This is used to protect the modification or use of
		pci_controller_root.
Architectures:	sparc64

Lock:		pci_poke_lock
Interrupts:	Saved
Functions:	pci_config_read8(), pci_config_read16(),
		pci_config_read32(), pci_config_write8(),
		pci_config_write16(), pci_config_write32()
Use:		Held while doing any sort of PCI config operation.
Architectures:	sparc64

Lock:		ctx_alloc_lock
Interrupts:	Saved
Functions:	get_new_mmu_context(), destroy_context()
Use:		Held while changing mmu context.
Architectures:	sparc64

Lock:		prom_entry_lock
Interrupts:	Ignored
Functions:	prom_get_lock(), prom_release_lock()
Use:		Held while accessing or modifying the contents of
		the prom.
Architectures:	sparc64

Lock:		timod_pagelock
Interrupts:	Ignored
Functions:	getpage()
Use:		Held while accessing or modifying the static variable
		'page' in timod.c.
Notes:		Could be made static.
Architectures:	sparc64

Lock:		mostek_lock
Interrupts:	Blocked, Saved
Functions:	kick_start_clock(), has_low_battery(), sbus_time_init(),
		set_rtc_mmss(), set_system_time(), get_rtc_time(), rtc_open()
Use:		Apparently held while modifying clock registers (but not
		while reading them.)
Architectures:	sparc64

#
# drivers/block
#
Lock:		io_request_lock
Interrupts:	Ignored, Blocked, Saved
Functions:	<many many functions under drivers/>
Use:		Held while accessing or modifying any I/O request list in
		the system or in any driver. Also held while executing
		some SCSI command functions in ibmmca.c.
Notes:		Its use in ibmmca.c is questionable.

Lock:		pi_spinlock
Interrupts:	Ignored, Blocked, Saved
Functions:	pi_wake_up(), pi_do_claimed()
Use:		Appears to be held while accessing or modifying
		pi_adapter fields.
Notes:		Could be made static.


#
# drivers/char
#
Lock:		kbd_controller_lock
Interrupts:	Saved
Functions:	keyboard_interrup(), kbd_write_command_w(),
		kbd_write_output_w(), kbd_write_cmd(),
		detect_auxiliary_port(), aux_write_dev(), aux_write_ack(),
		get_from_queue()
Use:		Appears to be held while accessing or modifying
		pi_adapter fields.
Notes:		Several different drivers use locks with this name. All but
		one have them declared static. qtronix.c has this declared
		global. That one should also probably be static, or if not,
		at least renamed to avoid confusion with the other drivers.


#
# drivers/ieee1394
#
Lock:		templates_lock
Interrupts:	Ignored
Functions:	hl_all_hosts(), hpsb_inc_host_usage(), add_template(),
		remove_template()
Use:		Held while accessing or modifying hpsb_host_template
		(or anything in the linked list represented by
		hpsb_host_template).

Lock:		host_info_lock
Interrupts:	Saved, Blocked
Functions:	fcp_request(), state_initialized(), handle_iso_listen(),
		dev_release()
Use:		Held while accessing or modifying host_info_list (or
		anything in the linked list represented by
		host_info_list).


#
# drivers/isdn
#
Lock:		eicon_lock
Interrupts:	Saved
Functions:	idi_handle_ind(), idi_handle_ack_ok(), idi_handle_ack(),
		idi_send_data(), eicon_io_rcv_dispatch(), eicon_io_transmit(),
		eicon_command(), if_readstatus(), eicon_putstatus(),
		eicon_init()
Use:		Not clear what it is guarding.


#
# drivers/parport
#
Lock:		parportlist_lock
Interrupts:	Ignored, Blocked
Functions:	parport_register_driver(), parport_unregister_driver(),
		parport_register_port(), parport_unregister_port(),
		parport_find_number(), parport_find_base()
Use:		Held while accessing or modifying portlist.
Notes:		Could be made static.

Lock:		driverlist_lock
Interrupts:	Ignored
Functions:	attach_driver_chain(), detach_driver_chain(),
		parport_register_driver(), parport_unregister_driver()
Use:		Held while accessing or modifying driver_chain (or
		anything in the linked list represented by driver_chain).
Notes:		Could be made static.

#
# drivers/s390
#
Lock:		tub3270_con_bcblock
Interrupts:	Saved
Functions:	tub3270_con_write(), tub3270_con_copy()
Use:		Held while accessing or modifying tub3270_con_bcb.
Notes:		Could be made static. Not all fields in tub3270_con_bcb
		are protected by the lock -- should they be?

Lock:		lock
Interrupts:	Saved
Functions:	iucv_sever(), add_pathid(), iucv_connect(), iucv_accept(),
		top_half_interrupt(), bottom_half_interrupt(), do_int(),
		iucv_register_program(), iucv_unregister()
Use:		Apparently used to serialize the above mentioned routines.
Notes:		Terrible name for a global variable. Could be made
		static, but still should be renamed.


#
# drivers/scsi
#
Lock:		sym53c8xx_lock
Interrupts:	Saved
Macros:		NCR_LOCK_DRIVER()
		    sym53c8xx.c, sym53c8xx_comm.h;
		NCR_UNLOCK_DRIVER()
		    sym53c8xx.c, sym53c8xx_comm.h;
Use:		Held while doing allocation from a device-specific pool.

Lock:		DRIVER_SMP_LOCK
Interrupts:	Saved
Macros:		NCR_LOCK_DRIVER()
		    sym53c8xx_comm.h;
		NCR_UNLOCK_DRIVER()
		    sym53c8xx_comm.h;
Use:		Held while doing allocation from a device-specific pool.
Notes:		This apparently conflicts with the sym53c8xx_lock, above.
		In fact, it appears that NCR_LOCK_DRIVER is defined
		using one or the other (or possibly both?) There are
		sufficient ifdefs that it is confusing to tell.

Lock:		dc390_drvlock
Interrupts:	Saved (but see Notes)
Macros:		DC390_LOCK_DRV()
		    tmscsim.c, scsiiom.c;
		DC390_UNLOCK_DRV()
		    tmscsim.c, scsiiom.c;
		DC390_LOCK_DRV_NI()
		    tmscsim.c, scsiiom.c;
		DC390_UNLOCK_DRV_NI()
		    tmscsim.c, scsiiom.c
Use:		Unable to tell (see Notes).
Notes:		This lock does different things (and is implemented
		different ways) depending on the value of USE_SPINLOCKS,
		which depends on the Linux version being compiled. It
		appears that for 2.4.5, this is a global spinlock which is
		generally used with spinlock_irq_saved(). Older versions
		may still use global sti/cli constructs. Because of
		the generous and innovative uses of #defines, it's not
		possible to easily tell what this lock guards.


#
# drivers/sound
#
Lock:		sound_loader_lock
Interrupts:	Ignored
Functions:	sound_insert_unit(), sound_remove_unit(), soundcore_open()
Use:		Held while adding or deleting structures to or from
		any chain in the 16 member chains variable.
Notes:		Could be made static.


#
# drivers/video
#
Lock:		hga_reg_lock
Interrupts:	Saved
Functions:	hga_clear_screen(), hga_txt_mode(), hga_gfx_mode(), hga_pan(),
		hga_blank()
Use:		Held while examining or modifying hga_mode, or when
		updating the devices registers.
Notes:		Could be made static.

Lock:		matroxfb_spinlock
Interrupts:	Never used
Functions:	Never used
Use:		Never used
Notes:		This spinlock is declared and exported, but apparently
		never used. It can probably be removed.


#
# fs/
#
Lock:		dcache_lock
Interrupts:	Ignored
Functions:	is_tree_busy(), autofs4_expire(), try_to_fill_dentry(),
		autofs4_root_revalidate(), autofs4_dir_rmdir(),
		coda_flag_children(), dentry_iput(), dput(),
		d_invalidate(), d_find_alias(), d_prune_aliases(),
		prune_one_dentry(), prune_dcache(), shrink_dcache_sb(),
		have_submounts(), select_parent(), d_alloc(),
		d_instantiate(), d_lookup(), d_validate(), d_delete(),
		d_rehash(), d_move(), sys_getcwd(), d_genocide(),
		free_dentries(), __follow_up(), __follow_down(),
		follow_dotdot(), ncp_dget_fpos(), ncp_renew_dentries(),
		ncp_invalidate_dircache_entries(), nfs_free_dentries(),
		nfsd_iget(), d_splice(), nfsd_findparent(), splice(),
		proc_permission(), ramfs_empty(), dcache_readdir(),
		add_vfsmnt(), move_vfsmnt(), remove_vfsmnt(),
		kern_umount(), do_umount(), sys_pivot_root(),
		umsdos_d_path(), vfat_revalidate(), d_drop(), d_path()
Use:		Held while accessing or modifying a struct dentry that
		may be in the dcache (and thus subject to change
		asynchronously.) Also used to serialize access to the
		vfs mount list (vfsmntlist).

Lock:		fat_inode_lock
Interrupts:	Ignored
Functions:	fat_attach(), fat_detach(), fat_iget(), fat_clear_inode(),
		fat_write_inode()
Use:		Held while accessing or modifying the inode cache
		associated with the FAT file system.

Lock:		modlist_lock
Interrupts:	Saved
Functions:	sys_create_module(), free_module(), search_exception_table()
Use:		Held while accessing or modifying the module_list.
Notes:		Currently also seems to require the BKL during creation --
		is that really necessary?

Lock:		mmlist_lock
Interrupts:	Ignored
Functions:	exec_mmap(), mmput(), copy_mm(), swap_out()
Use:		Held while accessing or modifying the mmlist (primarily,
		init_mm).

Lock:		files_lock
Interrupts:	Ignored
Macros:		file_list_lock()
		    sysrq.c, tty_io.c, dquot.c, file-table.c, generic.c;
		file_list_unlock()
		    sysrq.c, tty_io.c, dquot.c, file-table.c, generic.c;
Use:		Held while accessing or modifying any struct file list.

Lock:		entry_lock
Interrupts:	Ignored
Functions:	lock_entry(), unlock_entry(), hfs_cat_mark_dirty(),
		get_new_entry(), get_entry(), hfs_cat_put(),
		hfs_cat_invalidate(), hfs_cat_commit(), hfs_cat_move()
Use:		Held while accessing or modifying the fields state or
		hash in any hfs_cat_entry or the field rename_lock in
		an hfs_mdb structure.  The basic function appears to be
		to hold off changes in the entry list, although that's
		neither clearly documented nor clear from the code.
Notes:		This lock is only used in catalog.c, and thus could be
		static. It is specific to the HFS file system.

Lock:		pagecache_lock
Interrupts:	Ignored
Functions:	remove_inode_page(), __set_page_dirty(),
		invalidate_inode_pages(), truncate_list_pages(),
		truncate_inode_pages(), filemap_fdatasync(),
		filemap_fdatawait(), add_to_page_cache_locked(),
		add_to_page_cache(), add_to_page_cache_unique(),
		page_cache_read(), __find_get_page(), drop_behind(),
		do_generic_file_read(), mincore_page(),
		__find_get_swapcache_page(), __find_lock_page(),
		delete_from_swap_cache_nolock(), reclaim_page()
Use:		Held while examining or modifying the count or state of
		any page that may already be in use.

Lock:		inode_lock
Interrupts:	Ignored
Functions:	__mark_inode_dirty(), sync_one(), sync_inodes(),
		write_inode_now(), invalidate_inodes(), prune_icache(),
		get_empty_inode(), get_new_inode(), iunique(), igrab(),
		iget4(), insert_inode_hash(), remove_inode_hash(),
		iput(), remove_dquot_ref()
Use:		As described in inode.c, this lock is held during inode
		list manipulations. These lists include the s_dirty list
		of a superblock, the inode_unused list, the inode_in_use
		list, and the inode_hashtable list. In addition, it is
		held to change the i_state of an inode while the inode
		is in use.

Lock:		pagemap_lru_lock
Interrupts:	Ignored
Macros:		lru_cache_add()
		    fs/buffer.c, mm/filemap.c;
		lru_cache_del()
		    mm/swap_state.c, mm/filemap.c;
Functions:	invalidate_inode_pages(), shrink_mmap()
Use:		Held when examining or modifying the lru_cache.
Notes:		When the page_cache lock is also needed, it should be
		acquired first.

Lock:		swaplock
Interrupts:	Ignored
Macros:		swap_list_lock()
		    stram.c, swapfile.c;
		swap_list_unlock()
		    stram.c, swapfile.c;
Use:		Held when examining or modifying the swap_list.
Notes:		When an sdev_lock (swap_info_struct) is also needed, the
		swaplock should be acquired first.


#
# net/
#
Lock:		atm_dev_lock
Interrupts:	Ignored
Functions:	atm_release_vcc_sk(), atm_do_connect(), atm_connect_vcc(),
		atm_ioctl(), free_atm_dev(), atm_dev_register(), sigd_close()
Use:		Guards ATM device lists.

Lock:		netdev_fc_lock
Interrupts:	Ignored, Saved
Functions:	netdev_register_fc(), netdev_unregister_fc(), netdev_wakeup()
Use:		Held when examining or modifying netdev_fc_xoff,
		netdev_fc_mask, or netdev_fc_slots.
Notes:		Probably could be made static.

Lock:		inet_peer_idlock
Interrupts:	Blocked (bh)
Functions:	inet_getid()
Use:		Held when examining or modifying the ip_id_count on
		any struct inet_peer that is already in use. (It is not
		held on struct inet_peers that are being created and
		not yet inserted into the pool; see inet_getpeer()).
Notes:		Probably could be made static. The lock is not held in
		rt_fill_info() when the field is referenced but not
		modified; should it be?

Lock:		inet_peer_unused_lock
Interrupts:	Blocked (bh)
Functions:	inet_putpeer(), unlink_from_unused(), cleanup_once()
Use:		Held when examining or modifying inet_peer_unused_head or
		inet_peer_unused_tailp.
Notes:		Probably could be made static.

Lock:		rpc_credcache_lock
Interrupts:	Ignored
Functions:	rpcauth_free_credcache(), rpcauth_gc_credcache(),
		rpcauth_insert_credcache(), rpcauth_lookup_credcache(),
		rpcauth_remove_credcache()
Use:		Held while examining or modifying the credcache of any
		rpc_auth array in the system.
Notes:		Might be better to have one per rpc_auth if this is
		acquired often.

Lock:		pmap_lock
Interrupts:	Ignored
Functions:	rpc_getport(), pmap_getport_done()
Use:		Despite its name, pmap_lock seems to guard cl_binding
		in an rpc_client structure. With this flag set, it is
		apparently assumed that portmap assigning can proceed.
		This global spinlock protects all rpc_client structures
		on the system.
Notes:		Might be better to have one lock per rpc_client.

Lock:		rpc_queue_lock
Interrupts:	Blocked (bh)
Functions:	rpc_run_timer(), rpc_add_timer(), rpc_add_wait_queue(),
		rpc_remove_wait_queue(), rpc_sleep_on(), rpc_sleep_locked(),
		rpc_wake_up_task(), rpc_wake_up_next(), rpc_wake_up(),
		rpc_wake_up_status(), rpc_unlock_task(), __rpc_execute(),
		__rpc_schedule(), rpc_release_task(), rpc_child_exit(),
		rpc_run_child(), xprt_lookup_rqst(), xprt_append_pending(),
		xprt_remove_pending(), xprt_remove_pending_next()
Use:		Comment suggests: 
		    Spinlock for wait queues. Access to the latter also
		    has to be interrupt-safe in order to allow timers
		    to wake up sleeping tasks.
		However, it appears to be held while examining or
		modifying other fields in the rpc_task: tk_timeout_fn,
		tk_running, tk_wakeup, tk_timer, tk_rpcwait, tk_callback,
		tk_flags, tk_active, tk_lock, tk_status, tk_timeout as
		well as the global variable childq.  Only tk_timeout_fn,
		tk_wakeup, tk_lock, and childq seem to uniformly adhere
		to this (lock
		is always held.)
Notes:		Appears to guard more than the comments would suggest.

Lock:		rpc_sched_lock
Interrupts:	Blocked (bh)
Functions:	rpc_init_task(), rpc_release_task(), rpc_killall_tasks(),
		rpc_show_tasks()
Use:		Comment unhelpfully suggests: 
		    Spinlock for other critical sections of code.
		However, it appears to be held primarily while
		modifying the global variable all_tasks or the list
		that it heads up.
Notes:		Could be made static.

Lock:		xprt_sock_lock
Functions:	xprt_adjust_cwnd(), xprt_reconnect(), tcp_state_change(),
		tcp_write_space(), udp_write_space(), do_xprt_transmit(),
		xprt_reserve()
Use:		Comment unhelpfully suggests: 
		    Spinlock for critical sections of code.
		Not at all clear what it truly guards, although it does
		cause serialization in several apparently disjoint areas.
Notes:		Could be made static.

Lock:		xprt_lock
Functions:	xprt_reconnect(), xprt_reconn_status(),
		xprt_down_transmit(), xprt_up_transmit()
Use:		Comment unhelpfully suggests: 
		    Spinlock for critical sections of code.
		Not clear what it truly guards. It seems to reliably
		guard the struct rpc_xprt field "connecting", but it
		also is used in some other contexts where it is not
		clear what it is guarding.
Notes:		Could be made static. If it is truly used globally to
		guard fields in individual structures, then it is probably
		being misused.

5. The Big Kernel Lock

#
# The Big Kernel Lock
#
# In general, it is noted that the BKL seems to be held during many
# release/close routines, for the duration of the routine. It would seem
# this might be done so as to determine if data structures may be safely
# release, cleared, or modified in some way upon the last close. If so,
# however, it should be noted that those same counters are typically
# NOT locked during open, and thus it would seem race conditions are
# still possible.  Below, if a file seems to employ the lock for this
# purpose, it is noted as: 
#
#		Held during release function to no obvious purpose.
#
# In addition, the BKL is held in some places for some obvious operations
# without being at all obvious what about that operation requires
# locking. So, for example, I note here in several places "held during
# mmap" but cannot say, at this point, why (or if) it MUST be held
# during an mmap.  These are the sorts of questions this document should
# be able to answer, when completed.
#
Lock:		kernel_flag
Interrupts:	Ignored
Macros:		kernel_locked()
		    fs/dcache.c;
		release_kernel_lock()
		    kernel/sched.c
		reacquire_kernel_lock()
		    kernel/sched.c
		lock_kernel()
		    <many many files -- see below>
		unlock_kernel()
		    <many many files -- see below>
Use:		This was, originally, the only lock used in the Linux
		kernel.  Over the years, finer grained locking has evolved
		but there are still many bits of code which use this lock
		as their primary lock for certain data or code. Because
		of its widespread use as the sole lock for so long, it
		is impossible to generalize its usage.	It appears to
		be used in over 400 different places in the source code.
		Some specific usages are outlined here. Most usages are
		through the lock_kernel()/unlock_kernel() interfaces,
		which utilizes the spin_lock() call.
		
		alpha/kernel/osf_sys.c
		    Held while accessing fields in current (the currently
			running process).
		    Held while doing a ufs, cdfs, or procfs mount.
		    Held while adding a swap device.
		    Held while doing a shared memory attach.
		    Held while doing a osf_proplist_syscall.
		    Held while doing a create_module().
		alpha/kernel/ptrace.c
		    Held while doing a ptrace.
		alpha/kernel/signal.c
		    Held while modifying process flags. (grabbed but not
		    clearly released.)
		alpha/kernel/traps.c
		    Held while doing a printk. (grabbed but not clearly
		    released.)
		arm/kernel/ptrace.c
		    Held while doing a ptrace.
		cris/kernel/ptrace.c
		    Held while doing a ptrace.
		cris/kernel/signal.c
		    Held while modifying process flags. (grabbed but not
		    clearly released.)
		cris/kernel/sys_cris.c
		    Held while creating a pipe, and while doing an mmap.
		i386/kernel/apm.c
		    Held during release function to no obvious purpose.
		i386/kernel/mtrr.c
		    Held while deleting a memory type region. (It is
		    *not* held during this operation in other places
		    in the same file.
		i386/kernel/ptrace.c
		    Held while doing a ptrace.
		ia64/ia32/sys_ia32.c
		    Held while doing a 32-bit ptrace.
		    Held while doing a 32-bit recvmsg.
		    Held while doing a 32-bit query_module.
		    Held while doing a sys_iopl().
		    Held while doing a 32-bit sysctl().
		ia64/kernel/ptrace.c
		    Held while doing a ptrace.
		m68k/atari/joystick.c
		    Held during release function to no obvious purpose.
		m68k/bvme6000/rtc.c
		    Held during release function to no obvious purpose.
		m68k/kernel/process.c
		    Held while doing an execve.
		m68k/kernel/ptrace.c
		    Held while doing a ptrace.
		    Held while doing a trace.
		m68k/kernel/sys_m68k.d
		    Held while flushing the cpu cache.
		mips/kernel/ptrace.c
		    Held while doing a ptrace.
		mips/kernel/sysirix.c
		    Held while doing an llseek. (?)
		mips64/kernel/ptrace.c
		    Held while doing a ptrace.
		    Held while doing a 32-bit ptrace.
		mips64/sgi-ip27/ip27-rtc.c
		    Held during release function to no obvious purpose.
		parisc/hpux/fs.c
		    Held while doing a 64-bit stat, a 64-bit fstat, or a
		    64-bit lstat. Held while getting directory entries.
		parisc/hpux/sys_hpux.c
		    Held during a sys_ustat() call.
		    Held while creating a pipe.
		parisc/kernel/ptrace.c
		    Held while doing a ptrace().
		parisc/kernel/signal.c
		    Held while modifying process flags. (grabbed but not
		    clearly released.)
		parisc/kernel/sys_parisc.c
		    Held while creating a pipe(), and while doing an mmap().
		ppc/kernel/ppc-stub.c
		    Held for reasons that are not clear.
		ppc/kernel/process.c
		    Held while doing a clone.
		ppc/kernel/ptrace.c
		    Held while doing a ptrace.
		s390/kernel/process.c
		    Held while doing a fork (or clone).
		s390/kernel/ptrace.c
		    Held while doing a ptrace.
		s390/kernel/signal.c
		    Held while calling do_exit(SIGSEGV).
		s390/kernel/traps.c
		    Held while processing some traps.
		s390x/kernel/linux32.c
		    Held while doing a 32-bit mount, a 32-bit module
		    query, or a 32-bit sysctl.
		s390x/kernel/process.c
		    Held while doing a fork (or clone).
		s390x/kernel/ptrace.c
		    Held while doing a ptrace.
		s390x/kernel/signal.c
		    Held while calling do_exit(SIGSEGV).
		s390x/kernel/traps.c
		    Held while processing some traps.
		sh/kernel/ptrace.c
		    Held while doing a ptrace.
		sparc/kernel/ptrace.c
		    Held while doing a ptrace.
		sparc/kernel/sparc-stub.c
		    Held for reasons that are not clear.
		sparc/kernel/sys_sparc.c
		    Held during breakpoint processing.
		sparc/kernel/sys_sunos.c
		    Held when doing a brk().
		    Held while doing printk's about unsupported system calls.
		    Held while doing a mount().
		    Held while doing a killpg().
		    Held while determining the hostid.
		    Held while inspecting the stack of the current process(?)
		sparc/kernel/unaligned.c
		    Held whil processing a trap.
		sparc/kernel/windows.c
		    Held while "trying to push the windows in a threads
		    	window buffer to the user stack."
		sparc64/kernel/pci.c
		    Held while writing to the PCI.
		sparc64/kernel/ptrace.c
		    Held while doing a ptrace().
		sparc64/kernel/sys_sparc32.c
		    Held while doing a mount.
		    Held while checking modules.
		    Held while doing a sysctl.
		sparc64/solaris/fs.c
		    Held while doing calling report_statvfs64().
		    Held while setting resource limits.
		sparc64/solaris/ioctl.c
		    Held while executing an ioctl.
		sparc64/solaris/socket.c
		    Held while doing a sockfd_lookup().
		sparc64/solaris/socksys.c
		    Held while freeing a socket structure.
		    Held during release function to no obvious purpose.
		sparc64/solaris/timod.c
		    Held while doing a getmsg().
		    Held while doing a putmsg().
		drivers/block/acsi_slm.c
		    Held during release function to no obvious purpose.
		drivers/block/paride/pg.c
		    Not sure what it is protecting. It may be trying to
		    prevent a double free upon release, but if so, it's
		    leaving open other race conditions elsewhere in the code.
		    Release?
		drivers/block/paride/pt.c
		    Not sure what it is protecting. It may be trying to
		    prevent a double free upon release, but if so, it's
		    leaving open other race conditions elsewhere in the code.
		    Release?
		drivers/block/rd.c
		    Not sure what it is protecting. It may be initrd_users,
		    but in that case it is not protected everywhere. Release?
		drivers/char/acquirewdt.c
		    Not sure what it is protecting. acq_lock would appear
		drivers/char/advantechwdt.c
		    Held during release function to no obvious purpose.
		drivers/char/agp/agpgart_fe.c
		    Not sure what it is protecting. Seems to always be paired
		    with AGP_LOCK/UNLOCK. Release?
		drivers/char/busmouse.c
		    Not sure what it is protecting. It appears to be
		    protecting mse->active, but that is not protected
		    anywhere else (e.g., open). Release?
		drivers/char/drm/ffb_drv.c
		    Held during release function to no obvious purpose.
		drivers/char/drm/gamma_drv.c
		    Held during release function to no obvious purpose.
		drivers/char/drm/i810_dma.c
		    Not sure what it is protecting. May be protecting
		    its own drm_file_t structures.
		drivers/char/drm/mga_drv.c
		    Held during release function to no obvious purpose.
		drivers/char/drm/r128_drv.c
		    Held during release function to no obvious purpose.
		drivers/char/drm/radeon_drv.c
		    Held during release function to no obvious purpose.
		drivers/char/drm/tdfx_drv.c
		    Held during release function to no obvious purpose.
		drivers/char/drm/vm.c
		    Not sure what it is protecting.
		drivers/char/dsp56k.c
		    Held while modifying device-specific variable (in_use)
		    during release.  No protection during open, however.
		drivers/char/dtlk.c
		    Held while deleting device-specific timeout. Not held
		    at other times, however. Release?
		drivers/char/ftape/zftape/zftape-init.c
		    Held while modifying current->blocked (during release),
		    and held while doing an mmap().
		drivers/char/i810_rng.c
		    Held during release function to no obvious purpose.
		drivers/char/lp.c
		    Held during release function to no obvious purpose.
		drivers/char/mixcomwd.c
		    Held during release function to no obvious purpose.
		drivers/char/nvram.c
		    Held during release function to no obvious purpose.
		drivers/char/pc110pad.c
		    Held during release function to no obvious purpose.
		drivers/char/pc_keyb.c
		    Held during release function to no obvious purpose.
		drivers/char/pcwd.c
		    Held during release function to no obvious purpose.
		drivers/char/ppdev.c
		    Held during release function to no obvious purpose.
		drivers/char/qpmouse.c
		    Held during release function to no obvious purpose.
		drivers/char/qtronix.c
		    Held during release function to no obvious purpose.
		drivers/char/raw.c
		    Held during release function to no obvious purpose.
		drivers/char/sbc60xxwdt.c
		    Held during release function to no obvious purpose.
		drivers/char/softdog.c
		    Held during release function to no obvious purpose.
		drivers/char/stallion.c
		    Held while examining a global struct tty_struct.
		drivers/char/sysrq.c
		    Held while examining emergency_sync_scheduled.
		drivers/char/tpqic02.c
		    Held during release function to no obvious purpose.
		drivers/char/tty_io.c
		    Held during do_tty_hangup() -- code suggests it is
		    protecting a data structure I can't find. A comment
		    here screams "FIXME! What are the locking issues here?"
		    which suggests the reasons for grabbing this lock may
		    not be well understood.
		    Held while calling tty->ldisc.read().
		    Held while issuing write().
		    Held during release.
		drivers/char/wdt.c
		    Held during release function to no obvious purpose.
		drivers/char/wdt285.c
		    Held during release function to no obvious purpose.
		drivers/char/wdt977.c
		    Held during release function to no obvious purpose.
		drivers/char/wdt_pci.c
		    Held during release function to no obvious purpose.
		drivers/i2c/i2c-dev.c
		    Held during release function to no obvious purpose.
		drivers/i2o/i2o_block.c
		    Held while calling exit_files().
		drivers/i2o/i2o_config.c
		    Held during release function to no obvious purpose.
		drivers/i2o/i2o_core.c
		    Held while calling exit_files().
		drivers/ide/ide-tape.c
		    Held during release function to no obvious purpose.
		drivers/ieee1394/raw1394.c
		    Held during release function to no obvious purpose.
		drivers/ieee1394/video1394.c
		    Held during mmap call.
		    Held during release function to no obvious purpose.
		drivers/input/evdev.c
		    Held during release function to no obvious purpose.
		drivers/input/input.c
		    Held during open function, apparently to guard
		    against an f_ops change.
		drivers/input/joydev.c
		    Held during release function to no obvious purpose.
		drivers/input/mousedev.c
		    Held during release function to no obvious purpose.
		drivers/isdn/avmb1/capi.c
		    Held during release function to no obvious purpose.
		drivers/isdn/avmb1/capi.c
		    Held during release function to no obvious purpose.
		drivers/isdn/divert/divert_procfs.c
		    Held while adjusting if_used count or modifying the
		    divert_info linked list.
		drivers/isdn/hysdn/hysdn_procconf.c
		    Held while examining card in open or close.
		drivers/isdn/hysdn/hysdn_procfs.c
		    Held while examining card in open or close.
		drivers/isdn/hysdn/hysdn_proclog.c
		    Held while examining card in open or close.
		drivers/isdn/isdn_common.c
		    Held during read, write, poll, and close. Can't tell
		    what it is guarding.
		drivers/macintosh/adb.c
		    Held during release function to no obvious purpose.
		drivers/macintosh/via-pmu.c
		    Held during release function to no obvious purpose.
		drivers/md/lvm.c
		    Held during vmalloc() call.
		drivers/media/video/cpia.h
		    Held to guard access to a static structure (cam_list).
		drivers/media/video/msp3400.c
		    Held while calling daemonize(). (This is done
		    inconsistently throughout the kernel.)
		drivers/media/video/tvaudio.c
		    Held during daemonization.
		drivers/media/video/videodev.c
		    Held during open function.
		    Held during release function to no obvious purpose.
		    Held while doing an mmap().
		drivers/net/ppp_generic.c
		    Held during release function to no obvious purpose.
		drivers/net/wan/cosa.c
		    Held during release function to no obvious purpose.
		drivers/pci/syscall.c
		    Held during pci_read_config_{byte,word,dword}().
		    Not sure what it is guarding.
		drivers/pcmcia/ds.c
		    Held during release function to no obvious purpose.
		drivers/pnp/isapnp_proc.c (112)
		    guarding against modifying a
		drivers/sbus/audio/audio.c
		    Held during release function to no obvious purpose.
		drivers/scsi/cpqfcTSworker.c
		    Held for no obvious purpose (prior to calling exit_mm()?)
		drivers/scsi/scsi_error.c
		    Held during daemonize(). Not clear why it is held.
		drivers/scsi/sg.c
		    Held during release function to no obvious purpose.
		drivers/sgi/char/ds1286.c
		    Held during release function to no obvious purpose.
		drivers/sgi/char/graphics.c
		    Held during release function to no obvious purpose.
		drivers/sgi/char/shmiq.c
		    Held while doing an mmap(). Seems to be guarding the
		    local structure shmiqs.
		drivers/sgi/char/streamable.c
		    Held during release function to no obvious purpose.
		drivers/sound/cmpci.c
		    Held during release function to no obvious purpose.
		drivers/sound/dmasound/dmasound_core.c
		    Held during release function to no obvious purpose.
		drivers/sound/emu10k1/audio.c
		    Held during release function to no obvious purpose.
		    Held while doing an mmap().
		drivers/sound/emu10k1/midi.c
		    Held during release function to no obvious purpose.
		drivers/sound/es1370.c
		    Held during release function to no obvious purpose.
		    Held while doing an mmap().
		drivers/sound/es1371.c
		    Held during release function to no obvious purpose.
		    Held while doing an mmap().
		drivers/sound/esssolo1.c
		    Held during release function to no obvious purpose.
		    Held while doing an mmap().
		drivers/sound/i810_audio.c
		    Held during release function to no obvious purpose.
		    Held while doing an mmap().
		drivers/sound/maestro.c
		    Held during release function to no obvious purpose.
		    Held while doing an mmap().
		drivers/sound/msnd_pinnacle.c
		    Held during release function to no obvious purpose.
		drivers/sound/sonicvibes.c
		    Held during release function to no obvious purpose.
		    Held while doing an mmap().
		drivers/sound/soundcard.c
		    Held during release function to no obvious purpose.
		    Held while doing an mmap().
		    Reads and writes apparently made "atomic" by use of
		    big kernel lock. (Local spinlock would be just as
		    effective, if true.)
		drivers/sound/trident.c
		    Held during release function to no obvious purpose.
		    Held while doing an mmap().
		drivers/sound/vwsnd.c
		    Held during release function to no obvious purpose.
		drivers/sound/wavfront.c
		    Held during release function to no obvious purpose.
		drivers/usb/audio.c
		    Held during release function to no obvious purpose.
		    Held while doing an mmap().
		drivers/usb/dabusb.c
		    Held during release function to no obvious purpose.
		drivers/usb/devices.c
		    Held while doing an poll().
		drivers/usb/devio.c
		    Held while modifying what appears to be local structures
		    during ioctls, opens, and closes.
		drivers/usb/hub.c
		    Held during daemonize(). Not clear why it is held.
		drivers/usb/inode.c
		    Held (sometimes) to protect usb_bus_list, apparently.
		    However, this is done inconsistently.
		drivers/usb/microtek.c
		    Held while modifying what appears to be local structures.
		drivers/usb/printer.c
		    Held during open function to no obvious purpose. Oddly
		    enough, it is NOT held during the release function!
		drivers/usb/rio500.c
		    Held during open function to no obvious purpose.
		drivers/usb/scanner.c
		    Held during open function to no obvious purpose.
		drivers/usb/storage/usb.c
		    Held during daemonize(). Not clear why it is held.
		drivers/usb/uhci-debug.h
		    Held during open function to no obvious purpose.
		drivers/video/fbmem.c
		    Held during release function to no obvious purpose.
		fs/adfs/inode.c
		    Held while "writing an existing inode back to the
		    directory, and therefore the disk."
		fs/affs/inode.c
		    Apparently held during changes to or reads from the
		    inode structure.
		fs/affs/symlink.c
		    Held during use of the inode structure.
		    Held (unnecessarily) during a brelse().
		fs/attr.c
		    Apparently held during changes to or reads from the
		    inode structure.
		fs/autofs/root.c
		    Held during the entire of autofs_revalidate().
		    It appears to be protecting inode and/or dentry
		    entries but it's not clear.
		fs/autofs4/root.c
		    Held during the entire of autofs4_dentry_release().
		    It appears to be protecting inode and/or dentry
		    entries but it's not clear.
		fs/bfs/file.c
		    Held during bfs_get_block(), but from the comment,  it
		    appears to be used for serialization without much
		    thought as to what is actually being protected.
		fs/bfs/inode.c
		    Held during bfs_write_inode() and bfs_delete_inode().
		    It appears it might be used to protect inode entries
		    from changing.
		fs/block_dev.c
		    Held during open routine for block devices and in
		    blkdev_put(); not clear why. Could actually be used
		    to guard bd_openers.
		fs/buffer.c
		    Held during fsync_dev(), file_fsync(), fsync_super(),
		    and sync_old_buffers().
		fs/coda/dir.c
		    Held during all of coda_dentry_revalidate() and
		    coda_revalidate_inode().
		fs/coda/file.c
		    Held during coda_open(), coda_release(), and
		    coda_fsync().
		fs/coda/psdev.c
		    Held during coda_psdev_write(), coda_psdev_read(),
		    coda_psdev_open(), and coda_psdev_release().
		fs/coda/symlink.c
		    Held during coda_symlink_filler().
		fs/devfs/base.c
		    Held during write_inode(), open(), d_iput(),
		    d_revalidate_wait(), readlink(), follow_link(). and
		    close().
		fs/devices.c
		    Held during get_chrfops() and chrdev_open(). Appears
		    to be guarding the f_op member of the inode structure
		    (*any* inode structure).
		fs/dquot.c
		    Held during initialize(), drop(), transfer(), and
		    sys_quotactl().
		fs/efs/symlink.c
		    Held during symlink_readpage().
		fs/exec.c
		    Held during do_coredump() and compute_creds().
		fs/ext2/inode.c
		    Held during delete_inode(), discard_prealloc(),
		    get_block(), update_inode(), and write_inode().
		fs/fat/inode.c
		    Held during delete_inode(), clear_inode(), and
		    write_inode(),
		fs/fcntl.c
		    Held during do_fcntl().
		fs/fifo.c
		    Held during fifo_open().
		fs/filesystems.c
		    Held during sys_nfsservctl().
		fs/hfs/inode.c
		    Held during put_inode().
		fs/hfs/sysdep.c
		    Held during dentry_iput(), and revalidate_dentry().
		fs/hpfs/dir.c
		    Held during dir_release().
		fs/hpfs/file.c
		    Held during open(), and file_release().
		fs/hpfs/inode.c
		    Held during delete_inode().
		fs/hpfs/namei.c
		    Held during symlink_readpage().
		fs/ioctl.c
		    Held during sysioctl(). (Is this *really* held during
		    all file system related ioctls??)
		fs/isofs/inode.c
		    Held during isofs_get_block().
		fs/isofs/rock.c
		    Held during rock_ridge_symlink_readpage().
		fs/jffs/inode-v23.c
		    Held during jffs_delete_inode().
		fs/jffs/intrep.c
		    Held cduring jffs_garbage_collect_thread().
		fs/lockd/clntlock.c
		    Held during reclaimer().
		fs/lockd/svc.c
		    Held during lockd().
		fs/locks.c
		    Held during locks_mandatory_locked(),
		    locks_mandatory_area(), sys_flock(),
		    locks_remove_posix(), locks_remove_flock(),
		    posix_test_lock(), posix_lock_file(), __get_lease(),
		    fcntl_setlease(), lock_may_read(), lock_may_write(),
		    and get_locks_status().  Seems to be held when
		    examining or modifying the i_flock field of an inode.
		fs/minix/inode.c
		    Held during and write_inode().
		fs/minix/itree_common.c
		    Held during and get_block() and sync_file().
		fs/namei.c
		    Apparently held to prevent changing of i_op field 
		    of inode. Held during permission(), real_lookup(),
		    lookup_hash(), vfs_create(), vfs_mknod(), vfs_mkdir(),
		    vfs_rmdir(), vfs_unlink(), vfs_symlink(), vfs_link(),
		    and do_rename().
		fs/ncpfs/dir.c
		    Held during ncp_lookup_validate().
		fs/nfs/dir.c
		    Held during nfs_lookup_revalidate() and nfs_dentry_iput().
		fs/nfs/file.c
		    Held during nfs_fsync() and nfs_commit_write().
		fs/nfs/flushd.c
		    Held during nfs_reqlist_init(), nfs_reqlist_exit(), and
		    inode_schedule_scan().
		fs/nfs/inode.c
		    Held during nfs_open(), nfs_release(), and
		    __nfs_revalidate_inode(),
		fs/nfs/read.c
		    Held during nfs_readpage_sync() and nfs_pagein_one().
		fs/nfs/symlink.c
		    Held during nfs_symlink_filler().
		fs/nfs/write.c
		    Held during nfs_writepage(), nfs_flush_one(), and
		    nfs_commit_list().
		fs/nfsd/nfsctl.c
		    Held during handle_sys_nfsservctl().
		fs/nfsd/nfssvc.c
		    Held during nfsd().
		fs/ntfs/fs.c
		    Held during ntfs_write_inode() and _ntfs_clear_inode().
		fs/open.c
		    Held during vfs_statfs() and filp_close(), apparently
		    to insure that f_op does not change.
		fs/openpromfs/inode.c
		    Held during property_release().
		fs/proc/inode.c
		    Held during de_put().
		fs/proc/proc_misc.c
		    Held during locks_read_proc() to insure that i_flock
		    does not change (see get_locks_status()).
		fs/qnx4/fsync.c
		    Held during sync_file().
		fs/qnx4/inode.c
		    Held during delete_inode() and write_inode().
		fs/read_write.c
		    Held while calling llseek function. Apparently held
		    to insure that f_op does not change during call.
		fs/readdir.c
		    Held while calling vfsreaddir function. Apparently held
		    to insure that f_op does not change during call.
		fs/reiserfs/dir.c
		    Held during dir_fsync().
		fs/reiserfs/file.c
		    Held during file_release(), and sync_file().
		fs/reiserfs/inode.c
		    Held during delete_inode(), bmap(), get_block(),
		    write_inode(), dirty_inode(), map_block_for_writepage(),
		    and commit_write().
		fs/reiserfs/ioctl.c
		    Held for unpack().
		fs/reiserfs/journal.c
		    Held for journal_commit_thread().
		fs/reiserfs/super.c
		    Held for write_super() and write_super_lockfs().
		fs/romfs/inode.c
		    Held during readpage().
		fs/smbfs/dir.c
		    Held during smb_dir_open() and smb_lookup_validate().
		fs/smbfs/file.c
		    Held during smb_commit_write(), smb_file_open(), and
		    smb_file_release(). Apparently guards the openers
		    field in the samba-specific part of the fs union.
		fs/smbfs/inode.c
		    Held during smb_revalidate_inode() and smb_delete_inode().
		fs/smbfs/sock.c
		    Held during smb_data_callback().
		fs/super.c
		    Held during sys_ustat() (to guard superblock structures?)
		    Held during sys_mount(), sys_umount(), and
		    sys_pivot_root().
		fs/sysv/fsync.c
		    Held during sync_file().
		fs/sysv/inode.c
		    Held during sysv_delete_inode(), sysv_block_map(),
		    sysv_get_block(), and sysv_write_inode().
		fs/udf/file.c
		    Held during release_file().
		fs/udf/fsync.c
		    Held during sync_file().
		fs/udf/inode.c
		    Held during udf_put_inode(), udf_delete_inode(),
		    udf_get_block(), udf_write_inode(), and
		    udf_block_map().
		fs/udf/symlink.c
		    Held during symlink_filler().
		fs/ufs/inode.c
		    Held during ufs_frag_map(), ufs_getfrag_block(),
		    ufs_write_inode(), and ufs_delete_inode().
		include/linux/net.h
		    Held during SOCKCALL_WRAP and SOCKCALL_UWRAP (macros).
		    It appears most socket operations still use the BKL,
		    since these macros are used in the definition of
		    the the ops structures to create inline functions.
		include/linux/raid/md_compatible.h
		    Macro md_lock_kernel() declared here and actually used
		    in block/md.c. Appears to be held during thread
		    creation.
		init/main.c
		    Held during start_kernel() and init().
		kernel/acct.c
		    Held during check_free_space(), sys_acct(),
		    acct_auto_close(), and acct_process().
		    Appear to guard acct_active, acct_timer, and acct_file.
		kernel/exit.c
		    Held in do_exit().
		kernel/module.c
		    Held in sys_create_module(), sys_init_module(),
		    sys_delete_module(), sys_query_module(), and
		    sys_get_kernel_syms(). Appears to guard the module
		    list.
		kernel/sys.c
		    Held during sys_reboot().
		kernel/sysctl.c
		    Held during sys_sysctl().
		mm/memory.c
		    Held during do_swap_page() and shmem_getpage_locked(),
		    apparently while using the page cache. Held during
		    vmtruncate(), apparently to hold i_ops constant.
		mm/swapfile.c
		    Held during swapon()/swapoff(). Appears to be protecting
		    the swap list -- doesn't swap_list_lock() do that?
		net/ipv4/af_inet.c
		    Held during call of dlci_ioctl(). Not clear why this
		    serialization is necessary or what the BKL is guarding.
		net/netlink/netlink_dev.c
		    Held during release().
		net/socket.c
		    Explicitly *released* during a socket ioctl().
		net/sunrpc/sched.c
		    Held during rpciod() (daemon creation.)
Notes:		If you are writing new code (as opposed to fixing or
		extending old code) you should think very hard before
		using this lock. It may be that for compatibility reasons,
		this lock must be utilized in some sections of new
		code. Where possible, however, you should be attempting
		to update the new code by using a lock other than the
		kernel_flag -- one which is designed specifically for
		the needs of the new code.

6. Global Read/Write spinlocks

#
# read/write locks
#
Lock:		tasklist_lock
Interrupts:	read: Ignored
		write: Blocked and Saved
Functions:	sys_ptrace(), task_valid(), sys32_ptrace(),
		sync_thread_rbs(), wrap_mmu_context(), unswap_by_move(),
		irix_waitsys(), irix_prctl(), irix_syssgi(),
		mmu_context_overflow(), do_ptrace(), srmmu_set_pgdir(),
		do_tty_hangup(), disassociate_ctty(), release_dev(),
		tiocsctty(), do_SAK(), de_thread(), send_sigio(),
		task_state(), proc_pid_stat(), proc_pid_lookup(),
		get_pid_list(), proc_read_super(), chroot_fs_refs(),
		set_pgdir(), unhash_process(), sys_capget(), cap_set_pg,
		cap_set_all(), sys_capset(), session_of_pgrp(),
		will_become_orphaned_pgrp(), has_stopped_jobs(),
		forget_original_parent(), exit_notify(), sys_wait4(),
		get_pid(), do_fork(), schedule(), setscheduler(),
		sys_sched_getscheduler(), sys_sched_getparam(),
		sys_sched_rr_get_interval(), show_state(), kill_pg_info(),
		kill_sl_info(), kill_proc_info(), kill_something_info(),
		notify_parent(), sys_setpriority(), sys_getpriority(),
		sys_setpgid(), sys_getpgid(), sys_getsid(),
		count_active_tasks(), try_to_unuse(), swap_out(),
		match_pid(), match_sid()
Use:            Held for read when inspecting the task list
		    (find_task_by_pid(), for_each_task, or in general,
		    following pointers in the task list when you don't
		    want the structure of the list to change.)
		Held for write when changing the task list, or any item in the
		    task list which may affects the integrity of the list
		    (modifying pointers to other tasks, for instance)
Notes:		When kernel_flag is also needed, that lock should be
		acquired first.

Lock:		guid_lock
Interrupts:	read:  Saved
		write: Saved
Functions:	create_guid_entry(), associate_guid(), hpsb_guid_get_handle()
Use:            Held for read when inspecting the guid_list.
		Held for write when adding a new guid entry to guid_list.
Notes:		Could be made static.

Lock:		hl_drivers_lock
Interrupts:	read:  Ignored
		write: Blocked
Functions:	hpsb_register_highlevel(), hpsb_unregister_highlevel(),
		highlevel_iso_receive(), highlevel_fcp_request()
Macros:		DEFINE_MULTIPLEXER()
		    highlevel.c;
Use:            Held for read when inspecting the hl_drivers list.
		Held for write when adding a new high level driver entry to
		the hl_drivers list.
Notes:		Could be made static.

Lock:		addr_space_lock
Interrupts:	read:  Ignored
		write: Blocked
Functions:	hpsb_register_highlevel(), hpsb_unregister_highlevel(),
		highlevel_iso_receive(), highlevel_fcp_request()
Macros:		DEFINE_MULTIPLEXER()
		    highlevel.c;
Use:            Held for read when inspecting the hl_drivers list.
		Held for write when adding a new high level driver entry to
		the hl_drivers list.
Notes:		Could be made static.

Lock:		dev_base_lock
Interrupts:	read:  Ignored, Blocked
		write: Blocked
Functions:	dev_ifname32(), solaris_i(), bpq_init_driver(),
		get_strip_dev(), lapbeth_init_driver(), dev_get_by_name(),
		dev_get(), dev_get_by_index(), dev_clear_fastroute(),
		dev_ifname(), dev_get_info(), dev_get_wireless_info(),
		dev_ioctl(), register_netdevice(),
		unregister_netdevice(), net_dev_init(),
		dev_mc_read_proc(), rtnetlink_dump_ifinfo(), dn_bind(),
		dn_dev_dump_ifaddr(), decnet_dev_get_info(),
		inetdev_by_index(), inet_select_addr(),
		inet_dump_ifaddr(), inet_forward_change(), ip_mc_procinfo(),
		addrconf_forward_change(), ipv6_get_saddr(), igmp6_read_proc(),
		nr_dev_first(), nr_dev_get(), rose_dev_first(), rose_dev_get(),
		rose_dev_exists(), tc_dump_qdisc(), x25_init().
Use:            Excellent explanation found in drivers/net/Space.c. In part,
		    Pure readers hold dev_base_lock for reading.
		    Writers must hold the rtnl semaphore while they loop
		    through the dev_base list, and hold dev_base_lock
		    for writing when they do the actual updates.

Lock:		notifier_lock
Interrupts:	read:  Never used
		write: Ignored
Functions:	notify_chain_register(), notify_chain_unregister()
Use:            Held for write when modifying any notifier list anywhere.
Notes:		There is an ordinary spinlock named the same which is static
		to kcapi.c. A different name should be chosen for one or the
		other, to avoid confusion. The read side of this read/write
		lock never seems to be used, effectively making this a
		spinlock. This usage could be made static. Arguably, each
		notifier list should have its own lock but modifying the
		lists is probably an infrequent operation.

Lock:		xtime_lock
Interrupts:	read:  Ignored, Saved
		write: Ignored, Saved, Blocked
Functions:	generally, do_gettimeofday(), do_settimeofday() and
		timer_interrupt() in each architecture. See each
		architecture for specific uses.
Use:            Held for read when examining xtime.
		Held for write when modifying xtime.

Lock:		vmlist_lock
Interrupts:	read:  Ignored
		write: Ignored
Functions:	read_kcore(), get_vm_area(), vfree(), vread()
Use:            Held for read when examining vmlist.
		Held for write when modifying vmlist (or anything in
		the vmlist chain.)

Lock:		net_big_sklist_lock
Interrupts:	read:  Never used
		write: Blocked (bh)
Functions:	sklist_remove_socket(), sklist_insert_socket()
Use:            Held for write when modifying any socket list.
Notes:		Could be made static. Never used for reading, effectively
		making this a spinlock. Still used by only one driver,
		apparently (econet).

Lock:		dn_hash_lock
Interrupts:	read:  Ignored
		write: Ignored, Blocked (bh)
Functions:	dn_hash_sock(), dn_unhash_sock(), dn_unhash_sock_bh(),
		dn_sklist_find_listener(), dn_find_by_skb(), dn_get_info()
Use:		Held for read when examining dn_sklist.
		Held for write when modifying dn_sklist.
Notes:		Could be made static (seems to guard entirely static variables
		and is only used within one file.)

Lock:		inetdev_lock
Interrupts:	read:  Ignored
		write: Ignored, Blocked (bh)
Functions:	inetdev_init(), inetdev_destroy(), inet_select_addr(),
		inet_dump_ifaddr(), inet_forward_change(),
		fib_validate_source(), ip_route_input(),
		ip_route_output_slow().
Use:		Held for read when examining (or using) an ip_ptr from any
		    struct netdevice.
		Held for write when modifying an ip_ptr from any struct
		    netdevice.

Lock:		ip_ra_lock
Interrupts:	read:  Ignored
		write: Ignored, Blocked (bh)
Functions:	ip_call_ra_chain(), ip_ra_control()
Use:		Held for read when examining ip_ra_chain (or traversing
		    that list.)
		Held for write when modifying ip_ra_chain.  Since ip_ra_chain
		    is a linked list, this lock is also held when modifying
		    the integrity of that list.

Lock:		ip_fw_lock
Interrupts:	read:  Ignored
		write: Ignored, Blocked (bh)
Functions:	ip_fw_check(), ip_fw_ctl(), ip_chain_name_procinfo(),
		ipfw_init_or_cleanup()
Use:		Held for read when examining ip_fw_chains (or traversing
		    that list.)
		Held for write when modifying ip_fw_chains (or the integrity
		    of that list.) Also held for write when examining or
		    totalling counters, because according to the comments,
		    counters are updated by "readers".
Notes:		Could be made static.  Due to the comment about readers
		updating counters, it sounds like there is a locking issue.
		Inspection of the source does not reveal any counter updates
		while holding the read lock, so either the comment is false,
		neither the read nor write lock is utilized during these
		operations, or I missed something in my inspection.

Lock:		raw_v4_lock
Interrupts:	read:  Ignored
		write: Blocked (bh)
Functions:	icmp_unreach(), raw_v4_hash(), raw_v4_unhash(), raw_v4_input(),
		raw_get_info()
Use:		Held for read when examining any of the buckets in
		    the hash table raw_v4_htable.
		Held for write when modifying raw_v4_htable.  Since this
		    is a fixed size hash table, the table itself or its
		    integrity cannot change, as with a linked list. Holding
		    the lock for write means you are changing entries in any
		    one of the buckets.

Lock:		context_overflow_lock
Interrupts:	read:  never used
		write: Ignored
Functions:	mmu_context_overflow()
Use:		Seems to be guarding next_mmu_context. Only used as a
		write lock, which effectively makes it a simple spin lock.
		Could be made static.

Lock:		udp_hash_lock
Interrupts:	read:  Ignored
		write: Blocked (bh)
Functions:	udp_v4_get_port(), udp_v4_unhash(), udp_v4_lookup(),
		udp_v4_mcast_deliver(), udp_get_info(), udp_v6_get_port(),
		udp_v6_unhash(), udp_v6_lookup(), udpv6_mcast_deliver(),
		udp6_get_info()
Use:		Held for read when examining the hash table udp_hash.
		Held for write when modifying raw_v4_htable.  Since this
		    is a fixed size hash table, the table itself or its
		    integrity cannot change, as with a linked list. Holding
		    the lock for write means you are changing any entry in any
		    one of the buckets.

Lock:		addrconf_lock
Interrupts:	read:  Ignored
		write: Blocked (bh)
Functions:	in6_dev_get(), ipv6_add_dev(), addrconf_forward_change(),
		ipv6_add_addr(), ipv6_get_saddr(), ipv6_get_lladdr(), 
		addrconf_ifdown()
Use:		Comment states "protects inet6 devices".
		It is not clear from inspection when this should be
		acquired read and when it should be acquired write.
		It appears to guard the ip6_ptr field of all struct
		netdevices. That is, when one is going to modify that
		field on any struct net_device, one should acquire this
		lock.
		Could be made static.
Notes:		Seems like this would be better achieved by a per-structure
		lock. Currently a global lock seems to protect many local
		fields.

Lock:		fib6_walker_lock
Interrupts:	read:  Ignored
		write: Blocked (bh)
Functions:	fib6_walker_link(), fib6_walker_unlink(), fib6_repair_tree(),
		fib6_del_route()
Use:		Guards fib6_walker_list.
		Held for read when examining fib6_walker_list. This is a
		    linked list, so the integrity of the list is insured
		    while the lock is held.
		Held for write when modifying any connectivity in
		    fib6_walker_list. 
Notes:		Could be made static.

Lock:		ip6_fw_lock
Interrupts:	read:  not used
		write: Blocked (bh)
Functions:	ip6_rule_add(), ip6_rule_del()
Use:		Not clear exactly what it guards.
Notes:		Could be made static. This code is currently ifdeffed out.

Lock:		ip6_ra_lock
Interrupts:	read:  Ignored
		write: Blocked (bh)
Functions:	ip6_ra_control(), ip6_call_ra_chain()
Use:		Guards ip6_ra_chain.
		Held for read when examining ip6_ra_chain. This is a
		    linked list, so the integrity of the list is insured
		    while the lock is held.
		Held for write when modifying any connectivity in
		    ip6_ra_chain. 

Lock:		raw_v6_lock
Interrupts:	read:  Ignored
		write: Blocked (bh)
Functions:	icmp6_notify(), raw_v6_hash(), raw_v6_unhash(),
		ipv6_raw_deliver(), raw6_get_info()
Use:		Held for read when examining any of the buckets in
		    the hash table raw_v6_htable.
		Held for write when modifying raw_v6_htable.  Since this
		    is a fixed size hash table, the table itself or its
		    integrity cannot change, as with a linked list. Holding
		    the lock for write means you are changing any entry in any
		    one of the buckets.

Lock:		rt6_lock
Interrupts:	read:  Blocked (bh)
		write: Blocked (bh)
Functions:	rt6_redirect(), rt6_get_dflt_router(), rt6_purge_dflt_routers(),
		rt6_ifdown(), rt6_mtu_change(), inet6_dump_fib(),
		rt6_proc_info(), fib6_run_gc(), rt6_lookup(), rt6_ins(),
		ip6_route_input(), ip6_route_output(), ip6_route_del(),
		ip6_del_rt()
Use:		Comment claims "protects all the ip6 fib".
		Held for read when examining any of the tree described by
		    ip6_routing_table.
		Held for write when modifying any of the structure of the
		    tree described by ip6_routing_table. (Holding this
		    lock for write does not guarantee that the data itself
		    won't change; only that the linkages for the tree
		    won't change.)

Lock:		qdisc_tree_lock
Interrupts:	read:  Ignored
		write: Ignored
Functions:	sch_tree_lock(), sch_tree_unlock(), tcf_tree_lock(),
		tcf_tree_unlock(), tc_ctl_tfilter(), tc_dump_tfilter(),
		dev_graft_qdisc(), qdisc_create(), tc_dump_qdisc(),
		tc_dump_tclass(), dev_activate(), dev_init_scheduler(),
		dev_shutdown()
Use:		The comments near the declaration of this variable read,
		in part:
		    Modifications to data, participating in scheduling must
		    be additionally protected with dev->queue_lock spinlock.
		    The idea is the following:
			- enqueue, dequeue are serialized via top level device
			  spinlock dev->queue_lock.
			- tree walking is protected by read_lock(
			  qdisc_tree_lock) and this lock is used only in
			  process context.
			- updates to tree are made only under rtnl semaphore,
			  hence this lock may be made without local bh
			  disabling.
		qdisc_tree_lock must be grabbed BEFORE dev->queue_lock!

Lock:		unix_table_lock
Interrupts:	read:  Ignored
		write: Ignored
Functions:	unix_remove_socket(), unix_insert_socket(),
		unix_find_socket_byname(), unix_find_socket_byinode(),
		unix_autobind(), unix_bind(), unix_read_proc(), unix_gc()
Use:		Guards unix_socket_table[].
		Held for read when examining the hash tables in
		    unix_socket_table[].
		Held for write when modifying any bucket in the hash tables
		    represented in unix_socket_table[]. (Holding this
		    lock for write does not guarantee that the data itself
		    won't change; only that the linkages in the hash buckets
		    won't change.)


7. Additional spin locks

#
# static locks
#
Lock:		unload_lock
Interrupts:	Ignored
Functions:	try_inc_mod_count(), sys_delete_module(), get_module_symbol
Use:		Held while referencing or updating fields in any struct
		module. As its name suggests, this is most often used to
		prevent the module from being unloaded while it is being
		referenced or modified.

Lock:		softirq_mask_lock
Interrupts:	Saved
Functions:	open_softirq()
Use:		Held while modifying the contents of softirq_vec.

Lock:		pm_devs_lock
Interrupts:	Saved
Functions:	pm_register(), pm_unregister()
Use:		Held while modifying the pm_devs list.

Lock:		irq_controller_lock
Interrupts:	Saved, Ignored
Functions:	disable_irq(), enable_irq(), do_IRQ(), do_ecard_IRQ(),
		setup_arm_irq(), free_irq(), probe_irq_on(),
		probe_irq_off(), do_cobalt_IRQ(), do_piix4_master_IRQ(),
		disable_irq_nosync(), setup_irq()
Use:		Held while modifying the global array irq_desc.
Architectures:	i386, arm, sh

Lock:		io_tlb_lock
Interrupts:	Saved
Functions:	map_single(), unmap_single()
Use:		Held while modifying or examining io_tlb_list or
		io_tlb_index.
Architectures:	ia64

Lock:		uidhash_lock
Interrupts:	Ignored
Functions:	free_uid(), alloc_uid()
Use:		Held when updating or validating the uid hash table.
		(After acquiring the lock, this should be done by
		using the routines uid_hash_free(), uid_hash_remove(),
		uid_hash_find(), or uid_hash_insert().)

Lock:		lru_list_lock
Interrupts:	Ignored
Functions:	sync_buffers(), buffer_insert_inode_queue(),
		inode_has_buffers(),  __invalidate_buffers(),
		set_blocksize(), fsync_inode_buffers(),
		osync_inode_buffers(), invalidate_inode_buffers(),
		getblk(), refile_buffers(), __bforget(),
		try_to_free_buffers(), show_buffers(),
		flush_dirty_buffers()
Use:		Held while reading or writing the lru_list.
Notes:		if hash_table_lock and	unused_list_lock are also used,
		then the order should be lru_list_lock --> hash_table_lock
		--> unused_list_lock to avoid deadlocks.  The routines
		__removed_from_queues() and __insert_into_queues()
		expect this lock to be held upon entry.

Lock:		unused_list_lock
Interrupts:	Ignored
Functions:	get_unused_buffer_head, create_buffers, wait_kio, brw_kiovec,
		try_to_free_buffers
Use:		protects the unused_list
Notes:		If hash_table_lock and lru_list_lock are also used, then
		the order should be lru_list_lock > hash_table_lock >
		unused_list_lock to avoid deadlocks.  The routine
		__put_unused_buffer_head() expects this lock to be held
		upon entry.

#
# static read/write locks
#
lock:		hash_table_lock
Functions:	get_hash_table(), __invalidate_buffers(), set_blocksize(),
		getblk(), __bforget(), try_to_free_buffers()
Use:		Protects access to hash_table[]. This is a fixed size
		array, so it really protects each element (bucket) in
		the array and the next/prev linkage to any additional
		data items in the bucket.
		Held for read when examining any bucket in hash_table[].
		Held for write when modifying any bucket in hash_table[].
		    Note this only protects the integrity of the hash bucket
		    linked lists, not the data stored in those lists.
Notes:		If hash_table_lock and lru_list_lock are also used, then the
		order should be lru_list_lock > hash_table_lock >
		unused_list_lock to avoid deadlocks.  The routines
		__remove_from_queues() and __insert_into_queues() expect
		this lock to be held upon entry.

#
# locks found in structures
#
Lock:		isl_lock
Interrupts:	Saved, Ignored
Structure:	ia64_state_log_s
Macros:		IA64_LOG_LOCK_INIT()
		    mca.c;
		IA64_LOG_LOCK()
		    mca.c;
		IA64_LOG_UNLOCK()
		    mca.c;
Use:		Held while modifying or reading from ia64_state_log.

Lock:		__tcp_portalloc_lock
Structure:	tcp_hashinfo
Interrupts:	Ignored
Functions:	tcp_v4_get_port(), tcp_v6_get_port()
Use:		Held while acquiring a TCP port (essentially, while
		examining and modifying tcp_port_rover.)


8. Change Log

Changes from 2.4.4 to 2.4.5
    sys_fcntl64 no longer uses lock_kernel()
    nfs_lock began using lock_kernel()