1================= 2Directory Locking 3================= 4 5 6Locking scheme used for directory operations is based on two 7kinds of locks - per-inode (->i_rwsem) and per-filesystem 8(->s_vfs_rename_mutex). 9 10When taking the i_rwsem on multiple non-directory objects, we 11always acquire the locks in order by increasing address. We'll call 12that "inode pointer" order in the following. 13 14 15Primitives 16========== 17 18For our purposes all operations fall in 6 classes: 19 201. read access. Locking rules: 21 22 * lock the directory we are accessing (shared) 23 242. object creation. Locking rules: 25 26 * lock the directory we are accessing (exclusive) 27 283. object removal. Locking rules: 29 30 * lock the parent (exclusive) 31 * find the victim 32 * lock the victim (exclusive) 33 344. link creation. Locking rules: 35 36 * lock the parent (exclusive) 37 * check that the source is not a directory 38 * lock the source (exclusive; probably could be weakened to shared) 39 405. rename that is _not_ cross-directory. Locking rules: 41 42 * lock the parent (exclusive) 43 * find the source and target 44 * decide which of the source and target need to be locked. 45 The source needs to be locked if it's a non-directory, target - if it's 46 a non-directory or about to be removed. 47 * take the locks that need to be taken (exclusive), in inode pointer order 48 if need to take both (that can happen only when both source and target 49 are non-directories - the source because it wouldn't need to be locked 50 otherwise and the target because mixing directory and non-directory is 51 allowed only with RENAME_EXCHANGE, and that won't be removing the target). 52 536. cross-directory rename. The trickiest in the whole bunch. Locking rules: 54 55 * lock the filesystem 56 * if the parents don't have a common ancestor, fail the operation. 57 * lock the parents in "ancestors first" order (exclusive). If neither is an 58 ancestor of the other, lock the parent of source first. 59 * find the source and target. 60 * verify that the source is not a descendent of the target and 61 target is not a descendent of source; fail the operation otherwise. 62 * lock the subdirectories involved (exclusive), source before target. 63 * lock the non-directories involved (exclusive), in inode pointer order. 64 65The rules above obviously guarantee that all directories that are going 66to be read, modified or removed by method will be locked by the caller. 67 68 69Splicing 70======== 71 72There is one more thing to consider - splicing. It's not an operation 73in its own right; it may happen as part of lookup. We speak of the 74operations on directory trees, but we obviously do not have the full 75picture of those - especially for network filesystems. What we have 76is a bunch of subtrees visible in dcache and locking happens on those. 77Trees grow as we do operations; memory pressure prunes them. Normally 78that's not a problem, but there is a nasty twist - what should we do 79when one growing tree reaches the root of another? That can happen in 80several scenarios, starting from "somebody mounted two nested subtrees 81from the same NFS4 server and doing lookups in one of them has reached 82the root of another"; there's also open-by-fhandle stuff, and there's a 83possibility that directory we see in one place gets moved by the server 84to another and we run into it when we do a lookup. 85 86For a lot of reasons we want to have the same directory present in dcache 87only once. Multiple aliases are not allowed. So when lookup runs into 88a subdirectory that already has an alias, something needs to be done with 89dcache trees. Lookup is already holding the parent locked. If alias is 90a root of separate tree, it gets attached to the directory we are doing a 91lookup in, under the name we'd been looking for. If the alias is already 92a child of the directory we are looking in, it changes name to the one 93we'd been looking for. No extra locking is involved in these two cases. 94However, if it's a child of some other directory, the things get trickier. 95First of all, we verify that it is *not* an ancestor of our directory 96and fail the lookup if it is. Then we try to lock the filesystem and the 97current parent of the alias. If either trylock fails, we fail the lookup. 98If trylocks succeed, we detach the alias from its current parent and 99attach to our directory, under the name we are looking for. 100 101Note that splicing does *not* involve any modification of the filesystem; 102all we change is the view in dcache. Moreover, holding a directory locked 103exclusive prevents such changes involving its children and holding the 104filesystem lock prevents any changes of tree topology, other than having a 105root of one tree becoming a child of directory in another. In particular, 106if two dentries have been found to have a common ancestor after taking 107the filesystem lock, their relationship will remain unchanged until 108the lock is dropped. So from the directory operations' point of view 109splicing is almost irrelevant - the only place where it matters is one 110step in cross-directory renames; we need to be careful when checking if 111parents have a common ancestor. 112 113 114Multiple-filesystem stuff 115========================= 116 117For some filesystems a method can involve a directory operation on 118another filesystem; it may be ecryptfs doing operation in the underlying 119filesystem, overlayfs doing something to the layers, network filesystem 120using a local one as a cache, etc. In all such cases the operations 121on other filesystems must follow the same locking rules. Moreover, "a 122directory operation on this filesystem might involve directory operations 123on that filesystem" should be an asymmetric relation (or, if you will, 124it should be possible to rank the filesystems so that directory operation 125on a filesystem could trigger directory operations only on higher-ranked 126ones - in these terms overlayfs ranks lower than its layers, network 127filesystem ranks lower than whatever it caches on, etc.) 128 129 130Deadlock avoidance 131================== 132 133If no directory is its own ancestor, the scheme above is deadlock-free. 134 135Proof: 136 137There is a ranking on the locks, such that all primitives take 138them in order of non-decreasing rank. Namely, 139 140 * rank ->i_rwsem of non-directories on given filesystem in inode pointer 141 order. 142 * put ->i_rwsem of all directories on a filesystem at the same rank, 143 lower than ->i_rwsem of any non-directory on the same filesystem. 144 * put ->s_vfs_rename_mutex at rank lower than that of any ->i_rwsem 145 on the same filesystem. 146 * among the locks on different filesystems use the relative 147 rank of those filesystems. 148 149For example, if we have NFS filesystem caching on a local one, we have 150 151 1. ->s_vfs_rename_mutex of NFS filesystem 152 2. ->i_rwsem of directories on that NFS filesystem, same rank for all 153 3. ->i_rwsem of non-directories on that filesystem, in order of 154 increasing address of inode 155 4. ->s_vfs_rename_mutex of local filesystem 156 5. ->i_rwsem of directories on the local filesystem, same rank for all 157 6. ->i_rwsem of non-directories on local filesystem, in order of 158 increasing address of inode. 159 160It's easy to verify that operations never take a lock with rank 161lower than that of an already held lock. 162 163Suppose deadlocks are possible. Consider the minimal deadlocked 164set of threads. It is a cycle of several threads, each blocked on a lock 165held by the next thread in the cycle. 166 167Since the locking order is consistent with the ranking, all 168contended locks in the minimal deadlock will be of the same rank, 169i.e. they all will be ->i_rwsem of directories on the same filesystem. 170Moreover, without loss of generality we can assume that all operations 171are done directly to that filesystem and none of them has actually 172reached the method call. 173 174In other words, we have a cycle of threads, T1,..., Tn, 175and the same number of directories (D1,...,Dn) such that 176 177 T1 is blocked on D1 which is held by T2 178 179 T2 is blocked on D2 which is held by T3 180 181 ... 182 183 Tn is blocked on Dn which is held by T1. 184 185Each operation in the minimal cycle must have locked at least 186one directory and blocked on attempt to lock another. That leaves 187only 3 possible operations: directory removal (locks parent, then 188child), same-directory rename killing a subdirectory (ditto) and 189cross-directory rename of some sort. 190 191There must be a cross-directory rename in the set; indeed, 192if all operations had been of the "lock parent, then child" sort 193we would have Dn a parent of D1, which is a parent of D2, which is 194a parent of D3, ..., which is a parent of Dn. Relationships couldn't 195have changed since the moment directory locks had been acquired, 196so they would all hold simultaneously at the deadlock time and 197we would have a loop. 198 199Since all operations are on the same filesystem, there can't be 200more than one cross-directory rename among them. Without loss of 201generality we can assume that T1 is the one doing a cross-directory 202rename and everything else is of the "lock parent, then child" sort. 203 204In other words, we have a cross-directory rename that locked 205Dn and blocked on attempt to lock D1, which is a parent of D2, which is 206a parent of D3, ..., which is a parent of Dn. Relationships between 207D1,...,Dn all hold simultaneously at the deadlock time. Moreover, 208cross-directory rename does not get to locking any directories until it 209has acquired filesystem lock and verified that directories involved have 210a common ancestor, which guarantees that ancestry relationships between 211all of them had been stable. 212 213Consider the order in which directories are locked by the 214cross-directory rename; parents first, then possibly their children. 215Dn and D1 would have to be among those, with Dn locked before D1. 216Which pair could it be? 217 218It can't be the parents - indeed, since D1 is an ancestor of Dn, 219it would be the first parent to be locked. Therefore at least one of the 220children must be involved and thus neither of them could be a descendent 221of another - otherwise the operation would not have progressed past 222locking the parents. 223 224It can't be a parent and its child; otherwise we would've had 225a loop, since the parents are locked before the children, so the parent 226would have to be a descendent of its child. 227 228It can't be a parent and a child of another parent either. 229Otherwise the child of the parent in question would've been a descendent 230of another child. 231 232That leaves only one possibility - namely, both Dn and D1 are 233among the children, in some order. But that is also impossible, since 234neither of the children is a descendent of another. 235 236That concludes the proof, since the set of operations with the 237properties required for a minimal deadlock can not exist. 238 239Note that the check for having a common ancestor in cross-directory 240rename is crucial - without it a deadlock would be possible. Indeed, 241suppose the parents are initially in different trees; we would lock the 242parent of source, then try to lock the parent of target, only to have 243an unrelated lookup splice a distant ancestor of source to some distant 244descendent of the parent of target. At that point we have cross-directory 245rename holding the lock on parent of source and trying to lock its 246distant ancestor. Add a bunch of rmdir() attempts on all directories 247in between (all of those would fail with -ENOTEMPTY, had they ever gotten 248the locks) and voila - we have a deadlock. 249 250Loop avoidance 251============== 252 253These operations are guaranteed to avoid loop creation. Indeed, 254the only operation that could introduce loops is cross-directory rename. 255Suppose after the operation there is a loop; since there hadn't been such 256loops before the operation, at least on of the nodes in that loop must've 257had its parent changed. In other words, the loop must be passing through 258the source or, in case of exchange, possibly the target. 259 260Since the operation has succeeded, neither source nor target could have 261been ancestors of each other. Therefore the chain of ancestors starting 262in the parent of source could not have passed through the target and 263vice versa. On the other hand, the chain of ancestors of any node could 264not have passed through the node itself, or we would've had a loop before 265the operation. But everything other than source and target has kept 266the parent after the operation, so the operation does not change the 267chains of ancestors of (ex-)parents of source and target. In particular, 268those chains must end after a finite number of steps. 269 270Now consider the loop created by the operation. It passes through either 271source or target; the next node in the loop would be the ex-parent of 272target or source resp. After that the loop would follow the chain of 273ancestors of that parent. But as we have just shown, that chain must 274end after a finite number of steps, which means that it can't be a part 275of any loop. Q.E.D. 276 277While this locking scheme works for arbitrary DAGs, it relies on 278ability to check that directory is a descendent of another object. Current 279implementation assumes that directory graph is a tree. This assumption is 280also preserved by all operations (cross-directory rename on a tree that would 281not introduce a cycle will leave it a tree and link() fails for directories). 282 283Notice that "directory" in the above == "anything that might have 284children", so if we are going to introduce hybrid objects we will need 285either to make sure that link(2) doesn't work for them or to make changes 286in is_subdir() that would make it work even in presence of such beasts. 287