ltfs
ltfs copied to clipboard
Deadlock when unmounting LTFS after writing multiple small files
Deadlock when unmounting LTFS after writing multiple small files
LTFS 2.4.5.0 (or older versions) macFUSE 4.4.1 (or older versions) macOS 12.5.1
On Apple Silicon Macs ltfs runs in Rosetta, this works well. However we have discovered a deadlock situation when unmounting a tape. It's intermittent, but happens very often when the files written are small in size.
mount tape write some small files to tape, here the SRC folder has 5 x 7MB files. unmount
ltfs /Volumes/LTFS1 -o devname=0
cp -r /Volumes/SOURCE/SRC /Volumes/LTFS1/TEST
umount /Volumes/LTFS1
About 30% of the time this will lockup and then after 20 minutes the process will timeout. The same script will run repeatedly using an Intel Mac.
Writing a larger file (here a 1GB file) after the small ones prevents the deadlock
ltfs /Volumes/LTFS1 -o devname=0
cp -r /Volumes/SOURCE/SRC /Volumes/LTFS1/TEST
cp /Volumes/SOURCE/1G.bin /Volumes/LTFS$1/TEST/
umount /Volumes/LTFS1
Here is a sample of the deadlocked processes...
2576 Thread_17870 DispatchQueue_1: com.apple.main-thread (serial)
+ 2576 start (in ltfs) + 52 [0x100000eb4]
+ 2576 main (in ltfs) + 5713 [0x100004011]
+ 2576 single_drive_main (in ltfs) + 5707 [0x1000059fb]
+ 2576 fuse_main_real (in libfuse.2.dylib) + 12 [0x1088b259c]
+ 2576 ??? (in libfuse.2.dylib) load address 0x10889e000 + 0x145f1 [0x1088b25f1]
+ 2576 fuse_loop (in libfuse.2.dylib) + 48 [0x1088a3610]
+ 2576 fuse_session_loop (in libfuse.2.dylib) + 153 [0x1088ab599]
+ 2576 fuse_session_process_buf (in libfuse.2.dylib) + 25 [0x1088b09b9]
+ 2576 ??? (in libfuse.2.dylib) load address 0x10889e000 + 0xfc75 [0x1088adc75]
+ 2576 ??? (in libfuse.2.dylib) load address 0x10889e000 + 0x10989 [0x1088ae989]
+ 2576 ??? (in libfuse.2.dylib) load address 0x10889e000 + 0x882a [0x1088a682a]
+ 2576 ??? (in libfuse.2.dylib) load address 0x10889e000 + 0xc1ef [0x1088aa1ef]
+ 2576 fuse_fs_release (in libfuse.2.dylib) + 123 [0x1088a169b]
+ 2576 ??? (in libfuse.2.dylib) load address 0x10889e000 + 0x36c3 [0x1088a16c3]
+ 2576 ??? (in libfuse.2.dylib) load address 0x10889e000 + 0x1a1ce [0x1088b81ce]
+ 2576 fuse_fs_release (in libfuse.2.dylib) + 123 [0x1088a169b]
+ 2576 ??? (in libfuse.2.dylib) load address 0x10889e000 + 0x36c3 [0x1088a16c3]
+ 2576 ltfs_fuse_release (in ltfs) + 462 [0x10000850e]
+ 2576 ltfs_fsops_close (in libltfs.2.4.4.dylib) + 517 [0x10873c915]
+ 2576 iosched_close (in libltfs.2.4.4.dylib) + 615 [0x108728657]
+ 2576 unified_close (in libiosched-unified.2.4.4.dylib) + 320 [0x1086e6e40]
+ 2576 _unified_flush_unlocked (in libiosched-unified.2.4.4.dylib) + 646 [0x1086e71d6]
+ 2576 ltfs_fsraw_write (in libltfs.2.4.4.dylib) + 531 [0x1087479a3]
+ 2576 _ltfs_fsraw_write_data_unlocked (in libltfs.2.4.4.dylib) + 859 [0x1087462db]
+ 2576 writetoread_mrsw (in libltfs.2.4.4.dylib) + 33 [0x1087466b1]
+ 2576 _pthread_rwlock_lock_slow (in libsystem_pthread.dylib) + 565 [0x7ff81464e514]
+ 2576 _pthread_rwlock_lock_wait (in libsystem_pthread.dylib) + 56 [0x7ff81464fefd]
+ 2576 __psynch_rw_rdlock (in libsystem_kernel.dylib) + 10 [0x7ff814618a12]
+ 2576 ??? (in
I tried adding each of the the following commands after the write and before the unmount.
- flush
- sleep 5
- LTFS sync
None of these made any difference. The only solution seems to be writing a large file before un-mounting.
I'm not sure a deadlock really happens. Because we don't have a deadlock in this a few years at all.
You need to attach the debugger to the process and check the lock chain, which lock blocks other locks.
I can't say anything from the logs in the comments.
The two threads' stack traces indicate they're waiting for different resources. The top-most thread is blocked while trying to downgrade the multi-reader, single writer vol->lock
to reader mode. The bottom-most thread is blocked while trying to obtain a lock on the device backend's dev->backend_mutex
. @greengreengreengit, you mentioned that you've pasted a sample of the stack traces; we may need the full stack traces to check which locks the other threads are trying to obtain.
Now, there's something to note here. We have two implementations of multi-reader, single writer locks. The original one uses a logic based on try-locks, whereas the second one (which IIRC came as a NetBSD-related PR) uses a cleaner implementation based on pthread_rwlock_t
. @piste-jp-ibm, I am unaware of how the macOS builds are currently being distributed (or if users are expected to build their own package from the source code). Would you know which implementation is used by default on macOS? configure.ac
only enables the pthread_rwlock_t
implementation when building for NetBSD, although --enable-new-locking
is provided for those wanting to use it.
The issue only happens on Apple Silicon where there is a third thread. I cut it from the sample, because it did not seem to be involved. However it might be the clue, as when running on Intel we never see this lock issue AND this third thread does not exist. Note that the current IBM releases builds are for x86_64, so LTFS runs using Rosetta. Rosetta hasn't seemed to be an issue up until now. (Note that when mounting the tape we set sync_type=unmount to disable syncing, so that is why there is no 4th thread for a timer. Also note that issue occurs both with and without sync enabled)
Here is the full stack trace...
Call graph:
2574 Thread_272800 DispatchQueue_1: com.apple.main-thread (serial)
+ 2574 start (in ltfs) + 52 [0x100000eb4]
+ 2574 main (in ltfs) + 5713 [0x100004011]
+ 2574 single_drive_main (in ltfs) + 5707 [0x1000059fb]
+ 2574 fuse_main_real (in libfuse.2.dylib) + 12 [0x1088b356c]
+ 2574 ??? (in libfuse.2.dylib) load address 0x10889f000 + 0x145c1 [0x1088b35c1]
+ 2574 fuse_loop (in libfuse.2.dylib) + 48 [0x1088a45e0]
+ 2574 fuse_session_loop (in libfuse.2.dylib) + 153 [0x1088ac599]
+ 2574 fuse_session_process_buf (in libfuse.2.dylib) + 25 [0x1088b1979]
+ 2574 ??? (in libfuse.2.dylib) load address 0x10889f000 + 0xfc7c [0x1088aec7c]
+ 2574 ??? (in libfuse.2.dylib) load address 0x10889f000 + 0x10979 [0x1088af979]
+ 2574 ??? (in libfuse.2.dylib) load address 0x10889f000 + 0x880a [0x1088a780a]
+ 2574 ??? (in libfuse.2.dylib) load address 0x10889f000 + 0xc1ef [0x1088ab1ef]
+ 2574 fuse_fs_release (in libfuse.2.dylib) + 123 [0x1088a267b]
+ 2574 ??? (in libfuse.2.dylib) load address 0x10889f000 + 0x36a3 [0x1088a26a3]
+ 2574 ??? (in libfuse.2.dylib) load address 0x10889f000 + 0x1a1ae [0x1088b91ae]
+ 2574 fuse_fs_release (in libfuse.2.dylib) + 123 [0x1088a267b]
+ 2574 ??? (in libfuse.2.dylib) load address 0x10889f000 + 0x36a3 [0x1088a26a3]
+ 2574 ltfs_fuse_release (in ltfs) + 462 [0x10000850e]
+ 2574 ltfs_fsops_close (in libltfs.2.4.5.dylib) + 517 [0x10873c595]
+ 2574 iosched_close (in libltfs.2.4.5.dylib) + 615 [0x108728207]
+ 2574 unified_close (in libiosched-unified.2.4.5.dylib) + 320 [0x1086e6e40]
+ 2574 _unified_flush_unlocked (in libiosched-unified.2.4.5.dylib) + 646 [0x1086e71d6]
+ 2574 ltfs_fsraw_write (in libltfs.2.4.5.dylib) + 531 [0x108747623]
+ 2574 _ltfs_fsraw_write_data_unlocked (in libltfs.2.4.5.dylib) + 859 [0x108745f5b]
+ 2574 writetoread_mrsw (in libltfs.2.4.5.dylib) + 33 [0x108746331]
+ 2574 _pthread_rwlock_lock_slow (in libsystem_pthread.dylib) + 565 [0x7ff80c5a6514]
+ 2574 _pthread_rwlock_lock_wait (in libsystem_pthread.dylib) + 56 [0x7ff80c5a7efd]
+ 2574 __psynch_rw_rdlock (in libsystem_kernel.dylib) + 10 [0x7ff80c570a12]
+ 2574 ??? (in <unknown binary>) [0x7ff89ca3e940]
2574 Thread_272801: com.apple.rosetta.exceptionserver
+ 2574 ??? (in runtime) load address 0x7ff7ffd76000 + 0x13e58 [0x7ff7ffd89e58]
+ 2574 ??? (in runtime) load address 0x7ff7ffd76000 + 0x123e0 [0x7ff7ffd883e0]
+ 2574 ??? (in runtime) load address 0x7ff7ffd76000 + 0x4944 [0x7ff7ffd7a944]
2574 Thread_272806
2574 thread_start (in libsystem_pthread.dylib) + 15 [0x7ff80c5a4f6b]
2574 _pthread_start (in libsystem_pthread.dylib) + 125 [0x7ff80c5a94e1]
2574 _unified_writer_thread (in libiosched-unified.2.4.5.dylib) + 557 [0x1086e669d]
2574 _unified_process_queue (in libiosched-unified.2.4.5.dylib) + 144 [0x1086eb2c0]
2574 _unified_process_data_queue (in libiosched-unified.2.4.5.dylib) + 1542 [0x1086ebc96]
2574 ltfs_fsraw_write (in libltfs.2.4.5.dylib) + 531 [0x108747623]
2574 _ltfs_fsraw_write_data_unlocked (in libltfs.2.4.5.dylib) + 413 [0x108745d9d]
2574 tape_device_lock (in libltfs.2.4.5.dylib) + 127 [0x1087575ff]
2574 ltfs_mutex_lock (in libltfs.2.4.5.dylib) + 21 [0x108756635]
2574 _pthread_mutex_firstfit_lock_slow (in libsystem_pthread.dylib) + 205 [0x7ff80c5a4cbb]
2574 _pthread_mutex_firstfit_lock_wait (in libsystem_pthread.dylib) + 76 [0x7ff80c5a6e7e]
2574 __psynch_mutexwait (in libsystem_kernel.dylib) + 10 [0x7ff80c56ebd2]
2574 ??? (in <unknown binary>) [0x7ff89ca3e940]
@piste-jp-ibm, I am unaware of how the macOS builds are currently being distributed (or if users are expected to build their own package from the source code). Would you know which implementation is used by default on macOS?
configure.ac
only enables thepthread_rwlock_t
implementation when building for NetBSD, although--enable-new-locking
is provided for those wanting to use it.
It is enabled by default only on master
branch. So it is disabled by default on 2.4.5.0. It is same as IBM binary.
Here is the full stack trace...
The stack trace is little bit funny. Because we didn't use new-locking
option on 2.4.X. And pthread_rwlock
is used only when new-locking
is enabled...
From the stack trace,
- Thread_272800 is waiting the downgrade of vol->lock
- Thread_272801 waiting the lock of dev->backend_mutex
I can't find the root cause from the stack trace attached. We need to inspect the mutex itself and all threads.
So again copying a sequence of small files, say 10 x 7MB files and un-mounting ltfs locks up very frequently. Copy the same sequence of files, then copy a 1GB file, then un-mount it never locks up.
I am using the IBM release build 2.4.5 on macOS. Here is the lldb backtrace for all threads.
(lldb) thread backtrace all
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
* frame #0: 0x00007ff81de38a12 libsystem_kernel.dylib`__psynch_rw_rdlock + 10
frame #1: 0x00007ff81de6fefd libsystem_pthread.dylib`_pthread_rwlock_lock_wait + 56
frame #2: 0x00007ff81de6e514 libsystem_pthread.dylib`_pthread_rwlock_lock_slow + 565
frame #3: 0x0000000108746331 libltfs.2.4.5.dylib`writetoread_mrsw + 33
frame #4: 0x0000000108745f5b libltfs.2.4.5.dylib`_ltfs_fsraw_write_data_unlocked + 859
frame #5: 0x0000000108747623 libltfs.2.4.5.dylib`ltfs_fsraw_write + 531
frame #6: 0x00000001086e71d6 libiosched-unified.2.4.5.dylib`_unified_flush_unlocked + 646
frame #7: 0x00000001086e6e40 libiosched-unified.2.4.5.dylib`unified_close + 320
frame #8: 0x0000000108728207 libltfs.2.4.5.dylib`iosched_close + 615
frame #9: 0x000000010873c595 libltfs.2.4.5.dylib`ltfs_fsops_close + 517
frame #10: 0x000000010000850e ltfs`ltfs_fuse_release + 462
frame #11: 0x00000001088a26c3 libosxfuse_i64.2.dylib`___lldb_unnamed_symbol1$$libosxfuse_i64.2.dylib + 19
frame #12: 0x00000001088a269b libosxfuse_i64.2.dylib`fuse_fs_release + 123
frame #13: 0x00000001088b91ce libosxfuse_i64.2.dylib`___lldb_unnamed_symbol509$$libosxfuse_i64.2.dylib + 46
frame #14: 0x00000001088a26c3 libosxfuse_i64.2.dylib`___lldb_unnamed_symbol1$$libosxfuse_i64.2.dylib + 19
frame #15: 0x00000001088a269b libosxfuse_i64.2.dylib`fuse_fs_release + 123
frame #16: 0x00000001088ab1ef libosxfuse_i64.2.dylib`___lldb_unnamed_symbol142$$libosxfuse_i64.2.dylib + 79
frame #17: 0x00000001088a782a libosxfuse_i64.2.dylib`___lldb_unnamed_symbol64$$libosxfuse_i64.2.dylib + 138
frame #18: 0x00000001088af989 libosxfuse_i64.2.dylib`___lldb_unnamed_symbol235$$libosxfuse_i64.2.dylib + 121
frame #19: 0x00000001088aec75 libosxfuse_i64.2.dylib`___lldb_unnamed_symbol205$$libosxfuse_i64.2.dylib + 1077
frame #20: 0x00000001088b19b9 libosxfuse_i64.2.dylib`fuse_session_process_buf + 25
frame #21: 0x00000001088ac599 libosxfuse_i64.2.dylib`fuse_session_loop + 153
frame #22: 0x00000001088a4610 libosxfuse_i64.2.dylib`fuse_loop + 48
frame #23: 0x00000001088b35f1 libosxfuse_i64.2.dylib`___lldb_unnamed_symbol316$$libosxfuse_i64.2.dylib + 81
frame #24: 0x00000001088b359c libosxfuse_i64.2.dylib`fuse_main_real + 12
frame #25: 0x00000001000059fb ltfs`single_drive_main + 5707
frame #26: 0x0000000100004011 ltfs`main + 5713
frame #27: 0x0000000100000eb4 ltfs`start + 52
thread #2
frame #0: 0x00007ff81de36bd2 libsystem_kernel.dylib`__psynch_mutexwait + 10
frame #1: 0x00007ff81de6ee7e libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_wait + 76
frame #2: 0x00007ff81de6ccbb libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_slow + 205
frame #3: 0x0000000108756635 libltfs.2.4.5.dylib`ltfs_mutex_lock + 21
frame #4: 0x00000001087575ff libltfs.2.4.5.dylib`tape_device_lock + 127
frame #5: 0x0000000108745d9d libltfs.2.4.5.dylib`_ltfs_fsraw_write_data_unlocked + 413
frame #6: 0x0000000108747623 libltfs.2.4.5.dylib`ltfs_fsraw_write + 531
frame #7: 0x00000001086ebc96 libiosched-unified.2.4.5.dylib`_unified_process_data_queue + 1542
frame #8: 0x00000001086eb2c0 libiosched-unified.2.4.5.dylib`_unified_process_queue + 144
frame #9: 0x00000001086e669d libiosched-unified.2.4.5.dylib`_unified_writer_thread + 557
frame #10: 0x00007ff81de714e1 libsystem_pthread.dylib`_pthread_start + 125
frame #11: 0x00007ff81de6cf6b libsystem_pthread.dylib`thread_start + 15
(lldb)
Technically it looks this is not a deadlock. It looks Thread1
is just stopped and Thread2
is just waiting Thread1
.
We need to understand why Thread1
is waiting. To be more specific, we need to see the internal structure of mutex at frame4
and frame3
of Thread1
.
It can be done if we can have the actual source code and full debug information. But I don't know this effort have worth to do.
Do you have an option to build LTFS (in this repository) by yourself on M1/M2 machine? Why do you stick with IBM binary?
I don't think big vendor says "Yes, we can support Rosetta translated binary." on a BSD licensed S/W.
I can build on Intel, but obviously that is x86_64. When I build on Apple Silicon the code builds using arm64. However there are link errors as all the resource bundle files in messages like libtape_common_dat.a have been built for x86_64. How do I set the architecture used by genrb ?
How do I set the architecture used by genrb ?
Please confirm the binary of genrb
. In my best guess, it is a x86_64 binary and runs on Rosetta.
You need to install amd64 version ICU from the Homebrew, if so.
Thanks for the info, I had to remove the installed Intel ICU, now it builds an arm64 version. This seems to be a solution and so far unmounting works. However I need to package the build so that we can test on non development M1 Macs. The issue is that the build script links in various brew libraries that aren't installed by default.
For older IBM LTFS there was a build_package_osx.sh, is there an updated version of this script that has been used for the 2.4.5.0 Mac release ?
For older IBM LTFS there was a build_package_osx.sh, is there an updated version of this script that has been used for the 2.4.5.0 Mac release ?
I'm very sorry to say, I cannot answer this question.
But you can use the repository below with a few modification I believe.
https://github.com/piste2750/macpkg-ltfs