Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs fixes from Al Viro: "Followups to the parallel lookup work: - update docs - restore killability of the places that used to take ->i_mutex killably now that we have down_write_killable() merged - Additionally, it turns out that I missed a prerequisite for security_d_instantiate() stuff - ->getxattr() wasn't the only thing that could be called before dentry is attached to inode; with smack we needed the same treatment applied to ->setxattr() as well" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: switch ->setxattr() to passing dentry and inode separately switch xattr_handler->set() to passing dentry and inode separately restore killability of old mutex_lock_killable(&inode->i_mutex) users add down_write_killable_nested() update D/f/directory-locking
此提交包含在:
@@ -1,30 +1,37 @@
|
||||
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).
|
||||
|
||||
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
|
||||
that "inode pointer" order in the following.
|
||||
|
||||
For our purposes all operations fall in 5 classes:
|
||||
|
||||
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,
|
||||
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
|
||||
the parent and finds source and target. If target already exists, lock
|
||||
it. If source is a non-directory, lock it. If that means we need to
|
||||
lock both, lock them in inode pointer order.
|
||||
the parent and finds source and target. In case of exchange (with
|
||||
RENAME_EXCHANGE in rename2() flags argument) lock both. In any case,
|
||||
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:
|
||||
* lock parent
|
||||
* check that source is not a directory
|
||||
* lock source
|
||||
* call the method.
|
||||
All locks are exclusive.
|
||||
|
||||
6) cross-directory rename. The trickiest in the whole bunch. Locking
|
||||
rules:
|
||||
@@ -35,11 +42,12 @@ rules:
|
||||
fail with -ENOTEMPTY
|
||||
* if new parent is equal to or is a descendent of source
|
||||
fail with -ELOOP
|
||||
* If target exists, lock it. If source is a non-directory, lock
|
||||
it. In case that means we need to lock both source and target,
|
||||
do so in inode pointer order.
|
||||
* If it's an exchange, lock both the source and the target.
|
||||
* If the target exists, lock it. If the source is a non-directory,
|
||||
lock it. If we need to lock both, do so in inode pointer order.
|
||||
* 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
|
||||
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
|
||||
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.
|
||||
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
|
||||
waiting on another non-directory lock with a larger address. Therefore
|
||||
|
@@ -578,3 +578,10 @@ in your dentry operations instead.
|
||||
--
|
||||
[mandatory]
|
||||
->atomic_open() calls without O_CREAT may happen in parallel.
|
||||
--
|
||||
[mandatory]
|
||||
->setxattr() and xattr_handler.set() get dentry and inode passed separately.
|
||||
dentry might be yet to be attached to inode, so do _not_ use its ->d_inode
|
||||
in the instances. Rationale: !@#!@# security_d_instantiate() needs to be
|
||||
called before we attach dentry to inode and !@#!@##!@$!$#!@#$!@$!@$ smack
|
||||
->d_instantiate() uses not just ->getxattr() but ->setxattr() as well.
|
||||
|
新增問題並參考
封鎖使用者