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  }