@@ -21,6 +21,7 @@ import (
2121 "syscall"
2222 "unsafe"
2323
24+ "github.com/containerd/containerd/log"
2425 "github.com/pkg/errors"
2526 "golang.org/x/sys/unix"
2627)
@@ -30,9 +31,8 @@ func FMountat(dirfd uintptr, source, target, fstype string, flags uintptr, data
3031 var (
3132 sourceP , targetP , fstypeP , dataP * byte
3233 pid uintptr
33- ws unix.WaitStatus
3434 err error
35- errno syscall.Errno
35+ errno , status syscall.Errno
3636 )
3737
3838 sourceP , err = syscall .BytePtrFromString (source )
@@ -60,37 +60,62 @@ func FMountat(dirfd uintptr, source, target, fstype string, flags uintptr, data
6060 runtime .LockOSThread ()
6161 defer runtime .UnlockOSThread ()
6262
63+ var pipefds [2 ]int
64+ if err := syscall .Pipe2 (pipefds [:], syscall .O_CLOEXEC ); err != nil {
65+ return errors .Wrap (err , "failed to open pipe" )
66+ }
67+
68+ defer func () {
69+ // close both ends of the pipe in a deferred function, since open file
70+ // descriptor table is shared with child
71+ syscall .Close (pipefds [0 ])
72+ syscall .Close (pipefds [1 ])
73+ }()
74+
6375 pid , errno = forkAndMountat (dirfd ,
6476 uintptr (unsafe .Pointer (sourceP )),
6577 uintptr (unsafe .Pointer (targetP )),
6678 uintptr (unsafe .Pointer (fstypeP )),
6779 flags ,
68- uintptr (unsafe .Pointer (dataP )))
80+ uintptr (unsafe .Pointer (dataP )),
81+ pipefds [1 ],
82+ )
6983
7084 if errno != 0 {
7185 return errors .Wrap (errno , "failed to fork thread" )
7286 }
7387
74- _ , err = unix .Wait4 (int (pid ), & ws , 0 , nil )
75- for err == syscall .EINTR {
76- _ , err = unix .Wait4 (int (pid ), & ws , 0 , nil )
77- }
88+ defer func () {
89+ _ , err := unix .Wait4 (int (pid ), nil , 0 , nil )
90+ for err == syscall .EINTR {
91+ _ , err = unix .Wait4 (int (pid ), nil , 0 , nil )
92+ }
7893
79- if err != nil {
80- return errors .Wrapf (err , "failed to find pid=%d process" , pid )
81- }
94+ if err != nil {
95+ log .L .WithError (err ).Debugf ("failed to find pid=%d process" , pid )
96+ }
97+ }()
8298
83- errno = syscall .Errno (ws .ExitStatus ())
99+ _ , _ , errno = syscall .RawSyscall (syscall .SYS_READ ,
100+ uintptr (pipefds [0 ]),
101+ uintptr (unsafe .Pointer (& status )),
102+ unsafe .Sizeof (status ))
84103 if errno != 0 {
85- return errors .Wrap (errno , "failed to mount " )
104+ return errors .Wrap (errno , "failed to read pipe " )
86105 }
106+
107+ if status != 0 {
108+ return errors .Wrap (status , "failed to mount" )
109+ }
110+
87111 return nil
88112}
89113
90114// forkAndMountat will fork thread, change working dir and mount.
91115//
92116// precondition: the runtime OS thread must be locked.
93- func forkAndMountat (dirfd uintptr , source , target , fstype , flags , data uintptr ) (pid uintptr , errno syscall.Errno ) {
117+ func forkAndMountat (dirfd uintptr , source , target , fstype , flags , data uintptr , pipefd int ) (pid uintptr , errno syscall.Errno ) {
118+
94119 // block signal during clone
95120 beforeFork ()
96121
@@ -114,6 +139,7 @@ func forkAndMountat(dirfd uintptr, source, target, fstype, flags, data uintptr)
114139 _ , _ , errno = syscall .RawSyscall6 (syscall .SYS_MOUNT , source , target , fstype , flags , data , 0 )
115140
116141childerr:
142+ _ , _ , errno = syscall .RawSyscall (syscall .SYS_WRITE , uintptr (pipefd ), uintptr (unsafe .Pointer (& errno )), unsafe .Sizeof (errno ))
117143 syscall .RawSyscall (syscall .SYS_EXIT , uintptr (errno ), 0 , 0 )
118144 panic ("unreachable" )
119145}
0 commit comments