2015-03-24 07:19:42 +03:00
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fuse
2015-03-24 07:23:19 +03:00
import (
2018-02-07 18:12:44 +03:00
"context"
2015-04-29 04:44:00 +03:00
"fmt"
2015-07-24 08:07:55 +03:00
"io"
2015-03-24 07:23:19 +03:00
"log"
2015-07-24 08:07:55 +03:00
"os"
2015-04-29 04:44:00 +03:00
"path"
"runtime"
2015-04-02 03:10:55 +03:00
"sync"
2015-07-24 08:07:55 +03:00
"syscall"
2015-03-24 07:23:19 +03:00
2015-08-03 06:15:29 +03:00
"github.com/jacobsa/fuse/fuseops"
2015-07-24 07:33:27 +03:00
"github.com/jacobsa/fuse/internal/buffer"
2015-07-28 05:59:44 +03:00
"github.com/jacobsa/fuse/internal/freelist"
2015-07-24 03:19:21 +03:00
"github.com/jacobsa/fuse/internal/fusekernel"
2015-03-24 07:23:19 +03:00
)
2015-03-24 07:19:42 +03:00
2015-07-27 08:08:41 +03:00
type contextKeyType uint64
2015-07-28 05:52:38 +03:00
var contextKey interface { } = contextKeyType ( 0 )
2015-07-27 08:08:41 +03:00
2015-07-24 09:03:24 +03:00
// Ask the Linux kernel for larger read requests.
//
// As of 2015-03-26, the behavior in the kernel is:
//
2022-09-06 09:42:56 +03:00
// - (http://goo.gl/bQ1f1i, http://goo.gl/HwBrR6) Set the local variable
2015-07-24 09:03:24 +03:00
// ra_pages to be init_response->max_readahead divided by the page size.
//
2022-09-06 09:42:56 +03:00
// - (http://goo.gl/gcIsSh, http://goo.gl/LKV2vA) Set
2015-07-24 09:03:24 +03:00
// backing_dev_info::ra_pages to the min of that value and what was sent
// in the request's max_readahead field.
//
2022-09-06 09:42:56 +03:00
// - (http://goo.gl/u2SqzH) Use backing_dev_info::ra_pages when deciding
2015-07-24 09:03:24 +03:00
// how much to read ahead.
//
2022-09-06 09:42:56 +03:00
// - (http://goo.gl/JnhbdL) Don't read ahead at all if that field is zero.
2015-07-24 09:03:24 +03:00
//
// Reading a page at a time is a drag. Ask for a larger size.
const maxReadahead = 1 << 20
2017-01-03 02:44:49 +03:00
// Connection represents a connection to the fuse kernel process. It is used to
// receive and reply to requests from the kernel.
2015-03-24 07:19:42 +03:00
type Connection struct {
2015-08-12 05:32:39 +03:00
cfg MountConfig
2015-05-25 07:13:24 +03:00
debugLogger * log . Logger
2015-05-25 07:17:16 +03:00
errorLogger * log . Logger
2015-04-29 04:53:17 +03:00
2015-07-24 08:32:50 +03:00
// The device through which we're talking to the kernel, and the protocol
// version that we're using to talk to it.
dev * os . File
protocol fusekernel . Protocol
2015-05-05 03:41:09 +03:00
mu sync . Mutex
2015-07-24 03:19:21 +03:00
// A map from fuse "unique" request ID (*not* the op ID for logging used
// above) to a function that cancel's its associated context.
2015-05-05 03:41:09 +03:00
//
// GUARDED_BY(mu)
2015-07-24 03:19:21 +03:00
cancelFuncs map [ uint64 ] func ( )
2015-07-28 05:59:44 +03:00
// Freelists, serviced by freelists.go.
2015-07-28 09:13:18 +03:00
inMessages freelist . Freelist // GUARDED_BY(mu)
outMessages freelist . Freelist // GUARDED_BY(mu)
2015-03-24 07:19:42 +03:00
}
2015-07-27 07:52:35 +03:00
// State that is maintained for each in-flight op. This is stuffed into the
// context that the user uses to reply to the op.
type opState struct {
2015-07-29 03:51:24 +03:00
inMsg * buffer . InMessage
outMsg * buffer . OutMessage
op interface { }
2015-07-27 07:52:35 +03:00
}
2015-07-24 09:01:45 +03:00
// Create a connection wrapping the supplied file descriptor connected to the
// kernel. You must eventually call c.close().
2015-07-22 14:45:49 +03:00
//
// The loggers may be nil.
2015-03-24 07:34:50 +03:00
func newConnection (
2015-08-12 05:32:39 +03:00
cfg MountConfig ,
2015-05-25 07:13:24 +03:00
debugLogger * log . Logger ,
2015-05-25 07:17:16 +03:00
errorLogger * log . Logger ,
2020-01-28 12:10:08 +03:00
dev * os . File ) ( * Connection , error ) {
c := & Connection {
2015-08-12 05:32:39 +03:00
cfg : cfg ,
2015-07-24 09:29:59 +03:00
debugLogger : debugLogger ,
errorLogger : errorLogger ,
dev : dev ,
cancelFuncs : make ( map [ uint64 ] func ( ) ) ,
2015-07-24 09:01:45 +03:00
}
2015-07-24 09:29:59 +03:00
// Initialize.
2020-01-28 12:10:08 +03:00
if err := c . Init ( ) ; err != nil {
2015-07-24 09:29:59 +03:00
c . close ( )
2020-01-28 12:10:08 +03:00
return nil , fmt . Errorf ( "Init: %v" , err )
2015-07-24 09:01:45 +03:00
}
2020-01-28 12:10:08 +03:00
return c , nil
2015-07-24 09:29:59 +03:00
}
2017-01-03 02:44:49 +03:00
// Init performs the work necessary to cause the mount process to complete.
2020-01-28 12:10:08 +03:00
func ( c * Connection ) Init ( ) error {
2015-07-24 09:29:59 +03:00
// Read the init op.
2015-07-27 08:10:00 +03:00
ctx , op , err := c . ReadOp ( )
2015-07-24 09:29:59 +03:00
if err != nil {
2020-01-28 12:10:08 +03:00
return fmt . Errorf ( "Reading init op: %v" , err )
2015-03-24 07:36:09 +03:00
}
2015-07-27 08:52:13 +03:00
initOp , ok := op . ( * initOp )
2015-07-24 09:29:59 +03:00
if ! ok {
2015-07-27 08:10:00 +03:00
c . Reply ( ctx , syscall . EPROTO )
2020-01-28 12:10:08 +03:00
return fmt . Errorf ( "Expected *initOp, got %T" , op )
2015-07-24 09:29:59 +03:00
}
// Make sure the protocol version spoken by the kernel is new enough.
min := fusekernel . Protocol {
fusekernel . ProtoVersionMinMajor ,
fusekernel . ProtoVersionMinMinor ,
}
if initOp . Kernel . LT ( min ) {
2015-07-27 08:10:00 +03:00
c . Reply ( ctx , syscall . EPROTO )
2020-01-28 12:10:08 +03:00
return fmt . Errorf ( "Version too old: %v" , initOp . Kernel )
2015-07-24 09:29:59 +03:00
}
// Downgrade our protocol if necessary.
c . protocol = fusekernel . Protocol {
fusekernel . ProtoVersionMaxMajor ,
fusekernel . ProtoVersionMaxMinor ,
}
if initOp . Kernel . LT ( c . protocol ) {
2015-07-24 09:35:14 +03:00
c . protocol = initOp . Kernel
2015-07-24 09:29:59 +03:00
}
2020-02-15 10:04:53 +03:00
cacheSymlinks := initOp . Flags & fusekernel . InitCacheSymlinks > 0
2020-02-15 10:27:23 +03:00
noOpenSupport := initOp . Flags & fusekernel . InitNoOpenSupport > 0
noOpendirSupport := initOp . Flags & fusekernel . InitNoOpendirSupport > 0
2023-08-02 00:09:40 +03:00
readdirplusSupport := initOp . Flags & fusekernel . InitDoReaddirplus > 0
2020-02-15 10:04:53 +03:00
2015-07-24 09:29:59 +03:00
// Respond to the init op.
initOp . Library = c . protocol
initOp . MaxReadahead = maxReadahead
initOp . MaxWrite = buffer . MaxWriteSize
2015-07-29 07:05:22 +03:00
2015-07-29 07:20:34 +03:00
initOp . Flags = 0
2015-07-29 07:05:22 +03:00
// Tell the kernel not to use pitifully small 4 KiB writes.
initOp . Flags |= fusekernel . InitBigWrites
2021-09-04 18:48:39 +03:00
if c . cfg . EnableAsyncReads {
initOp . Flags |= fusekernel . InitAsyncRead
}
2021-08-03 00:29:12 +03:00
// kernel 4.20 increases the max from 32 -> 256
initOp . Flags |= fusekernel . InitMaxPages
initOp . MaxPages = 256
2015-07-29 07:05:22 +03:00
2015-08-12 05:32:39 +03:00
// Enable writeback caching if the user hasn't asked us not to.
if ! c . cfg . DisableWritebackCaching {
initOp . Flags |= fusekernel . InitWritebackCache
}
2015-08-11 08:54:41 +03:00
2020-02-15 10:04:53 +03:00
// Enable caching symlink targets in the kernel page cache if the user opted
// into it (might require fixing the size field of inode attributes first):
if c . cfg . EnableSymlinkCaching && cacheSymlinks {
initOp . Flags |= fusekernel . InitCacheSymlinks
}
2020-02-15 10:27:23 +03:00
// Tell the kernel to treat returning -ENOSYS on OpenFile as not needing
// OpenFile calls at all (Linux >= 3.16):
if c . cfg . EnableNoOpenSupport && noOpenSupport {
initOp . Flags |= fusekernel . InitNoOpenSupport
}
// Tell the kernel to treat returning -ENOSYS on OpenDir as not needing
// OpenDir calls at all (Linux >= 5.1):
if c . cfg . EnableNoOpendirSupport && noOpendirSupport {
initOp . Flags |= fusekernel . InitNoOpendirSupport
}
2023-08-02 00:09:40 +03:00
// Tell the kernel to do readdirplus (readdir+lookup in one call)
if c . cfg . UseReadDirPlus && readdirplusSupport {
initOp . Flags |= fusekernel . InitDoReaddirplus
}
2015-07-27 08:10:00 +03:00
c . Reply ( ctx , nil )
2020-01-28 12:10:08 +03:00
return nil
2015-03-24 07:36:09 +03:00
}
2015-03-24 07:23:19 +03:00
2015-04-29 04:53:17 +03:00
// Log information for an operation with the given ID. calldepth is the depth
// to use when recovering file:line information with runtime.Caller.
2015-05-25 07:13:24 +03:00
func ( c * Connection ) debugLog (
2015-07-29 07:29:31 +03:00
fuseID uint64 ,
2015-04-29 04:44:00 +03:00
calldepth int ,
2015-04-29 04:32:21 +03:00
format string ,
v ... interface { } ) {
2015-07-22 14:45:49 +03:00
if c . debugLogger == nil {
return
}
2015-04-29 04:44:00 +03:00
// Get file:line info.
var file string
var line int
var ok bool
_ , file , line , ok = runtime . Caller ( calldepth )
if ! ok {
file = "???"
}
2015-04-29 05:11:34 +03:00
fileLine := fmt . Sprintf ( "%v:%v" , path . Base ( file ) , line )
2015-04-29 04:44:00 +03:00
// Format the actual message to be printed.
msg := fmt . Sprintf (
2015-04-29 05:11:34 +03:00
"Op 0x%08x %24s] %v" ,
2015-07-29 07:29:31 +03:00
fuseID ,
2015-04-29 05:11:34 +03:00
fileLine ,
2015-04-29 04:44:00 +03:00
fmt . Sprintf ( format , v ... ) )
// Print it.
2015-05-25 07:13:24 +03:00
c . debugLogger . Println ( msg )
2015-04-29 04:32:21 +03:00
}
2015-05-05 03:41:09 +03:00
// LOCKS_EXCLUDED(c.mu)
func ( c * Connection ) recordCancelFunc (
2015-07-24 03:19:21 +03:00
fuseID uint64 ,
2015-05-05 03:41:52 +03:00
f func ( ) ) {
c . mu . Lock ( )
defer c . mu . Unlock ( )
2015-07-24 03:19:21 +03:00
if _ , ok := c . cancelFuncs [ fuseID ] ; ok {
panic ( fmt . Sprintf ( "Already have cancel func for request %v" , fuseID ) )
2015-05-05 03:41:52 +03:00
}
2015-07-24 03:19:21 +03:00
c . cancelFuncs [ fuseID ] = f
2015-05-05 03:41:52 +03:00
}
2015-05-05 03:41:09 +03:00
2015-05-05 03:14:54 +03:00
// Set up state for an op that is about to be returned to the user, given its
2015-07-24 03:19:21 +03:00
// underlying fuse opcode and request ID.
2015-05-05 03:14:54 +03:00
//
// Return a context that should be used for the op.
2015-05-05 03:41:09 +03:00
//
// LOCKS_EXCLUDED(c.mu)
2015-05-05 04:44:54 +03:00
func ( c * Connection ) beginOp (
2015-07-24 03:19:21 +03:00
opCode uint32 ,
2020-01-28 12:10:08 +03:00
fuseID uint64 ) context . Context {
2015-07-16 03:54:34 +03:00
// Start with the parent context.
2020-01-28 12:10:08 +03:00
ctx := c . cfg . OpContext
2015-05-05 08:06:01 +03:00
2015-05-05 03:41:09 +03:00
// Set up a cancellation function.
2015-05-05 04:44:54 +03:00
//
2015-06-03 01:51:28 +03:00
// Special case: On Darwin, osxfuse aggressively reuses "unique" request IDs.
// This matters for Forget requests, which have no reply associated and
// therefore have IDs that are immediately eligible for reuse. For these, we
// should not record any state keyed on their ID.
2015-05-05 04:44:54 +03:00
//
// Cf. https://github.com/osxfuse/osxfuse/issues/208
2015-07-24 03:19:21 +03:00
if opCode != fusekernel . OpForget {
2015-05-05 04:44:54 +03:00
var cancel func ( )
ctx , cancel = context . WithCancel ( ctx )
2015-07-24 03:19:21 +03:00
c . recordCancelFunc ( fuseID , cancel )
2015-05-05 04:44:54 +03:00
}
2015-05-05 03:14:54 +03:00
2020-01-28 12:10:08 +03:00
return ctx
2015-05-05 03:04:31 +03:00
}
2015-05-05 03:04:03 +03:00
2015-05-05 04:44:54 +03:00
// Clean up all state associated with an op to which the user has responded,
2015-07-24 03:19:21 +03:00
// given its underlying fuse opcode and request ID. This must be called before
// a response is sent to the kernel, to avoid a race where the request's ID
// might be reused by osxfuse.
2015-05-05 03:41:09 +03:00
//
// LOCKS_EXCLUDED(c.mu)
2015-07-24 03:19:21 +03:00
func ( c * Connection ) finishOp (
opCode uint32 ,
fuseID uint64 ) {
2015-05-05 03:41:09 +03:00
c . mu . Lock ( )
defer c . mu . Unlock ( )
// Even though the op is finished, context.WithCancel requires us to arrange
// for the cancellation function to be invoked. We also must remove it from
// our map.
2015-05-05 04:44:54 +03:00
//
// Special case: we don't do this for Forget requests. See the note in
// beginOp above.
2015-07-24 03:19:21 +03:00
if opCode != fusekernel . OpForget {
cancel , ok := c . cancelFuncs [ fuseID ]
2015-05-05 04:44:54 +03:00
if ! ok {
2015-07-24 03:19:21 +03:00
panic ( fmt . Sprintf ( "Unknown request ID in finishOp: %v" , fuseID ) )
2015-05-05 04:44:54 +03:00
}
2015-05-05 03:41:09 +03:00
2015-05-05 04:44:54 +03:00
cancel ( )
2015-07-24 03:19:21 +03:00
delete ( c . cancelFuncs , fuseID )
2015-05-05 04:44:54 +03:00
}
2015-05-05 03:04:31 +03:00
}
2015-05-05 03:04:03 +03:00
2015-05-05 05:21:57 +03:00
// LOCKS_EXCLUDED(c.mu)
2015-07-24 03:19:21 +03:00
func ( c * Connection ) handleInterrupt ( fuseID uint64 ) {
2015-05-05 05:21:57 +03:00
c . mu . Lock ( )
defer c . mu . Unlock ( )
// NOTE(jacobsa): fuse.txt in the Linux kernel documentation
// (https://goo.gl/H55Dnr) defines the kernel <-> userspace protocol for
// interrupts.
//
// In particular, my reading of it is that an interrupt request cannot be
// delivered to userspace before the original request. The part about the
// race and EAGAIN appears to be aimed at userspace programs that
2015-06-03 01:51:28 +03:00
// concurrently process requests (cf. http://goo.gl/BES2rs).
2015-05-05 05:21:57 +03:00
//
2015-06-03 01:51:28 +03:00
// So in this method if we can't find the ID to be interrupted, it means that
// the request has already been replied to.
//
// Cf. https://github.com/osxfuse/osxfuse/issues/208
// Cf. http://comments.gmane.org/gmane.comp.file-systems.fuse.devel/14675
2015-07-24 03:19:21 +03:00
cancel , ok := c . cancelFuncs [ fuseID ]
2015-05-05 05:21:57 +03:00
if ! ok {
return
}
cancel ( )
}
2015-07-24 07:33:27 +03:00
// Read the next message from the kernel. The message must later be destroyed
// using destroyInMessage.
2020-01-28 12:10:08 +03:00
func ( c * Connection ) readMessage ( ) ( * buffer . InMessage , error ) {
2015-07-24 08:04:28 +03:00
// Allocate a message.
2020-01-28 12:10:08 +03:00
m := c . getInMessage ( )
2015-07-24 08:04:28 +03:00
// Loop past transient errors.
for {
2021-08-25 11:05:53 +03:00
// Attempt a read.
2020-01-28 12:10:08 +03:00
err := m . Init ( c . dev )
2015-07-24 08:04:28 +03:00
2015-07-24 08:20:43 +03:00
// Special cases:
//
// * ENODEV means fuse has hung up.
//
// * EINTR means we should try again. (This seems to happen often on
// OS X, cf. http://golang.org/issue/11180)
//
if pe , ok := err . ( * os . PathError ) ; ok {
switch pe . Err {
case syscall . ENODEV :
2015-07-24 08:07:55 +03:00
err = io . EOF
2015-07-24 08:20:43 +03:00
case syscall . EINTR :
err = nil
continue
2015-07-24 08:07:55 +03:00
}
2015-07-24 08:20:43 +03:00
}
2015-07-24 08:07:55 +03:00
2015-07-24 08:20:43 +03:00
if err != nil {
2015-07-28 05:59:44 +03:00
c . putInMessage ( m )
2020-01-28 12:10:08 +03:00
return nil , err
2015-07-24 08:04:28 +03:00
}
2020-01-28 12:10:08 +03:00
return m , nil
2015-07-24 08:04:28 +03:00
}
2015-07-24 07:33:27 +03:00
}
2015-07-24 08:31:16 +03:00
// Write the supplied message to the kernel.
2023-03-23 00:30:11 +03:00
func ( c * Connection ) writeMessage ( outMsg * buffer . OutMessage ) error {
var err error
var n int
expectedLen := outMsg . Len ( )
if outMsg . Sglist != nil {
n , err = writev ( int ( c . dev . Fd ( ) ) , outMsg . Sglist )
} else {
// Avoid the retry loop in os.File.Write.
n , err = syscall . Write ( int ( c . dev . Fd ( ) ) , outMsg . OutHeaderBytes ( ) )
}
if err == nil && n != expectedLen {
err = fmt . Errorf ( "Wrote %d bytes; expected %d" , n , expectedLen )
}
if err != nil && c . errorLogger != nil {
c . errorLogger . Printf ( "writeMessage: %v %v" , err , outMsg . OutHeaderBytes ( ) )
}
outMsg . Sglist = nil
return err
2015-07-24 08:31:16 +03:00
}
2017-01-03 02:44:49 +03:00
// ReadOp consumes the next op from the kernel process, returning the op and a
// context that should be used for work related to the op. It returns io.EOF if
// the kernel has closed the connection.
2015-07-27 07:52:35 +03:00
//
// If err != nil, the user is responsible for later calling c.Reply with the
// returned context.
2015-03-24 07:23:19 +03:00
//
// This function delivers ops in exactly the order they are received from
2015-04-29 04:28:16 +03:00
// /dev/fuse. It must not be called multiple times concurrently.
2015-05-05 03:41:09 +03:00
//
// LOCKS_EXCLUDED(c.mu)
2020-01-28 12:10:08 +03:00
func ( c * Connection ) ReadOp ( ) ( _ context . Context , op interface { } , _ error ) {
2015-03-24 07:26:02 +03:00
// Keep going until we find a request we know how to convert.
for {
2015-07-24 07:33:27 +03:00
// Read the next message from the kernel.
2020-01-28 12:10:08 +03:00
inMsg , err := c . readMessage ( )
2015-03-24 07:26:02 +03:00
if err != nil {
2020-01-28 12:10:08 +03:00
return nil , nil , err
2015-03-24 07:26:02 +03:00
}
2015-07-27 08:08:41 +03:00
// Convert the message to an op.
2015-07-29 04:02:29 +03:00
outMsg := c . getOutMessage ( )
2021-08-25 11:05:53 +03:00
op , err = convertInMessage ( & c . cfg , inMsg , outMsg , c . protocol )
2015-07-27 08:08:41 +03:00
if err != nil {
2015-07-29 04:02:29 +03:00
c . putOutMessage ( outMsg )
2020-01-28 12:10:08 +03:00
return nil , nil , fmt . Errorf ( "convertInMessage: %v" , err )
2015-07-24 03:19:21 +03:00
}
2015-07-27 08:08:41 +03:00
// Choose an ID for this operation for the purposes of logging, and log it.
2015-07-29 08:13:22 +03:00
if c . debugLogger != nil {
c . debugLog ( inMsg . Header ( ) . Unique , 1 , "<- %s" , describeRequest ( op ) )
}
2015-07-24 03:19:21 +03:00
2015-07-27 08:08:41 +03:00
// Special case: handle interrupt requests inline.
2015-07-27 08:52:13 +03:00
if interruptOp , ok := op . ( * interruptOp ) ; ok {
2015-07-27 08:08:41 +03:00
c . handleInterrupt ( interruptOp . FuseID )
continue
2015-07-24 03:19:21 +03:00
}
2015-07-27 08:08:41 +03:00
// Set up a context that remembers information about this op.
2020-01-28 12:10:08 +03:00
ctx := c . beginOp ( inMsg . Header ( ) . Opcode , inMsg . Header ( ) . Unique )
2015-07-29 07:29:31 +03:00
ctx = context . WithValue ( ctx , contextKey , opState { inMsg , outMsg , op } )
2015-03-24 07:52:14 +03:00
2015-07-27 08:08:41 +03:00
// Return the op to the user.
2020-01-28 12:10:08 +03:00
return ctx , op , nil
2015-03-24 07:26:02 +03:00
}
}
2015-03-24 07:34:50 +03:00
2015-08-03 06:15:29 +03:00
// Skip errors that happen as a matter of course, since they spook users.
func ( c * Connection ) shouldLogError (
op interface { } ,
err error ) bool {
// We don't log non-errors.
if err == nil {
return false
}
// We can't log if there's nothing to log to.
if c . errorLogger == nil {
return false
}
switch op . ( type ) {
case * fuseops . LookUpInodeOp :
// It is totally normal for the kernel to ask to look up an inode by name
// and find the name doesn't exist. For example, this happens when linking
// a new file.
if err == syscall . ENOENT {
return false
}
2019-10-25 01:32:58 +03:00
case * fuseops . GetXattrOp , * fuseops . ListXattrOp :
2015-12-10 23:58:46 +03:00
if err == syscall . ENODATA || err == syscall . ERANGE {
return false
}
2015-08-03 06:15:29 +03:00
case * unknownOp :
// Don't bother the user with methods we intentionally don't support.
if err == syscall . ENOSYS {
return false
}
}
return true
}
2017-01-03 02:44:49 +03:00
// Reply replies to an op previously read using ReadOp, with the supplied error
// (or nil if successful). The context must be the context returned by ReadOp.
2015-07-27 08:12:43 +03:00
//
// LOCKS_EXCLUDED(c.mu)
2015-07-27 08:21:07 +03:00
func ( c * Connection ) Reply ( ctx context . Context , opErr error ) {
// Extract the state we stuffed in earlier.
2015-07-28 05:52:38 +03:00
var key interface { } = contextKey
foo := ctx . Value ( key )
state , ok := foo . ( opState )
2015-07-27 08:21:07 +03:00
if ! ok {
panic ( fmt . Sprintf ( "Reply called with invalid context: %#v" , ctx ) )
}
op := state . op
2015-07-29 03:51:24 +03:00
inMsg := state . inMsg
outMsg := state . outMsg
2015-07-29 07:29:31 +03:00
fuseID := inMsg . Header ( ) . Unique
2015-07-27 08:21:07 +03:00
2021-08-25 19:25:12 +03:00
suppressReuse := false
if wr , ok := op . ( * fuseops . WriteFileOp ) ; ok {
suppressReuse = wr . SuppressReuse
}
2015-07-29 03:51:24 +03:00
// Make sure we destroy the messages when we're done.
2021-08-25 19:25:12 +03:00
if ! suppressReuse {
defer c . putInMessage ( inMsg )
}
2015-07-29 03:51:24 +03:00
defer c . putOutMessage ( outMsg )
2015-07-27 08:21:07 +03:00
// Clean up state for this op.
2015-07-29 03:51:24 +03:00
c . finishOp ( inMsg . Header ( ) . Opcode , inMsg . Header ( ) . Unique )
2015-07-27 08:21:07 +03:00
// Debug logging
if c . debugLogger != nil {
if opErr == nil {
2016-05-16 03:07:28 +03:00
c . debugLog ( fuseID , 1 , "-> OK (%s)" , describeResponse ( op ) )
2015-07-27 08:21:07 +03:00
} else {
2015-08-06 08:37:32 +03:00
c . debugLog ( fuseID , 1 , "-> Error: %q" , opErr . Error ( ) )
2015-07-27 08:21:07 +03:00
}
}
// Error logging
2015-08-03 06:15:29 +03:00
if c . shouldLogError ( op , opErr ) {
2015-07-27 09:03:58 +03:00
c . errorLogger . Printf ( "%T error: %v" , op , opErr )
2015-07-27 08:21:07 +03:00
}
2015-07-28 09:14:58 +03:00
// Send the reply to the kernel, if one is required.
2015-07-29 03:51:24 +03:00
noResponse := c . kernelResponse ( outMsg , inMsg . Header ( ) . Unique , op , opErr )
2015-07-28 09:14:58 +03:00
2015-07-29 03:39:37 +03:00
if ! noResponse {
2023-03-23 00:30:11 +03:00
c . writeMessage ( outMsg )
2015-07-27 08:21:07 +03:00
}
2015-07-27 08:12:43 +03:00
}
2023-03-23 00:30:11 +03:00
// Send a notification to the kernel
// notification must be a pointer to one of fuseops.NotifyXXX structures
// To avoid a deadlock notifications must not be called in the execution path of a related filesytem operation or within any code that could hold a lock that could be needed to execute such an operation. As of kernel 4.18, a "related operation" is a lookup(), symlink(), mknod(), mkdir(), unlink(), rename(), link() or create() request for the parent, and a setattr(), unlink(), rmdir(), rename(), setxattr(), removexattr(), readdir() or readdirplus() request for the inode itself.
func ( c * Connection ) Notify ( notification interface { } ) error {
outMsg := c . getOutMessage ( )
defer c . putOutMessage ( outMsg )
c . kernelNotification ( outMsg , notification )
outMsg . OutHeader ( ) . Len = uint32 ( outMsg . Len ( ) )
return c . writeMessage ( outMsg )
}
2015-06-09 04:02:08 +03:00
// Close the connection. Must not be called until operations that were read
// from the connection have been responded to.
2020-01-28 12:10:08 +03:00
func ( c * Connection ) close ( ) error {
2015-07-24 08:35:31 +03:00
// Posix doesn't say that close can be called concurrently with read or
// write, but luckily we exclude the possibility of a race by requiring the
// user to respond to all ops first.
2020-01-28 12:10:08 +03:00
return c . dev . Close ( )
2015-03-24 07:36:09 +03:00
}