github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/p9/path_tree.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package p9 16 17 import ( 18 "fmt" 19 20 "github.com/SagerNet/gvisor/pkg/sync" 21 ) 22 23 // pathNode is a single node in a path traversal. 24 // 25 // These are shared by all fidRefs that point to the same path. 26 // 27 // Lock ordering: 28 // opMu 29 // childMu 30 // 31 // Two different pathNodes may only be locked if Server.renameMu is held for 32 // write, in which case they can be acquired in any order. 33 type pathNode struct { 34 // opMu synchronizes high-level, sematic operations, such as the 35 // simultaneous creation and deletion of a file. 36 // 37 // opMu does not directly protect any fields in pathNode. 38 opMu sync.RWMutex 39 40 // childMu protects the fields below. 41 childMu sync.RWMutex 42 43 // childNodes maps child path component names to their pathNode. 44 childNodes map[string]*pathNode 45 46 // childRefs maps child path component names to all of the their 47 // references. 48 childRefs map[string]map[*fidRef]struct{} 49 50 // childRefNames maps child references back to their path component 51 // name. 52 childRefNames map[*fidRef]string 53 } 54 55 func newPathNode() *pathNode { 56 return &pathNode{ 57 childNodes: make(map[string]*pathNode), 58 childRefs: make(map[string]map[*fidRef]struct{}), 59 childRefNames: make(map[*fidRef]string), 60 } 61 } 62 63 // forEachChildRef calls fn for each child reference. 64 func (p *pathNode) forEachChildRef(fn func(ref *fidRef, name string)) { 65 p.childMu.RLock() 66 defer p.childMu.RUnlock() 67 68 for name, m := range p.childRefs { 69 for ref := range m { 70 fn(ref, name) 71 } 72 } 73 } 74 75 // forEachChildNode calls fn for each child pathNode. 76 func (p *pathNode) forEachChildNode(fn func(pn *pathNode)) { 77 p.childMu.RLock() 78 defer p.childMu.RUnlock() 79 80 for _, pn := range p.childNodes { 81 fn(pn) 82 } 83 } 84 85 // pathNodeFor returns the path node for the given name, or a new one. 86 func (p *pathNode) pathNodeFor(name string) *pathNode { 87 p.childMu.RLock() 88 // Fast path, node already exists. 89 if pn, ok := p.childNodes[name]; ok { 90 p.childMu.RUnlock() 91 return pn 92 } 93 p.childMu.RUnlock() 94 95 // Slow path, create a new pathNode for shared use. 96 p.childMu.Lock() 97 98 // Re-check after re-lock. 99 if pn, ok := p.childNodes[name]; ok { 100 p.childMu.Unlock() 101 return pn 102 } 103 104 pn := newPathNode() 105 p.childNodes[name] = pn 106 p.childMu.Unlock() 107 return pn 108 } 109 110 // nameFor returns the name for the given fidRef. 111 // 112 // Precondition: addChild is called for ref before nameFor. 113 func (p *pathNode) nameFor(ref *fidRef) string { 114 p.childMu.RLock() 115 n, ok := p.childRefNames[ref] 116 p.childMu.RUnlock() 117 118 if !ok { 119 // This should not happen, don't proceed. 120 panic(fmt.Sprintf("expected name for %+v, none found", ref)) 121 } 122 123 return n 124 } 125 126 // addChildLocked adds a child reference to p. 127 // 128 // Precondition: As addChild, plus childMu is locked for write. 129 func (p *pathNode) addChildLocked(ref *fidRef, name string) { 130 if n, ok := p.childRefNames[ref]; ok { 131 // This should not happen, don't proceed. 132 panic(fmt.Sprintf("unexpected fidRef %+v with path %q, wanted %q", ref, n, name)) 133 } 134 135 p.childRefNames[ref] = name 136 137 m, ok := p.childRefs[name] 138 if !ok { 139 m = make(map[*fidRef]struct{}) 140 p.childRefs[name] = m 141 } 142 143 m[ref] = struct{}{} 144 } 145 146 // addChild adds a child reference to p. 147 // 148 // Precondition: ref may only be added once at a time. 149 func (p *pathNode) addChild(ref *fidRef, name string) { 150 p.childMu.Lock() 151 p.addChildLocked(ref, name) 152 p.childMu.Unlock() 153 } 154 155 // removeChild removes the given child. 156 // 157 // This applies only to an individual fidRef, which is not required to exist. 158 func (p *pathNode) removeChild(ref *fidRef) { 159 p.childMu.Lock() 160 161 // This ref may not exist anymore. This can occur, e.g., in unlink, 162 // where a removeWithName removes the ref, and then a DecRef on the ref 163 // attempts to remove again. 164 if name, ok := p.childRefNames[ref]; ok { 165 m, ok := p.childRefs[name] 166 if !ok { 167 // This should not happen, don't proceed. 168 p.childMu.Unlock() 169 panic(fmt.Sprintf("name %s missing from childfidRefs", name)) 170 } 171 172 delete(m, ref) 173 if len(m) == 0 { 174 delete(p.childRefs, name) 175 } 176 } 177 178 delete(p.childRefNames, ref) 179 180 p.childMu.Unlock() 181 } 182 183 // addPathNodeFor adds an existing pathNode as the node for name. 184 // 185 // Preconditions: newName does not exist. 186 func (p *pathNode) addPathNodeFor(name string, pn *pathNode) { 187 p.childMu.Lock() 188 189 if opn, ok := p.childNodes[name]; ok { 190 p.childMu.Unlock() 191 panic(fmt.Sprintf("unexpected pathNode %+v with path %q", opn, name)) 192 } 193 194 p.childNodes[name] = pn 195 p.childMu.Unlock() 196 } 197 198 // removeWithName removes all references with the given name. 199 // 200 // The provided function is executed after reference removal. The only method 201 // it may (transitively) call on this pathNode is addChildLocked. 202 // 203 // If a child pathNode for name exists, it is removed from this pathNode and 204 // returned by this function. Any operations on the removed tree must use this 205 // value. 206 func (p *pathNode) removeWithName(name string, fn func(ref *fidRef)) *pathNode { 207 p.childMu.Lock() 208 defer p.childMu.Unlock() 209 210 if m, ok := p.childRefs[name]; ok { 211 for ref := range m { 212 delete(m, ref) 213 delete(p.childRefNames, ref) 214 fn(ref) 215 } 216 } 217 218 // Return the original path node, if it exists. 219 origPathNode := p.childNodes[name] 220 delete(p.childNodes, name) 221 return origPathNode 222 }