summaryrefslogtreecommitdiff
path: root/AEpy/FusePatches.py
blob: f02ddd2a2a186e8144fee757d495ff2934a39c87 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# Ugly patches for fusepy to accommodate inflexible userspace applications.
#

from ctypes import c_uint, cast, POINTER, Structure
from fusepy import FUSE


class fuse_conn_info(Structure):
    _fields_ = [
        ('proto_major', c_uint),
        ('proto_minor', c_uint),
        ('async_read', c_uint),
        ('max_write', c_uint),
        ('max_readahead', c_uint),
        ('capable', c_uint),
        ('want', c_uint),
        ('max_background', c_uint),
        ('congestion_threshold', c_uint)
    ]


# Ugly patch for fusepy to allow changing max_readahead.
#
# This is necessary for FUSE filesystems which need to avoid unnecessary
# data transfers.
#
# Example:
# If a GIO (as in GLib/GNOME's GIO) based file manager (e.g. XFCE's Thunar)
# tries to determine each file's type by inspecting its header (GLib 2.50
# reads up to 4 KB of each file), this results in a lot of traffic. If the
# kernel increases this to 16 KB as part of its buffered I/O's readahead,
# things become very slow on exotically slow links or host media.
# In fact, this patch has been written with a 2 KByte/s link in mind.
#
# Why not turn off this header-sniffing feature in userspace?
# Because... Neither Thunar nor GLib/GIO have this option, and exotic FUSE
# filesystems still need to work on them until they have a mechanism to turn
# this off. Preferably with a hint in stat() or statfs().
#
# NOTE:
# The kernel will impose a lower bound on max_readahead.
# As of 4.9 on x86-64, this is 4096 bytes.
# (still a lot on a 2 KB/s link, but Thunar won't be *completely* useless)
#
def patch_max_readahead(max_readahead):
    old_init = FUSE.init

    def _new_fuse_init(self, conn):
        conn2 = cast(conn, POINTER(fuse_conn_info))
        conn2.contents.max_readahead = max_readahead
        return old_init(self, conn)

    FUSE.init = _new_fuse_init