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 (
|
2015-04-29 04:44:00 +03:00
|
|
|
"fmt"
|
2015-03-24 07:23:19 +03:00
|
|
|
"log"
|
2015-04-29 04:44:00 +03:00
|
|
|
"path"
|
|
|
|
"runtime"
|
2015-04-02 03:10:55 +03:00
|
|
|
"sync"
|
2015-03-24 07:23:19 +03:00
|
|
|
|
|
|
|
"github.com/jacobsa/bazilfuse"
|
|
|
|
"github.com/jacobsa/fuse/fuseops"
|
|
|
|
)
|
2015-03-24 07:19:42 +03:00
|
|
|
|
|
|
|
// A connection to the fuse kernel process.
|
|
|
|
type Connection struct {
|
2015-04-02 03:10:55 +03:00
|
|
|
logger *log.Logger
|
|
|
|
wrapped *bazilfuse.Conn
|
|
|
|
opsInFlight sync.WaitGroup
|
2015-04-29 04:53:17 +03:00
|
|
|
|
|
|
|
// For logging purposes only.
|
|
|
|
nextOpID uint32
|
2015-03-24 07:19:42 +03:00
|
|
|
}
|
|
|
|
|
2015-03-24 07:34:50 +03:00
|
|
|
// Responsibility for closing the wrapped connection is transferred to the
|
|
|
|
// result. You must call c.close() eventually.
|
|
|
|
func newConnection(
|
|
|
|
logger *log.Logger,
|
2015-03-24 07:36:09 +03:00
|
|
|
wrapped *bazilfuse.Conn) (c *Connection, err error) {
|
|
|
|
c = &Connection{
|
|
|
|
logger: logger,
|
|
|
|
wrapped: wrapped,
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
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-04-29 04:32:21 +03:00
|
|
|
func (c *Connection) log(
|
2015-04-29 04:53:17 +03:00
|
|
|
opID uint32,
|
2015-04-29 04:44:00 +03:00
|
|
|
calldepth int,
|
2015-04-29 04:32:21 +03:00
|
|
|
format string,
|
|
|
|
v ...interface{}) {
|
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 = "???"
|
|
|
|
}
|
|
|
|
|
|
|
|
// Format the actual message to be printed.
|
|
|
|
msg := fmt.Sprintf(
|
2015-04-29 04:53:17 +03:00
|
|
|
"Op 0x%08x %v:%v] %v",
|
2015-04-29 04:51:25 +03:00
|
|
|
opID,
|
2015-04-29 04:44:00 +03:00
|
|
|
path.Base(file),
|
|
|
|
line,
|
|
|
|
fmt.Sprintf(format, v...))
|
|
|
|
|
|
|
|
// Print it.
|
|
|
|
c.logger.Println(msg)
|
2015-04-29 04:32:21 +03:00
|
|
|
}
|
|
|
|
|
2015-03-24 07:19:42 +03:00
|
|
|
// Read the next op from the kernel process. Return io.EOF if the kernel has
|
|
|
|
// closed the connection.
|
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-03-24 07:26:02 +03:00
|
|
|
func (c *Connection) ReadOp() (op fuseops.Op, err error) {
|
|
|
|
var bfReq bazilfuse.Request
|
|
|
|
|
|
|
|
// Keep going until we find a request we know how to convert.
|
|
|
|
for {
|
|
|
|
// Read a bazilfuse request.
|
|
|
|
bfReq, err = c.wrapped.ReadRequest()
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-04-29 04:32:21 +03:00
|
|
|
// Choose an ID for this operation.
|
|
|
|
opID := c.nextOpID
|
|
|
|
c.nextOpID++
|
|
|
|
|
|
|
|
// Log the receipt of the operation.
|
2015-04-29 04:44:00 +03:00
|
|
|
c.log(opID, 1, "Received: %v", bfReq)
|
2015-03-24 07:52:14 +03:00
|
|
|
|
2015-03-24 07:51:36 +03:00
|
|
|
// Special case: responding to this is required to make mounting work on OS
|
|
|
|
// X. We don't currently expose the capability for the file system to
|
|
|
|
// intercept this.
|
|
|
|
if statfsReq, ok := bfReq.(*bazilfuse.StatfsRequest); ok {
|
2015-04-29 04:44:00 +03:00
|
|
|
c.log(opID, 1, "Responding OK to Statfs.")
|
2015-03-24 07:51:36 +03:00
|
|
|
statfsReq.Respond(&bazilfuse.StatfsResponse{})
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2015-03-24 07:26:02 +03:00
|
|
|
// Convert it, if possible.
|
2015-04-29 04:44:00 +03:00
|
|
|
logForOp := func(calldepth int, format string, v ...interface{}) {
|
|
|
|
c.log(opID, calldepth+1, format, v)
|
2015-04-29 04:35:28 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if op = fuseops.Convert(bfReq, logForOp, &c.opsInFlight); op == nil {
|
2015-04-29 04:44:00 +03:00
|
|
|
c.log(opID, 1, "Returning ENOSYS for unknown bazilfuse request: %v", bfReq)
|
2015-03-24 07:26:02 +03:00
|
|
|
bfReq.RespondError(ENOSYS)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2015-04-02 03:10:55 +03:00
|
|
|
c.opsInFlight.Add(1)
|
2015-03-24 07:26:02 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2015-03-24 07:34:50 +03:00
|
|
|
|
2015-03-24 07:36:09 +03:00
|
|
|
func (c *Connection) waitForReady() (err error) {
|
|
|
|
<-c.wrapped.Ready
|
|
|
|
err = c.wrapped.MountError
|
|
|
|
return
|
|
|
|
}
|
2015-03-24 07:34:50 +03:00
|
|
|
|
2015-04-02 03:10:55 +03:00
|
|
|
// Close the connection and wait for in-flight ops.
|
2015-03-24 07:36:09 +03:00
|
|
|
func (c *Connection) close() (err error) {
|
|
|
|
err = c.wrapped.Close()
|
2015-04-02 03:10:55 +03:00
|
|
|
c.opsInFlight.Wait()
|
2015-03-24 07:36:09 +03:00
|
|
|
return
|
|
|
|
}
|