update D/f/directory-locking
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
0985b65d3b
commit
d42b386834
@ -1,30 +1,37 @@
|
|||||||
Locking scheme used for directory operations is based on two
|
Locking scheme used for directory operations is based on two
|
||||||
kinds of locks - per-inode (->i_mutex) and per-filesystem
|
kinds of locks - per-inode (->i_rwsem) and per-filesystem
|
||||||
(->s_vfs_rename_mutex).
|
(->s_vfs_rename_mutex).
|
||||||
|
|
||||||
When taking the i_mutex on multiple non-directory objects, we
|
When taking the i_rwsem on multiple non-directory objects, we
|
||||||
always acquire the locks in order by increasing address. We'll call
|
always acquire the locks in order by increasing address. We'll call
|
||||||
that "inode pointer" order in the following.
|
that "inode pointer" order in the following.
|
||||||
|
|
||||||
For our purposes all operations fall in 5 classes:
|
For our purposes all operations fall in 5 classes:
|
||||||
|
|
||||||
1) read access. Locking rules: caller locks directory we are accessing.
|
1) read access. Locking rules: caller locks directory we are accessing.
|
||||||
|
The lock is taken shared.
|
||||||
|
|
||||||
2) object creation. Locking rules: same as above.
|
2) object creation. Locking rules: same as above, but the lock is taken
|
||||||
|
exclusive.
|
||||||
|
|
||||||
3) object removal. Locking rules: caller locks parent, finds victim,
|
3) object removal. Locking rules: caller locks parent, finds victim,
|
||||||
locks victim and calls the method.
|
locks victim and calls the method. Locks are exclusive.
|
||||||
|
|
||||||
4) rename() that is _not_ cross-directory. Locking rules: caller locks
|
4) rename() that is _not_ cross-directory. Locking rules: caller locks
|
||||||
the parent and finds source and target. If target already exists, lock
|
the parent and finds source and target. In case of exchange (with
|
||||||
it. If source is a non-directory, lock it. If that means we need to
|
RENAME_EXCHANGE in rename2() flags argument) lock both. In any case,
|
||||||
lock both, lock them in inode pointer order.
|
if the target already exists, lock it. If the source is a non-directory,
|
||||||
|
lock it. If we need to lock both, lock them in inode pointer order.
|
||||||
|
Then call the method. All locks are exclusive.
|
||||||
|
NB: we might get away with locking the the source (and target in exchange
|
||||||
|
case) shared.
|
||||||
|
|
||||||
5) link creation. Locking rules:
|
5) link creation. Locking rules:
|
||||||
* lock parent
|
* lock parent
|
||||||
* check that source is not a directory
|
* check that source is not a directory
|
||||||
* lock source
|
* lock source
|
||||||
* call the method.
|
* call the method.
|
||||||
|
All locks are exclusive.
|
||||||
|
|
||||||
6) cross-directory rename. The trickiest in the whole bunch. Locking
|
6) cross-directory rename. The trickiest in the whole bunch. Locking
|
||||||
rules:
|
rules:
|
||||||
@ -35,11 +42,12 @@ rules:
|
|||||||
fail with -ENOTEMPTY
|
fail with -ENOTEMPTY
|
||||||
* if new parent is equal to or is a descendent of source
|
* if new parent is equal to or is a descendent of source
|
||||||
fail with -ELOOP
|
fail with -ELOOP
|
||||||
* If target exists, lock it. If source is a non-directory, lock
|
* If it's an exchange, lock both the source and the target.
|
||||||
it. In case that means we need to lock both source and target,
|
* If the target exists, lock it. If the source is a non-directory,
|
||||||
do so in inode pointer order.
|
lock it. If we need to lock both, do so in inode pointer order.
|
||||||
* call the method.
|
* call the method.
|
||||||
|
All ->i_rwsem are taken exclusive. Again, we might get away with locking
|
||||||
|
the the source (and target in exchange case) shared.
|
||||||
|
|
||||||
The rules above obviously guarantee that all directories that are going to be
|
The rules above obviously guarantee that all directories that are going to be
|
||||||
read, modified or removed by method will be locked by caller.
|
read, modified or removed by method will be locked by caller.
|
||||||
@ -73,7 +81,7 @@ objects - A < B iff A is an ancestor of B.
|
|||||||
attempt to acquire some lock and already holds at least one lock. Let's
|
attempt to acquire some lock and already holds at least one lock. Let's
|
||||||
consider the set of contended locks. First of all, filesystem lock is
|
consider the set of contended locks. First of all, filesystem lock is
|
||||||
not contended, since any process blocked on it is not holding any locks.
|
not contended, since any process blocked on it is not holding any locks.
|
||||||
Thus all processes are blocked on ->i_mutex.
|
Thus all processes are blocked on ->i_rwsem.
|
||||||
|
|
||||||
By (3), any process holding a non-directory lock can only be
|
By (3), any process holding a non-directory lock can only be
|
||||||
waiting on another non-directory lock with a larger address. Therefore
|
waiting on another non-directory lock with a larger address. Therefore
|
||||||
|
Loading…
Reference in New Issue
Block a user