Skip to content

Commit c2e9411

Browse files
committed
Add sendfile support and fix Write partial issue
Signed-off-by: Jim Ma <[email protected]>
1 parent 467de38 commit c2e9411

File tree

1 file changed

+83
-22
lines changed

1 file changed

+83
-22
lines changed

alg_linux.go

Lines changed: 83 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -109,36 +109,51 @@ func (h *ihash) Close() error {
109109

110110
func (h *ihash) ReadFrom(r io.Reader) (int64, error) {
111111
if f, ok := r.(*os.File); ok {
112-
return h.readFromFile(f, -1)
112+
if w, err, handled := h.sendfile(f, -1); handled {
113+
return w, err
114+
}
115+
if w, err, handled := h.splice(f, -1); handled {
116+
return w, err
117+
}
113118
}
114119
if lr, ok := r.(*io.LimitedReader); ok {
115-
if f, ok := lr.R.(*os.File); ok {
116-
return h.readFromFile(f, lr.N)
117-
}
120+
return h.readFromLimitedReader(lr)
118121
}
119122
return genericReadFrom(h, r)
120123
}
121124

122-
func (h *ihash) readFromFile(f *os.File, limit int64) (int64, error) {
125+
func (h *ihash) readFromLimitedReader(lr *io.LimitedReader) (int64, error) {
126+
if f, ok := lr.R.(*os.File); ok {
127+
if w, err, handled := h.sendfile(f, lr.N); handled {
128+
return w, err
129+
}
130+
if w, err, handled := h.splice(f, lr.N); handled {
131+
return w, err
132+
}
133+
}
134+
return genericReadFrom(h, lr)
135+
}
136+
137+
func (h *ihash) splice(f *os.File, remain int64) (written int64, err error, handled bool) {
123138
offset, err := f.Seek(0, io.SeekCurrent)
124139
if err != nil {
125-
return 0, err
140+
return 0, nil, false
126141
}
127142
fi, err := f.Stat()
128143
if err != nil {
129-
return 0, err
144+
return 0, nil, false
130145
}
131-
if limit == -1 {
132-
limit = fi.Size() - offset
146+
if remain == -1 {
147+
remain = fi.Size() - offset
133148
}
134149
// mmap must align on a page boundary
135150
// mmap from 0, use data from offset
136151
bytes, err := syscall.Mmap(int(f.Fd()), 0, int(fi.Size()),
137152
syscall.PROT_READ, syscall.MAP_SHARED)
138153
if err != nil {
139-
return 0, err
154+
return 0, nil, false
140155
}
141-
bytes = bytes[offset : offset+limit]
156+
bytes = bytes[offset : offset+remain]
142157
defer syscall.Munmap(bytes)
143158

144159
var (
@@ -153,7 +168,7 @@ func (h *ihash) readFromFile(f *os.File, limit int64) (int64, error) {
153168
for {
154169
n, err := h.Write(bytes[start:end])
155170
if err != nil {
156-
return int64(start + n), err
171+
return int64(start + n), err, true
157172
}
158173
start += n
159174
if start >= total {
@@ -164,23 +179,69 @@ func (h *ihash) readFromFile(f *os.File, limit int64) (int64, error) {
164179
end = total
165180
}
166181
}
167-
return int64(total), nil
182+
return remain, nil, true
168183
}
169184

170-
// Write writes data to an AF_ALG socket, but instructs the kernel
171-
// not to finalize the hash.
172-
func (h *ihash) Write(b []byte) (int, error) {
173-
n, err := h.pipes[1].Vmsplice(b, 0)
185+
func (h *ihash) sendfile(f *os.File, remain int64) (written int64, err error, handled bool) {
186+
offset, err := f.Seek(0, io.SeekCurrent)
174187
if err != nil {
175-
return 0, err
188+
return 0, nil, false
176189
}
177-
178-
_, err = h.pipes[0].Splice(h.s.FD(), n, unix.SPLICE_F_MOVE|unix.SPLICE_F_MORE)
190+
fi, err := f.Stat()
179191
if err != nil {
180-
return 0, err
192+
return 0, nil, false
193+
}
194+
if remain == -1 {
195+
remain = fi.Size() - offset
196+
}
197+
sc, err := f.SyscallConn()
198+
if err != nil {
199+
return 0, nil, false
200+
}
201+
var (
202+
n int
203+
werr error
204+
)
205+
err = sc.Read(func(fd uintptr) bool {
206+
for {
207+
n, werr = syscall.Sendfile(h.s.FD(), int(fd), &offset, int(remain))
208+
if werr != nil {
209+
break
210+
}
211+
if int64(n) >= remain {
212+
break
213+
}
214+
remain -= int64(n)
215+
written += int64(n)
216+
}
217+
return true
218+
})
219+
if err == nil {
220+
err = werr
221+
}
222+
return written, err, true
223+
}
224+
225+
// Write writes data to an AF_ALG socket, but instructs the kernel
226+
// not to finalize the hash.
227+
func (h *ihash) Write(b []byte) (written int, err error) {
228+
for {
229+
n, err := h.pipes[1].Vmsplice(b, 0)
230+
written += n
231+
if err != nil {
232+
break
233+
}
234+
_, err = h.pipes[0].Splice(h.s.FD(), n, unix.SPLICE_F_MOVE|unix.SPLICE_F_MORE)
235+
if err != nil {
236+
break
237+
}
238+
if n >= len(b) {
239+
break
240+
}
241+
b = b[n:]
181242
}
182243

183-
return len(b), nil
244+
return
184245
}
185246

186247
// Sum reads data from an AF_ALG socket, and appends it to the input

0 commit comments

Comments
 (0)