Skip to content

Commit

Permalink
unix: add Mremap for linux
Browse files Browse the repository at this point in the history
For golang/go#60409

Change-Id: I75a9732ee996f0aeb91599d80803f96ada468c27
GitHub-Last-Rev: c348b61
GitHub-Pull-Request: #164
Reviewed-on: https://go-review.googlesource.com/c/sys/+/502715
Auto-Submit: Ian Lance Taylor <iant@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Run-TryBot: Ian Lance Taylor <iant@google.com>
  • Loading branch information
anton-kuklin authored and gopherbot committed Jun 16, 2023
1 parent ca096e4 commit e0c3b6e
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 6 deletions.
2 changes: 1 addition & 1 deletion unix/mkerrors.sh
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ ccflags="$@"
$2 ~ /^LOCK_(SH|EX|NB|UN)$/ ||
$2 ~ /^LO_(KEY|NAME)_SIZE$/ ||
$2 ~ /^LOOP_(CLR|CTL|GET|SET)_/ ||
$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|MCAST|EVFILT|NOTE|SHUT|PROT|MAP|MFD|T?PACKET|MSG|SCM|MCL|DT|MADV|PR|LOCAL|TCPOPT|UDP)_/ ||
$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|MCAST|EVFILT|NOTE|SHUT|PROT|MAP|MREMAP|MFD|T?PACKET|MSG|SCM|MCL|DT|MADV|PR|LOCAL|TCPOPT|UDP)_/ ||
$2 ~ /^NFC_(GENL|PROTO|COMM|RF|SE|DIRECTION|LLCP|SOCKPROTO)_/ ||
$2 ~ /^NFC_.*_(MAX)?SIZE$/ ||
$2 ~ /^RAW_PAYLOAD_/ ||
Expand Down
40 changes: 40 additions & 0 deletions unix/mremap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build linux
// +build linux

package unix

import "unsafe"

type mremapMmapper struct {
mmapper
mremap func(oldaddr uintptr, oldlength uintptr, newlength uintptr, flags int, newaddr uintptr) (xaddr uintptr, err error)
}

func (m *mremapMmapper) Mremap(oldData []byte, newLength int, flags int) (data []byte, err error) {
if newLength <= 0 || len(oldData) == 0 || len(oldData) != cap(oldData) || flags&MREMAP_FIXED != 0 {
return nil, EINVAL
}

pOld := &oldData[cap(oldData)-1]
m.Lock()
defer m.Unlock()
bOld := m.active[pOld]
if bOld == nil || &bOld[0] != &oldData[0] {
return nil, EINVAL
}
newAddr, errno := m.mremap(uintptr(unsafe.Pointer(&bOld[0])), uintptr(len(bOld)), uintptr(newLength), flags, 0)
if errno != nil {
return nil, errno
}
bNew := unsafe.Slice((*byte)(unsafe.Pointer(newAddr)), newLength)
pNew := &bNew[cap(bNew)-1]
if flags&MREMAP_DONTUNMAP == 0 {
delete(m.active, pOld)
}
m.active[pNew] = bNew
return bNew, nil
}
47 changes: 47 additions & 0 deletions unix/mremap_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build linux
// +build linux

package unix_test

import (
"testing"

"golang.org/x/sys/unix"
)

func TestMremap(t *testing.T) {
b, err := unix.Mmap(-1, 0, unix.Getpagesize(), unix.PROT_NONE, unix.MAP_ANON|unix.MAP_PRIVATE)
if err != nil {
t.Fatalf("Mmap: %v", err)
}
if err := unix.Mprotect(b, unix.PROT_READ|unix.PROT_WRITE); err != nil {
t.Fatalf("Mprotect: %v", err)
}

b[0] = 42

bNew, err := unix.Mremap(b, unix.Getpagesize()*2, unix.MREMAP_MAYMOVE)
if err != nil {
t.Fatalf("Mremap2: %v", err)
}
bNew[unix.Getpagesize()+1] = 84 // checks

if bNew[0] != 42 {
t.Fatal("first element value was changed")
}
if len(bNew) != unix.Getpagesize()*2 {
t.Fatal("new memory len not equal to specified len")
}
if cap(bNew) != unix.Getpagesize()*2 {
t.Fatal("new memory cap not equal to specified len")
}

_, err = unix.Mremap(b, unix.Getpagesize(), unix.MREMAP_FIXED)
if err != unix.EINVAL {
t.Fatalf("unix.MREMAP_FIXED should be forbidden")
}
}
17 changes: 12 additions & 5 deletions unix/syscall_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -2124,11 +2124,15 @@ func writevRacedetect(iovecs []Iovec, n int) {

// mmap varies by architecture; see syscall_linux_*.go.
//sys munmap(addr uintptr, length uintptr) (err error)
//sys mremap(oldaddr uintptr, oldlength uintptr, newlength uintptr, flags int, newaddr uintptr) (xaddr uintptr, err error)

var mapper = &mmapper{
active: make(map[*byte][]byte),
mmap: mmap,
munmap: munmap,
var mapper = &mremapMmapper{
mmapper: mmapper{
active: make(map[*byte][]byte),
mmap: mmap,
munmap: munmap,
},
mremap: mremap,
}

func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
Expand All @@ -2139,6 +2143,10 @@ func Munmap(b []byte) (err error) {
return mapper.Munmap(b)
}

func Mremap(oldData []byte, newLength int, flags int) (data []byte, err error) {
return mapper.Mremap(oldData, newLength, flags)
}

//sys Madvise(b []byte, advice int) (err error)
//sys Mprotect(b []byte, prot int) (err error)
//sys Mlock(b []byte) (err error)
Expand Down Expand Up @@ -2487,7 +2495,6 @@ func Getresgid() (rgid, egid, sgid int) {
// MqTimedreceive
// MqTimedsend
// MqUnlink
// Mremap
// Msgctl
// Msgget
// Msgrcv
Expand Down
3 changes: 3 additions & 0 deletions unix/zerrors_linux.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions unix/zsyscall_linux.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit e0c3b6e

Please sign in to comment.