Skip to content

[BUG]: sparse image mount fails on tight loop pool (App installer + CLI lifecycle) #214

Description

@da-ai-xian-zun

Kernel Version

6.1.112-android14-11-maybe-dirty (Lenovo TB520FU community GKI; max_loop=64, stock OEM cmdline was max_loop=48)

Kernel Source Link

https://github.com/da-ai-xian-zun/tb520fu-droidspaces-gki

Droidspaces Version

6.3.0 (stock release App + CLI from GitHub releases)

Rooting Method

KernelSU (SukiSU)

Device OEM & Model

Lenovo Yoga Tab Plus TB520FU (SM8650, ROW)

Android Version & ROM

Android 16 (SDK 36), ZUI 17.5.10.096 ROW

Execution Mode

DAEMON (also reproduced via App UI and direct CLI)

Networking Mode

NAT

Describe the Bug

On Lenovo TB520FU, stock Droidspaces v6.3.x shows two related failures:

  1. Actual: App sparse installer fails at mount step (after mkfs/e2fsck succeed). CLI stop/start on existing sparse container fails with LOOP_SET_FD: Resource busy without reboot.
  2. Expected: Both App sparse creation and CLI lifecycle should work stably in the same boot session.

In the same boot session, explicit high-minor losetup (e.g. loop48+) followed by mount succeeds. This is not a case of the kernel lacking loop support.

Upstream SparseImageInstaller.kt @ 76cbd21 already runs:

busybox mount -o loop,...  ||  system mount -o loop,...

On TB520FU (max_loop=64, ~48 loops already bound by the system), both auto-allocation paths fail. Raising max_loop from OEM 48 to 64 did not fix the App installer.

Related: Issue #81, PR #207 (TB520FU listed with sparse install open).

Steps to Reproduce

A — App sparse install

  1. Install stock Droidspaces v6.3.0 from releases; let the App deploy the backend CLI.
  2. Create a new container → Sparse Image (e.g. 4 GiB) → install.

B — CLI lifecycle

  1. Run an existing sparse container (debian-cli with rootfs.img).
  2. Without rebooting, run droidspaces stop then droidspaces start repeatedly (or tap Start in the App).

C — Control (same session)

# busybox mount -o loop alone → fails to setup loop device
# system mount -o loop alone → losetup failed / too many open files
# stock chain (busybox || mount) → both fail
losetup /dev/block/loop48 IMG && mount -t ext4 -o rw,... /dev/block/loop48 MNT
# succeeds

Logs / Screenshots

App UI — sparse install failure (stock v6.3.0, 2026-06-21):

[SPARSE] Mounting sparse image (Minimal loop,rw)...
[SPARSE] Error: Failed to mount sparse image. Your kernel might not support loop mounts here.

App UI — start existing sparse container (stock CLI session):

[-] LOOP_SET_FD: Resource busy
[-] Failed to mount image ... after 3 attempts
Command failed (exit code: 255)

ADB mount-chain test (sparse_upstream_mount_chain.sh):

RESULT_busybox_only: FAILED
RESULT_system_only: FAILED
RESULT_upstream_chain: FAILED
# explicit losetup loop48+: PASS

(Full .txt logs attached to this issue.)

TB520FU measured summary

Path Result
busybox mount -o loop FAIL
system mount -o loop FAIL
stock chain busybox || mount FAIL
manual high-minor losetup + mount PASS
stock CLI stop/start PASS after clean reboot; LOOP_SET_FD on dirty pool without reboot
stock App + loopfix CLI only (replace /data/local/Droidspaces/bin/droidspaces) App chain still FAIL; CLI debian-cli 5/5 stop/start with loopfix binary
patched build with high-minor scan fallback App sparse install + stop/start PASS on TB520FU

SELinux permissive: same auto-alloc results as enforcing.

Contrast — OnePlus Ace 5 Pro PKR110 (6.6.89-Gold_bug)

Item Result
stock App sparse create PASS
stock CLI stop/start ×10 PASS
isolated DS busybox mount -o loop FAIL
system/toybox mount -o loop (64 MiB test image) PASS

On TB520FU both halves of the stock chain fail; on PKR110 the chain can pass when the system/toybox half succeeds.

Code paths @ 76cbd21

Feature Files
App sparse mount SparseImageInstaller.kt, assets/sparsemgr.sh
CLI sparse mount src/mount.c

Replacing only the CLI binary does not change App sparse install (App uses sparsemgr.sh, not the deployed CLI).

Proposed fix (for reference)

I have a proposed fix on branch android/sparse-loop-scan. A fix has been implemented and submitted as PR #215. After the stock busybox || mount chain fails, it adds a high-minor losetup scan fallback (src/mount.c, App sparsemgr.sh / mount_loop_scan.sh, plus a small ContainerInstaller.kt config-before-umount ordering fix). Patches against 76cbd21 for review: https://github.com/da-ai-xian-zun/tb520fu-droidspaces-gki/tree/main/patches

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions