X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fstored%2Fbtape.c;h=f4fa3aa6ef55f314f227f6b4b5449325cced041f;hb=86b9b2cd15ac8fc2cf4dca39ccd3669c4a4ff81a;hp=f43040208233bcd79e6029a88d6eb1fe2e315709;hpb=6bedf90d2014a9232b7cf7d7d40c224acaad395d;p=bacula%2Fbacula diff --git a/bacula/src/stored/btape.c b/bacula/src/stored/btape.c index f430402082..f4fa3aa6ef 100644 --- a/bacula/src/stored/btape.c +++ b/bacula/src/stored/btape.c @@ -1,29 +1,21 @@ /* - Bacula® - The Network Backup Solution - - Copyright (C) 2000-2009 Free Software Foundation Europe e.V. - - The main author of Bacula is Kern Sibbald, with contributions from - many others, a complete list can be found in the file AUTHORS. - This program is Free Software; you can redistribute it and/or - modify it under the terms of version two of the GNU General Public - License as published by the Free Software Foundation and included - in the file LICENSE. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. - - Bacula® is a registered trademark of Kern Sibbald. - The licensor of Bacula is the Free Software Foundation Europe - (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, - Switzerland, email:ftf@fsfeurope.org. + Bacula(R) - The Network Backup Solution + + Copyright (C) 2000-2015 Kern Sibbald + Copyright (C) 2000-2014 Free Software Foundation Europe e.V. + + The original author of Bacula is Kern Sibbald, with contributions + from many others, a complete list can be found in the file AUTHORS. + + You may use this file and others of this release according to the + license defined in the LICENSE file, which includes the Affero General + Public License, v3.0 ("AGPLv3") and some additional permissions and + terms pursuant to its AGPLv3 Section 7. + + This notice must be preserved when any source code is + conveyed and/or propagated. + + Bacula(R) is a registered trademark of Kern Sibbald. */ /* * @@ -37,25 +29,22 @@ * Note, this program reads stored.conf, and will only * talk to devices that are configured. * - * Version $Id$ - * */ #include "bacula.h" #include "stored.h" #ifdef USE_VTAPE -#include "vtape.h" +#include "vtape_dev.h" #endif -/* Dummy functions */ -int generate_daemon_event(JCR *jcr, const char *event) { return 1; } extern bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code); /* External subroutines */ extern void free_config_resources(); /* Exported variables */ +void *start_heap; int quit = 0; char buf[100000]; int bsize = TAPE_BSIZE; @@ -76,6 +65,7 @@ DCR *dcr; DEVRES *device = NULL; int exit_code = 0; +#define REC_SIZE 32768 /* Forward referenced subroutines */ static void do_tape_cmds(); @@ -124,7 +114,6 @@ static int stop = 0; static uint64_t vol_size; static uint64_t VolBytes; static time_t now; -static double kbs; static int32_t file_index; static int end_of_tape = 0; static uint32_t LastBlock = 0; @@ -151,7 +140,6 @@ static int vol_num = 0; static JCR *jcr = NULL; - static void usage(); static void terminate_btape(int sig); int get_cmd(const char *prompt); @@ -168,11 +156,12 @@ int main(int margc, char *margv[]) uint32_t x32, y32; uint64_t x64, y64; char buf[1000]; - + setlocale(LC_ALL, ""); bindtextdomain("bacula", LOCALEDIR); textdomain("bacula"); init_stack_dump(); + lmgr_init_thread(); /* Sanity checks */ if (TAPE_BSIZE % B_DEV_BSIZE != 0 || TAPE_BSIZE / B_DEV_BSIZE == 0) { @@ -199,7 +188,7 @@ int main(int margc, char *margv[]) bsnprintf(buf, sizeof(buf), "%" llu, x64); i = bsscanf(buf, "%llu", &y64); if (i != 1 || x64 != y64) { - Pmsg3(-1, _("64 bit printf/scanf problem. i=%d x64=%" llu " y64=%" llu "\n"), + Pmsg3(-1, _("64 bit printf/scanf problem. i=%d x64=%" llu " y64=%" llu "\n"), i, x64, y64); exit(1); } @@ -274,6 +263,8 @@ int main(int margc, char *margv[]) config = new_config_parser(); parse_sd_config(config, configfile, M_ERROR_TERM); + setup_me(); + load_sd_plugins(me->plugin_directory); /* See if we can open a device */ if (margc == 0) { @@ -286,7 +277,7 @@ int main(int margc, char *margv[]) exit(1); } - jcr = setup_jcr("btape", margv[0], bsr, NULL, 0); /* write */ + jcr = setup_jcr("btape", margv[0], bsr, NULL, SD_APPEND); if (!jcr) { exit(1); } @@ -318,15 +309,10 @@ int main(int margc, char *margv[]) static void terminate_btape(int stat) { - sm_check(__FILE__, __LINE__, false); - if (configfile) { - free(configfile); - } - if (config) { - config->free_resources(); - free(config); - config = NULL; - } + Dsm_check(200); + free_jcr(jcr); + jcr = NULL; + if (args) { free_pool_memory(args); args = NULL; @@ -340,8 +326,6 @@ static void terminate_btape(int stat) free_bsr(bsr); } - free_jcr(jcr); - jcr = NULL; free_volume_lists(); @@ -349,11 +333,22 @@ static void terminate_btape(int stat) dev->term(); } - if (debug_level > 10) + if (configfile) { + free(configfile); + } + + if (config) { + config->free_resources(); + free(config); + config = NULL; + } + + if (chk_dbglvl(10)) print_memory_pool_stats(); if (this_block) { free_block(this_block); + this_block = NULL; } stop_watchdog(); @@ -366,16 +361,111 @@ static void terminate_btape(int stat) exit(stat); } + +btime_t total_time=0; +uint64_t total_size=0; + +static void init_total_speed() +{ + total_size = 0; + total_time = 0; +} + +static void print_total_speed() +{ + char ec1[50], ec2[50]; + uint64_t rate = total_size / total_time; + Pmsg2(000, _("Total Volume bytes=%sB. Total Write rate = %sB/s\n"), + edit_uint64_with_suffix(total_size, ec1), + edit_uint64_with_suffix(rate, ec2)); +} + +static void init_speed() +{ + time(&jcr->run_time); /* start counting time for rates */ + jcr->JobBytes=0; +} + +static void print_speed(uint64_t bytes) +{ + char ec1[50], ec2[50]; + uint64_t rate; + + now = time(NULL); + now -= jcr->run_time; + if (now <= 0) { + now = 1; /* don't divide by zero */ + } + + total_time += now; + total_size += bytes; + + rate = bytes / now; + Pmsg2(000, _("Volume bytes=%sB. Write rate = %sB/s\n"), + edit_uint64_with_suffix(bytes, ec1), + edit_uint64_with_suffix(rate, ec2)); +} + +/* + * Helper that fill a buffer with random data or not + */ +typedef enum { + FILL_RANDOM, + FILL_ZERO +} fill_mode_t; + +static void fill_buffer(fill_mode_t mode, char *buf, uint32_t len) +{ + int fd; + switch (mode) { + case FILL_RANDOM: + fd = open("/dev/urandom", O_RDONLY); + if (fd != -1) { + read(fd, buf, len); + close(fd); + } else { + uint32_t *p = (uint32_t *)buf; + srandom(time(NULL)); + for (uint32_t i=0; ir_dlock(); + dev->rLock(false); Dmsg1(200, "Opening device %s\n", dcr->VolumeName); - if (dev->open(dcr, OPEN_READ_WRITE) < 0) { - Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), dev->errmsg); + if (!dev->open(dcr, OPEN_READ_WRITE)) { + Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), dev->print_errmsg()); ok = false; goto bail_out; } @@ -383,7 +473,7 @@ static bool open_the_device() dev->set_append(); /* put volume in append mode */ bail_out: - dev->dunlock(); + dev->Unlock(); free_block(block); return ok; } @@ -422,7 +512,7 @@ static void labelcmd() */ static void readlabelcmd() { - int save_debug_level = debug_level; + int64_t save_debug_level = debug_level; int stat; stat = read_dev_volume_label(dcr); @@ -436,6 +526,9 @@ static void readlabelcmd() case VOL_IO_ERROR: Pmsg1(0, _("I/O error on device: ERR=%s"), dev->bstrerror()); break; + case VOL_TYPE_ERROR: + Pmsg1(0, _("Volume type error: ERR=%s\n"), dev->print_errmsg()); + break; case VOL_NAME_ERROR: Pmsg0(0, _("Volume name error\n")); break; @@ -638,7 +731,7 @@ static void capcmd() */ static void rectestcmd() { - DEV_BLOCK *block; + DEV_BLOCK *save_block; DEV_RECORD *rec; int i, blkno = 0; @@ -654,27 +747,29 @@ static void rectestcmd() return; } - sm_check(__FILE__, __LINE__, false); - block = new_block(dev); + Dsm_check(200); + save_block = dcr->block; + dcr->block = new_block(dev); rec = new_record(); for (i=1; i<500000; i++) { rec->data = check_pool_memory_size(rec->data, i); memset(rec->data, i & 0xFF, i); rec->data_len = i; - sm_check(__FILE__, __LINE__, false); - if (write_record_to_block(block, rec)) { - empty_block(block); + Dsm_check(200); + if (write_record_to_block(dcr, rec)) { + empty_block(dcr->block); blkno++; Pmsg2(0, _("Block %d i=%d\n"), blkno, i); } else { break; } - sm_check(__FILE__, __LINE__, false); + Dsm_check(200); } free_record(rec); - free_block(block); - sm_check(__FILE__, __LINE__, false); + free_block(dcr->block); + dcr->block = save_block; /* restore block to dcr */ + Dsm_check(200); } /* @@ -708,33 +803,33 @@ static bool re_read_block_test() rec->data = check_pool_memory_size(rec->data, block->buf_len); len = rec->data_len = block->buf_len-100; memset(rec->data, 1, rec->data_len); - if (!write_record_to_block(block, rec)) { + if (!write_record_to_block(dcr, rec)) { Pmsg0(0, _("Error writing record to block.\n")); goto bail_out; } - if (!write_block_to_dev(dcr)) { + if (!dcr->write_block_to_dev()) { Pmsg0(0, _("Error writing block to device.\n")); goto bail_out; } else { Pmsg1(0, _("Wrote first record of %d bytes.\n"), rec->data_len); } memset(rec->data, 2, rec->data_len); - if (!write_record_to_block(block, rec)) { + if (!write_record_to_block(dcr, rec)) { Pmsg0(0, _("Error writing record to block.\n")); goto bail_out; } - if (!write_block_to_dev(dcr)) { + if (!dcr->write_block_to_dev()) { Pmsg0(0, _("Error writing block to device.\n")); goto bail_out; } else { Pmsg1(0, _("Wrote second record of %d bytes.\n"), rec->data_len); } memset(rec->data, 3, rec->data_len); - if (!write_record_to_block(block, rec)) { + if (!write_record_to_block(dcr, rec)) { Pmsg0(0, _("Error writing record to block.\n")); goto bail_out; } - if (!write_block_to_dev(dcr)) { + if (!dcr->write_block_to_dev()) { Pmsg0(0, _("Error writing block to device.\n")); goto bail_out; } else { @@ -760,13 +855,12 @@ static bool re_read_block_test() goto bail_out; } Pmsg0(0, _("Backspace record OK.\n")); - if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) { - berrno be; - Pmsg1(0, _("Read block failed! ERR=%s\n"), be.bstrerror(dev->dev_errno)); + if (!dcr->read_block_from_dev(NO_BLOCK_NUMBER_CHECK)) { + Pmsg1(0, _("Read block failed! ERR=%s\n"), dev->print_errmsg()); goto bail_out; } memset(rec->data, 0, rec->data_len); - if (!read_record_from_block(dcr, block, rec)) { + if (!read_record_from_block(dcr, rec)) { berrno be; Pmsg1(0, _("Read block failed! ERR=%s\n"), be.bstrerror(dev->dev_errno)); goto bail_out; @@ -795,6 +889,220 @@ bail_out: return rc; } +static bool speed_test_raw(fill_mode_t mode, uint64_t nb_gb, uint32_t nb) +{ + DEV_BLOCK *block = dcr->block; + int stat; + uint32_t block_num = 0; + int my_errno; + char ed1[200]; + nb_gb *= 1024*1024*1024; /* convert size from nb to GB */ + + init_total_speed(); + fill_buffer(mode, block->buf, block->buf_len); + + Pmsg3(0, _("Begin writing %i files of %sB with raw blocks of %u bytes.\n"), + nb, edit_uint64_with_suffix(nb_gb, ed1), block->buf_len); + + for (uint32_t j=0; jJobBytes < nb_gb; ) { + stat = dev->d_write(dev->fd(), block->buf, block->buf_len); + if (stat == (int)block->buf_len) { + if ((block_num++ % 500) == 0) { + printf("+"); + fflush(stdout); + } + + mix_buffer(mode, block->buf, block->buf_len); + + jcr->JobBytes += stat; + + } else { + my_errno = errno; + printf("\n"); + berrno be; + printf(_("Write failed at block %u. stat=%d ERR=%s\n"), block_num, + stat, be.bstrerror(my_errno)); + return false; + } + } + printf("\n"); + weofcmd(); + print_speed(jcr->JobBytes); + } + print_total_speed(); + printf("\n"); + return true; +} + + +static bool speed_test_bacula(fill_mode_t mode, uint64_t nb_gb, uint32_t nb) +{ + DEV_BLOCK *block = dcr->block; + char ed1[200]; + DEV_RECORD *rec; + uint64_t last_bytes = dev->VolCatInfo.VolCatBytes; + uint64_t written=0; + + nb_gb *= 1024*1024*1024; /* convert size from nb to GB */ + + init_total_speed(); + + empty_block(block); + rec = new_record(); + rec->data = check_pool_memory_size(rec->data, block->buf_len); + rec->data_len = block->buf_len-100; + + fill_buffer(mode, rec->data, rec->data_len); + + Pmsg3(0, _("Begin writing %i files of %sB with blocks of %u bytes.\n"), + nb, edit_uint64_with_suffix(nb_gb, ed1), block->buf_len); + + for (uint32_t j=0; jwrite_block_to_dev()) { + Pmsg0(0, _("\nError writing block to device.\n")); + goto bail_out; + } + + if ((block->BlockNumber % 500) == 0) { + printf("+"); + fflush(stdout); + } + written += dev->VolCatInfo.VolCatBytes - last_bytes; + last_bytes = dev->VolCatInfo.VolCatBytes; + mix_buffer(mode, rec->data, rec->data_len); + } + printf("\n"); + weofcmd(); + print_speed(written); + } + print_total_speed(); + printf("\n"); + free_record(rec); + return true; + +bail_out: + free_record(rec); + return false; +} + +/* TODO: use UAContext */ +static int btape_find_arg(const char *keyword) +{ + for (int i=1; i 0) { + file_size = atoi(argv[i]); + if (file_size > 100) { + Pmsg0(0, _("The file_size is too big, stop this test with Ctrl-c.\n")); + } + } + + i = btape_find_arg("nb_file"); + if (i > 0) { + nb_file = atoi(argv[i]); + } + + if (btape_find_arg("skip_zero") > 0) { + do_zero = false; + } + + if (btape_find_arg("skip_random") > 0) { + do_random = false; + } + + if (btape_find_arg("skip_raw") > 0) { + do_raw = false; + } + + if (btape_find_arg("skip_block") > 0) { + do_block = false; + } + + if (do_raw) { + dev->rewind(dcr); + if (do_zero) { + Pmsg0(0, _("Test with zero data, should give the " + "maximum throughput.\n")); + if (file_size) { + ok(speed_test_raw(FILL_ZERO, file_size, nb_file)); + } else { + ok(speed_test_raw(FILL_ZERO, 1, nb_file)); + ok(speed_test_raw(FILL_ZERO, 2, nb_file)); + ok(speed_test_raw(FILL_ZERO, 4, nb_file)); + } + } + + if (do_random) { + Pmsg0(0, _("Test with random data, should give the minimum " + "throughput.\n")); + if (file_size) { + ok(speed_test_raw(FILL_RANDOM, file_size, nb_file)); + } else { + ok(speed_test_raw(FILL_RANDOM, 1, nb_file)); + ok(speed_test_raw(FILL_RANDOM, 2, nb_file)); + ok(speed_test_raw(FILL_RANDOM, 4, nb_file)); + } + } + } + + if (do_block) { + dev->rewind(dcr); + if (do_zero) { + Pmsg0(0, _("Test with zero data and bacula block structure.\n")); + if (file_size) { + ok(speed_test_bacula(FILL_ZERO, file_size, nb_file)); + } else { + ok(speed_test_bacula(FILL_ZERO, 1, nb_file)); + ok(speed_test_bacula(FILL_ZERO, 2, nb_file)); + ok(speed_test_bacula(FILL_ZERO, 4, nb_file)); + } + } + + if (do_random) { + Pmsg0(0, _("Test with random data, should give the minimum " + "throughput.\n")); + if (file_size) { + ok(speed_test_bacula(FILL_RANDOM, file_size, nb_file)); + } else { + ok(speed_test_bacula(FILL_RANDOM, 1, nb_file)); + ok(speed_test_bacula(FILL_RANDOM, 2, nb_file)); + ok(speed_test_bacula(FILL_RANDOM, 4, nb_file)); + } + } + } +} + const int num_recs = 10000; static bool write_two_files() @@ -804,7 +1112,14 @@ static bool write_two_files() int len, i, j; int *p; bool rc = false; /* bad return code */ + DEVICE *dev = dcr->dev; + /* + * Set big max_file_size so that write_record_to_block + * doesn't insert any additional EOF marks + * Do calculation in 64 bits to avoid overflow. + */ + dev->max_file_size = (uint64_t)2 * (uint64_t)num_recs * (uint64_t)dev->max_block_size; Pmsg2(-1, _("\n=== Write, rewind, and re-read test ===\n\n" "I'm going to write %d records and an EOF\n" "then write %d records and an EOF, then rewind,\n" @@ -828,11 +1143,11 @@ static bool write_two_files() for (j=0; jwrite_block_to_dev()) { Pmsg0(0, _("Error writing block to device.\n")); goto bail_out; } @@ -844,11 +1159,11 @@ static bool write_two_files() for (j=0; jwrite_block_to_dev()) { Pmsg0(0, _("Error writing block to device.\n")); goto bail_out; } @@ -905,19 +1220,18 @@ static bool write_read_test() /* Now read it back */ for (i=1; i<=2*num_recs; i++) { read_again: - if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) { - berrno be; + if (!dcr->read_block_from_dev(NO_BLOCK_NUMBER_CHECK)) { if (dev_state(dev, ST_EOF)) { Pmsg0(-1, _("Got EOF on tape.\n")); if (i == num_recs+1) { goto read_again; } } - Pmsg2(0, _("Read block %d failed! ERR=%s\n"), i, be.bstrerror(dev->dev_errno)); + Pmsg2(0, _("Read block %d failed! ERR=%s\n"), i, dev->print_errmsg()); goto bail_out; } memset(rec->data, 0, rec->data_len); - if (!read_record_from_block(dcr, block, rec)) { + if (!read_record_from_block(dcr, rec)) { berrno be; Pmsg2(0, _("Read record failed. Block %d! ERR=%s\n"), i, be.bstrerror(dev->dev_errno)); goto bail_out; @@ -941,7 +1255,7 @@ read_again: bail_out: free_record(rec); if (!rc) { - exit_code = 1; + exit_code = 1; } return rc; } @@ -1024,8 +1338,7 @@ static bool position_test() goto bail_out; } read_again: - if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) { - berrno be; + if (!dcr->read_block_from_dev(NO_BLOCK_NUMBER_CHECK)) { if (dev_state(dev, ST_EOF)) { Pmsg0(-1, _("Got EOF on tape.\n")); if (!got_eof) { @@ -1034,7 +1347,7 @@ read_again: } } Pmsg4(0, _("Read block %d failed! file=%d blk=%d. ERR=%s\n\n"), - recno, file, blk, be.bstrerror(dev->dev_errno)); + recno, file, blk, dev->print_errmsg()); Pmsg0(0, _("This may be because the tape drive block size is not\n" " set to variable blocking as normally used by Bacula.\n" " Please see the Tape Testing chapter in the manual and \n" @@ -1049,7 +1362,7 @@ read_again: goto bail_out; } memset(rec->data, 0, rec->data_len); - if (!read_record_from_block(dcr, block, rec)) { + if (!read_record_from_block(dcr, rec)) { berrno be; Pmsg1(0, _("Read record failed! ERR=%s\n"), be.bstrerror(dev->dev_errno)); goto bail_out; @@ -1176,7 +1489,7 @@ try_again: dcr->VolCatInfo.Slot = slot; /* Find out what is loaded, zero means device is unloaded */ Pmsg0(-1, _("3301 Issuing autochanger \"loaded\" command.\n")); - changer = edit_device_codes(dcr, changer, + changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded"); status = run_program(changer, timeout, results); Dmsg3(100, "run_prog: %s stat=%d result=\"%s\"\n", changer, status, results); @@ -1200,7 +1513,7 @@ try_again: dev->close(); Pmsg2(-1, _("3302 Issuing autochanger \"unload %d %d\" command.\n"), loaded, dev->drive_index); - changer = edit_device_codes(dcr, changer, + changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "unload"); status = run_program(changer, timeout, results); Pmsg2(-1, _("unload status=%s %d\n"), status==0?_("OK"):_("Bad"), status); @@ -1219,7 +1532,7 @@ try_again: dcr->VolCatInfo.Slot = slot; Pmsg2(-1, _("3303 Issuing autochanger \"load %d %d\" command.\n"), slot, dev->drive_index); - changer = edit_device_codes(dcr, changer, + changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "load"); Dmsg1(100, "Changer=%s\n", changer); dev->close(); @@ -1559,7 +1872,7 @@ static void fsrcmd() static void rbcmd() { dev->open(dcr, OPEN_READ_ONLY); - read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK); + dcr->read_block_from_dev(NO_BLOCK_NUMBER_CHECK); } /* @@ -1574,7 +1887,7 @@ static void wrcmd() if (!dev->is_open()) { open_the_device(); } - sm_check(__FILE__, __LINE__, false); + Dsm_check(200); empty_block(block); if (verbose > 1) { dump_block(block, "test"); @@ -1585,12 +1898,12 @@ static void wrcmd() rec->data = check_pool_memory_size(rec->data, i); memset(rec->data, i & 0xFF, i); rec->data_len = i; - sm_check(__FILE__, __LINE__, false); - if (!write_record_to_block(block, rec)) { + Dsm_check(200); + if (!write_record_to_block(dcr, rec)) { Pmsg0(0, _("Error writing record to block.\n")); goto bail_out; } - if (!write_block_to_dev(dcr)) { + if (!dcr->write_block_to_dev()) { Pmsg0(0, _("Error writing block to device.\n")); goto bail_out; } else { @@ -1599,8 +1912,7 @@ static void wrcmd() Pmsg0(0, _("Wrote block to device.\n")); bail_out: - sm_check(__FILE__, __LINE__, false); - sm_check(__FILE__, __LINE__, false); + Dsm_check(200); } /* @@ -1736,7 +2048,7 @@ static void scan_blocks() dev->update_pos(dcr); tot_files = dev->file; for (;;) { - if (!read_block_from_device(dcr, NO_BLOCK_NUMBER_CHECK)) { + if (!dcr->read_block_from_device(NO_BLOCK_NUMBER_CHECK)) { Dmsg1(100, "!read_block(): ERR=%s\n", dev->bstrerror()); if (dev->state & ST_EOT) { if (blocks > 0) { @@ -1776,7 +2088,7 @@ static void scan_blocks() printf(_("Short block read.\n")); continue; } - printf(_("Error reading block. ERR=%s\n"), dev->bstrerror()); + printf(_("Error reading block. ERR=%s\n"), dev->print_errmsg()); goto bail_out; } if (block->block_len != block_size) { @@ -1794,14 +2106,14 @@ static void scan_blocks() blocks++; tot_blocks++; bytes += block->block_len; - Dmsg6(100, "Blk_blk=%u dev_blk=%u blen=%u bVer=%d SessId=%u SessTim=%u\n", - block->BlockNumber, dev->block_num, block->block_len, block->BlockVer, + Dmsg7(100, "Blk_blk=%u file,blk=%u,%u blen=%u bVer=%d SessId=%u SessTim=%u\n", + block->BlockNumber, dev->file, dev->block_num, block->block_len, block->BlockVer, block->VolSessionId, block->VolSessionTime); if (verbose == 1) { DEV_RECORD *rec = new_record(); - read_record_from_block(dcr, block, rec); - Pmsg8(-1, _("Blk_block: %u dev_blk=%u blen=%u First rec FI=%s SessId=%u SessTim=%u Strm=%s rlen=%d\n"), - block->BlockNumber, dev->block_num, block->block_len, + read_record_from_block(dcr, rec); + Pmsg9(-1, _("Block=%u file,blk=%u,%u blen=%u First rec FI=%s SessId=%u SessTim=%u Strm=%s rlen=%d\n"), + block->BlockNumber, dev->file, dev->block_num, block->block_len, FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId, rec->VolSessionTime, stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len); rec->remainder = 0; @@ -1820,7 +2132,7 @@ bail_out: static void statcmd() { - int debug = debug_level; + int64_t debug = debug_level; debug_level = 30; Pmsg2(0, _("Device status: %u. ERR=%s\n"), status_dev(dev), dev->bstrerror()); #ifdef xxxx @@ -1838,11 +2150,12 @@ static void fillcmd() { DEV_RECORD rec; DEV_BLOCK *block = dcr->block; - char ec1[50]; + char ec1[50], ec2[50]; char buf1[100], buf2[100]; - int fd; - uint32_t i; + uint64_t write_eof; + uint64_t rate; uint32_t min_block_size; + int fd; struct tm tm; ok = true; @@ -1853,7 +2166,7 @@ static void fillcmd() BlockNumber = 0; exit_code = 0; - Pmsg0(-1, _("\n" + Pmsg1(-1, _("\n" "This command simulates Bacula writing to a tape.\n" "It requires either one or two blank tapes, which it\n" "will label and write.\n\n" @@ -1861,14 +2174,15 @@ static void fillcmd() "the tapes that are in slots 1 and 2, otherwise, you will\n" "be prompted to insert the tapes when necessary.\n\n" "It will print a status approximately\n" -"every 322 MB, and write an EOF every 3.2 GB. If you have\n" +"every 322 MB, and write an EOF every %s. If you have\n" "selected the simple test option, after writing the first tape\n" "it will rewind it and re-read the last block written.\n\n" "If you have selected the multiple tape test, when the first tape\n" "fills, it will ask for a second, and after writing a few more \n" "blocks, it will stop. Then it will begin re-reading the\n" "two tapes.\n\n" -"This may take a long time -- hours! ...\n\n")); +"This may take a long time -- hours! ...\n\n"), + edit_uint64_with_suffix(dev->max_file_size, buf1)); get_cmd(_("Do you want to run the simplified test (s) with one tape\n" "or the complete multiple tape (m) test: (s/m) ")); @@ -1890,6 +2204,7 @@ static void fillcmd() /* Use fixed block size to simplify read back */ min_block_size = dev->min_block_size; dev->min_block_size = dev->max_block_size; + write_eof = dev->max_file_size / REC_SIZE; /*compute when we add EOF*/ set_volume_name("TestVolume1", 1); dir_ask_sysop_to_create_appendable_volume(dcr); dev->set_append(); /* force volume to be relabeled */ @@ -1901,7 +2216,7 @@ static void fillcmd() */ Dmsg0(100, "just before acquire_device\n"); if (!acquire_device_for_append(dcr)) { - set_jcr_job_status(jcr, JS_ErrorTerminated); + jcr->setJobStatus(JS_ErrorTerminated); exit_code = 1; return; } @@ -1912,7 +2227,7 @@ static void fillcmd() * Write Begin Session Record */ if (!write_session_label(dcr, SOS_LABEL)) { - set_jcr_job_status(jcr, JS_ErrorTerminated); + jcr->setJobStatus(JS_ErrorTerminated); Jmsg1(jcr, M_FATAL, 0, _("Write session label failed. ERR=%s\n"), dev->bstrerror()); ok = false; @@ -1921,24 +2236,12 @@ static void fillcmd() memset(&rec, 0, sizeof(rec)); rec.data = get_memory(100000); /* max record size */ - -#define REC_SIZE 32768 rec.data_len = REC_SIZE; /* * Put some random data in the record */ - fd = open("/dev/urandom", O_RDONLY); - if (fd != -1) { - read(fd, rec.data, rec.data_len); - close(fd); - } else { - uint32_t *p = (uint32_t *)rec.data; - srandom(time(NULL)); - for (i=0; iVolSessionTime; rec.FileIndex = ++file_index; rec.Stream = STREAM_FILE_DATA; + rec.maskedStream = STREAM_FILE_DATA; /* Mix up the data just a bit */ - uint32_t *lp = (uint32_t *)rec.data; - lp[0] += lp[13]; - for (i=1; i < (rec.data_len-sizeof(uint32_t))/sizeof(uint32_t)-1; i++) { - lp[i] += lp[i-1]; - } + mix_buffer(FILL_RANDOM, rec.data, rec.data_len); Dmsg4(250, "before write_rec FI=%d SessId=%d Strm=%s len=%d\n", - rec.FileIndex, rec.VolSessionId, + rec.FileIndex, rec.VolSessionId, stream_to_ascii(buf1, rec.Stream, rec.FileIndex), rec.data_len); - while (!write_record_to_block(block, &rec)) { + while (!write_record_to_block(dcr, &rec)) { /* * When we get here we have just filled a block */ @@ -1979,6 +2279,7 @@ static void fillcmd() /* Write block to tape */ if (!flush_block(block, 1)) { + Pmsg0(000, _("Flush block failed.\n")); exit_code = 1; break; } @@ -1991,24 +2292,28 @@ static void fillcmd() if (now <= 0) { now = 1; /* prevent divide error */ } - kbs = (double)dev->VolCatInfo.VolCatBytes / (1000.0 * (double)now); - Pmsg4(-1, _("Wrote blk_block=%u, dev_blk_num=%u VolBytes=%s rate=%.1f KB/s\n"), - block->BlockNumber, dev->block_num, - edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1), (float)kbs); + rate = dev->VolCatInfo.VolCatBytes / now; + Pmsg5(-1, _("Wrote block=%u, file,blk=%u,%u VolBytes=%s rate=%sB/s\n"), + block->BlockNumber, dev->file, dev->block_num, + edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1), + edit_uint64_with_suffix(rate, ec2)); } - /* Every 32000 blocks (approx 2GB) write an EOF. + /* Every X blocks (dev->max_file_size) write an EOF. */ - if ((block->BlockNumber % 32000) == 0) { + if ((block->BlockNumber % write_eof) == 0) { now = time(NULL); (void)localtime_r(&now, &tm); strftime(buf1, sizeof(buf1), "%H:%M:%S", &tm); Pmsg1(-1, _("%s Flush block, write EOF\n"), buf1); flush_block(block, 0); +#ifdef needed_xxx dev->weof(1); +#endif } - /* Get out after writing 10 blocks to the second tape */ - if (++BlockNumber > 10 && stop != 0) { /* get out */ + /* Get out after writing 1000 blocks to the second tape */ + if (++BlockNumber > 1000 && stop != 0) { /* get out */ + Pmsg0(000, _("Wrote 1000 blocks on second tape. Done.\n")); break; } } @@ -2022,21 +2327,23 @@ static void fillcmd() FI_to_ascii(buf1, rec.FileIndex), rec.VolSessionId, stream_to_ascii(buf2, rec.Stream, rec.FileIndex), rec.data_len); - /* Get out after writing 10 blocks to the second tape */ - if (BlockNumber > 10 && stop != 0) { /* get out */ + /* Get out after writing 1000 blocks to the second tape */ + if (BlockNumber > 1000 && stop != 0) { /* get out */ char ed1[50]; - Pmsg1(-1, "Done writing %s records ...\n", + Pmsg1(-1, "Done writing %s records ...\n", edit_uint64_with_commas(write_count, ed1)); break; } - } + } /* end big for loop */ + if (vol_num > 1) { Dmsg0(100, "Write_end_session_label()\n"); /* Create Job status for end of session label */ if (!job_canceled(jcr) && ok) { - set_jcr_job_status(jcr, JS_Terminated); + jcr->setJobStatus(JS_Terminated); } else if (!ok) { - set_jcr_job_status(jcr, JS_ErrorTerminated); + Pmsg0(000, _("Job canceled.\n")); + jcr->setJobStatus(JS_ErrorTerminated); exit_code = 1; } if (!write_session_label(dcr, EOS_LABEL)) { @@ -2045,7 +2352,7 @@ static void fillcmd() exit_code = 1; } /* Write out final block of this session */ - if (!write_block_to_device(dcr)) { + if (!dcr->write_block_to_device()) { Pmsg0(-1, _("Set ok=false after write_block_to_device.\n")); ok = false; exit_code = 1; @@ -2074,32 +2381,37 @@ static void fillcmd() write(fd, last_block2->buf, last_block2->buf_len); write(fd, first_block->buf, first_block->buf_len); close(fd); - Pmsg2(-1, _("Wrote state file last_block_num1=%d last_block_num2=%d\n"), + Pmsg2(0, _("Wrote state file last_block_num1=%d last_block_num2=%d\n"), last_block_num1, last_block_num2); } else { berrno be; - Pmsg2(-1, _("Could not create state file: %s ERR=%s\n"), buf, + Pmsg2(0, _("Could not create state file: %s ERR=%s\n"), buf, be.bstrerror()); exit_code = 1; + ok = false; } now = time(NULL); (void)localtime_r(&now, &tm); strftime(buf1, sizeof(buf1), "%H:%M:%S", &tm); - if (simple) { - Pmsg3(-1, _("\n\n%s Done filling tape at %d:%d. Now beginning re-read of tape ...\n"), - buf1, jcr->dcr->dev->file, jcr->dcr->dev->block_num); - } - else { - Pmsg3(-1, _("\n\n%s Done filling tapes at %d:%d. Now beginning re-read of first tape ...\n"), - buf1, jcr->dcr->dev->file, jcr->dcr->dev->block_num); - } + if (ok) { + if (simple) { + Pmsg3(0, _("\n\n%s Done filling tape at %d:%d. Now beginning re-read of tape ...\n"), + buf1, jcr->dcr->dev->file, jcr->dcr->dev->block_num); + } else { + Pmsg3(0, _("\n\n%s Done filling tapes at %d:%d. Now beginning re-read of first tape ...\n"), + buf1, jcr->dcr->dev->file, jcr->dcr->dev->block_num); + } - jcr->dcr->block = block; - if (!do_unfill()) { - exit_code = 1; + jcr->dcr->block = block; + if (!do_unfill()) { + Pmsg0(000, _("do_unfill failed.\n")); + exit_code = 1; + ok = false; + } + } else { + Pmsg1(000, _("%s: Error during test.\n"), buf1); } - dev->min_block_size = min_block_size; free_memory(rec.data); } @@ -2151,6 +2463,11 @@ static void unfillcmd() this_block = NULL; } +/* + * This is the second part of the fill command. After the tape or + * tapes are written, we are called here to reread parts, particularly + * the last block. + */ static bool do_unfill() { DEV_BLOCK *block = dcr->block; @@ -2161,7 +2478,7 @@ static bool do_unfill() VolBytes = 0; LastBlock = 0; - Dmsg0(20, "Enter do_unfill\n"); + Pmsg0(000, "Enter do_unfill\n"); dev->set_cap(CAP_ANONVOLS); /* allow reading any volume */ dev->clear_cap(CAP_LABEL); /* don't label anything here */ @@ -2199,15 +2516,18 @@ static bool do_unfill() } autochanger = autoload_device(dcr, 1, NULL); if (autochanger != 1) { + Pmsg1(100, "Autochanger returned: %d\n", autochanger); dev->close(); get_cmd(_("Mount first tape. Press enter when ready: ")); + Pmsg0(000, "\n"); } } dev->close(); dev->num_writers = 0; + dcr->clear_writing(); if (!acquire_device_for_read(dcr)) { - Pmsg1(-1, "%s", dev->errmsg); + Pmsg1(-1, "%s", dev->print_errmsg()); goto bail_out; } /* @@ -2231,13 +2551,14 @@ static bool do_unfill() goto bail_out; } Pmsg1(-1, _("Reading block %u.\n"), last_block_num); - if (!read_block_from_device(dcr, NO_BLOCK_NUMBER_CHECK)) { - Pmsg1(-1, _("Error reading block: ERR=%s\n"), dev->bstrerror()); + if (!dcr->read_block_from_device(NO_BLOCK_NUMBER_CHECK)) { + Pmsg1(-1, _("Error reading block: ERR=%s\n"), dev->print_errmsg()); goto bail_out; } if (compare_blocks(last_block, block)) { if (simple) { Pmsg0(-1, _("\nThe last block on the tape matches. Test succeeded.\n\n")); + rc = true; } else { Pmsg0(-1, _("\nThe last block of the first tape matches.\n\n")); } @@ -2261,13 +2582,16 @@ static bool do_unfill() autochanger = autoload_device(dcr, 1, NULL); if (autochanger != 1) { + Pmsg1(100, "Autochanger returned: %d\n", autochanger); dev->close(); get_cmd(_("Mount second tape. Press enter when ready: ")); + Pmsg0(000, "\n"); } dev->clear_read(); + dcr->clear_writing(); if (!acquire_device_for_read(dcr)) { - Pmsg1(-1, "%s", dev->errmsg); + Pmsg1(-1, "%s", dev->print_errmsg()); goto bail_out; } @@ -2280,8 +2604,8 @@ static bool do_unfill() goto bail_out; } Pmsg1(-1, _("Reading block %d.\n"), dev->block_num); - if (!read_block_from_device(dcr, NO_BLOCK_NUMBER_CHECK)) { - Pmsg1(-1, _("Error reading block: ERR=%s\n"), dev->bstrerror()); + if (!dcr->read_block_from_device(NO_BLOCK_NUMBER_CHECK)) { + Pmsg1(-1, _("Error reading block: ERR=%s\n"), dev->print_errmsg()); goto bail_out; } if (compare_blocks(first_block, block)) { @@ -2296,8 +2620,8 @@ static bool do_unfill() goto bail_out; } Pmsg1(-1, _("Reading block %d.\n"), dev->block_num); - if (!read_block_from_device(dcr, NO_BLOCK_NUMBER_CHECK)) { - Pmsg1(-1, _("Error reading block: ERR=%s\n"), dev->bstrerror()); + if (!dcr->read_block_from_device(NO_BLOCK_NUMBER_CHECK)) { + Pmsg1(-1, _("Error reading block: ERR=%s\n"), dev->print_errmsg()); goto bail_out; } if (compare_blocks(last_block, block)) { @@ -2309,6 +2633,7 @@ bail_out: free_block(last_block1); free_block(last_block2); free_block(first_block); + last_block = first_block = last_block1 = last_block2 = NULL; return rc; } @@ -2326,7 +2651,10 @@ static bool quickie_cb(DCR *dcr, DEV_RECORD *rec) static bool compare_blocks(DEV_BLOCK *last_block, DEV_BLOCK *block) { char *p, *q; - uint32_t CheckSum, block_len; + union { + uint32_t CheckSum; + uint32_t block_len; + }; ser_declare; p = last_block->buf; @@ -2358,10 +2686,6 @@ static bool compare_blocks(DEV_BLOCK *last_block, DEV_BLOCK *block) return true; } - - - - /* * Write current block to tape regardless of whether or * not it is full. If the tape fills, attempt to @@ -2369,11 +2693,12 @@ static bool compare_blocks(DEV_BLOCK *last_block, DEV_BLOCK *block) */ static int flush_block(DEV_BLOCK *block, int dump) { - char ec1[50]; + char ec1[50], ec2[50]; + uint64_t rate; DEV_BLOCK *tblock; uint32_t this_file, this_block_num; - dev->r_dlock(); + dev->rLock(false); if (!this_block) { this_block = new_block(dev); } @@ -2383,7 +2708,7 @@ static int flush_block(DEV_BLOCK *block, int dump) /* Copy block */ this_file = dev->file; this_block_num = dev->block_num; - if (!write_block_to_dev(dcr)) { + if (!dcr->write_block_to_dev()) { Pmsg3(000, _("Last block at: %u:%u this_dev_block_num=%d\n"), last_file, last_block_num, this_block_num); if (vol_num == 1) { @@ -2415,11 +2740,12 @@ static int flush_block(DEV_BLOCK *block, int dump) if (now <= 0) { now = 1; /* don't divide by zero */ } - kbs = (double)dev->VolCatInfo.VolCatBytes / (1000 * now); + rate = dev->VolCatInfo.VolCatBytes / now; vol_size = dev->VolCatInfo.VolCatBytes; - Pmsg4(000, _("End of tape %d:%d. VolumeCapacity=%s. Write rate = %.1f KB/s\n"), + Pmsg4(000, _("End of tape %d:%d. Volume Bytes=%s. Write rate = %sB/s\n"), dev->file, dev->block_num, - edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1), kbs); + edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1), + edit_uint64_with_suffix(rate, ec2)); if (simple) { stop = -1; /* stop, but do simplified test */ @@ -2428,12 +2754,12 @@ static int flush_block(DEV_BLOCK *block, int dump) if (!fixup_device_block_write_error(jcr->dcr)) { Pmsg1(000, _("Cannot fixup device error. %s\n"), dev->bstrerror()); ok = false; - dev->dunlock(); + dev->Unlock(); return 0; } BlockNumber = 0; /* start counting for second tape */ } - dev->dunlock(); + dev->Unlock(); return 1; /* end of tape reached */ } @@ -2452,7 +2778,7 @@ static int flush_block(DEV_BLOCK *block, int dump) last_file = this_file; last_block_num = this_block_num; - dev->dunlock(); + dev->Unlock(); return 1; } @@ -2476,7 +2802,7 @@ static void qfillcmd() count = 1000; } - sm_check(__FILE__, __LINE__, false); + Dsm_check(200); i = block->buf_len - 100; ASSERT (i > 0); @@ -2484,22 +2810,25 @@ static void qfillcmd() memset(rec->data, i & 0xFF, i); rec->data_len = i; rewindcmd(); + init_speed(); + Pmsg1(0, _("Begin writing %d Bacula blocks to tape ...\n"), count); for (i=0; i < count; i++) { if (i % 100 == 0) { printf("+"); fflush(stdout); } - if (!write_record_to_block(block, rec)) { + if (!write_record_to_block(dcr, rec)) { Pmsg0(0, _("Error writing record to block.\n")); goto bail_out; } - if (!write_block_to_dev(dcr)) { + if (!dcr->write_block_to_dev()) { Pmsg0(0, _("Error writing block to device.\n")); goto bail_out; } } printf("\n"); + print_speed(dev->VolCatInfo.VolCatBytes); weofcmd(); if (dev->has_cap(CAP_TWOEOF)) { weofcmd(); @@ -2508,7 +2837,7 @@ static void qfillcmd() scan_blocks(); bail_out: - sm_check(__FILE__, __LINE__, false); + Dsm_check(200); } /* @@ -2518,23 +2847,13 @@ static void rawfill_cmd() { DEV_BLOCK *block = dcr->block; int stat; - int fd; uint32_t block_num = 0; uint32_t *p; int my_errno; - uint32_t i; - fd = open("/dev/urandom", O_RDONLY); - if (fd) { - read(fd, block->buf, block->buf_len); - close(fd); - } else { - uint32_t *p = (uint32_t *)block->buf; - srandom(time(NULL)); - for (i=0; ibuf_len/sizeof(uint32_t); i++) { - p[i] = random(); - } - } + fill_buffer(FILL_RANDOM, block->buf, block->buf_len); + init_speed(); + p = (uint32_t *)block->buf; Pmsg1(0, _("Begin writing raw blocks of %u bytes.\n"), block->buf_len); for ( ;; ) { @@ -2545,10 +2864,10 @@ static void rawfill_cmd() printf("+"); fflush(stdout); } - p[0] += p[13]; - for (i=1; i<(block->buf_len-sizeof(uint32_t))/sizeof(uint32_t)-1; i++) { - p[i] += p[i-1]; - } + + mix_buffer(FILL_RANDOM, block->buf, block->buf_len); + + jcr->JobBytes += stat; continue; } break; @@ -2558,6 +2877,8 @@ static void rawfill_cmd() berrno be; printf(_("Write failed at block %u. stat=%d ERR=%s\n"), block_num, stat, be.bstrerror(my_errno)); + + print_speed(jcr->JobBytes); weofcmd(); } @@ -2586,6 +2907,7 @@ static struct cmdstruct commands[] = { {NT_("rewind"), rewindcmd, _("rewind the tape")}, {NT_("scan"), scancmd, _("read() tape block by block to EOT and report")}, {NT_("scanblocks"),scan_blocks, _("Bacula read block by block to EOT and report")}, + {NT_("speed"), speed_test, _("[file_size=n(GB)|nb_file=3|skip_zero|skip_random|skip_raw|skip_block] report drive speed")}, {NT_("status"), statcmd, _("print tape status")}, {NT_("test"), testcmd, _("General test Bacula tape functions")}, {NT_("weof"), weofcmd, _("write an EOF on the tape")}, @@ -2603,7 +2925,7 @@ do_tape_cmds() bool found; while (!quit && get_cmd("*")) { - sm_check(__FILE__, __LINE__, false); + Dsm_check(200); found = false; parse_args(cmd, &args, &argc, argk, argv, MAX_CMD_ARGS); for (i=0; i \n" " -b specify bootstrap file\n" " -c set configuration file to file\n" @@ -2643,7 +2965,7 @@ PROG_COPYRIGHT " -s turn off signals\n" " -v be verbose\n" " -? print this message.\n" -"\n"), 2000, VERSION, BDATE); +"\n"), 2000, "", VERSION, BDATE); } @@ -2685,6 +3007,7 @@ get_cmd(const char *prompt) /* Dummies to replace askdir.c */ bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;} bool dir_send_job_status(JCR *jcr) {return 1;} +bool flush_jobmedia_queue(JCR *jcr) { return true; } bool dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { @@ -2695,7 +3018,7 @@ bool dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing) { Dmsg0(20, "Enter dir_get_volume_info\n"); - bstrncpy(dcr->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dcr->VolCatInfo.VolCatName)); + dcr->setVolCatName(dcr->VolumeName); return 1; } @@ -2712,14 +3035,14 @@ bool dir_find_next_appendable_volume(DCR *dcr) return dcr->VolumeName[0] != 0; } -bool dir_ask_sysop_to_mount_volume(DCR *dcr, int /* mode */) +bool dir_ask_sysop_to_mount_volume(DCR *dcr, bool /* writing */) { DEVICE *dev = dcr->dev; Dmsg0(20, "Enter dir_ask_sysop_to_mount_volume\n"); if (dcr->VolumeName[0] == 0) { return dir_ask_sysop_to_create_appendable_volume(dcr); } - Pmsg1(-1, "%s", dev->errmsg); /* print reason */ + Pmsg1(-1, "%s", dev->print_errmsg()); /* print reason */ if (dcr->VolumeName[0] == 0 || strcmp(dcr->VolumeName, "TestVolume2") == 0) { fprintf(stderr, _("Mount second Volume on device %s and press return when ready: "), dev->print_name()); @@ -2748,10 +3071,12 @@ bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) } autochanger = autoload_device(dcr, 1, NULL); if (autochanger != 1) { + Pmsg1(100, "Autochanger returned: %d\n", autochanger); fprintf(stderr, _("Mount blank Volume on device %s and press return when ready: "), dev->print_name()); dev->close(); getchar(); + Pmsg0(000, "\n"); } labelcmd(); VolumeName = NULL; @@ -2761,7 +3086,8 @@ bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) static bool my_mount_next_read_volume(DCR *dcr) { - char ec1[50]; + char ec1[50], ec2[50]; + uint64_t rate; JCR *jcr = dcr->jcr; DEV_BLOCK *block = dcr->block; @@ -2779,9 +3105,10 @@ static bool my_mount_next_read_volume(DCR *dcr) if (now <= 0) { now = 1; } - kbs = (double)VolBytes / (1000.0 * (double)now); - Pmsg3(-1, _("Read block=%u, VolBytes=%s rate=%.1f KB/s\n"), block->BlockNumber, - edit_uint64_with_commas(VolBytes, ec1), (float)kbs); + rate = VolBytes / now; + Pmsg3(-1, _("Read block=%u, VolBytes=%s rate=%sB/s\n"), block->BlockNumber, + edit_uint64_with_commas(VolBytes, ec1), + edit_uint64_with_suffix(rate, ec2)); if (strcmp(dcr->VolumeName, "TestVolume2") == 0) { end_of_tape = 1; @@ -2803,8 +3130,8 @@ static void set_volume_name(const char *VolName, int volnum) DCR *dcr = jcr->dcr; VolumeName = VolName; vol_num = volnum; - bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName)); - bstrncpy(dcr->VolCatInfo.VolCatName, VolName, sizeof(dcr->VolCatInfo.VolCatName)); + dev->setVolCatName(VolName); + dcr->setVolCatName(VolName); bstrncpy(dcr->VolumeName, VolName, sizeof(dcr->VolumeName)); dcr->VolCatInfo.Slot = volnum; dcr->VolCatInfo.InChanger = true;