Preconditions: f.mu must be locked.
(alloc *allocState)
| 887 | |
| 888 | // Preconditions: f.mu must be locked. |
| 889 | func (f *MemoryFile) extendChunksLocked(alloc *allocState) error { |
| 890 | unfree := &f.unfreeSmall |
| 891 | if alloc.huge { |
| 892 | unfree = &f.unfreeHuge |
| 893 | } |
| 894 | |
| 895 | oldChunks := f.chunksLoad() |
| 896 | oldNrChunks := uint64(len(oldChunks)) |
| 897 | oldFileSize := oldNrChunks * chunkSize |
| 898 | |
| 899 | // Determine how many chunks we need to satisfy alloc. |
| 900 | tail := uint64(0) |
| 901 | if oldNrChunks != 0 { |
| 902 | if lastChunk := oldChunks[oldNrChunks-1]; lastChunk.huge == alloc.huge { |
| 903 | // We can use free pages at the end of the current last chunk. |
| 904 | if ufgap := unfree.FindGap(oldFileSize - 1); ufgap.Ok() { |
| 905 | tail = ufgap.Range().Length() |
| 906 | } |
| 907 | } |
| 908 | } |
| 909 | incNrChunks := (alloc.length + chunkMask - tail) / chunkSize |
| 910 | incFileSize := incNrChunks * chunkSize |
| 911 | newNrChunks := oldNrChunks + incNrChunks |
| 912 | if newNrChunks > maxChunks || newNrChunks < oldNrChunks /* overflow */ { |
| 913 | return linuxerr.ENOMEM |
| 914 | } |
| 915 | newFileSize := newNrChunks * chunkSize |
| 916 | |
| 917 | // Extend the backing file and obtain mappings for the new chunks. If the |
| 918 | // backing file is memory-backed, and THP is enabled, Linux will align our |
| 919 | // mapping to a hugepage boundary; see |
| 920 | // mm/shmem.c:shmem_get_unmapped_area(). |
| 921 | // |
| 922 | // In tests, f.file may be nil. |
| 923 | var mapStart uintptr |
| 924 | if f.file != nil { |
| 925 | if err := f.file.Truncate(int64(newFileSize)); err != nil { |
| 926 | return err |
| 927 | } |
| 928 | m, _, errno := unix.Syscall6( |
| 929 | unix.SYS_MMAP, |
| 930 | 0, |
| 931 | uintptr(incFileSize), |
| 932 | unix.PROT_READ|unix.PROT_WRITE, |
| 933 | unix.MAP_SHARED, |
| 934 | f.file.Fd(), |
| 935 | uintptr(oldFileSize)) |
| 936 | if errno != 0 { |
| 937 | return errno |
| 938 | } |
| 939 | mapStart = m |
| 940 | f.madviseChunkMapping(mapStart, uintptr(incFileSize), alloc.huge) |
| 941 | } |
| 942 | |
| 943 | // Update chunk state. |
| 944 | newChunks := make([]chunkInfo, newNrChunks) |
| 945 | copy(newChunks, oldChunks) |
| 946 | m := mapStart |
no test coverage detected