diff --git a/messages/libltfs/root.txt b/messages/libltfs/root.txt index 32882de3..d0242b9b 100644 --- a/messages/libltfs/root.txt +++ b/messages/libltfs/root.txt @@ -834,6 +834,8 @@ v 17290I:string { "Partitioning the medium with the destructive method." } 17291I:string { "Unpartitioning the medium with the destructive method." } 17292I:string { "Current position is (%llu, %llu), Error position is (%llu, %llu)." } + 17293I:string { "Position mismatch. Cached tape position = %llu. Current tape position = %llu." } + 17294I:string { "Continue signal (%d) received" } // For Debug 19999I:string { "%s %s %d." } diff --git a/src/libltfs/ltfs.c b/src/libltfs/ltfs.c index ae077bb9..36369f0f 100644 --- a/src/libltfs/ltfs.c +++ b/src/libltfs/ltfs.c @@ -205,6 +205,46 @@ bool ltfs_is_interrupted(void) return interrupted; } +bool caught_sigcont = false; +void _ltfs_sigcont(int signal) +{ + ltfsmsg(LTFS_INFO, 17294I, signal); + ltfs_sigcont_set(true); +} + +void ltfs_sigcont_set(bool sig_val) +{ + caught_sigcont = sig_val; +} + +bool ltfs_caught_sigcont(void) +{ + return caught_sigcont; +} + +int ltfs_extra_signal_handlers(void) +{ + ltfs_sighandler_t ret; + ret = signal(SIGCONT, _ltfs_sigcont); + if (ret == SIG_ERR) { + return -LTFS_SIG_HANDLER_ERR; + } + + return 0; +} + +int ltfs_unset_extra_signal_handler(void) +{ + ltfs_sighandler_t rc; + int ret = 0; + + rc = signal(SIGCONT, SIG_DFL); + if (rc == SIG_ERR) + ret = -LTFS_SIG_HANDLER_ERR; + + return ret; +} + /** * This function can be used to enable libltfs signal handler * to kill ltfs, mkltfs, ltfsck cleanly @@ -2383,12 +2423,13 @@ int ltfs_write_index(char partition, char *reason, struct ltfs_volume *vol) struct tape_offset old_selfptr, old_backptr; struct ltfs_timespec modtime_old = { .tv_sec = 0, .tv_nsec = 0 }; bool generation_inc = false; - struct tc_position physical_selfptr; + struct tc_position physical_selfptr, current_position; char *cache_path_save = NULL; bool write_perm = (strcmp(reason, SYNC_WRITE_PERM) == 0); bool update_vollock = false; int volstat = -1, new_volstat = 0; char *bc_print = NULL; + unsigned long long diff; CHECK_ARG_NULL(vol, -LTFS_NULL_ARG); @@ -2505,6 +2546,24 @@ int ltfs_write_index(char partition, char *reason, struct ltfs_volume *vol) vol->index->backptr = old_backptr; goto out_write_perm; } + + /* Get the tape position from the tape drive by using the SCSI command READPOS*/ + ret = tape_get_position_from_drive(vol->device, ¤t_position); + if (ret < 0) { + /* Return error since the current tape position was unable to be determined, so there could be an undetected position mismatch */ + ltfsmsg(LTFS_ERR, 11081E, ret); + return -1; + } + + /* Prior to writing the index, compare the current location of the head position to the head location + that is kept in the cache of ltfs (physical_selfptr). If they are different return error (-1) */ + diff = ((unsigned long long)physical_selfptr.block - (unsigned long long)current_position.block); + if (diff) { + /* Position mismatch, diff not equal zero */ + ltfsmsg(LTFS_INFO, 17293I, (unsigned long long)physical_selfptr.block, (unsigned long long)current_position.block); + return -1; + } + old_selfptr = vol->index->selfptr; vol->index->selfptr.partition = partition; vol->index->selfptr.partition = vol->label->part_num2id[physical_selfptr.partition]; diff --git a/src/libltfs/ltfs.h b/src/libltfs/ltfs.h index cdbd9fe1..5a792f55 100644 --- a/src/libltfs/ltfs.h +++ b/src/libltfs/ltfs.h @@ -592,8 +592,12 @@ int ltfs_fs_init(void); void ltfs_set_log_level(int log_level); void ltfs_set_syslog_level(int syslog_level); bool ltfs_is_interrupted(void); +bool ltfs_caught_sigcont(void); +void ltfs_sigcont_set(bool sig_val); int ltfs_set_signal_handlers(void); int ltfs_unset_signal_handlers(void); +int ltfs_extra_signal_handlers(void); +int ltfs_unset_extra_signal_handler(void); int ltfs_finish(); /* Public wrappers for tape_* functions */ diff --git a/src/libltfs/tape.c b/src/libltfs/tape.c index 798618d2..1387f078 100644 --- a/src/libltfs/tape.c +++ b/src/libltfs/tape.c @@ -1105,7 +1105,7 @@ int tape_get_position(struct device_data *dev, struct tc_position *pos) /** * Get current tape position by querying the device. */ -int tape_update_position(struct device_data *dev, struct tc_position *pos) +int tape_get_position_from_drive(struct device_data *dev, struct tc_position *pos) { int ret; @@ -1187,6 +1187,9 @@ int tape_spacefm(struct device_data *dev, int count) ssize_t tape_write(struct device_data *dev, const char *buf, size_t count, bool ignore_less, bool ignore_nospc) { ssize_t ret; + struct tc_position current_position; + int ret_for_current_position = 0; + unsigned long long diff = 0; CHECK_ARG_NULL(dev, -LTFS_NULL_ARG); CHECK_ARG_NULL(buf, -LTFS_NULL_ARG); @@ -1241,6 +1244,25 @@ ssize_t tape_write(struct device_data *dev, const char *buf, size_t count, bool count = -LTFS_LESS_SPACE; } + if (ltfs_caught_sigcont()) { + // Unset flag to avoid checking it again if it is not needed + ltfs_sigcont_set(false); + + ret_for_current_position = tape_get_position_from_drive(dev, ¤t_position); + if (ret_for_current_position) { + /* Return error since the current tape position was unable to be determined, so there could be an undetected position mismatch */ + ltfsmsg(LTFS_ERR, 11081E, ret); + return -LTFS_WRITE_ERROR; + } + + diff = ((unsigned long long)dev->position.block - (unsigned long long)current_position.block); + if (diff) { + /* Position mismatch, diff not equal zero */ + ltfsmsg(LTFS_INFO, 17293I, (unsigned long long)dev->position.block, (unsigned long long)current_position.block); + return -LTFS_WRITE_ERROR; + } + } + ltfs_mutex_lock(&dev->append_pos_mutex); dev->append_pos[dev->position.partition] = dev->position.block; ltfs_mutex_unlock(&dev->append_pos_mutex); diff --git a/src/libltfs/tape.h b/src/libltfs/tape.h index 91870105..a94ab95f 100644 --- a/src/libltfs/tape.h +++ b/src/libltfs/tape.h @@ -160,7 +160,7 @@ int tape_force_read_only(struct device_data *dev); int tape_rewind(struct device_data *dev); int tape_get_position(struct device_data *dev, struct tc_position *pos); -int tape_update_position(struct device_data *dev, struct tc_position *pos); +int tape_get_position_from_drive(struct device_data *dev, struct tc_position *pos); int tape_seek(struct device_data *dev, struct tc_position *pos); int tape_seek_eod(struct device_data *dev, tape_partition_t partition); diff --git a/src/main.c b/src/main.c index 9b62b061..533ec70d 100644 --- a/src/main.c +++ b/src/main.c @@ -1241,10 +1241,14 @@ int single_drive_main(struct fuse_args *args, struct ltfs_fuse_data *priv) ltfsmsg(LTFS_INFO, 14111I); ltfsmsg(LTFS_INFO, 14112I); ltfsmsg(LTFS_INFO, 14113I); + /* Set handlers for signals that need to be caught while fuse main is running*/ + ltfs_extra_signal_handlers(); ret = fuse_main(args->argc, args->argv, <fs_ops, priv); if (ret != 0) { ltfsmsg(LTFS_WARN, 14123W, ret); } + /* Unset extra handlers once fuse main exits */ + ltfs_unset_extra_signal_handler(); /* Setup signal handler again to terminate cleanly */ ret = ltfs_set_signal_handlers();