Skip to content

Add FUSE3 support and TANDBERG LTO-6 HH drive#590

Open
mhorimoto wants to merge 3 commits into
LinearTapeFileSystem:mainfrom
mhorimoto:fuse3-support-and-tandberg-lto6
Open

Add FUSE3 support and TANDBERG LTO-6 HH drive#590
mhorimoto wants to merge 3 commits into
LinearTapeFileSystem:mainfrom
mhorimoto:fuse3-support-and-tandberg-lto6

Conversation

@mhorimoto
Copy link
Copy Markdown

Summary of changes

  • Add FUSE3 support for AlmaLinux9/RHEL9 (FUSE 3.x)
  • Add TANDBERG LTO-6 HH drive support

Description

FUSE3 support (AlmaLinux9 / RHEL9)

The original code was written for FUSE2 and fails to build on systems
with FUSE3 (AlmaLinux 9.7, RHEL 9.x).

  • Update FUSE_USE_VERSION from 26 to 30
  • Fix filler() calls to use 5 arguments (FUSE3 API)
  • Remove deprecated fuse_operations members: fgetattr, ftruncate, flag_nullpath_ok
  • Update fuse_parse_cmdline() to use struct fuse_cmdline_opts (FUSE3 API)
  • Add fuse_lowlevel.h include in main.c
  • Remove deprecated FUSE2 options: hard_remove, sync_read, big_writes, use_ino

TANDBERG LTO-6 HH drive support

TANDBERG LTO-6 HH drives were not in the supported device table,
causing a segfault in _raw_open().

  • Add VENDOR_TANDBERG to vendor enum in tape_drivers.h
  • Add TANDBERG_VENDOR_ID definition in hp_tape.h
  • Add TANDBERG LTO-6 HH drive entry in hp_tape.c
  • Add TANDBERG vendor handling in vendor_compat.c
  • Use LogPage 0x31 for TANDBERG capacity reading in sg_tape.c

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Test environment

  • OS: AlmaLinux 9.7 (kernel 5.14.0-611.54.6.el9_7.x86_64)
  • FUSE: 3.10.2-9.el9
  • Drive: TANDBERG LTO-6 HH (firmware 3319, serial HUJ430176D)
  • Result: Successfully mounted LTFS volume read-only

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have confirmed my fix is effective or that my feature works

FUSE3 support (for AlmaLinux9/RHEL9 with FUSE 3.x):
- Update FUSE_USE_VERSION from 26 to 30
- Fix filler() calls to use 5 arguments (FUSE3 API)
- Remove deprecated fuse_operations members: fgetattr, ftruncate, flag_nullpath_ok
- Update fuse_parse_cmdline() to use struct fuse_cmdline_opts (FUSE3 API)
- Add fuse_lowlevel.h include in main.c
- Remove deprecated FUSE2 options: hard_remove, sync_read, big_writes, use_ino

TANDBERG LTO-6 HH support:
- Add VENDOR_TANDBERG to vendor enum in tape_drivers.h
- Add TANDBERG_VENDOR_ID definition in hp_tape.h
- Add TANDBERG LTO-6 HH drive entry in hp_tape.c
- Add TANDBERG vendor handling in vendor_compat.c
  (get_vendor_id, get_supported_devs, init_error_table, init_timeout)
- Use LogPage 0x31 for TANDBERG capacity reading in sg_tape.c

Tested with:
  TANDBERG LTO-6 HH (firmware 3319, serial HUJ430176D)
  AlmaLinux 9.7 (kernel 5.14.0-611.54.6.el9_7.x86_64)
  FUSE 3.10.2-9.el9
Copy link
Copy Markdown
Member

@Piloalucard Piloalucard May 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @mhorimoto ! Thank you for opening this PR! Seems good so far, I will continue reviewing, but I think we may need to also add from LTO-5 to LTO-9, within the same format you used.
https://ltoworld.com/ I used this page as a source to see which LTO drives exists for Tandberg, renamed to Overland. One constraint is that we do not have Tandberg/Overland hardware to test them.
What do you think?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @Piloalucard san.
Thank you for your review!
I will research the Tandberg/Overland LTO-5 to LTO-9 drive entries using ltoworld.com and add them in the same format.
However, I only have a Tandberg LTO-6 drive, so I can only verify the LTO-6 entry with actual hardware. The other entries (LTO-5, LTO-7 to LTO-9) will be based on research only, without real device testing.
I'll update this PR once the investigation is complete.

Comment thread src/main.c Outdated
Comment thread src/main.c
Comment thread src/main.c Outdated
- Disable async read via FUSE_CAP_ASYNC_READ in ltfs_fuse_mount()
  instead of removed -osync_read option (FUSE3)
