Author: kevans
Date: Wed Jan  8 19:08:44 2020
New Revision: 356512
URL: https://svnweb.freebsd.org/changeset/base/356512

Log:
  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

Modified:
  head/sys/kern/uipc_shm.c
  head/tests/sys/posixshm/posixshm_test.c

Modified: head/sys/kern/uipc_shm.c
==============================================================================
--- head/sys/kern/uipc_shm.c    Wed Jan  8 19:06:22 2020        (r356511)
+++ head/sys/kern/uipc_shm.c    Wed Jan  8 19:08:44 2020        (r356512)
@@ -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
 };
 
@@ -1435,6 +1437,32 @@ shm_get_seals(struct file *fp, int *seals)
        shmfd = fp->f_data;
        *seals = shmfd->shm_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

Modified: head/tests/sys/posixshm/posixshm_test.c
==============================================================================
--- head/tests/sys/posixshm/posixshm_test.c     Wed Jan  8 19:06:22 2020        
(r356511)
+++ head/tests/sys/posixshm/posixshm_test.c     Wed Jan  8 19:08:44 2020        
(r356512)
@@ -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());
 }
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to