From 6a86ec70eaf29537fdbf02af10e536ee1d8e4fa9 Mon Sep 17 00:00:00 2001 From: Anagh Kumar Baranwal <6824881+darthShadow@users.noreply.github.com> Date: Mon, 10 Feb 2020 10:27:22 +0530 Subject: [PATCH] Added support for Max Pages Signed-off-by: Anagh Kumar Baranwal <6824881+darthShadow@users.noreply.github.com> --- cmd/mount/mount.go | 3 +++ fs/config/flags/flags.go | 8 ++++++++ vendor/bazil.org/fuse/fuse.go | 18 +++++++++++++++++- vendor/bazil.org/fuse/fuse_kernel.go | 4 ++++ vendor/bazil.org/fuse/fuse_linux.go | 4 +++- vendor/bazil.org/fuse/options.go | 9 +++++++++ vendor/bazil.org/fuse/options_darwin.go | 4 ++++ vendor/bazil.org/fuse/options_freebsd.go | 4 ++++ vendor/bazil.org/fuse/options_linux.go | 10 ++++++++++ vfs/vfs.go | 2 ++ vfs/vfsflags/vfsflags_linux.go | 22 ++++++++++++++++++++++ vfs/vfsflags/vfsflags_unix.go | 2 +- 12 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 vfs/vfsflags/vfsflags_linux.go diff --git a/cmd/mount/mount.go b/cmd/mount/mount.go index 7a086dd30..8819a0411 100644 --- a/cmd/mount/mount.go +++ b/cmd/mount/mount.go @@ -73,6 +73,9 @@ func mountOptions(device string) (options []fuse.MountOption) { if len(mountlib.ExtraFlags) > 0 { fs.Errorf(nil, "--fuse-flag not supported with this FUSE backend") } + if vfsflags.Opt.MaxPages != 0 { + options = append(options, fuse.MaxPages(vfsflags.Opt.MaxPages)) + } return options } diff --git a/fs/config/flags/flags.go b/fs/config/flags/flags.go index bd27810fa..330b7514d 100644 --- a/fs/config/flags/flags.go +++ b/fs/config/flags/flags.go @@ -98,6 +98,14 @@ func IntVarP(flags *pflag.FlagSet, p *int, name, shorthand string, value int, us setDefaultFromEnv(flags, name) } +// Uint16VarP defines a flag which can be overridden by an environment variable +// +// It is a thin wrapper around pflag.Uint16VarP +func Uint16VarP(flags *pflag.FlagSet, p *uint16, name, shorthand string, value uint16, usage string) { + flags.Uint16VarP(p, name, shorthand, value, usage) + setDefaultFromEnv(flags, name) +} + // Uint32VarP defines a flag which can be overridden by an environment variable // // It is a thin wrapper around pflag.Uint32VarP diff --git a/vendor/bazil.org/fuse/fuse.go b/vendor/bazil.org/fuse/fuse.go index cd5833843..431669cd2 100644 --- a/vendor/bazil.org/fuse/fuse.go +++ b/vendor/bazil.org/fuse/fuse.go @@ -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 { @@ -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. @@ -1229,6 +1240,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 { @@ -1244,12 +1258,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) } diff --git a/vendor/bazil.org/fuse/fuse_kernel.go b/vendor/bazil.org/fuse/fuse_kernel.go index 44b1fec0f..89277d326 100644 --- a/vendor/bazil.org/fuse/fuse_kernel.go +++ b/vendor/bazil.org/fuse/fuse_kernel.go @@ -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 @@ -710,6 +712,8 @@ type initOut struct { Flags uint32 Unused uint32 MaxWrite uint32 + _ uint32 // Unused, refers to TimeGran + MaxPages uint16 } type interruptIn struct { diff --git a/vendor/bazil.org/fuse/fuse_linux.go b/vendor/bazil.org/fuse/fuse_linux.go index 5fb96f9ae..a1e414b19 100644 --- a/vendor/bazil.org/fuse/fuse_linux.go +++ b/vendor/bazil.org/fuse/fuse_linux.go @@ -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 diff --git a/vendor/bazil.org/fuse/options.go b/vendor/bazil.org/fuse/options.go index d7abf2b7f..0aaee65e7 100644 --- a/vendor/bazil.org/fuse/options.go +++ b/vendor/bazil.org/fuse/options.go @@ -16,6 +16,7 @@ type mountConfig struct { maxReadahead uint32 initFlags InitFlags osxfuseLocations []OSXFUSEPaths + maxPages uint16 } func escapeComma(s string) string { @@ -317,3 +318,11 @@ func AllowNonEmptyMount() MountOption { return nil } } + +// MaxPages 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) +} diff --git a/vendor/bazil.org/fuse/options_darwin.go b/vendor/bazil.org/fuse/options_darwin.go index a85e64cbf..f82faa581 100644 --- a/vendor/bazil.org/fuse/options_darwin.go +++ b/vendor/bazil.org/fuse/options_darwin.go @@ -38,3 +38,7 @@ func noBrowse(conf *mountConfig) error { conf.options["nobrowse"] = "" return nil } + +func maxPages(count uint16) MountOption { + return dummyOption +} diff --git a/vendor/bazil.org/fuse/options_freebsd.go b/vendor/bazil.org/fuse/options_freebsd.go index 2c956e7fb..e62f9c6f6 100644 --- a/vendor/bazil.org/fuse/options_freebsd.go +++ b/vendor/bazil.org/fuse/options_freebsd.go @@ -30,3 +30,7 @@ func exclCreate(conf *mountConfig) error { func noBrowse(conf *mountConfig) error { return nil } + +func maxPages(count uint16) MountOption { + return dummyOption +} diff --git a/vendor/bazil.org/fuse/options_linux.go b/vendor/bazil.org/fuse/options_linux.go index 2c925b18d..87ed7045f 100644 --- a/vendor/bazil.org/fuse/options_linux.go +++ b/vendor/bazil.org/fuse/options_linux.go @@ -27,3 +27,13 @@ func exclCreate(conf *mountConfig) error { func noBrowse(conf *mountConfig) error { return nil } + +func maxPages(count uint16) MountOption { + return func(conf *mountConfig) error { + if count > 256 || count == 0 { + count = 256 + } + conf.maxPages = count + return nil + } +} diff --git a/vfs/vfs.go b/vfs/vfs.go index 58e7630b1..e5ee5027b 100644 --- a/vfs/vfs.go +++ b/vfs/vfs.go @@ -55,6 +55,7 @@ var DefaultOpt = Options{ CaseInsensitive: runtime.GOOS == "windows" || runtime.GOOS == "darwin", // default to true on Windows and Mac, false otherwise WriteWait: 1000 * time.Millisecond, ReadWait: 5 * time.Millisecond, + MaxPages: 0, // Only for Linux } // Node represents either a directory (*Dir) or a file (*File) @@ -206,6 +207,7 @@ type Options struct { CaseInsensitive bool WriteWait time.Duration // time to wait for in-sequence write ReadWait time.Duration // time to wait for in-sequence read + MaxPages uint16 } // New creates a new VFS and root directory. If opt is nil, then diff --git a/vfs/vfsflags/vfsflags_linux.go b/vfs/vfsflags/vfsflags_linux.go new file mode 100644 index 000000000..ca2c671de --- /dev/null +++ b/vfs/vfsflags/vfsflags_linux.go @@ -0,0 +1,22 @@ +// +build linux + +package vfsflags + +import ( + "github.com/rclone/rclone/fs/config/flags" + "github.com/spf13/pflag" + "golang.org/x/sys/unix" +) + +// add any extra platform specific flags +func platformFlags(flagSet *pflag.FlagSet) { + flags.IntVarP(flagSet, &Opt.Umask, "umask", "", Opt.Umask, "Override the permission bits set by the filesystem.") + Opt.Umask = unix.Umask(0) // read the umask + unix.Umask(Opt.Umask) // set it back to what it was + Opt.UID = uint32(unix.Geteuid()) + Opt.GID = uint32(unix.Getegid()) + flags.Uint32VarP(flagSet, &Opt.UID, "uid", "", Opt.UID, "Override the uid field set by the filesystem.") + flags.Uint32VarP(flagSet, &Opt.GID, "gid", "", Opt.GID, "Override the gid field set by the filesystem.") + + flags.Uint16VarP(flagSet, &Opt.MaxPages, "max-pages", "", Opt.MaxPages, "Set the Max Pages to be passed onto the FUSE library") +} diff --git a/vfs/vfsflags/vfsflags_unix.go b/vfs/vfsflags/vfsflags_unix.go index 36fe6335d..87fa3b59c 100644 --- a/vfs/vfsflags/vfsflags_unix.go +++ b/vfs/vfsflags/vfsflags_unix.go @@ -1,4 +1,4 @@ -// +build linux darwin freebsd +// +build darwin freebsd package vfsflags