aboutsummaryrefslogtreecommitdiff
path: root/en/devices/architecture/kernel/squashfs.html
blob: 93b97ad08c95cb869b1810f7edf61c8e679dd273 (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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
<html devsite>
  <head>
    <title>Optimizing SquashFS at the Kernel Level</title>
    <meta name="project_path" value="/_project.yaml" />
    <meta name="book_path" value="/_book.yaml" />
  </head>
  <body>
  <!--
      Copyright 2017 The Android Open Source Project

      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      See the License for the specific language governing permissions and
      limitations under the License.
  -->

    <p>
    SquashFS is a compressed read-only filesystem for Linux. The file system is
    read-only by design and thus suitable for use on the system partition. Many
    Android devices may benefit from using this file system for their system
    partition, for example, the following:
    </p><ul>
    <li>Devices with a low capacity storage such as Android Watch.
    <li>Devices with a slow flash storage (compression reduces the number of block
    I/Os).</li></ul>
    <p>
    Unfortunately the performance of SquashFS lags behind ext4.
    </p>
    <h2 id="optimizations">Optimizations</h2>
    <p>
    The following optimizations have been implemented to improve the performance of
    SquashFS.
    </p>
    <h3 id="reduce-the-memory-usage-and-memcpy">Reduce the memory usage and
    memcpy</h3>
    <p>
    When reading a block (default 128K), SquashFS tries to grab all the pages
    covering this block.
    </p>
    <p>
    If a single page is up-to-date or locked, it falls back to allocating a full
    block, submitting a read request, and then copying its content to the pages.
    </p>
    <p>
    This approach is very ineffective; after some time the page cache is likely to
    contain pages that are up-to-date even if the adjacent pages are not.
    </p>
    <p>
    The code is now able to handle blocks with holes (=missing pages).  This
    improves performance in the following ways:
    </p><ul>
      <li>Reduces the number of <code>memcpy</code> calls
    <li>Decreases memory allocations</li></ul>
    <h3 id="asynchronous-reads">Asynchronous reads</h3>
    <p>
    SquashFS still uses the deprecated <code>ll_rw_block()</code> function. There
    are two problems with this approach:
    </p><ul>
    <li>As the name implies, the function waits for the reads to complete before
    returning. This is redundant since <code>.readpage()</code> already waits on the
    page's lock. Moreover, we need an asynchronous mechanism to efficiently
    implement <code>.readpages()</code>.
    <li>Merging the read requests entirely depends on the I/O scheduler.
    <code>ll_rw_block()</code> simply creates one request per buffer. SquashFS has
    more information than the I/O scheduler about what should be merged. Moreover,
    merging the request means that we rely less on the I/O scheduler.</li></ul>
    <p>
    For these reasons, the  <code>ll_rw_block()</code> function has been replaced
    with <code>submit_bio()</code>.
    </p>
    <h3 id="readpages-prefetching">Readpages (prefetching)</h3>
    <p>
    SquashFS does not implement <code>.readpages()</code>, so the kernel repeatedly
    calls <code>.readpage()</code>.
    </p>
    <p>
    Now that our read requests are asynchronous, the kernel can truly prefetch pages
    using its asynchronous read-ahead mechanism.
    </p>
    <h3 id="optimize-reading-uncompressed-blocks">Optimize reading uncompressed
    blocks</h3>
    <p>
    Modern systems such as Android contain a lot of files that are already
    compressed. As a consequence, the image contains a lot of blocks that can't be
    compressed.
    </p>
    <p>
    SquashFS handles compressed and uncompressed blocks using the same logic: when
    asked to read a single page, it actually reads a full block (default 128k).
    While this is necessary for compressed blocks, it is just a waste of resources
    for uncompressed blocks.
    </p>
    <p>
    Instead of reading a full block, SquashFS now just reads what is advised by the
    readahead algorithm.
    </p>
    <p>
    This greatly improves the performance of random reads.
    </p>
    <h2 id="code">Code</h2>
    <p>
    SquashFS code optimizations are available in AOSP:
    </p><ul>
    <li><a
    href="https://android-review.googlesource.com/#/q/topic:squashfs">https://android-review.googlesource.com/#/q/topic:squashfs</a></li></ul>
  </body>
</html>