-Locks for a given file are cached in a per-file doubly linked list. The overall
-lock life cycle is as following:
-
-- The lock is created in the CLS_NEW state. At this moment the lock doesn't
- actually protect anything;
-
-- The Lock is enqueued, that is, sent to server, passing through the
- CLS_QUEUING state. In this state multiple network communications with
- multiple servers may occur;
-
-- Once fully enqueued, the lock moves into the CLS_ENQUEUED state where it
- waits for a final reply from the server or servers;
-
-- When a reply granting this lock is received, the lock moves into the CLS_HELD
- state. In this state the lock protects file data, and pages in the lock
- extent can be cached (and dirtied for a write lock);
-
-- When the lock is not actively used, it is `unused' and, moving through the
- CLS_UNLOCKING state, lands in the CLS_CACHED state. In this state the lock
- still protects cached data. The difference with CLS_HELD state is that a lock
- in the CLS_CACHED state can be cancelled;
-
-- Ultimately, the lock is either cancelled, or destroyed without cancellation.
- In any case, it is moved in CLS_FREEING state and eventually freed.
-
- A lock can be cancelled by a client either voluntarily (in reaction to memory
- pressure, by explicit user request, or as part of early cancellation), or
- involuntarily, when a blocking AST arrives.
-
- A lock can be destroyed without cancellation when its object is destroyed
- (there should be no cached data at this point), or during eviction (when
- cached data are invalid);
-
-- If an unrecoverable error occurs at any point (e.g., due to network timeout,
- or a server's refusal to grant a lock), the lock is moved into the
- CLS_FREEING state.
-
-The description above matches the slow IO path. In the common fast path there
-is already a cached lock covering the extent which the IO is against. In this
-case, the cl_lock_find() function finds the cached lock. If the found lock is
-in the CLS_HELD state, it can be used for IO immediately. If the found lock is
-in CLS_CACHED state, it is removed from the cache and transitions to CLS_HELD.
-If the lock is in the CLS_QUEUING or CLS_ENQUEUED state, some other IO is
-currently in the process of enqueuing it, and the current thread helps that
-other thread by continuing the enqueue operation.
-
-The actual process of finding a lock in the cache is in fact more involved than
-the above description, because there are cases when a lock matching the IO
-extent and mode still cannot be used for this IO. For example, locks covering
-multiple stripes cannot be used for regular IO, due to the danger of cascading
-evictions. For such situations, every layer can optionally define
-cl_lock_operations::clo_fits_into() method that might declare a given lock
-unsuitable for a given IO. See lov_lock_fits_into() as an example.
-
-5.2. Top-lock and Sub-locks
-===========================
-
-A top-lock protects cached pages of a top-object, and is based on a set of
-sub-locks, protecting cached pages of sub-objects:
-
- +--------->list of locks
- | |
- | V
- cl_object_header<------------cl_lock
- | ->cld_obj |
- V V
- vvp_object<---------------vvp_lock
- | ->cls_obj |
- V V
- lov_object<---------------lov_lock
- | ->cls_obj |
- +---+---+---+---+ +---+---+---+---+
- | | | | | | | | | |
- . | . . . . . . | .
- | |
- | +-------------->list of locks |
- | | | |
- V | V V
- cl_object_header<----------------------cl_lock
- | ->cp_obj |
- V V
- lovsub_object<---------------------lovsub_lock
- | ->cls_obj |
- V V
- osc_object<------------------------osc_lock
- ->cls_obj
-
-When a top-lock is created, it creates sub-locks based on the striping method
-(RAID0 currently). Sub-locks are `created' in the same manner as top-locks: by
-calling cl_lock_find() function to go through the lock cache. To enqueue a
-top-lock all of its sub-locks have to be enqueued also, with ordering
-constraints defined by enqueue options:
-
-- To enqueue a regular top-lock, each sub-lock has to be enqueued and granted
- before the next one can be enqueued. This is necessary to avoid deadlock;
-
-- For `try-lock' style top-lock (e.g., a glimpse request, or O_NONBLOCK IO
- locks), requests can be enqueued in parallel, because dead-lock is not
- possible in this case.
-
-Sub-lock state depends on its top-lock state:
-
-- When top-lock is being enqueued, its sub-locks are in QUEUING, ENQUEUED,
- or HELD state;
-
-- When a top-lock is in HELD state, its sub-locks are in HELD state too;
-
-- When a top-lock is in CACHED state, its sub-locks are in CACHED state too;
-
-- When a top-lock is in FREEING state, it detaches itself from all sub-locks,
- and those are usually deleted too.
-
-A sub-lock can be cancelled while its top-lock is in CACHED state. To maintain
-an invariant that CACHED lock is immediately ready for re-use by IO, the
-top-lock is moved into NEW state. The next attempt to use this lock will
-enqueue it again, resulting in the creation and enqueue of any missing
-sub-locks. As follows from the description above, the top-lock provides
-somewhat weaker guarantees than one might expect:
-
-- Some of its sub-locks can be missing, and
-
-- Top-lock does not necessarily protect the whole of its extent.
-
-In other words, a top-lock is potentially porous, and in effect, it is just a
-hint, describing what sub-locks are likely to exist. Nonetheless, in the most
-important cases of a file per client, and of clients working in the disjoint
-areas of a shared file this hint is precise.
-
-5.3. Lock State Machine
-=======================
+The lock requirements are collected in cl_io_lock(). In cl_io_lock(), the
+->cio_lock() method for each layers are invoked to decide the lock extent by
+IO region, layout, and buffers. For example, in the VVP layer, it has to search
+buffers of IO and if the buffers belong to a Lustre file mmap region, the locks
+for the corresponding file will be requred.
+
+Once the lock requirements are collected, cl_lock_request() is called to create
+and initialize individual locks. In cl_lock_request(), ->clo_enqueue() is called
+for each layers. Especially on the OSC layer, osc_lock_enqueue() is called to
+match or create LDLM lock to fulfill the lock requirement.
+
+cl_lock is not cacheable. The locks will be destroyed after IO is complete. The
+lock destroying process starts from cl_io_unlock() where cl_lock_release() is
+called for each cl_lock. In cl_lock_release(), ->clo_cancel() methods are called
+for each layer to release the resource held by cl_lock. The most important
+resource held by cl_lock is the LDLM lock on the OSC layer. It will be released
+by osc_lock_cancel(). LDLM locks can still be cached in memory after being
+detached from cl_lock.
+
+5.2. cl_lock and LDLM Lock
+==========================