posixshm: implement posix_fallocate(2)
Linux expects to be able to use posix_fallocate(2) on a memfd. Other places would use this with shm_open(2) to act as a smarter ftruncate(2). Test has been added to go along with this. Reviewed by: kib (earlier version) Differential Revision: https://reviews.freebsd.org/D23042
This commit is contained in:
parent
7ce4072267
commit
f10405323a
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=356512
@ -138,6 +138,7 @@ static fo_fill_kinfo_t shm_fill_kinfo;
|
||||
static fo_mmap_t shm_mmap;
|
||||
static fo_get_seals_t shm_get_seals;
|
||||
static fo_add_seals_t shm_add_seals;
|
||||
static fo_fallocate_t shm_fallocate;
|
||||
|
||||
/* File descriptor operations. */
|
||||
struct fileops shm_ops = {
|
||||
@ -157,6 +158,7 @@ struct fileops shm_ops = {
|
||||
.fo_mmap = shm_mmap,
|
||||
.fo_get_seals = shm_get_seals,
|
||||
.fo_add_seals = shm_add_seals,
|
||||
.fo_fallocate = shm_fallocate,
|
||||
.fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE
|
||||
};
|
||||
|
||||
@ -1437,6 +1439,32 @@ shm_get_seals(struct file *fp, int *seals)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
shm_fallocate(struct file *fp, off_t offset, off_t len, struct thread *td)
|
||||
{
|
||||
void *rl_cookie;
|
||||
struct shmfd *shmfd;
|
||||
size_t size;
|
||||
int error;
|
||||
|
||||
/* This assumes that the caller already checked for overflow. */
|
||||
error = 0;
|
||||
shmfd = fp->f_data;
|
||||
size = offset + len;
|
||||
rl_cookie = rangelock_wlock(&shmfd->shm_rl, 0, OFF_MAX,
|
||||
&shmfd->shm_mtx);
|
||||
if (size > shmfd->shm_size) {
|
||||
VM_OBJECT_WLOCK(shmfd->shm_object);
|
||||
error = shm_dotruncate_locked(shmfd, size, rl_cookie);
|
||||
VM_OBJECT_WUNLOCK(shmfd->shm_object);
|
||||
}
|
||||
rangelock_unlock(&shmfd->shm_rl, rl_cookie, &shmfd->shm_mtx);
|
||||
/* Translate to posix_fallocate(2) return value as needed. */
|
||||
if (error == ENOMEM)
|
||||
error = ENOSPC;
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
sysctl_posix_shm_list(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
|
@ -918,6 +918,44 @@ ATF_TC_BODY(mode, tc)
|
||||
umask(restore_mask);
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(fallocate);
|
||||
ATF_TC_BODY(fallocate, tc)
|
||||
{
|
||||
struct stat st;
|
||||
int error, fd, sz;
|
||||
|
||||
/*
|
||||
* Primitive test case for posix_fallocate with shmd. Effectively
|
||||
* expected to work like a smarter ftruncate that will grow the region
|
||||
* as needed in a race-free way.
|
||||
*/
|
||||
fd = shm_open(SHM_ANON, O_RDWR, 0666);
|
||||
ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
|
||||
/* Set the initial size. */
|
||||
sz = 32;
|
||||
ATF_REQUIRE(ftruncate(fd, sz) == 0);
|
||||
|
||||
/* Now grow it. */
|
||||
error = 0;
|
||||
sz *= 2;
|
||||
ATF_REQUIRE_MSG((error = posix_fallocate(fd, 0, sz)) == 0,
|
||||
"posix_fallocate failed; error=%d", error);
|
||||
ATF_REQUIRE(fstat(fd, &st) == 0);
|
||||
ATF_REQUIRE(st.st_size == sz);
|
||||
/* Attempt to shrink it; should succeed, but not change the size. */
|
||||
ATF_REQUIRE_MSG((error = posix_fallocate(fd, 0, sz / 2)) == 0,
|
||||
"posix_fallocate failed; error=%d", error);
|
||||
ATF_REQUIRE(fstat(fd, &st) == 0);
|
||||
ATF_REQUIRE(st.st_size == sz);
|
||||
/* Grow it using an offset of sz and len of sz. */
|
||||
ATF_REQUIRE_MSG((error = posix_fallocate(fd, sz, sz)) == 0,
|
||||
"posix_fallocate failed; error=%d", error);
|
||||
ATF_REQUIRE(fstat(fd, &st) == 0);
|
||||
ATF_REQUIRE(st.st_size == (sz * 2));
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
ATF_TP_ADD_TCS(tp)
|
||||
{
|
||||
|
||||
@ -951,6 +989,7 @@ ATF_TP_ADD_TCS(tp)
|
||||
ATF_TP_ADD_TC(tp, object_resize);
|
||||
ATF_TP_ADD_TC(tp, cloexec);
|
||||
ATF_TP_ADD_TC(tp, mode);
|
||||
ATF_TP_ADD_TC(tp, fallocate);
|
||||
|
||||
return (atf_no_error());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user