Changeset View
Changeset View
Standalone View
Standalone View
lib/libc/sys/shm_open.c
Show All 25 Lines | |||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | ||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/types.h> | #include <sys/param.h> | ||||
#include <sys/filio.h> | |||||
#include <sys/mman.h> | #include <sys/mman.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <fcntl.h> | #include <fcntl.h> | ||||
#include <limits.h> | #include <limits.h> | ||||
#include <stdlib.h> | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <unistd.h> | |||||
#include "libc_private.h" | #include "libc_private.h" | ||||
__weak_reference(shm_open, _shm_open); | __weak_reference(shm_open, _shm_open); | ||||
__weak_reference(shm_open, __sys_shm_open); | __weak_reference(shm_open, __sys_shm_open); | ||||
#define MEMFD_NAME_PREFIX "memfd:" | #define MEMFD_NAME_PREFIX "memfd:" | ||||
int | int | ||||
shm_open(const char *path, int flags, mode_t mode) | shm_open(const char *path, int flags, mode_t mode) | ||||
{ | { | ||||
return (__sys_shm_open2(path, flags | O_CLOEXEC, mode, 0, NULL)); | return (__sys_shm_open2(path, flags | O_CLOEXEC, mode, 0, NULL)); | ||||
} | } | ||||
#define K(x) ((size_t)(x) * 1024) | |||||
#define M(x) (K(x) * 1024) | |||||
#define G(x) (M(x) * 1024) | |||||
static const struct { | |||||
int mask; | |||||
size_t pgsize; | |||||
} mfd_huge_sizes[] = { | |||||
{ .mask = MFD_HUGE_64KB, .pgsize = K(64) }, | |||||
{ .mask = MFD_HUGE_512KB, .pgsize = K(512) }, | |||||
{ .mask = MFD_HUGE_1MB, .pgsize = M(1) }, | |||||
{ .mask = MFD_HUGE_2MB, .pgsize = M(2) }, | |||||
{ .mask = MFD_HUGE_8MB, .pgsize = M(8) }, | |||||
{ .mask = MFD_HUGE_16MB, .pgsize = M(16) }, | |||||
{ .mask = MFD_HUGE_32MB, .pgsize = M(32) }, | |||||
{ .mask = MFD_HUGE_256MB, .pgsize = M(256) }, | |||||
markj: So in order to open an existing largepage object with shm_open_largepage(), one has to… | |||||
{ .mask = MFD_HUGE_512MB, .pgsize = M(512) }, | |||||
{ .mask = MFD_HUGE_1GB, .pgsize = G(1) }, | |||||
{ .mask = MFD_HUGE_2GB, .pgsize = G(2) }, | |||||
{ .mask = MFD_HUGE_16GB, .pgsize = G(16) }, | |||||
}; | |||||
/* | /* | ||||
* The path argument is passed to the kernel, but the kernel doesn't currently | * The path argument is passed to the kernel, but the kernel doesn't currently | ||||
* do anything with it. Linux exposes it in linprocfs for debugging purposes | * do anything with it. Linux exposes it in linprocfs for debugging purposes | ||||
* only, but our kernel currently will not do the same. | * only, but our kernel currently will not do the same. | ||||
*/ | */ | ||||
int | int | ||||
memfd_create(const char *name, unsigned int flags) | memfd_create(const char *name, unsigned int flags) | ||||
{ | { | ||||
char memfd_name[NAME_MAX + 1]; | char memfd_name[NAME_MAX + 1]; | ||||
size_t namelen; | size_t namelen, *pgs; | ||||
int oflags, shmflags; | struct shm_largepage_conf slc; | ||||
int error, fd, i, npgs, oflags, pgidx, saved_errno, shmflags; | |||||
if (name == NULL) | if (name == NULL) | ||||
return (EBADF); | return (EBADF); | ||||
namelen = strlen(name); | namelen = strlen(name); | ||||
if (namelen + sizeof(MEMFD_NAME_PREFIX) - 1 > NAME_MAX) | if (namelen + sizeof(MEMFD_NAME_PREFIX) - 1 > NAME_MAX) | ||||
return (EINVAL); | return (EINVAL); | ||||
if ((flags & ~(MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB | | if ((flags & ~(MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB | | ||||
MFD_HUGE_MASK)) != 0) | MFD_HUGE_MASK)) != 0) | ||||
return (EINVAL); | return (EINVAL); | ||||
/* Size specified but no HUGETLB. */ | /* Size specified but no HUGETLB. */ | ||||
if ((flags & MFD_HUGE_MASK) != 0 && (flags & MFD_HUGETLB) == 0) | if (((flags & MFD_HUGE_MASK) != 0 && (flags & MFD_HUGETLB) == 0) || | ||||
__bitcount(flags & MFD_HUGE_MASK) > 1) | |||||
return (EINVAL); | return (EINVAL); | ||||
/* We don't actually support HUGETLB. */ | |||||
if ((flags & MFD_HUGETLB) != 0) | |||||
return (ENOSYS); | |||||
/* We've already validated that we're sufficiently sized. */ | /* We've already validated that we're sufficiently sized. */ | ||||
snprintf(memfd_name, NAME_MAX + 1, "%s%s", MEMFD_NAME_PREFIX, name); | snprintf(memfd_name, NAME_MAX + 1, "%s%s", MEMFD_NAME_PREFIX, name); | ||||
oflags = O_RDWR; | oflags = O_RDWR; | ||||
shmflags = 0; | shmflags = 0; | ||||
if ((flags & MFD_CLOEXEC) != 0) | if ((flags & MFD_CLOEXEC) != 0) | ||||
oflags |= O_CLOEXEC; | oflags |= O_CLOEXEC; | ||||
if ((flags & MFD_ALLOW_SEALING) != 0) | if ((flags & MFD_ALLOW_SEALING) != 0) | ||||
shmflags |= SHM_ALLOW_SEALING; | shmflags |= SHM_ALLOW_SEALING; | ||||
return (__sys_shm_open2(SHM_ANON, oflags, 0, shmflags, memfd_name)); | if ((flags & MFD_HUGETLB) == 0) | ||||
shmflags |= SHM_LARGEPAGE; | |||||
fd = __sys_shm_open2(SHM_ANON, oflags, 0, shmflags, memfd_name); | |||||
if (fd == -1 || (flags & MFD_HUGETLB) == 0) | |||||
return (fd); | |||||
pgs = NULL; | |||||
npgs = getpagesizes(NULL, 0); | |||||
if (npgs == -1) | |||||
goto clean; | |||||
pgs = calloc(npgs, sizeof(size_t)); | |||||
if (pgs == NULL) | |||||
goto clean; | |||||
error = getpagesizes(pgs, npgs); | |||||
if (error == -1) | |||||
goto clean; | |||||
if ((flags & MFD_HUGE_MASK) == 0) { | |||||
if (npgs == 1) { | |||||
errno = EOPNOTSUPP; | |||||
goto clean; | |||||
} | |||||
pgidx = 1; | |||||
} else { | |||||
for (i = 0; i < nitems(mfd_huge_sizes); i++) { | |||||
if (mfd_huge_sizes[i].mask == (flags & MFD_HUGE_MASK)) | |||||
break; | |||||
} | |||||
for (pgidx = 0; pgidx < npgs; pgidx++) { | |||||
if (mfd_huge_sizes[i].pgsize == pgs[pgidx]) | |||||
break; | |||||
} | |||||
if (pgidx == npgs) { | |||||
errno = EOPNOTSUPP; | |||||
goto clean; | |||||
} | |||||
} | |||||
free(pgs); | |||||
pgs = NULL; | |||||
memset(&slc, 0, sizeof(slc)); | |||||
slc.psind = pgidx; | |||||
slc.alloc_policy = SHM_LARGEPAGE_ALLOC_DEFAULT; | |||||
error = ioctl(fd, FIOSHMLPGCNF, &slc); | |||||
if (error == -1) | |||||
goto clean; | |||||
return (fd); | |||||
clean: | |||||
saved_errno = errno; | |||||
close(fd); | |||||
free(pgs); | |||||
errno = saved_errno; | |||||
return (-1); | |||||
} | } |
So in order to open an existing largepage object with shm_open_largepage(), one has to reproduce the original psind, alloc_policy parameters (otherwise FIOSHMLPGCNF will fail), or open it with shm_open(). Does it suggest that shm_open_largepage() should really be shm_create_largepage(), i.e., O_CREAT is implicit, and shm_open() is always used to open existing largepage objects?