- Comment out -ouse_ino option: verified removed in FUSE3
  (causes mount failure: 'fuse: unknown option(s): -o use_ino')
- Tested on AlmaLinux 9.7 with FUSE3, LTO-6 Tandberg drive
  Mount, file read, and data integrity (cmp) all confirmed OK
@mhorimoto
Copy link
Copy Markdown
Author

Tested on AlmaLinux 9.7 with FUSE3 (LTO-6 Tandberg drive, firmware 3319).

Results:

  • Mount succeeded without segmentation fault
  • File listing and read verified
  • cmp confirmed data integrity (no difference)
  • Unmount and eject completed normally

Regarding -ouse_ino:
After actual testing, this option causes a mount failure on FUSE3:
fuse: unknown option(s): '-o use_ino'
Therefore it remains commented out.

Regarding sync_read:
Replaced with FUSE_CAP_ASYNC_READ flag in ltfs_fuse_mount() init callback.

@mhorimoto
Copy link
Copy Markdown
Author

@madjesc I have addressed your review comments in the latest commit (6b75ff0).

Summary of changes:

  • -ouse_ino: Confirmed removed in FUSE3 by actual testing. Mount fails with this option. Keeping it commented out.
  • sync_read: Replaced with FUSE_CAP_ASYNC_READ in ltfs_fuse_mount() init callback.
  • hard_remove: Awaiting your investigation results.

Could you please re-review? Thank you.

@madjesc
Copy link
Copy Markdown

madjesc commented May 23, 2026

Hello @mhorimoto
Can you share which version of FUSE3 are you using? I had a lot of problems on Fedora

mcardenas@fedora:~/Proyects/ltfs$ pkg-config --modversion fuse3
3.16.2

Can you test these changes on alma9?

diff --git a/configure.ac b/configure.ac
index f28d2b2..2bc2bc7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -286,7 +286,7 @@ fi
 dnl
 dnl Check for FUSE, libuuid, and libxml2
 dnl
-PKG_CHECK_MODULES([FUSE_MODULE], [fuse >= 2.6.0])
+PKG_CHECK_MODULES([FUSE_MODULE], [fuse3 >= 3.0.0])
 PKG_CHECK_MODULES([LIBXML2_MODULE], [libxml-2.0 >= 2.6.16])

 if test "x${host_mac}" = "xyes"
diff --git a/src/libltfs/xattr.h b/src/libltfs/xattr.h
index 66f82fe..43e96c5 100644
--- a/src/libltfs/xattr.h
+++ b/src/libltfs/xattr.h
@@ -66,7 +66,8 @@ extern "C" {
 #include "libltfs/arch/freebsd/xattr.h"
 #endif

-#include "fuse.h"
+#include "ltfs_fuse_version.h"
+#include <fuse.h>
 #include "ltfs.h"

 #define LTFS_PRIVATE_PREFIX "ltfs."
diff --git a/src/ltfs_fuse.c b/src/ltfs_fuse.c
index 66f3d3a..06d15e9 100644
--- a/src/ltfs_fuse.c
+++ b/src/ltfs_fuse.c
@@ -278,7 +278,7 @@ int ltfs_fuse_fgetattr(const char *path, struct stat *stbuf, struct fuse_file_in
 	return errormap_fuse_error(ret);
 }

-int ltfs_fuse_getattr(const char *path, struct stat *stbuf)
+int ltfs_fuse_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *finfo)
 {
 	struct ltfs_fuse_data *priv = fuse_get_context()->private_data;
 	struct dentry_attr attr;
@@ -591,7 +591,7 @@ int ltfs_fuse_flush(const char *path, struct fuse_file_info *fi)
 	return errormap_fuse_error(ret);
 }

