github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/fdpipe/pipe_state.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 fdpipe
    16  
    17  import (
    18  	"fmt"
    19  	"io/ioutil"
    20  
    21  	"github.com/SagerNet/gvisor/pkg/context"
    22  	"github.com/SagerNet/gvisor/pkg/sentry/fs"
    23  	"github.com/SagerNet/gvisor/pkg/sync"
    24  )
    25  
    26  // beforeSave is invoked by stateify.
    27  func (p *pipeOperations) beforeSave() {
    28  	if p.flags.Read {
    29  		data, err := ioutil.ReadAll(p.file)
    30  		if err != nil && !isBlockError(err) {
    31  			panic(fmt.Sprintf("failed to read from pipe: %v", err))
    32  		}
    33  		p.readAheadBuffer = append(p.readAheadBuffer, data...)
    34  	} else if p.flags.Write {
    35  		file, err := p.opener.NonBlockingOpen(context.Background(), fs.PermMask{Write: true})
    36  		if err != nil {
    37  			panic(&fs.ErrSaveRejection{
    38  				Err: fmt.Errorf("write-only pipe end cannot be re-opened as %#v: %w", p, err),
    39  			})
    40  		}
    41  		file.Close()
    42  	}
    43  }
    44  
    45  // saveFlags is invoked by stateify.
    46  func (p *pipeOperations) saveFlags() fs.FileFlags {
    47  	return p.flags
    48  }
    49  
    50  // readPipeOperationsLoading is used to ensure that write-only pipe fds are
    51  // opened after read/write and read-only pipe fds, to avoid ENXIO when
    52  // multiple pipe fds refer to different ends of the same pipe.
    53  var readPipeOperationsLoading sync.WaitGroup
    54  
    55  // loadFlags is invoked by stateify.
    56  func (p *pipeOperations) loadFlags(flags fs.FileFlags) {
    57  	// This is a hack to ensure that readPipeOperationsLoading includes all
    58  	// readable pipe fds before any asynchronous calls to
    59  	// readPipeOperationsLoading.Wait().
    60  	if flags.Read {
    61  		readPipeOperationsLoading.Add(1)
    62  	}
    63  	p.flags = flags
    64  }
    65  
    66  // afterLoad is invoked by stateify.
    67  func (p *pipeOperations) afterLoad() {
    68  	load := func() error {
    69  		if !p.flags.Read {
    70  			readPipeOperationsLoading.Wait()
    71  		} else {
    72  			defer readPipeOperationsLoading.Done()
    73  		}
    74  		var err error
    75  		p.file, err = p.opener.NonBlockingOpen(context.Background(), fs.PermMask{
    76  			Read:  p.flags.Read,
    77  			Write: p.flags.Write,
    78  		})
    79  		if err != nil {
    80  			return fmt.Errorf("unable to open pipe %v: %v", p, err)
    81  		}
    82  		if err := p.init(); err != nil {
    83  			return fmt.Errorf("unable to initialize pipe %v: %v", p, err)
    84  		}
    85  		return nil
    86  	}
    87  
    88  	// Do background opening of pipe ends. Note for write-only pipe ends we
    89  	// have to do it asynchronously to avoid blocking the restore.
    90  	fs.Async(fs.CatchError(load))
    91  }