github.com/iceber/iouring-go@v0.0.0-20230403020409-002cfd2e2a90/link_request.go (about) 1 //go:build linux 2 // +build linux 3 4 package iouring 5 6 import ( 7 "errors" 8 "time" 9 "unsafe" 10 11 "golang.org/x/sys/unix" 12 13 iouring_syscall "github.com/iceber/iouring-go/syscall" 14 ) 15 16 func (iour *IOURing) SubmitLinkRequests(requests []PrepRequest, ch chan<- Result) (RequestSet, error) { 17 return iour.submitLinkRequest(requests, ch, false) 18 } 19 20 func (iour *IOURing) SubmitHardLinkRequests(requests []PrepRequest, ch chan<- Result) (RequestSet, error) { 21 return iour.submitLinkRequest(requests, ch, true) 22 } 23 24 func (iour *IOURing) submitLinkRequest(requests []PrepRequest, ch chan<- Result, hard bool) (RequestSet, error) { 25 // TODO(iceber): no length limit 26 if len(requests) > int(*iour.sq.entries) { 27 return nil, errors.New("too many requests") 28 } 29 30 flags := iouring_syscall.IOSQE_FLAGS_IO_LINK 31 if hard { 32 flags = iouring_syscall.IOSQE_FLAGS_IO_HARDLINK 33 } 34 35 iour.submitLock.Lock() 36 defer iour.submitLock.Unlock() 37 38 if iour.IsClosed() { 39 return nil, ErrIOURingClosed 40 } 41 42 var sqeN uint32 43 userDatas := make([]*UserData, 0, len(requests)) 44 for i := range requests { 45 sqe := iour.getSQEntry() 46 sqeN++ 47 48 userData, err := iour.doRequest(sqe, requests[i], ch) 49 if err != nil { 50 iour.sq.fallback(sqeN) 51 return nil, err 52 } 53 userDatas = append(userDatas, userData) 54 55 sqe.CleanFlags(iouring_syscall.IOSQE_FLAGS_IO_HARDLINK | iouring_syscall.IOSQE_FLAGS_IO_LINK) 56 if i < len(requests)-1 { 57 sqe.SetFlags(flags) 58 } 59 } 60 61 // must be located before the lock operation to 62 // avoid the compiler's adjustment of the code order. 63 // issue: https://github.com/Iceber/iouring-go/issues/8 64 rset := newRequestSet(userDatas) 65 66 iour.userDataLock.Lock() 67 for _, data := range userDatas { 68 iour.userDatas[data.id] = data 69 } 70 iour.userDataLock.Unlock() 71 72 if _, err := iour.submit(); err != nil { 73 iour.userDataLock.Lock() 74 for _, data := range userDatas { 75 delete(iour.userDatas, data.id) 76 } 77 iour.userDataLock.Unlock() 78 79 return nil, err 80 } 81 82 return rset, nil 83 } 84 85 func linkTimeout(t time.Duration) PrepRequest { 86 timespec := unix.NsecToTimespec(t.Nanoseconds()) 87 88 return func(sqe iouring_syscall.SubmissionQueueEntry, userData *UserData) { 89 userData.hold(×pec) 90 userData.request.resolver = timeoutResolver 91 92 sqe.PrepOperation(iouring_syscall.IORING_OP_LINK_TIMEOUT, -1, uint64(uintptr(unsafe.Pointer(×pec))), 1, 0) 93 } 94 }