Skip to content

Commit

Permalink
fuse: add request.suppressReply
Browse files Browse the repository at this point in the history
Replace some control flow with setting the boolean. Whether or not to
send a reply is part of the protocol (rather than I/O), so this should
be part of request and protocolServer.

Change-Id: Ia3eb27b0eca61caf8fcb649e75a6adb88a4b91f1
  • Loading branch information
hanwen committed Nov 1, 2024
1 parent 2736607 commit 9574542
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 32 deletions.
4 changes: 4 additions & 0 deletions fuse/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ type request struct {

cancel chan struct{}

suppressReply bool

// written under Server.interruptMu
interrupted bool

Expand Down Expand Up @@ -77,7 +79,9 @@ func (r *request) outHeader() *OutHeader {
return (*OutHeader)(unsafe.Pointer(&r.outputBuf[0]))
}

// TODO - benchmark to see if this is necessary?
func (r *request) clear() {
r.suppressReply = false
r.inputBuf = nil
r.outputBuf = nil
r.inPayload = nil
Expand Down
69 changes: 37 additions & 32 deletions fuse/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -592,13 +592,15 @@ func (ms *Server) cancelAll() {
}

func (ms *Server) handleRequest(req *requestAlloc) Status {
defer ms.returnRequest(req)
if ms.opts.SingleThreaded {
ms.requestProcessingMu.Lock()
defer ms.requestProcessingMu.Unlock()
}

h, inSize, outSize, outPayloadSize, code := parseRequest(req.inputBuf, &ms.kernelSettings)
if !code.Ok() {
ms.opts.Logger.Printf("parseRequest: %v", code)
return code
}

Expand All @@ -609,31 +611,17 @@ func (ms *Server) handleRequest(req *requestAlloc) Status {
if outPayloadSize > 0 {
req.outPayload = ms.buffers.AllocBuffer(uint32(outPayloadSize))
}
code = ms.innerHandleRequest(h, &req.request)
ms.returnRequest(req)
ms.innerHandleRequest(h, &req.request)
code = ms.write(&req.request)
return code
}

func (ms *Server) innerHandleRequest(h *operationHandler, req *request) Status {
ms.addInflight(req)
defer ms.dropInflight(req)

if req.status.Ok() && ms.opts.Debug {
ms.opts.Logger.Println(req.InputDebug())
}

if req.inHeader().NodeId == pollHackInode ||
req.inHeader().NodeId == FUSE_ROOT_ID && h.FileNames > 0 && req.filename() == pollHackName {
doPollHackLookup(ms, req)
} else if req.status.Ok() && h.Func == nil {
ms.opts.Logger.Printf("Unimplemented opcode %v", operationName(req.inHeader().Opcode))
req.status = ENOSYS
} else if req.status.Ok() {
h.Func(ms, req)
func (ms *Server) write(req *request) Status {
if req.suppressReply {
return OK
}

errNo := ms.write(req)
if errNo != 0 {
errno := ms.systemWrite(req)
if errno != 0 {
// Ignore ENOENT for INTERRUPT responses which
// indicates that the referred request is no longer
// known by the kernel. This is a normal if the
Expand All @@ -645,35 +633,55 @@ func (ms *Server) innerHandleRequest(h *operationHandler, req *request) Status {
// RELEASE. This is because RELEASE is analogous to
// FORGET, and is not synchronized with the calling
// process, but does require a response.
if ms.opts.Debug || !(errNo == ENOENT && (req.inHeader().Opcode == _OP_INTERRUPT ||
if ms.opts.Debug || !(errno == ENOENT && (req.inHeader().Opcode == _OP_INTERRUPT ||
req.inHeader().Opcode == _OP_RELEASEDIR ||
req.inHeader().Opcode == _OP_RELEASE)) {
ms.opts.Logger.Printf("writer: Write/Writev failed, err: %v. opcode: %v",
errNo, operationName(req.inHeader().Opcode))
errno, operationName(req.inHeader().Opcode))
}
}
return Status(errNo)
return errno
}

func (ms *Server) write(req *request) Status {
func (ms *Server) innerHandleRequest(h *operationHandler, req *request) {
ms.addInflight(req)
defer ms.dropInflight(req)

if req.status.Ok() && ms.opts.Debug {
ms.opts.Logger.Println(req.InputDebug())
}

if req.inHeader().NodeId == pollHackInode ||
req.inHeader().NodeId == FUSE_ROOT_ID && h.FileNames > 0 && req.filename() == pollHackName {
doPollHackLookup(ms, req)
} else if req.status.Ok() && h.Func == nil {
ms.opts.Logger.Printf("Unimplemented opcode %v", operationName(req.inHeader().Opcode))
req.status = ENOSYS
} else if req.status.Ok() {
h.Func(ms, req)
}

// Forget/NotifyReply do not wait for reply from filesystem server.
switch req.inHeader().Opcode {
case _OP_FORGET, _OP_BATCH_FORGET, _OP_NOTIFY_REPLY:
return OK
req.suppressReply = true
case _OP_INTERRUPT:
// ? what other status can interrupt generate?
if req.status.Ok() {
return OK
req.suppressReply = true
}
}
if req.status == EINTR {
ms.interruptMu.Lock()
dead := ms.connectionDead
ms.interruptMu.Unlock()
if dead {
return OK
req.suppressReply = true
}
}

if req.suppressReply {
return
}
if req.inHeader().Opcode == _OP_INIT && ms.kernelSettings.Minor <= 22 {
// v8-v22 don't have TimeGran and further fields.
// This includes osxfuse (a.k.a. macfuse).
Expand All @@ -684,9 +692,6 @@ func (ms *Server) write(req *request) Status {
if ms.opts.Debug {
ms.opts.Logger.Println(req.OutputDebug())
}

s := ms.systemWrite(req)
return s
}

func (ms *Server) notifyWrite(req *request) Status {
Expand Down

0 comments on commit 9574542

Please sign in to comment.