-int ltfs_fuse_utimens(const char *path, const struct timespec ts[2])
+int ltfs_fuse_utimens(const char *path, const struct timespec ts[2], struct fuse_file_info *finfo)
 {
 	struct ltfs_fuse_data *priv = fuse_get_context()->private_data;
 	struct ltfs_timespec tsTmp[2];
@@ -618,7 +618,7 @@ int ltfs_fuse_utimens(const char *path, const struct timespec ts[2])
  * Change the mode of a file or directory. Since LTFS does not support full Unix permissions,
  * this function just sets or clears the read-only flag.
  */
-int ltfs_fuse_chmod(const char *path, mode_t mode)
+int ltfs_fuse_chmod(const char *path, mode_t mode, struct fuse_file_info *finfo)
 {
 	struct ltfs_fuse_data *priv = fuse_get_context()->private_data;
 	ltfs_file_id id;
@@ -642,7 +642,7 @@ int ltfs_fuse_chmod(const char *path, mode_t mode)
  * Set ownership of a file or directory. Succeeds, but has no effect: user/group are
  * controlled by mount-time options uid and gid.
  */
-int ltfs_fuse_chown(const char *path, uid_t user, gid_t group)
+int ltfs_fuse_chown(const char *path, uid_t user, gid_t group, struct fuse_file_info *finfo)
 {
 	ltfs_request_trace(FUSE_REQ_ENTER(REQ_CHOWN), ((uint64_t)user << 32) + group, 0);
 	ltfs_request_trace(FUSE_REQ_EXIT(REQ_CHOWN), 0, 0);
@@ -746,7 +746,7 @@ int ltfs_fuse_mkdir(const char *path, mode_t mode)
 	return errormap_fuse_error(ret);
 }

-int ltfs_fuse_truncate(const char *path, off_t length)
+int ltfs_fuse_truncate(const char *path, off_t length, struct fuse_file_info *finfo)
 {
 	struct ltfs_fuse_data *priv = fuse_get_context()->private_data;
 	ltfs_file_id id;
@@ -815,7 +815,7 @@ int ltfs_fuse_rmdir(const char *path)
 	return errormap_fuse_error(ret);
 }

-int ltfs_fuse_rename(const char *from, const char *to)
+int ltfs_fuse_rename(const char *from, const char *to, unsigned int flags)
 {
 	struct ltfs_fuse_data *priv = fuse_get_context()->private_data;
 	ltfs_file_id id;
@@ -865,7 +865,7 @@ int _ltfs_fuse_filldir(void *buf, const char *name, void *priv)
 }

 int ltfs_fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
-	off_t offset, struct fuse_file_info *fi)
+	off_t offset, struct fuse_file_info *fi, enum fuse_readdir_flags flags)
 {
 	struct ltfs_fuse_data *priv = fuse_get_context()->private_data;
 	struct ltfs_file_handle *file = FILEHANDLE_TO_STRUCT(fi->fh);
@@ -1061,7 +1061,7 @@ int ltfs_fuse_removexattr(const char *path, const char *name)
  * Mount the filesystem. This function assumes a volume has been
  * allocated and ltfs_mount has been called; it just does some secondary setup.
  */
-void * ltfs_fuse_mount(struct fuse_conn_info *conn)
+void * ltfs_fuse_mount(struct fuse_conn_info *conn, struct fuse_config *config)
 {
 	struct ltfs_fuse_data *priv = fuse_get_context()->private_data;
 	struct statvfs *stats = &priv->fs_stats;

@madjesc
Copy link
Copy Markdown

madjesc commented May 23, 2026

@mhorimoto seems that both -ouse_ino and -ohard_remove were removed from the fuse options layer.
Now they can be configured on the init fuse operation using fuse_config.

diff --git a/src/ltfs_fuse.c b/src/ltfs_fuse.c
index 06d15e9..fdbe963 100644
--- a/src/ltfs_fuse.c
+++ b/src/ltfs_fuse.c
@@ -1075,6 +1075,8 @@ void * ltfs_fuse_mount(struct fuse_conn_info *conn, struct fuse_config *config)
 	 */
 	if (conn->capable & FUSE_CAP_ASYNC_READ)
 		conn->want &= ~FUSE_CAP_ASYNC_READ;
+	config->use_ino = true;
+	config->hard_remove = true;

 	if (priv->pid_orig != getpid()) {
 		/*

@mhorimoto
Copy link
Copy Markdown
Author

@madjesc Thank you for your investigation!

FUSE3 version on AlmaLinux 9.7:

pkg-config --modversion fuse3
3.10.2

I will now apply your suggested changes:

  • config->use_ino = true and config->hard_remove = true in ltfs_fuse_mount()
  • configure.ac and xattr.h fixes

Will report the results after testing.

- Add fuse_config *config parameter to ltfs_fuse_mount()
- Set config->use_ino = true and config->hard_remove = true
- Update configure.ac to require fuse3 >= 3.0.0
- Fix xattr.h to include ltfs_fuse_version.h and <fuse.h>
- Tested on AlmaLinux 9.7 / FUSE3 3.10.2 / LTO-6 Tandberg drive
  12.7GB file read verified with cmp
@mhorimoto
Copy link
Copy Markdown
Author

@madjesc Thank you for the suggestion!

I have applied your proposed changes and tested on AlmaLinux 9.7:

  • FUSE3 version: 3.10.2
  • Added fuse_config *config parameter to ltfs_fuse_mount()
  • Set config->use_ino = true and config->hard_remove = true
  • Updated configure.ac to require fuse3 >= 3.0.0
  • Fixed xattr.h to include ltfs_fuse_version.h and <fuse.h>

Test results (LTO-6 Tandberg drive, firmware 3319):

  • Mount succeeded without errors
  • 12.7GB file read and verified with cmp (no difference)
  • Unmount and eject completed normally

Could you please re-review?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants