ReadInPages sends FUSE_READ requests for the size after round it up to a multiple of page size, blocks on it for reply, processes the reply and returns the payload (or joined payloads) as a byte slice. This is used for the general purpose reading. We do not support direct IO (which read the exact nu
(ctx context.Context, fd *regularFileFD, off uint64, size uint32)
| 31 | // We do not support direct IO (which read the exact number of bytes) |
| 32 | // at this moment. |
| 33 | func (fs *filesystem) ReadInPages(ctx context.Context, fd *regularFileFD, off uint64, size uint32) ([][]byte, uint32, error) { |
| 34 | attributeVersion := fs.conn.attributeVersion.Load() |
| 35 | |
| 36 | // Round up to a multiple of page size. |
| 37 | readSize, _ := hostarch.PageRoundUp(uint64(size)) |
| 38 | |
| 39 | // One request cannot exceed either maxRead or maxPages. |
| 40 | maxPages := fs.conn.maxRead >> hostarch.PageShift |
| 41 | if maxPages > uint32(fs.conn.maxPages) { |
| 42 | maxPages = uint32(fs.conn.maxPages) |
| 43 | } |
| 44 | |
| 45 | var outs [][]byte |
| 46 | var sizeRead uint32 |
| 47 | |
| 48 | // readSize is a multiple of hostarch.PageSize. |
| 49 | // Always request bytes as a multiple of pages. |
| 50 | pagesRead, pagesToRead := uint32(0), uint32(readSize>>hostarch.PageShift) |
| 51 | |
| 52 | // Reuse the same struct for unmarshalling to avoid unnecessary memory allocation. |
| 53 | in := linux.FUSEReadIn{ |
| 54 | Fh: fd.Fh, |
| 55 | LockOwner: 0, // TODO(gvisor.dev/issue/3245): file lock |
| 56 | ReadFlags: 0, // TODO(gvisor.dev/issue/3245): |= linux.FUSE_READ_LOCKOWNER |
| 57 | Flags: fd.statusFlags(), |
| 58 | } |
| 59 | |
| 60 | // This loop is intended for fragmented read where the bytes to read is |
| 61 | // larger than either the maxPages or maxRead. |
| 62 | // For the majority of reads with normal size, this loop should only |
| 63 | // execute once. |
| 64 | for pagesRead < pagesToRead { |
| 65 | pagesCanRead := pagesToRead - pagesRead |
| 66 | if pagesCanRead > maxPages { |
| 67 | pagesCanRead = maxPages |
| 68 | } |
| 69 | |
| 70 | in.Offset = off + (uint64(pagesRead) << hostarch.PageShift) |
| 71 | in.Size = pagesCanRead << hostarch.PageShift |
| 72 | |
| 73 | // TODO(gvisor.dev/issue/3247): support async read. |
| 74 | res, err := fd.inode().callRaw(ctx, linux.FUSE_READ, &in) |
| 75 | if err != nil { |
| 76 | return nil, 0, err |
| 77 | } |
| 78 | |
| 79 | // Not enough bytes in response, |
| 80 | // either we reached EOF, |
| 81 | // or the FUSE server sends back a response |
| 82 | // that cannot even fit the hdr. |
| 83 | if len(res.data) <= res.hdr.SizeBytes() { |
| 84 | // We treat both case as EOF here for now |
| 85 | // since there is no reliable way to detect |
| 86 | // the over-short hdr case. |
| 87 | break |
| 88 | } |
| 89 | |
| 90 | // Directly using the slice to avoid extra copy. |
no test coverage detected