Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for Max Pages, which was introduced from Linux Kernel 4.20 #237

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion fuse.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ func (e *MountpointDoesNotExistError) Error() string {
// progress.
func Mount(dir string, options ...MountOption) (*Conn, error) {
conf := mountConfig{
options: make(map[string]string),
options: make(map[string]string),
maxPages: 32,
}
for _, option := range options {
if err := option(&conf); err != nil {
Expand Down Expand Up @@ -238,10 +239,20 @@ func initMount(c *Conn, conf *mountConfig) error {
MaxWrite: maxWrite,
Flags: InitBigWrites | conf.initFlags,
}

setMaxPages(r, s, conf)

r.Respond(s)
return nil
}

func setMaxPages(request *InitRequest, response *InitResponse, conf *mountConfig) {
if (request.Flags & InitMaxPages) == InitMaxPages {
response.Flags |= InitMaxPages
response.MaxPages = conf.maxPages
}
}

// A Request represents a single FUSE request received from the kernel.
// Use a type switch to determine the specific kind.
// A request of unrecognized type will have concrete type *Header.
Expand Down Expand Up @@ -1249,6 +1260,9 @@ type InitResponse struct {
// Maximum size of a single write operation.
// Linux enforces a minimum of 4 KiB.
MaxWrite uint32
// Maximum number of pages in a single write operation.
// Linux enforces a minimum of 32.
MaxPages uint16
}

func (r *InitResponse) String() string {
Expand All @@ -1264,12 +1278,14 @@ func (r *InitRequest) Respond(resp *InitResponse) {
out.MaxReadahead = resp.MaxReadahead
out.Flags = uint32(resp.Flags)
out.MaxWrite = resp.MaxWrite
out.MaxPages = resp.MaxPages

// MaxWrite larger than our receive buffer would just lead to
// errors on large writes.
if out.MaxWrite > maxWrite {
out.MaxWrite = maxWrite
}

r.respond(buf)
}

Expand Down
4 changes: 4 additions & 0 deletions fuse_kernel.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,8 @@ const (
InitWritebackCache InitFlags = 1 << 16
InitNoOpenSupport InitFlags = 1 << 17

InitMaxPages InitFlags = 1 << 22 // Linux only

InitCaseSensitive InitFlags = 1 << 29 // OS X only
InitVolRename InitFlags = 1 << 30 // OS X only
InitXtimes InitFlags = 1 << 31 // OS X only
Expand Down Expand Up @@ -708,6 +710,8 @@ type initOut struct {
Flags uint32
Unused uint32
MaxWrite uint32
_ uint32 // Unused, refers to TimeGran
MaxPages uint16
}

type interruptIn struct {
Expand Down
4 changes: 3 additions & 1 deletion fuse_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ package fuse
//
// Linux 4.2.0 has been observed to cap this value at 128kB
// (FUSE_MAX_PAGES_PER_REQ=32, 4kB pages).
const maxWrite = 128 * 1024
// From Linux 4.20, the cap has been increased to 1MiB
// (FUSE_MAX_PAGES_PER_REQ=256, 4kB pages).
const maxWrite = 1 * 1024 * 1024 // 1 MiB
9 changes: 9 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type mountConfig struct {
maxReadahead uint32
initFlags InitFlags
osxfuseLocations []OSXFUSEPaths
maxPages uint16
}

func escapeComma(s string) string {
Expand Down Expand Up @@ -294,3 +295,11 @@ func AllowNonEmptyMount() MountOption {
return nil
}
}

// EnableMaxPages enables the configuration of the maximum number of pages
// in the request & response from the kernel.
//
// Linux only. Others ignore this option.
func MaxPages(count uint16) MountOption {
return maxPages(count)
}
4 changes: 4 additions & 0 deletions options_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,7 @@ func noBrowse(conf *mountConfig) error {
conf.options["nobrowse"] = ""
return nil
}

func maxPages(count uint16) MountOption {
return dummyOption
}
4 changes: 4 additions & 0 deletions options_freebsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,7 @@ func exclCreate(conf *mountConfig) error {
func noBrowse(conf *mountConfig) error {
return nil
}

func maxPages(count uint16) MountOption {
return dummyOption
}
12 changes: 12 additions & 0 deletions options_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,15 @@ func exclCreate(conf *mountConfig) error {
func noBrowse(conf *mountConfig) error {
return nil
}

func maxPages(count uint16) MountOption {
return func(conf *mountConfig) error {
if count < 32 {
count = 32 // The minimum allowed by the kernel
} else if count > 256 {
count = 256 // The maximum allowed by the kernel
}
conf.maxPages = count
return nil
}
}