Commit 0c12bdf7 authored by David du Colombier's avatar David du Colombier

net: always wake up the readers on close on Plan 9

Previously, in acceptPlan9 we set netFD.ctl to the listener's
/net/tcp/*/listen file instead of the accepted connection's
/net/tcp/*/ctl file.

In netFD.Read, we write "close" to netFD.ctl to close the
connection and wake up the readers. However, in the
case of an accepted connection, we got the error
"write /net/tcp/*/listen: inappropriate use of fd"
because the /net/tcp/*/listen doesn't handle the "close" message.

In this case, the connection wasn't closed and the readers
weren't awake.

We modified the netFD structure so that netFD.ctl represents
the accepted connection and netFD.listen represents the
listener.

Change-Id: Ie38c7dbaeaf77fe9ff7da293f09e86d1a01b3e1e
Reviewed-on: https://go-review.googlesource.com/31390
Run-TryBot: David du Colombier <0intro@gmail.com>
Reviewed-by: 's avatarBrad Fitzpatrick <bradfitz@golang.org>
parent c1a1328c
...@@ -17,11 +17,11 @@ type netFD struct { ...@@ -17,11 +17,11 @@ type netFD struct {
fdmu fdMutex fdmu fdMutex
// immutable until Close // immutable until Close
net string net string
n string n string
dir string dir string
ctl, data *os.File listen, ctl, data *os.File
laddr, raddr Addr laddr, raddr Addr
} }
var ( var (
...@@ -32,8 +32,16 @@ func sysInit() { ...@@ -32,8 +32,16 @@ func sysInit() {
netdir = "/net" netdir = "/net"
} }
func newFD(net, name string, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) { func newFD(net, name string, listen, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) {
return &netFD{net: net, n: name, dir: netdir + "/" + net + "/" + name, ctl: ctl, data: data, laddr: laddr, raddr: raddr}, nil return &netFD{
net: net,
n: name,
dir: netdir + "/" + net + "/" + name,
listen: listen,
ctl: ctl, data: data,
laddr: laddr,
raddr: raddr,
}, nil
} }
func (fd *netFD) init() error { func (fd *netFD) init() error {
...@@ -64,8 +72,14 @@ func (fd *netFD) destroy() { ...@@ -64,8 +72,14 @@ func (fd *netFD) destroy() {
err = err1 err = err1
} }
} }
if fd.listen != nil {
if err1 := fd.listen.Close(); err1 != nil && err == nil {
err = err1
}
}
fd.ctl = nil fd.ctl = nil
fd.data = nil fd.data = nil
fd.listen = nil
} }
func (fd *netFD) Read(b []byte) (n int, err error) { func (fd *netFD) Read(b []byte) (n int, err error) {
...@@ -124,11 +138,10 @@ func (fd *netFD) Close() error { ...@@ -124,11 +138,10 @@ func (fd *netFD) Close() error {
} }
if fd.net == "tcp" { if fd.net == "tcp" {
// The following line is required to unblock Reads. // The following line is required to unblock Reads.
// For some reason, WriteString returns an error: _, err := fd.ctl.WriteString("close")
// "write /net/tcp/39/listen: inappropriate use of fd" if err != nil {
// But without it, Reads on dead conns hang forever. return err
// See Issue 9554. }
fd.ctl.WriteString("close")
} }
err := fd.ctl.Close() err := fd.ctl.Close()
if fd.data != nil { if fd.data != nil {
...@@ -136,8 +149,14 @@ func (fd *netFD) Close() error { ...@@ -136,8 +149,14 @@ func (fd *netFD) Close() error {
err = err1 err = err1
} }
} }
if fd.listen != nil {
if err1 := fd.listen.Close(); err1 != nil && err == nil {
err = err1
}
}
fd.ctl = nil fd.ctl = nil
fd.data = nil fd.data = nil
fd.listen = nil
return err return err
} }
......
...@@ -81,7 +81,7 @@ func newFileFD(f *os.File) (net *netFD, err error) { ...@@ -81,7 +81,7 @@ func newFileFD(f *os.File) (net *netFD, err error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return newFD(comp[1], name, ctl, nil, laddr, nil) return newFD(comp[1], name, nil, ctl, nil, laddr, nil)
} }
func fileConn(f *os.File) (Conn, error) { func fileConn(f *os.File) (Conn, error) {
......
...@@ -213,7 +213,7 @@ func dialPlan9Blocking(ctx context.Context, net string, laddr, raddr Addr) (fd * ...@@ -213,7 +213,7 @@ func dialPlan9Blocking(ctx context.Context, net string, laddr, raddr Addr) (fd *
f.Close() f.Close()
return nil, err return nil, err
} }
return newFD(proto, name, f, data, laddr, raddr) return newFD(proto, name, nil, f, data, laddr, raddr)
} }
func listenPlan9(ctx context.Context, net string, laddr Addr) (fd *netFD, err error) { func listenPlan9(ctx context.Context, net string, laddr Addr) (fd *netFD, err error) {
...@@ -232,11 +232,11 @@ func listenPlan9(ctx context.Context, net string, laddr Addr) (fd *netFD, err er ...@@ -232,11 +232,11 @@ func listenPlan9(ctx context.Context, net string, laddr Addr) (fd *netFD, err er
f.Close() f.Close()
return nil, err return nil, err
} }
return newFD(proto, name, f, nil, laddr, nil) return newFD(proto, name, nil, f, nil, laddr, nil)
} }
func (fd *netFD) netFD() (*netFD, error) { func (fd *netFD) netFD() (*netFD, error) {
return newFD(fd.net, fd.n, fd.ctl, fd.data, fd.laddr, fd.raddr) return newFD(fd.net, fd.n, fd.listen, fd.ctl, fd.data, fd.laddr, fd.raddr)
} }
func (fd *netFD) acceptPlan9() (nfd *netFD, err error) { func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
...@@ -245,27 +245,34 @@ func (fd *netFD) acceptPlan9() (nfd *netFD, err error) { ...@@ -245,27 +245,34 @@ func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
return nil, err return nil, err
} }
defer fd.readUnlock() defer fd.readUnlock()
f, err := os.Open(fd.dir + "/listen") listen, err := os.Open(fd.dir + "/listen")
if err != nil { if err != nil {
return nil, err return nil, err
} }
var buf [16]byte var buf [16]byte
n, err := f.Read(buf[:]) n, err := listen.Read(buf[:])
if err != nil { if err != nil {
f.Close() listen.Close()
return nil, err return nil, err
} }
name := string(buf[:n]) name := string(buf[:n])
ctl, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/ctl", os.O_RDWR, 0)
if err != nil {
listen.Close()
return nil, err
}
data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0) data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0)
if err != nil { if err != nil {
f.Close() listen.Close()
ctl.Close()
return nil, err return nil, err
} }
raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote") raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote")
if err != nil { if err != nil {
listen.Close()
ctl.Close()
data.Close() data.Close()
f.Close()
return nil, err return nil, err
} }
return newFD(fd.net, name, f, data, fd.laddr, raddr) return newFD(fd.net, name, listen, ctl, data, fd.laddr, raddr)
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment