From: Kern Sibbald Date: Sat, 10 Jan 2004 13:32:42 +0000 (+0000) Subject: Doc updates + first cut Volume polling code X-Git-Tag: Release-1.34.0~169 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=40432ed8ae67601ac81fb74c7eb5a153cb2f8ad9;p=bacula%2Fbacula Doc updates + first cut Volume polling code git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@999 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/kernstodo b/bacula/kernstodo index e5f1dce9ce..2034f73c26 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -1,5 +1,5 @@ Kern's ToDo List - 22 December 2003 + 09 January 2004 Documentation to do: (any release a little bit at a time) - Document running a test version. @@ -41,6 +41,7 @@ For 1.33 Testing/Documentation: - Add counter variable test. - Document ln -sf /usr/lib/libncurses.so /usr/lib/libtermcap.so and install the esound-devĀ  package for compiling Console on SuSE. + This should read 'Document LDFLAGS="-L/usr/lib/termcap" ... ' - Add an example of using a FIFO in dirdconf.wml - Add an item to the FAQ about running jobs in different timezones. - Add some examples of job editing codes. @@ -55,19 +56,13 @@ For 1.33 Testing/Documentation: - Add subsections to the Disaster Recovery index section. For 1.33 -- Look at code in recycle_oldes_purged_volume() recycle.c. Why not - let SQL do ORDER BY LastWritten ASC? -- Look at find_next_volume() algorithm. Currently, it selects: - +---------+------------+---------------------+-----------+ - | MediaId | VolumeName | LastWritten | VolBytes | - +---------+------------+---------------------+-----------+ - | 3 | Test13 | 0000-00-00 00:00:00 | 1 | - | 4 | Test14 | 0000-00-00 00:00:00 | 1 | - | 1 | test11 | 2003-12-03 18:39:55 | 4,004,926 | - | 2 | test12 | 2004-01-04 15:25:56 | 2,078,691 | - +---------+------------+---------------------+-----------+ - but perhaps it should fill already used Volumes first, and use - Append volumes before Purged, or Recycled, ... +- Add level to estimate command. +- Check time/dates printed during restore when using Win32 API. +- Possibly remove the "|| ap == NULL" on lines 123 and 207 of lib/var.c, + which creates compile problems on alpha systems. + var.c:123: no match for `va_list & == long int' +- Check "restore" 3 (JobId), then it asks for Storage resource. Does + it verify that the correct volume is chosen? - Volume "add"ed to Pool gets recycled in first use. VolBytes=0 - Get rid of 0 dates in LastWritten, ... - Make Bacula "poll a drive". @@ -116,6 +111,7 @@ For 1.33 resources, like Level? If so, I think I'd make it an optional directive in Job, Client, and Pool, with precedence such that Job overrides Client which in turn overrides Pool. +- Print a message when a job starts if the conf file is not current. - Finish work on conio.c - To pass Include 1 or two letter commands I Name Include name - first record @@ -1071,3 +1067,16 @@ Done: (see kernsdone for more) gnome-console is built, but the binary and .conf are not being installed. - Permit Bacula and apcupsd donations (not done for apcupsd). - Fix Ctl-C crashing the Console (readline?). +- Look at code in recycle_oldes_purged_volume() recycle.c. Why not + let SQL do ORDER BY LastWritten ASC? +- Look at find_next_volume() algorithm. Currently, it selects: + +---------+------------+---------------------+-----------+ + | MediaId | VolumeName | LastWritten | VolBytes | + +---------+------------+---------------------+-----------+ + | 3 | Test13 | 0000-00-00 00:00:00 | 1 | + | 4 | Test14 | 0000-00-00 00:00:00 | 1 | + | 1 | test11 | 2003-12-03 18:39:55 | 4,004,926 | + | 2 | test12 | 2004-01-04 15:25:56 | 2,078,691 | + +---------+------------+---------------------+-----------+ + but perhaps it should fill already used Volumes first, and use + Append volumes before Purged, or Recycled, ... diff --git a/bacula/src/dird/backup.c b/bacula/src/dird/backup.c index 2480afbcee..0fe51441a9 100644 --- a/bacula/src/dird/backup.c +++ b/bacula/src/dird/backup.c @@ -385,14 +385,18 @@ static void backup_cleanup(JCR *jcr, int TermCode, char *since, FILESET_DBR *fsr msg_type = M_ERROR; /* Generate error message */ if (jcr->store_bsock) { bnet_sig(jcr->store_bsock, BNET_TERMINATE); - pthread_cancel(jcr->SD_msg_chan); + if (jcr->SD_msg_chan) { + pthread_cancel(jcr->SD_msg_chan); + } } break; case JS_Canceled: term_msg = _("Backup Canceled"); if (jcr->store_bsock) { bnet_sig(jcr->store_bsock, BNET_TERMINATE); - pthread_cancel(jcr->SD_msg_chan); + if (jcr->SD_msg_chan) { + pthread_cancel(jcr->SD_msg_chan); + } } break; default: diff --git a/bacula/src/dird/msgchan.c b/bacula/src/dird/msgchan.c index 1f3d42bb9c..94b8c664f8 100644 --- a/bacula/src/dird/msgchan.c +++ b/bacula/src/dird/msgchan.c @@ -196,6 +196,7 @@ static void msg_thread_cleanup(void *arg) P(jcr->mutex); jcr->sd_msg_thread_done = true; pthread_cond_broadcast(&jcr->term_wait); /* wakeup any waiting threads */ + jcr->SD_msg_chan = 0; V(jcr->mutex); free_jcr(jcr); /* release jcr */ } diff --git a/bacula/src/dird/restore.c b/bacula/src/dird/restore.c index 6dfb15ef14..47e6bd4db2 100644 --- a/bacula/src/dird/restore.c +++ b/bacula/src/dird/restore.c @@ -287,14 +287,18 @@ static void restore_cleanup(JCR *jcr, int TermCode) msg_type = M_ERROR; /* Generate error message */ if (jcr->store_bsock) { bnet_sig(jcr->store_bsock, BNET_TERMINATE); - pthread_cancel(jcr->SD_msg_chan); + if (jcr->SD_msg_chan) { + pthread_cancel(jcr->SD_msg_chan); + } } break; case JS_Canceled: term_msg = _("Restore Canceled"); if (jcr->store_bsock) { bnet_sig(jcr->store_bsock, BNET_TERMINATE); - pthread_cancel(jcr->SD_msg_chan); + if (jcr->SD_msg_chan) { + pthread_cancel(jcr->SD_msg_chan); + } } break; default: diff --git a/bacula/src/stored/askdir.c b/bacula/src/stored/askdir.c index 027b3f75aa..81138f0465 100644 --- a/bacula/src/stored/askdir.c +++ b/bacula/src/stored/askdir.c @@ -54,7 +54,7 @@ static char OK_media[] = "1000 OK VolName=%127s VolJobs=%u VolFiles=%u" static char OK_create[] = "1000 OK CreateJobMedia\n"; /* Forward referenced functions */ -static int wait_for_sysop(JCR *jcr, DEVICE *dev, int wait_sec); +static int wait_for_sysop(JCR *jcr, DEVICE *dev); /* * Send current JobStatus to Director @@ -159,7 +159,7 @@ int dir_find_next_appendable_volume(JCR *jcr) int dir_update_volume_info(JCR *jcr, DEVICE *dev, int label) { BSOCK *dir = jcr->dir_bsock; - time_t EndTime = time(NULL); + time_t LastWritten = time(NULL); char ed1[50], ed2[50], ed3[50], ed4[50]; VOLUME_CAT_INFO *vol = &dev->VolCatInfo; @@ -188,7 +188,7 @@ int dir_update_volume_info(JCR *jcr, DEVICE *dev, int label) vol->VolCatBlocks, edit_uint64(vol->VolCatBytes, ed1), vol->VolCatMounts, vol->VolCatErrors, vol->VolCatWrites, edit_uint64(vol->VolCatMaxBytes, ed2), - EndTime, vol->VolCatStatus, vol->Slot, label, + LastWritten, vol->VolCatStatus, vol->Slot, label, vol->InChanger, edit_uint64(vol->VolReadTime, ed3), edit_uint64(vol->VolWriteTime, ed4) ); @@ -262,8 +262,9 @@ int dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) } + /* - * Request to mount next Volume, which Volume not specified + * Request the sysop to create an appendable volume * * Entered with device blocked. * Leaves with device blocked. @@ -280,37 +281,34 @@ int dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) * actually be mounted. The calling routine must read it and * verify the label. */ -int dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev) +int dir_ask_sysop_to_create_appendable_volume(JCR *jcr, DEVICE *dev) { int stat = 0, jstat; - /* ******FIXME******* put these on config variable */ - int min_wait = 60 * 60; - int max_wait = 24 * 60 * 60; - int max_num_wait = 9; /* 5 waits =~ 1 day, then 1 day at a time */ - - int wait_sec; - int num_wait = 0; + bool unmounted; - Dmsg0(130, "enter dir_ask_sysop_to_mount_next_volume\n"); + Dmsg0(130, "enter dir_ask_sysop_to_create_appendable_volume\n"); ASSERT(dev->dev_blocked); - wait_sec = min_wait; for ( ;; ) { if (job_canceled(jcr)) { - Mmsg(&dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"), + Mmsg(&dev->errmsg, + _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"), jcr->Job, jcr->dev_name); Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg); return 0; } if (dir_find_next_appendable_volume(jcr)) { /* get suggested volume */ jstat = JS_WaitMount; + unmounted = (dev->dev_blocked == BST_UNMOUNTED) || + (dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP); /* * If we have a valid volume name and we are not * removable media, return now, or if we have a * Slot for an autochanger, otherwise wait * for the operator to mount the media. */ - if ((jcr->VolumeName[0] && !dev_cap(dev, CAP_REM) && dev_cap(dev, CAP_LABEL)) || - (jcr->VolumeName[0] && jcr->VolCatInfo.Slot)) { + if (!unmounted && ((jcr->VolumeName[0] && !dev_cap(dev, CAP_REM) && + dev_cap(dev, CAP_LABEL)) || + (jcr->VolumeName[0] && jcr->VolCatInfo.Slot))) { Dmsg0(100, "Return 1 from mount without wait.\n"); return 1; } @@ -322,32 +320,33 @@ int dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev) jcr->VolumeName, jcr->dev_name, jcr->Job); } else { jstat = JS_WaitMedia; - Jmsg(jcr, M_MOUNT, 0, _( + if (!dev->poll) { + Jmsg(jcr, M_MOUNT, 0, _( "Job %s waiting. Cannot find any appendable volumes.\n\ Please use the \"label\" command to create a new Volume for:\n\ Storage: %s\n\ Media type: %s\n\ Pool: %s\n"), - jcr->Job, - jcr->dev_name, - jcr->media_type, - jcr->pool_name); + jcr->Job, + jcr->dev_name, + jcr->media_type, + jcr->pool_name); + } } jcr->JobStatus = jstat; dir_send_job_status(jcr); - stat = wait_for_sysop(jcr, dev, wait_sec); + stat = wait_for_sysop(jcr, dev); + if (dev->poll) { + Dmsg1(200, "Poll timeout in create append vol on device %s\n", dev_name(dev)); + continue; + } if (stat == ETIMEDOUT) { - wait_sec *= 2; /* double wait time */ - if (wait_sec > max_wait) { /* but not longer than maxtime */ - wait_sec = max_wait; - } - num_wait++; - if (num_wait >= max_num_wait) { + if (!double_dev_wait_time(dev)) { Mmsg(&dev->errmsg, _("Gave up waiting to mount Storage Device \"%s\" for Job %s\n"), - jcr->dev_name, jcr->Job); + dev_name(dev), jcr->Job); Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg); Dmsg1(190, "Gave up waiting on device %s\n", dev_name(dev)); return 0; /* exceeded maximum waits */ @@ -366,22 +365,30 @@ Please use the \"label\" command to create a new Volume for:\n\ } Dmsg1(190, "Someone woke me for device %s\n", dev_name(dev)); - /* Restart wait counters */ - wait_sec = min_wait; - num_wait = 0; /* If no VolumeName, and cannot get one, try again */ if (jcr->VolumeName[0] == 0 && !job_canceled(jcr) && !dir_find_next_appendable_volume(jcr)) { Jmsg(jcr, M_MOUNT, 0, _( "Someone woke me up, but I cannot find any appendable\n\ volumes for Job=%s.\n"), jcr->Job); + /* Restart wait counters after user interaction */ + init_dev_wait_timers(dev); continue; } + unmounted = (dev->dev_blocked == BST_UNMOUNTED) || + (dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP); + if (unmounted) { + continue; /* continue to wait */ + } + + /* + * Device mounted, we have a volume, break and return + */ break; } set_jcr_job_status(jcr, JS_Running); dir_send_job_status(jcr); - Dmsg0(130, "leave dir_ask_sysop_to_mount_next_volume\n"); + Dmsg0(130, "leave dir_ask_sysop_to_mount_create_appendable_volume\n"); return 1; } @@ -400,47 +407,55 @@ volumes for Job=%s.\n"), jcr->Job); int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev) { int stat = 0; - /* ******FIXME******* put these on config variable */ - int min_wait = 60 * 60; - int max_wait = 24 * 60 * 60; - int max_num_wait = 9; /* 5 waits =~ 1 day, then 1 day at a time */ - int wait_sec; - int num_wait = 0; char *msg; - Dmsg0(130, "enter dir_ask_sysop_to_mount_next_volume\n"); + Dmsg0(130, "enter dir_ask_sysop_to_mount_volume\n"); if (!jcr->VolumeName[0]) { Mmsg0(&dev->errmsg, _("Cannot request another volume: no volume name given.\n")); return 0; } ASSERT(dev->dev_blocked); - wait_sec = min_wait; for ( ;; ) { if (job_canceled(jcr)) { Mmsg(&dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"), jcr->Job, jcr->dev_name); return 0; } - msg = _("Please mount"); - Jmsg(jcr, M_MOUNT, 0, _("%s Volume \"%s\" on Storage Device \"%s\" for Job %s\n"), - msg, jcr->VolumeName, jcr->dev_name, jcr->Job); - Dmsg3(190, "Mount %s on %s for Job %s\n", - jcr->VolumeName, jcr->dev_name, jcr->Job); + + /* + * If we have a valid volume name and we are not + * removable media, return now, or if we have a + * Slot for an autochanger, otherwise wait + * for the operator to mount the media. + */ + if ((jcr->VolumeName[0] && !dev_cap(dev, CAP_REM) && dev_cap(dev, CAP_LABEL)) || + (jcr->VolumeName[0] && jcr->VolCatInfo.Slot)) { + Dmsg0(100, "Return 1 from mount without wait.\n"); + return 1; + } + + if (!dev->poll) { + msg = _("Please mount"); + Jmsg(jcr, M_MOUNT, 0, _("%s Volume \"%s\" on Storage Device \"%s\" for Job %s\n"), + msg, jcr->VolumeName, jcr->dev_name, jcr->Job); + Dmsg3(190, "Mount %s on %s for Job %s\n", + jcr->VolumeName, jcr->dev_name, jcr->Job); + } jcr->JobStatus = JS_WaitMount; dir_send_job_status(jcr); - stat = wait_for_sysop(jcr, dev, wait_sec); /* wait on device */ + stat = wait_for_sysop(jcr, dev); /* wait on device */ + if (dev->poll) { + Dmsg1(200, "Poll timeout in mount vol on device %s\n", dev_name(dev)); + Dmsg1(200, "Blocked=%d\n", dev->dev_blocked); + return 1; + } if (stat == ETIMEDOUT) { - wait_sec *= 2; /* double wait time */ - if (wait_sec > max_wait) { /* but not longer than maxtime */ - wait_sec = max_wait; - } - num_wait++; - if (num_wait >= max_num_wait) { + if (!double_dev_wait_time(dev)) { Mmsg(&dev->errmsg, _("Gave up waiting to mount Storage Device \"%s\" for Job %s\n"), - jcr->dev_name, jcr->Job); + dev_name(dev), jcr->Job); Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg); Dmsg1(190, "Gave up waiting on device %s\n", dev_name(dev)); return 0; /* exceeded maximum waits */ @@ -458,59 +473,66 @@ int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev) strerror(stat)); } Dmsg1(190, "Someone woke me for device %s\n", dev_name(dev)); - - /* Restart wait counters */ - wait_sec = min_wait; - num_wait = 0; break; } set_jcr_job_status(jcr, JS_Running); dir_send_job_status(jcr); - Dmsg0(130, "leave dir_ask_sysop_to_mount_next_volume\n"); + Dmsg0(130, "leave dir_ask_sysop_to_mount_volume\n"); return 1; } /* * Wait for SysOp to mount a tape */ -static int wait_for_sysop(JCR *jcr, DEVICE *dev, int wait_sec) +static int wait_for_sysop(JCR *jcr, DEVICE *dev) { struct timeval tv; struct timezone tz; struct timespec timeout; - int dev_blocked; - time_t start = time(NULL); time_t last_heartbeat = 0; + time_t first_start = time(NULL); int stat = 0; int add_wait; + bool unmounted; + P(dev->mutex); + unmounted = (dev->dev_blocked == BST_UNMOUNTED) || + (dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP); + + dev->poll = false; /* - * Wait requested time (wait_sec). However, we also wake up every + * Wait requested time (dev->rem_wait_sec). However, we also wake up every * HB_TIME seconds and send a heartbeat to the FD and the Director * to keep stateful firewalls from closing them down while waiting * for the operator. */ - add_wait = wait_sec; + add_wait = dev->rem_wait_sec; if (me->heartbeat_interval && add_wait > me->heartbeat_interval) { add_wait = me->heartbeat_interval; } + if (!unmounted && dev->vol_poll_interval && add_wait > dev->vol_poll_interval) { + add_wait = dev->vol_poll_interval; + } gettimeofday(&tv, &tz); timeout.tv_nsec = tv.tv_usec * 1000; timeout.tv_sec = tv.tv_sec + add_wait; - P(dev->mutex); - dev_blocked = dev->dev_blocked; - dev->dev_blocked = BST_WAITING_FOR_SYSOP; /* indicate waiting for mount */ + if (!unmounted) { + dev->dev_prev_blocked = dev->dev_blocked; + dev->dev_blocked = BST_WAITING_FOR_SYSOP; /* indicate waiting for mount */ + } for ( ; !job_canceled(jcr); ) { - time_t now; + time_t now, start; Dmsg3(100, "I'm going to sleep on device %s. HB=%d wait=%d\n", dev_name(dev), - (int)me->heartbeat_interval, wait_sec); + (int)me->heartbeat_interval, dev->wait_sec); + start = time(NULL); stat = pthread_cond_timedwait(&dev->wait_next_vol, &dev->mutex, &timeout); Dmsg1(100, "Wokeup from sleep on device stat=%d\n", stat); now = time(NULL); + dev->rem_wait_sec -= (now - start); /* Note, this always triggers the first time. We want that. */ if (me->heartbeat_interval) { @@ -527,19 +549,38 @@ static int wait_for_sysop(JCR *jcr, DEVICE *dev, int wait_sec) } } - if (dev->dev_blocked == BST_MOUNT) { /* mount request ? */ - stat = 0; - break; - } + /* + * Check if user unmounted the device while we were waiting + */ + unmounted = (dev->dev_blocked == BST_UNMOUNTED) || + (dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP); if (stat != ETIMEDOUT) { /* we blocked the device */ break; /* on error return */ } - if (now - start >= wait_sec) { /* on exceeding wait time return */ + if (dev->rem_wait_sec <= 0) { /* on exceeding wait time return */ Dmsg0(100, "Exceed wait time.\n"); break; } - add_wait = wait_sec - (now - start); + + if (!unmounted && dev->vol_poll_interval && + (now - first_start >= dev->vol_poll_interval)) { + Dmsg1(200, "In wait blocked=%d\n", dev->dev_blocked); + dev->poll = true; + break; + } + /* + * Check if user mounted the device while we were waiting + */ + if (dev->dev_blocked == BST_MOUNT) { /* mount request ? */ + stat = 0; + break; + } + + add_wait = dev->wait_sec - (now - start); + if (add_wait < 0) { + add_wait = 0; + } if (me->heartbeat_interval && add_wait > me->heartbeat_interval) { add_wait = me->heartbeat_interval; } @@ -549,7 +590,9 @@ static int wait_for_sysop(JCR *jcr, DEVICE *dev, int wait_sec) Dmsg1(100, "Additional wait %d sec.\n", add_wait); } - dev->dev_blocked = dev_blocked; /* restore entry state */ + if (!unmounted) { + dev->dev_blocked = dev->dev_prev_blocked; /* restore entry state */ + } V(dev->mutex); return stat; } diff --git a/bacula/src/stored/bcopy.c b/bacula/src/stored/bcopy.c index 9efa2a7965..6255e65247 100644 --- a/bacula/src/stored/bcopy.c +++ b/bacula/src/stored/bcopy.c @@ -256,7 +256,7 @@ int dir_get_volume_info(JCR *jcr, enum get_vol_info_rw writing) { return 1;} int dir_find_next_appendable_volume(JCR *jcr) { return 1;} int dir_update_volume_info(JCR *jcr, DEVICE *dev, int relabel) { return 1; } int dir_create_jobmedia_record(JCR *jcr) { return 1; } -int dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev) { return 1; } +int dir_ask_sysop_to_create_appendable_volume(JCR *jcr, DEVICE *dev) { return 1; } int dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) { return 1;} int dir_send_job_status(JCR *jcr) {return 1;} diff --git a/bacula/src/stored/bextract.c b/bacula/src/stored/bextract.c index 1ac47c0700..950ff5bbb2 100644 --- a/bacula/src/stored/bextract.c +++ b/bacula/src/stored/bextract.c @@ -437,7 +437,7 @@ int dir_get_volume_info(JCR *jcr, enum get_vol_info_rw writing) { return 1;} int dir_find_next_appendable_volume(JCR *jcr) { return 1;} int dir_update_volume_info(JCR *jcr, DEVICE *dev, int relabel) { return 1; } int dir_create_jobmedia_record(JCR *jcr) { return 1; } -int dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev) { return 1; } +int dir_ask_sysop_to_create_appendable_volume(JCR *jcr, DEVICE *dev) { return 1; } int dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) { return 1;} int dir_send_job_status(JCR *jcr) {return 1;} diff --git a/bacula/src/stored/block.c b/bacula/src/stored/block.c index c74902de4b..585f89ca34 100644 --- a/bacula/src/stored/block.c +++ b/bacula/src/stored/block.c @@ -412,6 +412,7 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) block->write_failed = true; if (weof_dev(dev, 1) != 0) { /* end tape */ Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); + dev->VolCatInfo.VolCatErrors++; } /* Don't do update after second EOF or file count will be wrong */ Dmsg0(100, "dir_update_volume_info\n"); @@ -419,6 +420,7 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) dir_update_volume_info(jcr, dev, 0); if (dev_cap(dev, CAP_TWOEOF) && weof_dev(dev, 1) != 0) { /* write eof */ Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); + dev->VolCatInfo.VolCatErrors++; } dev->state |= (ST_EOF | ST_EOT | ST_WEOT); return 0; @@ -433,6 +435,7 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) if (weof_dev(dev, 1) != 0) { /* write eof */ Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); block->write_failed = true; + dev->VolCatInfo.VolCatErrors++; dev->state |= (ST_EOF | ST_EOT | ST_WEOT); Dmsg0(100, "dir_update_volume_info\n"); dev->VolCatInfo.VolCatFiles = dev->file; @@ -499,12 +502,14 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) block->write_failed = true; if (weof_dev(dev, 1) != 0) { /* end the tape */ + dev->VolCatInfo.VolCatErrors++; Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); } Dmsg0(100, "dir_update_volume_info\n"); dev->VolCatInfo.VolCatFiles = dev->file; dir_update_volume_info(jcr, dev, 0); if (dev_cap(dev, CAP_TWOEOF) && weof_dev(dev, 1) != 0) { /* end the tape */ + dev->VolCatInfo.VolCatErrors++; Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); } dev->state |= (ST_EOF | ST_EOT | ST_WEOT); diff --git a/bacula/src/stored/bls.c b/bacula/src/stored/bls.c index 350d7b7911..0525a4af79 100644 --- a/bacula/src/stored/bls.c +++ b/bacula/src/stored/bls.c @@ -400,7 +400,7 @@ int dir_get_volume_info(JCR *jcr, enum get_vol_info_rw writing) { return 1;} int dir_find_next_appendable_volume(JCR *jcr) { return 1;} int dir_update_volume_info(JCR *jcr, DEVICE *dev, int relabel) { return 1; } int dir_create_jobmedia_record(JCR *jcr) { return 1; } -int dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev) { return 1; } +int dir_ask_sysop_to_create_appendable_volume(JCR *jcr, DEVICE *dev) { return 1; } int dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) { return 1;} int dir_send_job_status(JCR *jcr) {return 1;} diff --git a/bacula/src/stored/bscan.c b/bacula/src/stored/bscan.c index d0d406c7a2..4eaf150c39 100644 --- a/bacula/src/stored/bscan.c +++ b/bacula/src/stored/bscan.c @@ -1114,7 +1114,7 @@ int dir_get_volume_info(JCR *jcr, enum get_vol_info_rw writing) { return 1;} int dir_find_next_appendable_volume(JCR *jcr) { return 1;} int dir_update_volume_info(JCR *jcr, DEVICE *dev, int relabel) { return 1; } int dir_create_jobmedia_record(JCR *jcr) { return 1; } -int dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev) { return 1; } +int dir_ask_sysop_to_create_appendable_volume(JCR *jcr, DEVICE *dev) { return 1; } int dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) { return 1;} int dir_send_job_status(JCR *jcr) {return 1;} diff --git a/bacula/src/stored/btape.c b/bacula/src/stored/btape.c index 0b75970041..4c586c694a 100644 --- a/bacula/src/stored/btape.c +++ b/bacula/src/stored/btape.c @@ -2245,7 +2245,7 @@ int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev) return 1; } -int dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev) +int dir_ask_sysop_to_create_appendable_volume(JCR *jcr, DEVICE *dev) { /* Close device so user can use autochanger if desired */ if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) { diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index 2dc51f42b6..0140d4211c 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -147,6 +147,11 @@ init_dev(DEVICE *dev, DEVRES *device) dev->max_rewind_wait = device->max_rewind_wait; dev->max_open_wait = device->max_open_wait; dev->max_open_vols = device->max_open_vols; + dev->vol_poll_interval = device->vol_poll_interval; + /* Sanity check */ + if (dev->vol_poll_interval && dev->vol_poll_interval < 60) { + dev->vol_poll_interval = 60; + } dev->device = device; if (tape) { @@ -1386,3 +1391,37 @@ JCR *next_attached_jcr(DEVICE *dev, JCR *jcr) } return jcr->next_dev; } + +/* + * This routine initializes the device wait timers + */ +void init_dev_wait_timers(DEVICE *dev) +{ + /* ******FIXME******* put these on config variables */ + dev->min_wait = 60 * 60; + dev->max_wait = 24 * 60 * 60; + dev->max_num_wait = 9; /* 5 waits =~ 1 day, then 1 day at a time */ + dev->wait_sec = dev->min_wait; + dev->rem_wait_sec = dev->wait_sec; + dev->num_wait = 0; + dev->poll = false; + dev->BadVolName[0] = 0; +} + +/* + * Returns: true if time doubled + * false if max time expired + */ +bool double_dev_wait_time(DEVICE *dev) +{ + dev->wait_sec *= 2; /* double wait time */ + if (dev->wait_sec > dev->max_wait) { /* but not longer than maxtime */ + dev->wait_sec = dev->max_wait; + } + dev->num_wait++; + dev->rem_wait_sec = dev->wait_sec; + if (dev->num_wait >= dev->max_num_wait) { + return false; + } + return true; +} diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index 32d717f0ae..78d9d7b514 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -142,6 +142,7 @@ struct VOLUME_CAT_INFO { typedef struct s_steal_lock { pthread_t no_wait_id; /* id of no wait thread */ int dev_blocked; /* state */ + int dev_prev_blocked; /* previous blocked state */ } bsteal_lock_t; struct DEVRES; /* Device resource defined in stored_conf.h */ @@ -157,6 +158,7 @@ public: pthread_cond_t wait_next_vol; /* wait for tape to be mounted */ pthread_t no_wait_id; /* this thread must not wait */ int dev_blocked; /* set if we must wait (i.e. change tape) */ + int dev_prev_blocked; /* previous blocked state */ int num_waiting; /* number of threads waiting */ int num_writers; /* number of writing threads */ int use_count; /* usage count on this device */ @@ -180,12 +182,22 @@ public: uint32_t max_rewind_wait; /* max secs to allow for rewind */ uint32_t max_open_wait; /* max secs to allow for open */ uint32_t max_open_vols; /* max simultaneous open volumes */ + utime_t vol_poll_interval; /* interval between polling Vol mount */ DEVRES *device; /* pointer to Device Resource */ btimer_id tid; /* timer id */ VOLUME_CAT_INFO VolCatInfo; /* Volume Catalog Information */ VOLUME_LABEL VolHdr; /* Actual volume label */ + /* Device wait times ***FIXME*** look at durations */ + char BadVolName[MAX_NAME_LENGTH]; /* Last wrong Volume mounted */ + bool poll; /* set to poll Volume */ + int min_wait; + int max_wait; + int max_num_wait; + int wait_sec; + int rem_wait_sec; + int num_wait; }; diff --git a/bacula/src/stored/device.c b/bacula/src/stored/device.c index eaacb8fcd4..46ffd38ace 100644 --- a/bacula/src/stored/device.c +++ b/bacula/src/stored/device.c @@ -366,6 +366,7 @@ void _steal_device_lock(char *file, int line, DEVICE *dev, bsteal_lock_t *hold, Dmsg4(100, "steal lock. old=%d new=%d from %s:%d\n", dev->dev_blocked, state, file, line); hold->dev_blocked = dev->dev_blocked; + hold->dev_prev_blocked = dev->dev_prev_blocked; hold->no_wait_id = dev->no_wait_id; dev->dev_blocked = state; dev->no_wait_id = pthread_self(); @@ -382,5 +383,6 @@ void _give_back_device_lock(char *file, int line, DEVICE *dev, bsteal_lock_t *ho dev->dev_blocked, hold->dev_blocked, file, line); P(dev->mutex); dev->dev_blocked = hold->dev_blocked; + dev->dev_prev_blocked = hold->dev_prev_blocked; dev->no_wait_id = hold->no_wait_id; } diff --git a/bacula/src/stored/dircmd.c b/bacula/src/stored/dircmd.c index ab506c3a58..efc3343bcf 100644 --- a/bacula/src/stored/dircmd.c +++ b/bacula/src/stored/dircmd.c @@ -599,7 +599,7 @@ static int unmount_cmd(JCR *jcr) P(dev->mutex); /* Use P to avoid indefinite block */ if (!(dev->state & ST_OPENED)) { Dmsg0(90, "Device already unmounted\n"); - bnet_fsend(dir, _("3901 Device %s is already unmounted.\n"), dev_name(dev)); + bnet_fsend(dir, _("3901 Device \"%s\" is already unmounted.\n"), dev_name(dev)); } else if (dev->dev_blocked == BST_WAITING_FOR_SYSOP) { Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting, @@ -608,18 +608,18 @@ static int unmount_cmd(JCR *jcr) offline_or_rewind_dev(dev); force_close_dev(dev); dev->dev_blocked = BST_UNMOUNTED_WAITING_FOR_SYSOP; - bnet_fsend(dir, _("3001 Device %s unmounted.\n"), dev_name(dev)); + bnet_fsend(dir, _("3001 Device \"%s\" unmounted.\n"), dev_name(dev)); } else if (dev->dev_blocked == BST_DOING_ACQUIRE) { - bnet_fsend(dir, _("3902 Device %s is busy in acquire.\n"), dev_name(dev)); + bnet_fsend(dir, _("3902 Device \"%s\" is busy in acquire.\n"), dev_name(dev)); } else if (dev->dev_blocked == BST_WRITING_LABEL) { - bnet_fsend(dir, _("3903 Device %s is being labeled.\n"), dev_name(dev)); + bnet_fsend(dir, _("3903 Device \"%s\" is being labeled.\n"), dev_name(dev)); } else if (dev_state(dev, ST_READ) || dev->num_writers) { if (dev_state(dev, ST_READ)) { Dmsg0(90, "Device in read mode\n"); - bnet_fsend(dir, _("3904 Device %s is busy with 1 reader.\n"), dev_name(dev)); + bnet_fsend(dir, _("3904 Device \"%s\" is busy reading.\n"), dev_name(dev)); } else { Dmsg1(90, "Device busy with %d writers\n", dev->num_writers); bnet_fsend(dir, _("3905 Device %s is busy with %d writer(s).\n"), @@ -789,7 +789,7 @@ static int readlabel_cmd(JCR *jcr) dev = jcr->device->dev; P(dev->mutex); /* Use P to avoid indefinite block */ - if (!(dev->state & ST_OPENED)) { + if (!dev_state(dev, ST_OPENED)) { if (open_dev(dev, NULL, READ_WRITE) < 0) { bnet_fsend(dir, _("3994 Connot open device: %s\n"), strerror_dev(dev)); } else { @@ -845,9 +845,9 @@ static void read_volume_label(JCR *jcr, DEVICE *dev, int Slot) block = new_block(dev); /* Ensure that the device is open -- autoload_device() closes it */ - for ( ; !(dev->state & ST_OPENED); ) { + for ( ; !dev_state(dev, ST_OPENED); ) { if (open_dev(dev, jcr->VolumeName, READ_WRITE) < 0) { - bnet_fsend(dir, _("3910 Unable to open device %s. ERR=%s\n"), + bnet_fsend(dir, _("3910 Unable to open device \"%s\". ERR=%s\n"), dev_name(dev), strerror_dev(dev)); goto bail_out; } @@ -856,7 +856,7 @@ static void read_volume_label(JCR *jcr, DEVICE *dev, int Slot) dev->state &= ~ST_LABEL; /* force read of label */ switch (read_dev_volume_label(jcr, dev, block)) { case VOL_OK: - bnet_fsend(dir, _("3001 Volume=%s Slot=%d\n"), dev->VolHdr.VolName, Slot); + bnet_fsend(dir, _("3001 Volume=\"%s\" Slot=%d\n"), dev->VolHdr.VolName, Slot); Dmsg1(100, "Volume: %s\n", dev->VolHdr.VolName); break; default: diff --git a/bacula/src/stored/mount.c b/bacula/src/stored/mount.c index de54ad9684..0ba90a615f 100644 --- a/bacula/src/stored/mount.c +++ b/bacula/src/stored/mount.c @@ -30,10 +30,6 @@ #include "bacula.h" /* pull in global headers */ #include "stored.h" /* pull in Storage Deamon headers */ -/* Forward referenced routines */ -static void mark_volume_in_error(JCR *jcr, DEVICE *dev); - - /* * If release is set, we rewind the current volume, * which we no longer want, and ask the user (console) @@ -54,13 +50,16 @@ int mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release Dmsg0(100, "Enter mount_next_volume()\n"); + init_dev_wait_timers(dev); + /* * Attempt to mount the next volume. If something non-fatal goes * wrong, we come back here to re-try (new op messages, re-read * Volume, ...) */ mount_next_vol: - if (retry++ > 5) { + /* Ignore retry if this is poll request */ + if (!dev->poll && retry++ > 8) { Jmsg(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"), dev_name(dev)); return 0; @@ -82,9 +81,9 @@ mount_next_vol: * in jcr->VolCatInfo */ Dmsg0(100, "Before dir_find_next\n"); - if (!dir_find_next_appendable_volume(jcr)) { + while (!dir_find_next_appendable_volume(jcr)) { Dmsg0(100, "not dir_find_next\n"); - if (!dir_ask_sysop_to_mount_next_volume(jcr, dev)) { + if (!dir_ask_sysop_to_create_appendable_volume(jcr, dev)) { return 0; } } @@ -123,7 +122,7 @@ mount_next_vol: Dmsg2(100, "Ask=%d autochanger=%d\n", ask, autochanger); release = true; /* release next time if we "recurse" */ - if (ask && !dir_ask_sysop_to_mount_next_volume(jcr, dev)) { + if (ask && !dir_ask_sysop_to_mount_volume(jcr, dev)) { Dmsg0(100, "Error return ask_sysop ...\n"); return 0; /* error return */ } @@ -179,6 +178,13 @@ read_volume: VOLUME_CAT_INFO VolCatInfo; Dmsg1(100, "Vol NAME Error Name=%s\n", jcr->VolumeName); + /* If polling and got a previous bad name, ignore it */ + if (dev->poll && strcmp(dev->BadVolName, dev->VolHdr.VolName) == 0) { + ask = true; + Dmsg1(200, "Vol Name error supress due to poll. Name=%s\n", + jcr->VolumeName); + goto mount_next_vol; + } /* * OK, we got a different volume mounted. First save the * requested Volume info (jcr) structure, then query if @@ -189,6 +195,7 @@ read_volume: /* Check if this is a valid Volume in the pool */ pm_strcpy(&jcr->VolumeName, dev->VolHdr.VolName); if (!dir_get_volume_info(jcr, GET_VOL_INFO_FOR_WRITE)) { + bstrncpy(dev->BadVolName, dev->VolHdr.VolName, sizeof(dev->BadVolName)); Jmsg(jcr, M_WARNING, 0, _("Director wanted Volume \"%s\".\n" " Current Volume \"%s\" not acceptable because:\n" " %s"), @@ -240,7 +247,11 @@ read_volume: case VOL_NO_MEDIA: default: /* Send error message */ - Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg); + if (!dev->poll) { + Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg); + } else { + Dmsg1(200, "Msg suppressed by poll: %s\n", jcr->errmsg); + } ask = true; goto mount_next_vol; } @@ -375,7 +386,10 @@ The number of files mismatch! Volume=%u Catalog=%u\n"), return 1; } -static void mark_volume_in_error(JCR *jcr, DEVICE *dev) +/* + * Mark volume in error in catalog + */ +void mark_volume_in_error(JCR *jcr, DEVICE *dev) { Jmsg(jcr, M_INFO, 0, _("Marking Volume \"%s\" in Error in Catalog.\n"), jcr->VolumeName); diff --git a/bacula/src/stored/protos.h b/bacula/src/stored/protos.h index 3e1d1560e5..10b4122db9 100644 --- a/bacula/src/stored/protos.h +++ b/bacula/src/stored/protos.h @@ -40,7 +40,7 @@ enum get_vol_info_rw { int dir_get_volume_info(JCR *jcr, enum get_vol_info_rw); int dir_find_next_appendable_volume(JCR *jcr); int dir_update_volume_info(JCR *jcr, DEVICE *dev, int label); -int dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev); +int dir_ask_sysop_to_create_appendable_volume(JCR *jcr, DEVICE *dev); int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev); int dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec); int dir_send_job_status(JCR *jcr); @@ -103,6 +103,8 @@ JCR *next_attached_jcr(DEVICE *dev, JCR *jcr); int dev_can_write(DEVICE *dev); int offline_or_rewind_dev(DEVICE *dev); int reposition_dev(DEVICE *dev, uint32_t file, uint32_t block); +void init_dev_wait_timers(DEVICE *dev); +bool double_dev_wait_time(DEVICE *dev); /* Get info about device */ @@ -115,15 +117,15 @@ int dev_is_tape(DEVICE *dev); /* From device.c */ int open_device(DEVICE *dev); int fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); -void _lock_device(char *file, int line, DEVICE *dev); -void _unlock_device(char *file, int line, DEVICE *dev); -void _block_device(char *file, int line, DEVICE *dev, int state); -void _unblock_device(char *file, int line, DEVICE *dev); -void _steal_device_lock(char *file, int line, DEVICE *dev, bsteal_lock_t *hold, int state); -void _give_back_device_lock(char *file, int line, DEVICE *dev, bsteal_lock_t *hold); -void set_new_volume_parameters(JCR *jcr, DEVICE *dev); -void set_new_file_parameters(JCR *jcr, DEVICE *dev); -int device_is_unmounted(DEVICE *dev); +void _lock_device(char *file, int line, DEVICE *dev); +void _unlock_device(char *file, int line, DEVICE *dev); +void _block_device(char *file, int line, DEVICE *dev, int state); +void _unblock_device(char *file, int line, DEVICE *dev); +void _steal_device_lock(char *file, int line, DEVICE *dev, bsteal_lock_t *hold, int state); +void _give_back_device_lock(char *file, int line, DEVICE *dev, bsteal_lock_t *hold); +void set_new_volume_parameters(JCR *jcr, DEVICE *dev); +void set_new_file_parameters(JCR *jcr, DEVICE *dev); +int device_is_unmounted(DEVICE *dev); /* From dircmd.c */ void *connection_request(void *arg); @@ -161,6 +163,7 @@ bool match_set_eof(BSR *bsr, DEV_RECORD *rec); int mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release); int mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); void release_volume(JCR *jcr, DEVICE *dev); +void mark_volume_in_error(JCR *jcr, DEVICE *dev); /* From autochanger.c */ int autoload_device(JCR *jcr, DEVICE *dev, int writing, BSOCK *dir); @@ -178,13 +181,13 @@ void free_vol_list(JCR *jcr); void create_vol_list(JCR *jcr); /* From record.c */ -char *FI_to_ascii(int fi); -char *stream_to_ascii(int stream, int fi); -int write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec); -int can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec); -int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec); +char *FI_to_ascii(int fi); +char *stream_to_ascii(int stream, int fi); +int write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec); +int can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec); +int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec); DEV_RECORD *new_record(); -void free_record(DEV_RECORD *rec); +void free_record(DEV_RECORD *rec); /* From read_record.c */ int read_records(JCR *jcr, DEVICE *dev, diff --git a/bacula/src/stored/status.c b/bacula/src/stored/status.c index b9dbce14b6..a50611ddc6 100644 --- a/bacula/src/stored/status.c +++ b/bacula/src/stored/status.c @@ -76,17 +76,17 @@ int status_cmd(JCR *jcr) * List devices */ LockRes(); - for (device=NULL; (device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device)); ) { + foreach_res(device, R_DEVICE) { for (dev=device->dev; dev; dev=dev->next) { - if (dev->state & ST_OPENED) { - if (dev->state & ST_LABEL) { - bnet_fsend(user, _("Device %s is mounted with Volume \"%s\"\n"), + if (dev_state(dev, ST_OPENED)) { + if (dev_state(dev, ST_LABEL)) { + bnet_fsend(user, _("Device \"%s\" is mounted with Volume \"%s\"\n"), dev_name(dev), dev->VolHdr.VolName); } else { - bnet_fsend(user, _("Device %s open but no Bacula volume is mounted.\n"), dev_name(dev)); + bnet_fsend(user, _("Device \"%s\" open but no Bacula volume is mounted.\n"), dev_name(dev)); } send_blocked_status(jcr, dev); - if (dev->state & ST_APPEND) { + if (dev_state(dev, ST_APPEND)) { bpb = dev->VolCatInfo.VolCatBlocks; if (bpb <= 0) { bpb = 1; @@ -116,7 +116,7 @@ int status_cmd(JCR *jcr) edit_uint64_with_commas(dev->block_num, b2)); } else { - bnet_fsend(user, _("Device %s is not open.\n"), dev_name(dev)); + bnet_fsend(user, _("Device \"%s\" is not open.\n"), dev_name(dev)); send_blocked_status(jcr, dev); } } @@ -132,7 +132,7 @@ int status_cmd(JCR *jcr) job_type_to_str(jcr->JobType), jcr->Job); } if (jcr->device) { - bnet_fsend(user, _("%s %s job %s using Volume \"%s\" on device %s\n"), + bnet_fsend(user, _("%s %s job %s using Volume \"%s\" on device \"%s\"\n"), job_level_to_str(jcr->JobLevel), job_type_to_str(jcr->JobType), jcr->Job, diff --git a/bacula/src/stored/stored_conf.c b/bacula/src/stored/stored_conf.c index 918dafba5e..f2006f339d 100644 --- a/bacula/src/stored/stored_conf.c +++ b/bacula/src/stored/stored_conf.c @@ -105,6 +105,7 @@ static struct res_items dev_items[] = { {"maximumchangerwait", store_pint, ITEM(res_dev.max_changer_wait), 0, ITEM_DEFAULT, 5 * 60}, {"maximumopenwait", store_pint, ITEM(res_dev.max_open_wait), 0, ITEM_DEFAULT, 5 * 60}, {"maximumopenvolumes", store_pint, ITEM(res_dev.max_open_vols), 0, ITEM_DEFAULT, 1}, + {"volumepollinterval", store_time, ITEM(res_dev.vol_poll_interval), 0, 0, 0}, {"offlineonunmount", store_yesno, ITEM(res_dev.cap_bits), CAP_OFFLINEUNMOUNT, ITEM_DEFAULT, 0}, {"maximumrewindwait", store_pint, ITEM(res_dev.max_rewind_wait), 0, ITEM_DEFAULT, 5 * 60}, {"minimumblocksize", store_pint, ITEM(res_dev.min_block_size), 0, 0, 0}, diff --git a/bacula/src/stored/stored_conf.h b/bacula/src/stored/stored_conf.h index 7cf81d72d8..7540e06215 100644 --- a/bacula/src/stored/stored_conf.h +++ b/bacula/src/stored/stored_conf.h @@ -83,6 +83,7 @@ struct DEVRES { uint32_t min_block_size; /* min block size */ uint32_t max_block_size; /* max block size */ uint32_t max_volume_jobs; /* max jobs to put on one volume */ + utime_t vol_poll_interval; /* interval between polling volume during mount */ int64_t max_volume_files; /* max files to put on one volume */ int64_t max_volume_size; /* max bytes to put on one volume */ int64_t max_file_size; /* max file size in bytes */ diff --git a/bacula/src/version.h b/bacula/src/version.h index b10fbc0fc4..8946634f62 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -2,8 +2,8 @@ #undef VERSION #define VERSION "1.33" #define VSTRING "1" -#define BDATE "06 Jan 2004" -#define LSMDATE "06Jan04" +#define BDATE "10 Jan 2004" +#define LSMDATE "10Jan04" /* Debug flags */ #undef DEBUG