diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-02 12:59:09 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-02 12:59:09 -0400 |
commit | 8747a29173c6eb6f4b3e8d3b3bcabc0fa132678a (patch) | |
tree | e9c58072f6b681788c4692cb5b219e8d05bef330 /tools | |
parent | cc67ccecd3e6e2827b6706bad3287786202498f5 (diff) | |
parent | c4fb5f37001514c0004d17b79cf74a499b9bc320 (diff) |
Merge branch 'core-rcu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull RCU updates from Ingo Molnar:
"The main RCU subsystem changes in this cycle were:
- Miscellaneous fixes, perhaps most notably removing obsolete code
whose only purpose in life was to gather information for the
now-removed RCU debugfs facility. Other notable changes include
removing NO_HZ_FULL_ALL in favor of the nohz_full kernel boot
parameter, minor optimizations for expedited grace periods, some
added tracing, creating an RCU-specific workqueue using Tejun's new
WQ_MEM_RECLAIM flag, and several cleanups to code and comments.
- SRCU cleanups and optimizations.
- Torture-test updates, perhaps most notably the adding of ARMv8
support, but also including numerous cleanups and usability fixes"
* 'core-rcu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (37 commits)
rcu: Create RCU-specific workqueues with rescuers
torture: Provide more sensible nreader/nwriter defaults for rcuperf
torture: Grace periods do not piggyback off of themselves
torture: Adjust rcuperf trace processing to allow for workqueues
torture: Default jitter off when running rcuperf
torture: Specify qemu memory size with --memory argument
rcutorture: Add basic ARM64 support to run scripts
rcutorture: Update kvm.sh header comment
rcutorture: Record which grace-period primitives are tested
rcutorture: Re-enable testing of dynamic expediting
rcutorture: Avoid fake-writer use of undefined primitives
rcutorture: Abstract function and module names
rcutorture: Replace multi-instance kzalloc() with kcalloc()
rcu: Remove SRCU throttling
srcu: Remove dead code in srcu_gp_end()
srcu: Reduce scans of srcu_data in counter wrap check
srcu: Prevent sdp->srcu_gp_seq_needed_exp counter wrap
srcu: Abstract function name
rcu: Make expedited RCU CPU selection avoid unnecessary stores
rcu: Trace expedited GP delays due to transitioning CPUs
...
Diffstat (limited to 'tools')
11 files changed, 44 insertions, 43 deletions
diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh b/tools/testing/selftests/rcutorture/bin/functions.sh index 07a13779eece..65f6655026f0 100644 --- a/tools/testing/selftests/rcutorture/bin/functions.sh +++ b/tools/testing/selftests/rcutorture/bin/functions.sh | |||
@@ -136,6 +136,9 @@ identify_boot_image () { | |||
136 | qemu-system-x86_64|qemu-system-i386) | 136 | qemu-system-x86_64|qemu-system-i386) |
137 | echo arch/x86/boot/bzImage | 137 | echo arch/x86/boot/bzImage |
138 | ;; | 138 | ;; |
139 | qemu-system-aarch64) | ||
140 | echo arch/arm64/boot/Image | ||
141 | ;; | ||
139 | *) | 142 | *) |
140 | echo vmlinux | 143 | echo vmlinux |
141 | ;; | 144 | ;; |
@@ -158,6 +161,9 @@ identify_qemu () { | |||
158 | elif echo $u | grep -q "Intel 80386" | 161 | elif echo $u | grep -q "Intel 80386" |
159 | then | 162 | then |
160 | echo qemu-system-i386 | 163 | echo qemu-system-i386 |
164 | elif echo $u | grep -q aarch64 | ||
165 | then | ||
166 | echo qemu-system-aarch64 | ||
161 | elif uname -a | grep -q ppc64 | 167 | elif uname -a | grep -q ppc64 |
162 | then | 168 | then |
163 | echo qemu-system-ppc64 | 169 | echo qemu-system-ppc64 |
@@ -176,16 +182,20 @@ identify_qemu () { | |||
176 | # Output arguments for the qemu "-append" string based on CPU type | 182 | # Output arguments for the qemu "-append" string based on CPU type |
177 | # and the TORTURE_QEMU_INTERACTIVE environment variable. | 183 | # and the TORTURE_QEMU_INTERACTIVE environment variable. |
178 | identify_qemu_append () { | 184 | identify_qemu_append () { |
185 | local console=ttyS0 | ||
179 | case "$1" in | 186 | case "$1" in |
180 | qemu-system-x86_64|qemu-system-i386) | 187 | qemu-system-x86_64|qemu-system-i386) |
181 | echo noapic selinux=0 initcall_debug debug | 188 | echo noapic selinux=0 initcall_debug debug |
182 | ;; | 189 | ;; |
190 | qemu-system-aarch64) | ||
191 | console=ttyAMA0 | ||
192 | ;; | ||
183 | esac | 193 | esac |
184 | if test -n "$TORTURE_QEMU_INTERACTIVE" | 194 | if test -n "$TORTURE_QEMU_INTERACTIVE" |
185 | then | 195 | then |
186 | echo root=/dev/sda | 196 | echo root=/dev/sda |
187 | else | 197 | else |
188 | echo console=ttyS0 | 198 | echo console=$console |
189 | fi | 199 | fi |
190 | } | 200 | } |
191 | 201 | ||
@@ -197,6 +207,9 @@ identify_qemu_args () { | |||
197 | case "$1" in | 207 | case "$1" in |
198 | qemu-system-x86_64|qemu-system-i386) | 208 | qemu-system-x86_64|qemu-system-i386) |
199 | ;; | 209 | ;; |
210 | qemu-system-aarch64) | ||
211 | echo -machine virt,gic-version=host -cpu host | ||
212 | ;; | ||
200 | qemu-system-ppc64) | 213 | qemu-system-ppc64) |
201 | echo -enable-kvm -M pseries -nodefaults | 214 | echo -enable-kvm -M pseries -nodefaults |
202 | echo -device spapr-vscsi | 215 | echo -device spapr-vscsi |
@@ -254,7 +267,7 @@ specify_qemu_cpus () { | |||
254 | echo $2 | 267 | echo $2 |
255 | else | 268 | else |
256 | case "$1" in | 269 | case "$1" in |
257 | qemu-system-x86_64|qemu-system-i386) | 270 | qemu-system-x86_64|qemu-system-i386|qemu-system-aarch64) |
258 | echo $2 -smp $3 | 271 | echo $2 -smp $3 |
259 | ;; | 272 | ;; |
260 | qemu-system-ppc64) | 273 | qemu-system-ppc64) |
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh index 963f71289d22..8948f7926b21 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh | |||
@@ -39,30 +39,31 @@ sed -e 's/us : / : /' | | |||
39 | tr -d '\015' | | 39 | tr -d '\015' | |
40 | awk ' | 40 | awk ' |
41 | $8 == "start" { | 41 | $8 == "start" { |
42 | if (starttask != "") | 42 | if (startseq != "") |
43 | nlost++; | 43 | nlost++; |
44 | starttask = $1; | 44 | starttask = $1; |
45 | starttime = $3; | 45 | starttime = $3; |
46 | startseq = $7; | 46 | startseq = $7; |
47 | seqtask[startseq] = starttask; | ||
47 | } | 48 | } |
48 | 49 | ||
49 | $8 == "end" { | 50 | $8 == "end" { |
50 | if (starttask == $1 && startseq == $7) { | 51 | if (startseq == $7) { |
51 | curgpdur = $3 - starttime; | 52 | curgpdur = $3 - starttime; |
52 | gptimes[++n] = curgpdur; | 53 | gptimes[++n] = curgpdur; |
53 | gptaskcnt[starttask]++; | 54 | gptaskcnt[starttask]++; |
54 | sum += curgpdur; | 55 | sum += curgpdur; |
55 | if (curgpdur > 1000) | 56 | if (curgpdur > 1000) |
56 | print "Long GP " starttime "us to " $3 "us (" curgpdur "us)"; | 57 | print "Long GP " starttime "us to " $3 "us (" curgpdur "us)"; |
57 | starttask = ""; | 58 | startseq = ""; |
58 | } else { | 59 | } else { |
59 | # Lost a message or some such, reset. | 60 | # Lost a message or some such, reset. |
60 | starttask = ""; | 61 | startseq = ""; |
61 | nlost++; | 62 | nlost++; |
62 | } | 63 | } |
63 | } | 64 | } |
64 | 65 | ||
65 | $8 == "done" { | 66 | $8 == "done" && seqtask[$7] != $1 { |
66 | piggybackcnt[$1]++; | 67 | piggybackcnt[$1]++; |
67 | } | 68 | } |
68 | 69 | ||
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh index 1b78a12740e5..5f8fbb0d7c17 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh | |||
@@ -177,8 +177,8 @@ then | |||
177 | exit 0 | 177 | exit 0 |
178 | fi | 178 | fi |
179 | echo "NOTE: $QEMU either did not run or was interactive" > $resdir/console.log | 179 | echo "NOTE: $QEMU either did not run or was interactive" > $resdir/console.log |
180 | echo $QEMU $qemu_args -m 512 -kernel $KERNEL -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd | 180 | echo $QEMU $qemu_args -m $TORTURE_QEMU_MEM -kernel $KERNEL -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd |
181 | ( $QEMU $qemu_args -m 512 -kernel $KERNEL -append "$qemu_append $boot_args"& echo $! > $resdir/qemu_pid; wait `cat $resdir/qemu_pid`; echo $? > $resdir/qemu-retval ) & | 181 | ( $QEMU $qemu_args -m $TORTURE_QEMU_MEM -kernel $KERNEL -append "$qemu_append $boot_args"& echo $! > $resdir/qemu_pid; wait `cat $resdir/qemu_pid`; echo $? > $resdir/qemu-retval ) & |
182 | commandcompleted=0 | 182 | commandcompleted=0 |
183 | sleep 10 # Give qemu's pid a chance to reach the file | 183 | sleep 10 # Give qemu's pid a chance to reach the file |
184 | if test -s "$resdir/qemu_pid" | 184 | if test -s "$resdir/qemu_pid" |
diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index 7d1f607f0f76..56610dbbdf73 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh | |||
@@ -1,10 +1,8 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | # | 2 | # |
3 | # Run a series of 14 tests under KVM. These are not particularly | 3 | # Run a series of tests under KVM. By default, this series is specified |
4 | # well-selected or well-tuned, but are the current set. | 4 | # by the relevant CFLIST file, but can be overridden by the --configs |
5 | # | 5 | # command-line argument. |
6 | # Edit the definitions below to set the locations of the various directories, | ||
7 | # as well as the test duration. | ||
8 | # | 6 | # |
9 | # Usage: kvm.sh [ options ] | 7 | # Usage: kvm.sh [ options ] |
10 | # | 8 | # |
@@ -44,6 +42,7 @@ TORTURE_BOOT_IMAGE="" | |||
44 | TORTURE_INITRD="$KVM/initrd"; export TORTURE_INITRD | 42 | TORTURE_INITRD="$KVM/initrd"; export TORTURE_INITRD |
45 | TORTURE_KCONFIG_ARG="" | 43 | TORTURE_KCONFIG_ARG="" |
46 | TORTURE_KMAKE_ARG="" | 44 | TORTURE_KMAKE_ARG="" |
45 | TORTURE_QEMU_MEM=512 | ||
47 | TORTURE_SHUTDOWN_GRACE=180 | 46 | TORTURE_SHUTDOWN_GRACE=180 |
48 | TORTURE_SUITE=rcu | 47 | TORTURE_SUITE=rcu |
49 | resdir="" | 48 | resdir="" |
@@ -70,6 +69,7 @@ usage () { | |||
70 | echo " --kconfig Kconfig-options" | 69 | echo " --kconfig Kconfig-options" |
71 | echo " --kmake-arg kernel-make-arguments" | 70 | echo " --kmake-arg kernel-make-arguments" |
72 | echo " --mac nn:nn:nn:nn:nn:nn" | 71 | echo " --mac nn:nn:nn:nn:nn:nn" |
72 | echo " --memory megabytes | nnnG" | ||
73 | echo " --no-initrd" | 73 | echo " --no-initrd" |
74 | echo " --qemu-args qemu-arguments" | 74 | echo " --qemu-args qemu-arguments" |
75 | echo " --qemu-cmd qemu-system-..." | 75 | echo " --qemu-cmd qemu-system-..." |
@@ -147,6 +147,11 @@ do | |||
147 | TORTURE_QEMU_MAC=$2 | 147 | TORTURE_QEMU_MAC=$2 |
148 | shift | 148 | shift |
149 | ;; | 149 | ;; |
150 | --memory) | ||
151 | checkarg --memory "(memory size)" $# "$2" '^[0-9]\+[MG]\?$' error | ||
152 | TORTURE_QEMU_MEM=$2 | ||
153 | shift | ||
154 | ;; | ||
150 | --no-initrd) | 155 | --no-initrd) |
151 | TORTURE_INITRD=""; export TORTURE_INITRD | 156 | TORTURE_INITRD=""; export TORTURE_INITRD |
152 | ;; | 157 | ;; |
@@ -174,6 +179,12 @@ do | |||
174 | checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\|rcuperf\)$' '^--' | 179 | checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\|rcuperf\)$' '^--' |
175 | TORTURE_SUITE=$2 | 180 | TORTURE_SUITE=$2 |
176 | shift | 181 | shift |
182 | if test "$TORTURE_SUITE" = rcuperf | ||
183 | then | ||
184 | # If you really want jitter for rcuperf, specify | ||
185 | # it after specifying rcuperf. (But why?) | ||
186 | jitter=0 | ||
187 | fi | ||
177 | ;; | 188 | ;; |
178 | *) | 189 | *) |
179 | echo Unknown argument $1 | 190 | echo Unknown argument $1 |
@@ -288,6 +299,7 @@ TORTURE_KMAKE_ARG="$TORTURE_KMAKE_ARG"; export TORTURE_KMAKE_ARG | |||
288 | TORTURE_QEMU_CMD="$TORTURE_QEMU_CMD"; export TORTURE_QEMU_CMD | 299 | TORTURE_QEMU_CMD="$TORTURE_QEMU_CMD"; export TORTURE_QEMU_CMD |
289 | TORTURE_QEMU_INTERACTIVE="$TORTURE_QEMU_INTERACTIVE"; export TORTURE_QEMU_INTERACTIVE | 300 | TORTURE_QEMU_INTERACTIVE="$TORTURE_QEMU_INTERACTIVE"; export TORTURE_QEMU_INTERACTIVE |
290 | TORTURE_QEMU_MAC="$TORTURE_QEMU_MAC"; export TORTURE_QEMU_MAC | 301 | TORTURE_QEMU_MAC="$TORTURE_QEMU_MAC"; export TORTURE_QEMU_MAC |
302 | TORTURE_QEMU_MEM="$TORTURE_QEMU_MEM"; export TORTURE_QEMU_MEM | ||
291 | TORTURE_SHUTDOWN_GRACE="$TORTURE_SHUTDOWN_GRACE"; export TORTURE_SHUTDOWN_GRACE | 303 | TORTURE_SHUTDOWN_GRACE="$TORTURE_SHUTDOWN_GRACE"; export TORTURE_SHUTDOWN_GRACE |
292 | TORTURE_SUITE="$TORTURE_SUITE"; export TORTURE_SUITE | 304 | TORTURE_SUITE="$TORTURE_SUITE"; export TORTURE_SUITE |
293 | if ! test -e $resdir | 305 | if ! test -e $resdir |
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS03 b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03 index c70c51d5ded1..28568b72a31b 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TASKS03 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03 | |||
@@ -9,5 +9,4 @@ CONFIG_PREEMPT=y | |||
9 | CONFIG_HZ_PERIODIC=n | 9 | CONFIG_HZ_PERIODIC=n |
10 | CONFIG_NO_HZ_IDLE=n | 10 | CONFIG_NO_HZ_IDLE=n |
11 | CONFIG_NO_HZ_FULL=y | 11 | CONFIG_NO_HZ_FULL=y |
12 | CONFIG_NO_HZ_FULL_ALL=y | ||
13 | #CHECK#CONFIG_RCU_EXPERT=n | 12 | #CHECK#CONFIG_RCU_EXPERT=n |
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot index cd2a188eeb6d..838297c58318 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot +++ b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot | |||
@@ -1 +1 @@ | |||
rcutorture.torture_type=tasks | rcutorture.torture_type=tasks nohz_full=1 | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 b/tools/testing/selftests/rcutorture/configs/rcu/TREE04 index 27d22695d64c..24c9f6012e35 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE04 | |||
@@ -7,7 +7,6 @@ CONFIG_PREEMPT=n | |||
7 | CONFIG_HZ_PERIODIC=n | 7 | CONFIG_HZ_PERIODIC=n |
8 | CONFIG_NO_HZ_IDLE=n | 8 | CONFIG_NO_HZ_IDLE=n |
9 | CONFIG_NO_HZ_FULL=y | 9 | CONFIG_NO_HZ_FULL=y |
10 | CONFIG_NO_HZ_FULL_ALL=y | ||
11 | CONFIG_RCU_FAST_NO_HZ=y | 10 | CONFIG_RCU_FAST_NO_HZ=y |
12 | CONFIG_RCU_TRACE=y | 11 | CONFIG_RCU_TRACE=y |
13 | CONFIG_HOTPLUG_CPU=n | 12 | CONFIG_HOTPLUG_CPU=n |
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot index e34c33430447..e6071bb96c7d 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot | |||
@@ -1 +1 @@ | |||
rcutorture.torture_type=rcu_bh rcutree.rcu_fanout_leaf=4 | rcutorture.torture_type=rcu_bh rcutree.rcu_fanout_leaf=4 nohz_full=1-7 | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE07 b/tools/testing/selftests/rcutorture/configs/rcu/TREE07 index 0f4759f4232e..d7afb271a586 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE07 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE07 | |||
@@ -7,7 +7,6 @@ CONFIG_PREEMPT=n | |||
7 | CONFIG_HZ_PERIODIC=n | 7 | CONFIG_HZ_PERIODIC=n |
8 | CONFIG_NO_HZ_IDLE=n | 8 | CONFIG_NO_HZ_IDLE=n |
9 | CONFIG_NO_HZ_FULL=y | 9 | CONFIG_NO_HZ_FULL=y |
10 | CONFIG_NO_HZ_FULL_ALL=n | ||
11 | CONFIG_RCU_FAST_NO_HZ=n | 10 | CONFIG_RCU_FAST_NO_HZ=n |
12 | CONFIG_RCU_TRACE=y | 11 | CONFIG_RCU_TRACE=y |
13 | CONFIG_HOTPLUG_CPU=y | 12 | CONFIG_HOTPLUG_CPU=y |
diff --git a/tools/testing/selftests/rcutorture/configs/rcuperf/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcuperf/ver_functions.sh index b9603115d7c7..d36b8fd6f0fc 100644 --- a/tools/testing/selftests/rcutorture/configs/rcuperf/ver_functions.sh +++ b/tools/testing/selftests/rcutorture/configs/rcuperf/ver_functions.sh | |||
@@ -20,32 +20,10 @@ | |||
20 | # | 20 | # |
21 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 21 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> |
22 | 22 | ||
23 | # rcuperf_param_nreaders bootparam-string | ||
24 | # | ||
25 | # Adds nreaders rcuperf module parameter if not already specified. | ||
26 | rcuperf_param_nreaders () { | ||
27 | if ! echo "$1" | grep -q "rcuperf.nreaders" | ||
28 | then | ||
29 | echo rcuperf.nreaders=-1 | ||
30 | fi | ||
31 | } | ||
32 | |||
33 | # rcuperf_param_nwriters bootparam-string | ||
34 | # | ||
35 | # Adds nwriters rcuperf module parameter if not already specified. | ||
36 | rcuperf_param_nwriters () { | ||
37 | if ! echo "$1" | grep -q "rcuperf.nwriters" | ||
38 | then | ||
39 | echo rcuperf.nwriters=-1 | ||
40 | fi | ||
41 | } | ||
42 | |||
43 | # per_version_boot_params bootparam-string config-file seconds | 23 | # per_version_boot_params bootparam-string config-file seconds |
44 | # | 24 | # |
45 | # Adds per-version torture-module parameters to kernels supporting them. | 25 | # Adds per-version torture-module parameters to kernels supporting them. |
46 | per_version_boot_params () { | 26 | per_version_boot_params () { |
47 | echo $1 `rcuperf_param_nreaders "$1"` \ | 27 | echo $1 rcuperf.shutdown=1 \ |
48 | `rcuperf_param_nwriters "$1"` \ | ||
49 | rcuperf.shutdown=1 \ | ||
50 | rcuperf.verbose=1 | 28 | rcuperf.verbose=1 |
51 | } | 29 | } |
diff --git a/tools/testing/selftests/rcutorture/doc/rcu-test-image.txt b/tools/testing/selftests/rcutorture/doc/rcu-test-image.txt index 66efb59a1bd1..449cf579d6f9 100644 --- a/tools/testing/selftests/rcutorture/doc/rcu-test-image.txt +++ b/tools/testing/selftests/rcutorture/doc/rcu-test-image.txt | |||
@@ -1,4 +1,4 @@ | |||
1 | This document describes one way to created the rcu-test-image file | 1 | This document describes one way to create the rcu-test-image file |
2 | that contains the filesystem used by the guest-OS kernel. There are | 2 | that contains the filesystem used by the guest-OS kernel. There are |
3 | probably much better ways of doing this, and this filesystem could no | 3 | probably much better ways of doing this, and this filesystem could no |
4 | doubt be smaller. It is probably also possible to simply download | 4 | doubt be smaller. It is probably also possible to simply download |