fuse: remove the 1GiB buffer view limit#101
Conversation
174d49c to
9d910cf
Compare
|
I understand that this may solve a real problem for you. However we still need to support 32-bit systems and this looks a bit complicated to me. The expression So perhaps the following change should do the trick. From: buff := (*[1 << 30]byte)(unsafe.Pointer(buff0))To: buff := (*[1 << (30 + 10*(^uint(0)>>32&1))]byte)(unsafe.Pointer(buff0))Full diff: diff --git c/fuse/host.go i/fuse/host.go
index 083c03c..5176029 100644
--- c/fuse/host.go
+++ i/fuse/host.go
@@ -135,7 +135,7 @@ func hostReadlink(path0 *c_char, buff0 *c_char, size0 c_size_t) (errc0 c_int) {
fsop := hostHandleGet(c_fuse_get_context().private_data).fsop
path := c_GoString(path0)
errc, rslt := fsop.Readlink(path)
- buff := (*[1 << 30]byte)(unsafe.Pointer(buff0))
+ buff := (*[1 << (30 + 10*(^uint(0)>>32&1))]byte)(unsafe.Pointer(buff0))
copy(buff[:size0-1], rslt)
rlen := len(rslt)
if c_size_t(rlen) < size0 {
@@ -284,7 +284,7 @@ func hostRead(path0 *c_char, buff0 *c_char, size0 c_size_t, ofst0 c_fuse_off_t,
defer recoverAsErrno(&nbyt0)
fsop := hostHandleGet(c_fuse_get_context().private_data).fsop
path := c_GoString(path0)
- buff := (*[1 << 30]byte)(unsafe.Pointer(buff0))
+ buff := (*[1 << (30 + 10*(^uint(0)>>32&1))]byte)(unsafe.Pointer(buff0))
nbyt := fsop.Read(path, buff[:size0], int64(ofst0), uint64(fi0.fh))
return c_int(nbyt)
}
@@ -294,7 +294,7 @@ func hostWrite(path0 *c_char, buff0 *c_char, size0 c_size_t, ofst0 c_fuse_off_t,
defer recoverAsErrno(&nbyt0)
fsop := hostHandleGet(c_fuse_get_context().private_data).fsop
path := c_GoString(path0)
- buff := (*[1 << 30]byte)(unsafe.Pointer(buff0))
+ buff := (*[1 << (30 + 10*(^uint(0)>>32&1))]byte)(unsafe.Pointer(buff0))
nbyt := fsop.Write(path, buff[:size0], int64(ofst0), uint64(fi0.fh))
return c_int(nbyt)
}
@@ -346,7 +346,7 @@ func hostSetxattr(path0 *c_char, name0 *c_char, buff0 *c_char, size0 c_size_t,
fsop := hostHandleGet(c_fuse_get_context().private_data).fsop
path := c_GoString(path0)
name := c_GoString(name0)
- buff := (*[1 << 30]byte)(unsafe.Pointer(buff0))
+ buff := (*[1 << (30 + 10*(^uint(0)>>32&1))]byte)(unsafe.Pointer(buff0))
errc := fsop.Setxattr(path, name, buff[:size0], int(flags))
return c_int(errc)
}
@@ -364,7 +364,7 @@ func hostGetxattr(path0 *c_char, name0 *c_char, buff0 *c_char, size0 c_size_t) (
if len(rslt) > int(size0) {
return -c_int(ERANGE)
}
- buff := (*[1 << 30]byte)(unsafe.Pointer(buff0))
+ buff := (*[1 << (30 + 10*(^uint(0)>>32&1))]byte)(unsafe.Pointer(buff0))
copy(buff[:size0], rslt)
}
return c_int(len(rslt))
@@ -374,7 +374,7 @@ func hostListxattr(path0 *c_char, buff0 *c_char, size0 c_size_t) (nbyt0 c_int) {
defer recoverAsErrno(&nbyt0)
fsop := hostHandleGet(c_fuse_get_context().private_data).fsop
path := c_GoString(path0)
- buff := (*[1 << 30]byte)(unsafe.Pointer(buff0))
+ buff := (*[1 << (30 + 10*(^uint(0)>>32&1))]byte)(unsafe.Pointer(buff0))
size := int(size0)
nbyt := 0
fill := func(name1 string) bool {
@@ -599,7 +599,7 @@ func hostGetpath(path0 *c_char, buff0 *c_char, size0 c_size_t,
fifh = uint64(fi0.fh)
}
errc, rslt := intf.Getpath(path, fifh)
- buff := (*[1 << 30]byte)(unsafe.Pointer(buff0))
+ buff := (*[1 << (30 + 10*(^uint(0)>>32&1))]byte)(unsafe.Pointer(buff0))
copy(buff[:size0-1], rslt)
rlen := len(rslt)
if c_size_t(rlen) < size0 { |
|
And maybe specifying: const maxwidth = 1 << (30 + 10*(^uint(0)>>32&1))And then changing the buff := (*[maxwidth]byte)(unsafe.Pointer(buff0))Would be even better. |
9d910cf to
ef379a9
Compare
|
Thanks for the review, and for the clear explanation of the I agree that raising the fixed buffer view limit with a compile-time width check is a better fit for this codebase: it keeps the existing pattern, stays 32-bit safe, and still fixes the >1 GiB read issue we hit on 64-bit Windows. I've updated the PR to drop the const maxwidth = 1 << (30 + 10*(^uint(0)>>32&1))
buff := (*[maxwidth]byte)(unsafe.Pointer(buff0))at the affected call sites. The revised patch is pushed to the branch. Thanks again! |
Adopt maintainer suggestion: use a compile-time maxwidth constant (1 GiB on 32-bit, 1 TiB on 64-bit) instead of the fixed 1 GiB array view, so large Read/Write requests no longer panic before reaching the filesystem callback.
ef379a9 to
ec5fe93
Compare
|
Thank you. I have merged this in. |
This replaces the fixed
(*[1 << 30]byte)(unsafe.Pointer(...))buffer view with anunsafe.Sliceview sized to the actual request.Why this change:
hostRead,hostWrite,hostSetxattr,hostGetxattr,hostListxattr,hostReadlink, andhostGetpathis at most 1 GiB longbuff[:size0]can panic before the filesystem callback is reachedrecoverAsErrnothen converts that panic into-EIO, which surfaces as an unexpected I/O failure to the callerWhat this patch does:
size0-1Validation:
IO DEVICE ERRORfor a singleReadFilerequest larger than 1 GiB before this changego test ./fusepasses locally