1

This is a (spiritual) follow-up to the previously answered question How to bind mount a folder inside /sdcard with correct permissions?.

Device: Samsung Galaxy Tab S2 8.0
ROM: LineageOS 16.0 (Android 9) with Magisk
Other things to note: SELinux set to permissive

This in-car tablet with OTG storage via permanently-mounted USB hub. When the car is powered on, the tablet, USB hub, and any peripherals receive power, the tablet switches into OTG mode, and all USB devices are enumerated correctly (confirmed via lsusb in a root shell).

If I reboot the tablet while it is powered, then use the instructions in the above-linked answer, everything seems to work as intended. In summary, after booting, I can mount my USB device to its mount-point as follows

$ su -mm (switch to a global namespace root shell)
# mkdir /data/media/0/usb1 (create the mount point)
# mount -t exfat -o <options string> /dev/block/sdb1 /mnt/runtime/write/emulated/0/usb1

which results in the following mounts:

# mount
...
/dev/block/sdb1 on /mnt/runtime/default/emulated/0/usb1 <options>
/dev/block/sdb1 on /mnt/runtime/read/emulated/0/usb1 <options>
/dev/block/sdb1 on /mnt/runtime/write/emulated/0/usb1 <options>
/dev/block/sdb1 on /storage/emulated/0/usb1 <options>
/dev/block/sdb1 on /storage/emulated/0/usb1 <options>

Just to be clear, the final mount to /storage/emulated/0/usb1 does in fact appear twice. In any case, at this point, everything work as expected as long as the tablet remains powered; all apps can access the data on the USB OTG storage with no issue.

When powered-off and back on, the OTG storage needs to be unmounted and then remounted, since the device gets re-probed (e.g. the USB-OTG storage partition /dev/block/sdb1 will disappear on loss of power, and then when power is applied, it will appear again as /dev/block/sdc1). I've narrowed the issue down to the fact that running umount in a global namespace root shell doesn't seem to propagate to all other mount namespaces. In a root shell, everything works just fine.

umount called on these mounts returns no errors and running mount in a root shell confirms that the drive is no longer mounted. However, even after this, it seems that all of the non-global mount namespaces still retain the mount. There are two things that indicate this:

  1. It's impossible to delete the mount point directory, in any shell (including a root shell):
$ su -mm
# rmdir /data/media/0/usb1
rm: cannot remove /data/media/0/usb1 : Device or resource busy

I've tried running lsof in a root shell, but don't see anything holding a handle open to the mount point directory. I haven't built or downloaded an nsenter binary to switch into the mount namespace of different apps to check, but I suspect the mount is still held open in other namespaces. I say this because...

  1. Apps can still access the USB-OTG storage, even after it's been unmounted in a root shell. The access remains until the tablet loses power, at which point the mount point directory appears empty to all applications. Upon power restoration, if I mount the new partition in /dev/block to the same mount point as before, root shells have no issue accessing the data, however all other apps just see it as an empty directory.

I've tried using a bind mount as follows...

# mount -t exfat /dev/block/sdb1 /mnt/media_rw/usb1
# mount -t sdcardfs /mnt/media_rw/usb1 /mnt/runtime/write/emulated/0/usb1

...but this just pushes the problem to the "base" mount point. On power loss and restore, remounting the exFAT mount and then the bind sdcardfs mount to /sdcard just results in an "empty" folder for apps, but the root shell works properly (both in the /mnt/media_rw_usb1 directory as well as the mount point in /sdcard/usb1). In this case, it becomes impossible to delete the /mnt/media_rw_usb1 directory with the same Device or resource busy error.

I'm thoroughly stumped on how to handle this. I've gotten by in the past by using a Tasker script to use nsenter to enter into the mount namespace of the apps I need to access the drive, and run loops to unmount the directory in question until an error returns, at which point I run a separate task to mount the OTG storage again. I'd like to avoid this approach, though, since it's really kludgy and it's actually quite slow.

I think I've given enough information. Thanks in advance.

11
  • while grep -qw '/[^ ]*/usb1' /proc/mounts; do umount -l $(grep -owm1 '/[^ ]*/usb1' /proc/mounts); done; should unmount all old entries for /data/media/0/usb1 in a loop – alecxs Oct 23 '20 at 10:08
  • @alecxs I'm not sure that will be of any use... the drive is actually unmounted in the shell. The issue is that the unmount is not propagating to all other app namespaces. – Shamtam Oct 23 '20 at 11:41
  • ah wait, you didn't meant the 5 lines in your question.. you can set namespaces to global in magisk settings – alecxs Oct 23 '20 at 11:50
  • @alecxs That doesn't make any difference. Apps still run in their own mount namespaces on Android 6+ – Shamtam Oct 23 '20 at 14:17
  • you must reboot to apply that settings – alecxs Oct 23 '20 at 15:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.