
The Symptom
qBittorrent would start a torrent at a decent 2-3 MB/s and then crawl to zero within a couple of minutes. I tested with an Ubuntu ISO where the tracker reported over two thousand seeders, and still only a handful of peers would actually connect. At the same time Jellyfin streams felt laggy, and a few other containers bind-mounting the same NAS share were doing everything a little slower than they should.
The common denominator was obvious in hindsight: every affected service was reading from, or writing to, the same CIFS mount.
The Real Culprit
Rocky 9 ships with kernel 5.14, and that kernel sets cache=strict as the default for CIFS. There is a well-documented regression in that code path where __readahead_batch() returns a partial batch under heavy random IO. Once the kernel hits that state, the mount builds up backpressure and reads/writes start stalling in unpredictable ways.
Red Hat has a solution article for it (#7107471, subscriber only), and libtorrent and qBittorrent both have upstream issues tracking the same symptom. The fun part is that the default mount options most guides recommend make it worse, not better.
“But Shouldn’t This Affect Every CIFS Read?”
Yes. And it does. That was the most confusing part of debugging this.
BitTorrent just happens to be the loudest victim because it does small, random, concurrent writes while simultaneously reading pieces back for hash checking and seeding. That workload hits the broken readahead path hard and immediately: peers time out, libtorrent stops accepting new connections, and the download flatlines in a way you cannot miss.
Other services on the same mount were affected too, they were just quieter about it:
- Jellyfin streamed video fine most of the time because sequential reads with large block sizes work around the bug. But seeking and library scans were noticeably slow.
- Syncthing took longer than expected on large file sets but did not error out.
- Paperless-ngx and Photoprism felt generally sluggish during indexing, which I had written off as “that’s just how indexing feels.”
Basically, if you have a service on kernel 5.14 CIFS that you think is slow but not broken, it is probably also suffering. Torrents were just the canary in the coal mine.
The Fix
The fix is entirely in /etc/fstab. Here is what I had before, which is pretty much what every “how to mount CIFS on Linux” tutorial will tell you to write:
//192.168.1.10/share /mnt/share cifs credentials=/.smbcredentials,uid=1000,gid=1000,vers=3.1.1,noperm,rsize=65536,_netdev 0 0
And here is what actually works on a modern kernel with a modern SMB server:
//192.168.1.10/share /mnt/share cifs credentials=/.smbcredentials,uid=1000,gid=1000,vers=3.1.1,noperm,hard,cache=loose,actimeo=120,nobrl,rsize=1048576,wsize=1048576,_netdev,x-systemd.automount 0 0
The important bits:
hardinstead of the defaultsoft. A soft mount returns EIO on timeout, which is exactly the wrong behaviour when the goal is a reliable bulk-data share. Hard mounts wait for the NAS to come back.cache=loosebypasses the broken__readahead_batchcode path entirely. This is the single most important change.actimeo=120gives the attribute cache 120 seconds instead of the anemic 1 second default, which saves a huge amount of pointless metadata chatter with the NAS.nobrldisables byte-range locks. BitTorrent does not need them, Jellyfin does not need them, and they are a common source of weird hangs on CIFS.rsize=1048576andwsize=1048576bump block size to 1 MB. The old 64 KB default made sense in 2005, not in 2026 when SMB 3.1.1 can happily push megabyte-sized operations.
One thing that does not work on Rocky 9’s kernel: multichannel=no. It is not a valid mount option here and the mount will fail with invalid argument. Do not put it in your fstab.
Applying the Change
CIFS mounts cannot be remounted while anything is holding files open on them, which means every container with a bind mount onto the share has to be stopped first.
# Stop every container that touches the share
for d in qbittorrent jellyfin syncthing paperless-ng photoprism; do
cd /var/lib/docker/compose/$d && sudo docker compose stop
done
# Remount
sudo systemctl stop mnt-share.automount mnt-share.mount
sudo systemctl daemon-reload
sudo systemctl start mnt-share.automount
sudo ls /mnt/share/ >/dev/null
# Verify
findmnt /mnt/share --real
# Start the consumers again
for d in jellyfin syncthing paperless-ng photoprism qbittorrent; do
cd /var/lib/docker/compose/$d && sudo docker compose up -d
done
The sudo ls is there to trigger the automount unit. Without it findmnt will show nothing and you will think the mount failed.
Before and After
The clearest benchmark was a large Ubuntu ISO torrent with over two thousand seeders. Before the fix it had been stuck at 9.6% for over an hour. After the new fstab took effect it finished in 15 minutes, averaging 10 MB/s with peaks around 30 MB/s. Jellyfin seeks became instant again, and the general “this NAS feels slow” mood just went away.
Conclusion
If you are running any kind of homelab stack where Docker containers bind-mount a CIFS share, and you are on a kernel 5.14-ish distro like Rocky 9, look at your mount options. The default cache=strict combined with soft and a tiny rsize is a trap, and the failure mode is not “broken” but “slow and flaky in a way that looks like a hundred other problems.” Torrents will tell you about it loudly. Everything else will just quietly suffer.