Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go-fuse
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Levin Zimmermann
go-fuse
Commits
d87cbd06
Commit
d87cbd06
authored
May 01, 2011
by
Han-Wen Nienhuys
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Move request type into separate file.
parent
00e91a48
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
163 additions
and
168 deletions
+163
-168
fuse/Makefile
fuse/Makefile
+1
-0
fuse/fuse.go
fuse/fuse.go
+19
-168
fuse/misc.go
fuse/misc.go
+7
-0
fuse/request.go
fuse/request.go
+136
-0
No files found.
fuse/Makefile
View file @
d87cbd06
...
...
@@ -4,6 +4,7 @@ include $(GOROOT)/src/Make.inc
TARG
=
github.com/hanwen/go-fuse/fuse
GOFILES
=
misc.go
\
request.go
\
fuse.go
\
direntry.go
\
mount.go
\
...
...
fuse/fuse.go
View file @
d87cbd06
// Code that handles the control loop, and en/decoding messages
// to/from the kernel. Dispatches calls into RawFileSystem.
package
fuse
import
(
"bytes"
"fmt"
"log"
"os"
"reflect"
"syscall"
"time"
"unsafe"
)
// TODO make generic option setting.
const
(
// bufSize should be a power of two to minimize lossage in
// BufferPool.
...
...
@@ -22,83 +14,8 @@ const (
maxRead
=
bufSize
-
PAGESIZE
)
type
request
struct
{
inputBuf
[]
byte
// These split up inputBuf.
inHeader
*
InHeader
// generic header
inData
unsafe
.
Pointer
// per op data
arg
[]
byte
// flat data.
// Unstructured data, a pointer to the relevant XxxxOut struct.
outData
unsafe
.
Pointer
status
Status
flatData
[]
byte
// Header + structured data for what we send back to the kernel.
// May be followed by flatData.
outHeaderBytes
[]
byte
// Start timestamp for timing info.
startNs
int64
preWriteNs
int64
}
func
(
me
*
request
)
filename
()
string
{
return
string
(
me
.
arg
[
:
len
(
me
.
arg
)
-
1
])
}
func
(
me
*
request
)
filenames
(
count
int
)
[]
string
{
names
:=
bytes
.
Split
(
me
.
arg
[
:
len
(
me
.
arg
)
-
1
],
[]
byte
{
0
},
count
)
nameStrings
:=
make
([]
string
,
len
(
names
))
for
i
,
n
:=
range
names
{
nameStrings
[
i
]
=
string
(
n
)
}
return
nameStrings
}
func
(
me
*
request
)
InputDebug
(
h
*
operationHandler
)
string
{
val
:=
" "
if
h
.
DecodeIn
!=
nil
{
val
=
fmt
.
Sprintf
(
" data: %v "
,
h
.
DecodeIn
(
me
.
inData
))
}
names
:=
""
if
h
.
FileNames
>
0
{
names
=
fmt
.
Sprintf
(
"names: %v"
,
me
.
filenames
(
h
.
FileNames
))
}
return
fmt
.
Sprintf
(
"Dispatch: %v, NodeId: %v.%v%v"
,
me
.
inHeader
.
opcode
,
me
.
inHeader
.
NodeId
,
val
,
names
)
}
func
(
me
*
request
)
OutputDebug
(
h
*
operationHandler
)
string
{
var
val
interface
{}
if
h
.
DecodeOut
!=
nil
{
val
=
h
.
DecodeOut
(
me
.
outData
)
}
dataStr
:=
""
if
val
!=
nil
{
dataStr
=
fmt
.
Sprintf
(
"%v"
,
val
)
}
max
:=
1024
if
len
(
dataStr
)
>
max
{
dataStr
=
dataStr
[
:
max
]
+
fmt
.
Sprintf
(
" ...trimmed (response size %d)"
,
len
(
me
.
outHeaderBytes
))
}
flatStr
:=
""
if
len
(
me
.
flatData
)
>
0
{
flatStr
=
fmt
.
Sprintf
(
" %d bytes data
\n
"
,
len
(
me
.
flatData
))
}
return
fmt
.
Sprintf
(
"Serialize: %v code: %v value: %v%v"
,
me
.
inHeader
.
opcode
,
me
.
status
,
dataStr
,
flatStr
)
}
////////////////////////////////////////////////////////////////
// State related to this mount point.
// MountState contains the logic for reading from the FUSE device and
// translating it to RawFileSystem interface calls.
type
MountState
struct
{
// Empty if unmounted.
mountPoint
string
...
...
@@ -193,9 +110,6 @@ func (me *MountState) BufferPoolStats() string {
return
me
.
buffers
.
String
()
}
////////////////////////////////////////////////////////////////
// Logic for the control loop.
func
(
me
*
MountState
)
newRequest
(
oldReq
*
request
)
*
request
{
if
oldReq
!=
nil
{
me
.
buffers
.
FreeBuffer
(
oldReq
.
flatData
)
...
...
@@ -224,7 +138,7 @@ func (me *MountState) readRequest(req *request) os.Error {
return
err
}
func
(
me
*
MountState
)
discardRequest
(
req
*
request
)
{
func
(
me
*
MountState
)
recordStats
(
req
*
request
)
{
if
me
.
LatencyMap
!=
nil
{
endNs
:=
time
.
Nanoseconds
()
dt
:=
endNs
-
req
.
startNs
...
...
@@ -237,8 +151,9 @@ func (me *MountState) discardRequest(req *request) {
}
}
// Normally, callers should run Loop() and wait for FUSE to exit, but
// tests will want to run this in a goroutine.
// Loop initiates the FUSE loop. Normally, callers should run Loop()
// and wait for it to exit, but tests will want to run this in a
// goroutine.
//
// If threaded is given, each filesystem operation executes in a
// separate goroutine.
...
...
@@ -256,7 +171,6 @@ func (me *MountState) Loop(threaded bool) {
}
func
(
me
*
MountState
)
loop
()
{
// See fuse_kern_chan_receive()
var
lastReq
*
request
for
{
req
:=
me
.
newRequest
(
lastReq
)
...
...
@@ -267,7 +181,6 @@ func (me *MountState) loop() {
// Retry.
if
errNo
==
syscall
.
ENOENT
{
me
.
discardRequest
(
req
)
continue
}
...
...
@@ -284,95 +197,33 @@ func (me *MountState) loop() {
log
.
Printf
(
"Failed to read from fuse conn: %v"
,
err
)
break
}
me
.
handle
(
req
)
}
}
func
(
me
*
MountState
)
chopMessage
(
req
*
request
)
*
operationHandler
{
inHSize
:=
unsafe
.
Sizeof
(
InHeader
{})
if
len
(
req
.
inputBuf
)
<
inHSize
{
log
.
Printf
(
"Short read for input header: %v"
,
req
.
inputBuf
)
return
nil
}
req
.
inHeader
=
(
*
InHeader
)(
unsafe
.
Pointer
(
&
req
.
inputBuf
[
0
]))
req
.
arg
=
req
.
inputBuf
[
inHSize
:
]
handler
:=
getHandler
(
req
.
inHeader
.
opcode
)
if
handler
==
nil
||
handler
.
Func
==
nil
{
msg
:=
"Unimplemented"
if
handler
==
nil
{
msg
=
"Unknown"
}
log
.
Printf
(
"%s opcode %v"
,
msg
,
req
.
inHeader
.
opcode
)
req
.
status
=
ENOSYS
return
handler
}
if
len
(
req
.
arg
)
<
handler
.
InputSize
{
log
.
Printf
(
"Short read for %v: %v"
,
req
.
inHeader
.
opcode
,
req
.
arg
)
req
.
status
=
EIO
return
handler
me
.
handleRequest
(
req
)
}
if
handler
.
InputSize
>
0
{
req
.
inData
=
unsafe
.
Pointer
(
&
req
.
arg
[
0
])
req
.
arg
=
req
.
arg
[
handler
.
InputSize
:
]
}
return
handler
}
func
(
me
*
MountState
)
handle
(
req
*
request
)
{
defer
me
.
discardRequest
(
req
)
handler
:=
me
.
chopMessage
(
req
)
func
(
me
*
MountState
)
handleRequest
(
req
*
request
)
{
defer
me
.
recordStats
(
req
)
if
handler
==
nil
{
req
.
parse
()
if
req
.
handler
==
nil
{
return
}
if
req
.
status
==
OK
{
me
.
dispatch
(
req
,
handler
)
if
me
.
Debug
{
log
.
Println
(
req
.
InputDebug
())
}
req
.
handler
.
Func
(
me
,
req
)
}
// If we try to write OK, nil, we will get
// error: writer: Writev [[16 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0]]
// failed, err: writev: no such file or directory
if
req
.
inHeader
.
opcode
!=
_OP_FORGET
{
serialize
(
req
,
handler
,
me
.
Debug
)
req
.
serialize
()
if
me
.
Debug
{
log
.
Println
(
req
.
OutputDebug
())
}
me
.
Write
(
req
)
}
}
func
(
me
*
MountState
)
dispatch
(
req
*
request
,
handler
*
operationHandler
)
{
if
me
.
Debug
{
log
.
Println
(
req
.
InputDebug
(
handler
))
}
handler
.
Func
(
me
,
req
)
}
// Thanks to Andrew Gerrand for this hack.
func
asSlice
(
ptr
unsafe
.
Pointer
,
byteCount
int
)
[]
byte
{
h
:=
&
reflect
.
SliceHeader
{
uintptr
(
ptr
),
byteCount
,
byteCount
}
return
*
(
*
[]
byte
)(
unsafe
.
Pointer
(
h
))
}
func
serialize
(
req
*
request
,
handler
*
operationHandler
,
debug
bool
)
{
dataLength
:=
handler
.
OutputSize
if
req
.
outData
==
nil
||
req
.
status
!=
OK
{
dataLength
=
0
}
sizeOfOutHeader
:=
unsafe
.
Sizeof
(
OutHeader
{})
req
.
outHeaderBytes
=
make
([]
byte
,
sizeOfOutHeader
+
dataLength
)
outHeader
:=
(
*
OutHeader
)(
unsafe
.
Pointer
(
&
req
.
outHeaderBytes
[
0
]))
outHeader
.
Unique
=
req
.
inHeader
.
Unique
outHeader
.
Status
=
-
req
.
status
outHeader
.
Length
=
uint32
(
sizeOfOutHeader
+
dataLength
+
len
(
req
.
flatData
))
copy
(
req
.
outHeaderBytes
[
sizeOfOutHeader
:
],
asSlice
(
req
.
outData
,
dataLength
))
if
debug
{
log
.
Println
(
req
.
OutputDebug
(
handler
))
}
}
fuse/misc.go
View file @
d87cbd06
...
...
@@ -7,6 +7,7 @@ import (
"fmt"
"log"
"math"
"reflect"
"regexp"
"syscall"
"unsafe"
...
...
@@ -147,3 +148,9 @@ func MyPID() string {
v
,
_
:=
os
.
Readlink
(
"/proc/self"
)
return
v
}
// Thanks to Andrew Gerrand for this hack.
func
asSlice
(
ptr
unsafe
.
Pointer
,
byteCount
int
)
[]
byte
{
h
:=
&
reflect
.
SliceHeader
{
uintptr
(
ptr
),
byteCount
,
byteCount
}
return
*
(
*
[]
byte
)(
unsafe
.
Pointer
(
h
))
}
fuse/request.go
0 → 100644
View file @
d87cbd06
package
fuse
import
(
"fmt"
"bytes"
"log"
"unsafe"
)
type
request
struct
{
inputBuf
[]
byte
// These split up inputBuf.
inHeader
*
InHeader
// generic header
inData
unsafe
.
Pointer
// per op data
arg
[]
byte
// flat data.
// Unstructured data, a pointer to the relevant XxxxOut struct.
outData
unsafe
.
Pointer
status
Status
flatData
[]
byte
// Header + structured data for what we send back to the kernel.
// May be followed by flatData.
outHeaderBytes
[]
byte
// Start timestamp for timing info.
startNs
int64
preWriteNs
int64
// All information pertaining to opcode of this request.
handler
*
operationHandler
}
func
(
me
*
request
)
filename
()
string
{
return
string
(
me
.
arg
[
:
len
(
me
.
arg
)
-
1
])
}
func
(
me
*
request
)
filenames
(
count
int
)
[]
string
{
names
:=
bytes
.
Split
(
me
.
arg
[
:
len
(
me
.
arg
)
-
1
],
[]
byte
{
0
},
count
)
nameStrings
:=
make
([]
string
,
len
(
names
))
for
i
,
n
:=
range
names
{
nameStrings
[
i
]
=
string
(
n
)
}
return
nameStrings
}
func
(
me
*
request
)
InputDebug
()
string
{
val
:=
" "
if
me
.
handler
.
DecodeIn
!=
nil
{
val
=
fmt
.
Sprintf
(
" data: %v "
,
me
.
handler
.
DecodeIn
(
me
.
inData
))
}
names
:=
""
if
me
.
handler
.
FileNames
>
0
{
names
=
fmt
.
Sprintf
(
"names: %v"
,
me
.
filenames
(
me
.
handler
.
FileNames
))
}
return
fmt
.
Sprintf
(
"Dispatch: %v, NodeId: %v.%v%v"
,
me
.
inHeader
.
opcode
,
me
.
inHeader
.
NodeId
,
val
,
names
)
}
func
(
me
*
request
)
OutputDebug
()
string
{
var
val
interface
{}
if
me
.
handler
.
DecodeOut
!=
nil
{
val
=
me
.
handler
.
DecodeOut
(
me
.
outData
)
}
dataStr
:=
""
if
val
!=
nil
{
dataStr
=
fmt
.
Sprintf
(
"%v"
,
val
)
}
max
:=
1024
if
len
(
dataStr
)
>
max
{
dataStr
=
dataStr
[
:
max
]
+
fmt
.
Sprintf
(
" ...trimmed (response size %d)"
,
len
(
me
.
outHeaderBytes
))
}
flatStr
:=
""
if
len
(
me
.
flatData
)
>
0
{
flatStr
=
fmt
.
Sprintf
(
" %d bytes data
\n
"
,
len
(
me
.
flatData
))
}
return
fmt
.
Sprintf
(
"Serialize: %v code: %v value: %v%v"
,
me
.
inHeader
.
opcode
,
me
.
status
,
dataStr
,
flatStr
)
}
func
(
req
*
request
)
parse
()
{
inHSize
:=
unsafe
.
Sizeof
(
InHeader
{})
if
len
(
req
.
inputBuf
)
<
inHSize
{
log
.
Printf
(
"Short read for input header: %v"
,
req
.
inputBuf
)
return
}
req
.
inHeader
=
(
*
InHeader
)(
unsafe
.
Pointer
(
&
req
.
inputBuf
[
0
]))
req
.
arg
=
req
.
inputBuf
[
inHSize
:
]
req
.
handler
=
getHandler
(
req
.
inHeader
.
opcode
)
if
req
.
handler
==
nil
||
req
.
handler
.
Func
==
nil
{
msg
:=
"Unimplemented"
if
req
.
handler
==
nil
{
msg
=
"Unknown"
}
log
.
Printf
(
"%s opcode %v"
,
msg
,
req
.
inHeader
.
opcode
)
req
.
status
=
ENOSYS
return
}
if
len
(
req
.
arg
)
<
req
.
handler
.
InputSize
{
log
.
Printf
(
"Short read for %v: %v"
,
req
.
inHeader
.
opcode
,
req
.
arg
)
req
.
status
=
EIO
return
}
if
req
.
handler
.
InputSize
>
0
{
req
.
inData
=
unsafe
.
Pointer
(
&
req
.
arg
[
0
])
req
.
arg
=
req
.
arg
[
req
.
handler
.
InputSize
:
]
}
}
func
(
req
*
request
)
serialize
()
{
dataLength
:=
req
.
handler
.
OutputSize
if
req
.
outData
==
nil
||
req
.
status
!=
OK
{
dataLength
=
0
}
sizeOfOutHeader
:=
unsafe
.
Sizeof
(
OutHeader
{})
req
.
outHeaderBytes
=
make
([]
byte
,
sizeOfOutHeader
+
dataLength
)
outHeader
:=
(
*
OutHeader
)(
unsafe
.
Pointer
(
&
req
.
outHeaderBytes
[
0
]))
outHeader
.
Unique
=
req
.
inHeader
.
Unique
outHeader
.
Status
=
-
req
.
status
outHeader
.
Length
=
uint32
(
sizeOfOutHeader
+
dataLength
+
len
(
req
.
flatData
))
copy
(
req
.
outHeaderBytes
[
sizeOfOutHeader
:
],
asSlice
(
req
.
outData
,
dataLength
))
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment