appropriate way to call fcntl(2) from Go on darwin?

118 views
Skip to first unread message

Jason E. Aten

unread,
Mar 18, 2025, 3:08:06 AM3/18/25
to golang-nuts
I'm porting some C code that does manual filesystem "extent" 
file space management from Linux to Darwin (and into Go). 

The Linux fallocate() call and its FALLOC_FL_INSERT_RANGE 
operation are not directly available on Darwin, but suggestions from StackOverflow
indicate that fcntl(2) with F_PREALLOCATE might be a close substitute.

It seems to be working. Full code here in this playground, but I have a couple of questions--
Can I get away without the runtime.Pinner? (Am I still safe from 'store' being pre-maturely garbage collected without the pin, since Go memory has been converted to an uintptr before calling unix.Syscall())

Is there a more appropriate way to call fcntl() (on Darwin)?

Thanks for any guidance here.

Jason

Ian Lance Taylor

unread,
Mar 18, 2025, 10:21:37 AM3/18/25
to Jason E. Aten, golang-nuts
On Tue, Mar 18, 2025 at 12:08 AM Jason E. Aten <j.e....@gmail.com> wrote:
>
> I'm porting some C code that does manual filesystem "extent"
> file space management from Linux to Darwin (and into Go).
>
> The Linux fallocate() call and its FALLOC_FL_INSERT_RANGE
> operation are not directly available on Darwin, but suggestions from StackOverflow
> indicate that fcntl(2) with F_PREALLOCATE might be a close substitute.
>
> It seems to be working. Full code here in this playground, but I have a couple of questions--
>
> https://go.dev/play/p/Z5JB__fUBpI
>
> Can I get away without the runtime.Pinner? (Am I still safe from 'store' being pre-maturely garbage collected without the pin, since Go memory has been converted to an uintptr before calling unix.Syscall())

You don't need the runtime.Pinner but you do need to do the conversion
to uintptr in the call to unix.Syscall. That is

unix.Syscall(fcntl64Syscall, uintptr(fd),
uintptr(syscall.F_PREALLOCATE), uintptr(unsafe.Pointer(ustore)))

This uses rule 4 at https://pkg.go.dev/unsafe#Pointer. The memory will
be pinned for the duration of the system call.


> Is there a more appropriate way to call fcntl() (on Darwin)?

Darwin doesn't particularly like calling unix.Syscall directly,
although it does work. They prefer that you call the C function. You
could do that via cgo by calling C.fcntl.

Or in this case it seems simpler to just use the unix.FcntlFstore
function which already exists and does the right thing.

Ian

Jason E. Aten

unread,
Mar 18, 2025, 11:27:42 AM3/18/25
to golang-nuts
Thank you so much, Ian.

On Tuesday, March 18, 2025 at 2:21:37 PM UTC Ian Lance Taylor wrote:
Or in this case it seems simpler to just use the unix.FcntlFstore
function which already exists and does the right thing.

I think I may have stumbled on/been tripped up by a bug in pkg.go.dev then,
because when I looked there, I did not see unix.FcntlFstore(). The
list was simply these two: FcntlFlock, and FcntlInt. Copy and pasting it:

...
func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error
func FcntlInt(fd uintptr, cmd, arg int) (int, error)
func FdToClockID(fd int) int32
...

with no FcntlFstore in sight.  (Apologies for the screenshot attached, but
it provides perhaps believable evidence of the same claim).

Is it worth filing a bug on pkg.go.dev for this? Or maybe there is a way I don't
know about to have the darwin-specific calls show up in pkg.go.dev?

Thanks again.
Jason


no_listing_for_FcntlFstore_in_pkg_go_dev.png
 

Jason E. Aten

unread,
Mar 18, 2025, 11:50:07 AM3/18/25
to golang-nuts
I filed https://github.com/golang/go/issues/72923 just in case, since its easier to do this while everything is top of desk.

I appreciate all the help. Thanks again.

Ian Lance Taylor

unread,
Mar 18, 2025, 12:13:05 PM3/18/25
to Jason E. Aten, golang-nuts
It's definitely awkward for packages like x/sys/unix that provide a different API depending on the target. If you look over on the right and scroll down a bit, you'll see a "Rendered for" drop down selection. If you select darwin/amd64, you'll be redirected to https://pkg.go.dev/golang.org/x/sys/unix?GOOS=darwin, which does show the function: https://pkg.go.dev/golang.org/x/sys/unix?GOOS=darwin#FcntlFstore . It would be nice if this could be clearer.

Ian
Reply all
Reply to author
Forward
0 new messages