github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/lisafs/server.go (about)

     1  // Copyright 2021 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 lisafs
    16  
    17  import (
    18  	"github.com/nicocha30/gvisor-ligolo/pkg/abi/linux"
    19  	"github.com/nicocha30/gvisor-ligolo/pkg/sync"
    20  )
    21  
    22  // Server serves a filesystem tree. Multiple connections on different mount
    23  // points can be started on a server. The server provides utilities to safely
    24  // modify the filesystem tree across its connections (mount points). Note that
    25  // it does not support synchronizing filesystem tree mutations across other
    26  // servers serving the same filesystem subtree. Server also manages the
    27  // lifecycle of all connections.
    28  type Server struct {
    29  	// connWg counts the number of active connections being tracked.
    30  	connWg sync.WaitGroup
    31  
    32  	// renameMu synchronizes rename operations within this filesystem tree.
    33  	renameMu sync.RWMutex
    34  
    35  	// handlers is a list of RPC handlers which can be indexed by the handler's
    36  	// corresponding MID.
    37  	handlers []RPCHandler
    38  
    39  	// root is the root of the filesystem tree being managed by this server.
    40  	// root is immutable. Server holds a ref on root for its entire lifetime.
    41  	root *Node
    42  
    43  	// impl is the server implementation which embeds this server.
    44  	impl ServerImpl
    45  
    46  	// opts is the server specific options. This dictates how some of the
    47  	// messages are handled.
    48  	opts ServerOpts
    49  }
    50  
    51  // ServerOpts defines some server implementation specific behavior.
    52  type ServerOpts struct {
    53  	// WalkStatSupported is set to true if it's safe to call
    54  	// ControlFDImpl.WalkStat and let the file implementation perform the walk
    55  	// without holding locks on any of the descendant's Nodes.
    56  	WalkStatSupported bool
    57  
    58  	// SetAttrOnDeleted is set to true if it's safe to call ControlFDImpl.SetStat
    59  	// for deleted files.
    60  	SetAttrOnDeleted bool
    61  
    62  	// AllocateOnDeleted is set to true if it's safe to call OpenFDImpl.Allocate
    63  	// for deleted files.
    64  	AllocateOnDeleted bool
    65  }
    66  
    67  // Init must be called before first use of the server.
    68  func (s *Server) Init(impl ServerImpl, opts ServerOpts) {
    69  	s.impl = impl
    70  	s.opts = opts
    71  	s.handlers = handlers[:]
    72  	s.root = &Node{}
    73  	// s owns the ref on s.root.
    74  	s.root.InitLocked("", nil)
    75  }
    76  
    77  // SetHandlers overrides the server's RPC handlers. Mainly should only be used
    78  // for tests.
    79  func (s *Server) SetHandlers(handlers []RPCHandler) {
    80  	s.handlers = handlers
    81  }
    82  
    83  // withRenameReadLock invokes fn with the server's rename mutex locked for
    84  // reading. This ensures that no rename operations occur concurrently.
    85  func (s *Server) withRenameReadLock(fn func() error) error {
    86  	s.renameMu.RLock()
    87  	defer s.renameMu.RUnlock()
    88  	return fn()
    89  }
    90  
    91  // StartConnection starts the connection on a separate goroutine and tracks it.
    92  func (s *Server) StartConnection(c *Connection) {
    93  	s.connWg.Add(1)
    94  	go func() {
    95  		c.Run()
    96  		s.connWg.Done()
    97  	}()
    98  }
    99  
   100  // Wait waits for all connections started via StartConnection() to terminate.
   101  func (s *Server) Wait() {
   102  	s.connWg.Wait()
   103  }
   104  
   105  // Destroy releases resources being used by this server.
   106  func (s *Server) Destroy() {
   107  	s.root.DecRef(nil)
   108  }
   109  
   110  // ServerImpl contains the implementation details for a Server.
   111  // Implementations of ServerImpl should contain their associated Server by
   112  // value as their first field.
   113  type ServerImpl interface {
   114  	// Mount is called when a Mount RPC is made. It mounts the connection on
   115  	// mountNode. Mount may optionally donate a host FD to the mount point.
   116  	//
   117  	// Mount has a read concurrency guarantee on mountNode.
   118  	Mount(c *Connection, mountNode *Node) (*ControlFD, linux.Statx, int, error)
   119  
   120  	// SupportedMessages returns a list of messages that the server
   121  	// implementation supports.
   122  	SupportedMessages() []MID
   123  
   124  	// MaxMessageSize is the maximum payload length (in bytes) that can be sent
   125  	// to this server implementation.
   126  	MaxMessageSize() uint32
   127  }