diff --git a/doc/design-2.0-locking.rst b/doc/design-2.0-locking.rst
index fd712a440b6d172d14dfb9c4328a0515be503fb5..2c38a8ec1dc3768ebeed5686dd42ef37d15a7097 100644
--- a/doc/design-2.0-locking.rst
+++ b/doc/design-2.0-locking.rst
@@ -171,6 +171,43 @@ level.  In the future we may want to split logical units in independent
 "tasklets" with their own locking requirements. A different design doc (or mini
 design doc) will cover the move from Logical Units to tasklets.
 
+Lock acquisition code path
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In general when acquiring locks we should use a code path equivalent to::
+
+  lock.acquire()
+  try:
+    ...
+    # other code
+  finally:
+    lock.release()
+
+This makes sure we release all locks, and avoid possible deadlocks. Of course
+extra care must be used not to leave, if possible locked structures in an
+unusable state.
+
+In order to avoid this extra indentation and code changes everywhere in the
+Logical Units code, we decided to allow LUs to declare locks, and then execute
+their code with their locks acquired. In the new world LUs are called like
+this::
+
+  # user passed names are expanded to the internal lock/resource name,
+  # then known needed locks are declared
+  lu.ExpandNames()
+  ... some locking/adding of locks may happen ...
+  # late declaration of locks for one level: this is useful because sometimes
+  # we can't know which resource we need before locking the previous level
+  lu.DeclareLocks() # for each level (cluster, instance, node)
+  ... more locking/adding of locks can happen ...
+  # these functions are called with the proper locks held
+  lu.CheckPrereq()
+  lu.Exec()
+  ... locks declared for removal are removed, all acquired locks released ...
+
+The Processor and the LogicalUnit class will contain exact documentation on how
+locks are supposed to be declared.
+
 Caveats
 -------