@@ -375,18 +375,33 @@ func (c *Connection) readMessage() (*buffer.InMessage, error) {
375375}
376376
377377// Write the supplied message to the kernel.
378- func (c * Connection ) writeMessage (msg []byte ) error {
379- // Avoid the retry loop in os.File.Write.
380- n , err := syscall .Write (int (c .dev .Fd ()), msg )
381- if err != nil {
382- return err
378+ func (c * Connection ) writeMessage (outMsg * buffer.OutMessage ) error {
379+ var err error
380+ var n int
381+ expectedLen := outMsg .Len ()
382+ if outMsg .Sglist != nil {
383+ if fusekernel .IsPlatformFuseT {
384+ // writev is not atomic on macos, restrict to fuse-t platform
385+ writeLock .Lock ()
386+ defer writeLock .Unlock ()
387+ }
388+ n , err = writev (int (c .dev .Fd ()), outMsg .Sglist )
389+ } else {
390+ // Avoid the retry loop in os.File.Write.
391+ n , err = syscall .Write (int (c .dev .Fd ()), outMsg .OutHeaderBytes ())
383392 }
384-
385- if n != len (msg ) {
386- return fmt .Errorf ("Wrote %d bytes; expected %d" , n , len (msg ))
393+ if err == nil && n != expectedLen {
394+ err = fmt .Errorf ("Wrote %d bytes; expected %d" , n , expectedLen )
387395 }
388-
389- return nil
396+ if err != nil {
397+ writeErrMsg := fmt .Sprintf ("writeMessage: %v %v" , err , outMsg .OutHeaderBytes ())
398+ if c .errorLogger != nil {
399+ c .errorLogger .Print (writeErrMsg )
400+ }
401+ return fmt .Errorf (writeErrMsg )
402+ }
403+ outMsg .Sglist = nil
404+ return err
390405}
391406
392407// ReadOp consumes the next op from the kernel process, returning the op and a
@@ -527,25 +542,7 @@ func (c *Connection) Reply(ctx context.Context, opErr error) error {
527542 noResponse := c .kernelResponse (outMsg , inMsg .Header ().Unique , op , opErr )
528543
529544 if ! noResponse {
530- var err error
531- if outMsg .Sglist != nil {
532- if fusekernel .IsPlatformFuseT {
533- // writev is not atomic on macos, restrict to fuse-t platform
534- writeLock .Lock ()
535- defer writeLock .Unlock ()
536- }
537- _ , err = writev (int (c .dev .Fd ()), outMsg .Sglist )
538- } else {
539- err = c .writeMessage (outMsg .OutHeaderBytes ())
540- }
541- if err != nil {
542- writeErrMsg := fmt .Sprintf ("writeMessage: %v %v" , err , outMsg .OutHeaderBytes ())
543- if c .errorLogger != nil {
544- c .errorLogger .Print (writeErrMsg )
545- }
546- return fmt .Errorf (writeErrMsg )
547- }
548- outMsg .Sglist = nil
545+ c .writeMessage (outMsg )
549546 }
550547
551548 return nil
@@ -561,6 +558,17 @@ func (c *Connection) callbackForOp(op interface{}) func() {
561558 return nil
562559}
563560
561+ // Send a notification to the kernel
562+ // notification must be a pointer to one of fuseops.NotifyXXX structures
563+ // 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.
564+ func (c * Connection ) Notify (notification interface {}) error {
565+ outMsg := c .getOutMessage ()
566+ defer c .putOutMessage (outMsg )
567+ c .kernelNotification (outMsg , notification )
568+ outMsg .OutHeader ().Len = uint32 (outMsg .Len ())
569+ return c .writeMessage (outMsg )
570+ }
571+
564572// Close the connection. Must not be called until operations that were read
565573// from the connection have been responded to.
566574func (c * Connection ) close () error {
0 commit comments