This patch fixes two bugs. 1. Reported by Phil: where when the end of a Volume was reached, Bacula went into a loop requesting the next Volume then gave up. 2. Reported by Lars: the order of the next Volume selected by Bacula was not as expected. Apply the patch with: cd patch -p0 <1.32f-2-eom-nextvol.patch make ... Index: ReleaseNotes =================================================================== RCS file: /cvsroot/bacula/bacula/ReleaseNotes,v retrieving revision 1.52.2.9.2.7 retrieving revision 1.52.2.9.2.8 diff -u -b -r1.52.2.9.2.7 -r1.52.2.9.2.8 --- ReleaseNotes 31 Dec 2003 09:10:55 -0000 1.52.2.9.2.7 +++ ReleaseNotes 5 Jan 2004 16:49:44 -0000 1.52.2.9.2.8 @@ -1,7 +1,14 @@ - Release Notes for Bacula 1.32f + Release Notes for Bacula 1.32g Bacula code: Total files = 262 Total lines = 80,318 (*.h *.c *.in) + +Changes since 1.32f +- Fix bug reported by Phil (could not duplicate here) where at the end + of a Volume, Bacula wanted a new Volume and got into a loop requesting + it, then gave up. +- Modify selection of next Volume to select most currently appended Volume, + or if none oldest recycled Volume (problem reported by Lars). Changes since 1.32e: - Note, this change affects only the Win32 FD. Index: src/cats/sql_find.c =================================================================== RCS file: /cvsroot/bacula/bacula/src/cats/sql_find.c,v retrieving revision 1.23.2.7.2.1 retrieving revision 1.23.2.7.2.2 diff -u -b -r1.23.2.7.2.1 -r1.23.2.7.2.2 --- src/cats/sql_find.c 7 Dec 2003 15:01:42 -0000 1.23.2.7.2.1 +++ src/cats/sql_find.c 5 Jan 2004 16:49:45 -0000 1.23.2.7.2.2 @@ -7,7 +7,7 @@ * * Kern Sibbald, December 2000 * - * Version $Id: sql_find.c,v 1.23.2.7.2.1 2003/12/07 15:01:42 kerns Exp $ + * Version $Id: sql_find.c,v 1.23.2.7.2.2 2004/01/05 16:49:45 kerns Exp $ */ /* @@ -218,6 +218,7 @@ { SQL_ROW row; int numrows; + char *order; db_lock(mdb); if (item == -1) { /* find oldest volume */ @@ -232,12 +233,19 @@ item = 1; } else { /* Find next available volume */ + if (strcmp(mr->VolStatus, "Recycled") == 0 || + strcmp(mr->VolStatus, "Purged") == 0) { + order = "ORDER BY LastWritten ASC,MediaId"; /* take oldest */ + } else { + order = "ORDER BY LastWritten DESC,MediaId"; /* take most recently written */ + } Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks," -"VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes," -"VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,Recycle,Slot," -"FirstWritten,LastWritten,VolStatus " -"FROM Media WHERE PoolId=%u AND MediaType='%s' AND VolStatus='%s' " -"ORDER BY LastWritten,MediaId", mr->PoolId, mr->MediaType, mr->VolStatus); + "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes," + "VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,Recycle,Slot," + "FirstWritten,LastWritten,VolStatus " + "FROM Media WHERE PoolId=%u AND MediaType='%s' AND VolStatus='%s' " + "%s LIMIT 1", + mr->PoolId, mr->MediaType, mr->VolStatus, order); } if (!QUERY_DB(jcr, mdb, mdb->cmd)) { db_unlock(mdb); Index: src/stored/mount.c =================================================================== RCS file: /cvsroot/bacula/bacula/src/stored/mount.c,v retrieving revision 1.42.2.9.2.3 retrieving revision 1.42.2.9.2.4 diff -u -b -r1.42.2.9.2.3 -r1.42.2.9.2.4 --- src/stored/mount.c 8 Dec 2003 20:53:47 -0000 1.42.2.9.2.3 +++ src/stored/mount.c 5 Jan 2004 16:49:45 -0000 1.42.2.9.2.4 @@ -5,7 +5,7 @@ * * Kern Sibbald, August MMII * - * Version $Id: mount.c,v 1.42.2.9.2.3 2003/12/08 20:53:47 kerns Exp $ + * Version $Id: mount.c,v 1.42.2.9.2.4 2004/01/05 16:49:45 kerns Exp $ */ /* Copyright (C) 2000-2003 Kern Sibbald and John Walker @@ -30,7 +30,8 @@ #include "bacula.h" /* pull in global headers */ #include "stored.h" /* pull in Storage Deamon headers */ -/* Forward referenced functions */ +/* Forward referenced routines */ +static void mark_volume_in_error(JCR *jcr, DEVICE *dev); /* @@ -47,11 +48,17 @@ */ int mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release) { - int retry = 0, autochanger; - bool ask, recycle; + int retry = 0; + bool ask = false, recycle, autochanger; + int vol_label_status; Dmsg0(100, "Enter mount_next_volume()\n"); + /* + * 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) { Jmsg(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"), @@ -62,8 +69,8 @@ Jmsg(jcr, M_FATAL, 0, _("Job %d canceled.\n"), jcr->JobId); return 0; } - autochanger = 0; - recycle = ask = false; + autochanger = false; /* Assume no autochanger */ + recycle = false; if (release) { Dmsg0(100, "mount_next_volume release=1\n"); release_volume(jcr, dev); @@ -97,15 +104,10 @@ * It assumes that the device is not already in use! * */ - - dev->state &= ~(ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF); - for ( ;; ) { - int vol_label_status; autochanger = autoload_device(jcr, dev, 1, NULL); Dmsg1(100, "autoload_dev returns %d\n", autochanger); - /* * If we autochanged to correct Volume or (we have not just * released the Volume AND we can automount) we go ahead @@ -116,7 +118,7 @@ ask = false; /* don't ask SYSOP this time */ } Dmsg2(100, "Ask=%d autochanger=%d\n", ask, autochanger); - release = 1; /* release next time if we "recurse" */ + release = true; /* release next time if we "recurse" */ if (ask && !dir_ask_sysop_to_mount_next_volume(jcr, dev)) { Dmsg0(100, "Error return ask_sysop ...\n"); @@ -181,14 +183,15 @@ /* 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)) { - Mmsg(&jcr->errmsg, _("Director wanted Volume \"%s\".\n" + Jmsg(jcr, M_WARNING, 0, _("Director wanted Volume \"%s\".\n" " Current Volume \"%s\" not acceptable because:\n" " %s"), VolCatInfo.VolCatName, dev->VolHdr.VolName, jcr->dir_bsock->msg); /* Restore desired volume name, note device info out of sync */ memcpy(&jcr->VolCatInfo, &VolCatInfo, sizeof(jcr->VolCatInfo)); - goto mount_error; + ask = true; + goto mount_next_vol; } Dmsg1(100, "want new name=%s\n", jcr->VolumeName); memcpy(&dev->VolCatInfo, &jcr->VolCatInfo, sizeof(dev->VolCatInfo)); @@ -230,15 +233,11 @@ /* NOTE! Fall-through wanted. */ case VOL_NO_MEDIA: default: -mount_error: /* Send error message */ Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg); ask = true; - /* was - goto ask_again; */ goto mount_next_vol; } - break; - } /* * See if we have a fresh tape or a tape with data. @@ -322,6 +321,10 @@ Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume \"%s\" on device %s\n"), jcr->VolumeName, dev_name(dev)); } + /* + * End writing real Volume label (from pre-labeled tape), or recycling + * the volume. + */ } else { /* @@ -335,11 +338,7 @@ if (!eod_dev(dev)) { Jmsg(jcr, M_ERROR, 0, _("Unable to position to end of data %s. ERR=%s\n"), dev_name(dev), strerror_dev(dev)); - Jmsg(jcr, M_INFO, 0, _("Marking Volume \"%s\" in Error in Catalog.\n"), - jcr->VolumeName); - bstrncpy(dev->VolCatInfo.VolCatStatus, "Error", sizeof(dev->VolCatInfo.VolCatStatus)); - Dmsg0(100, "dir_update_vol_info. Set Error.\n"); - dir_update_volume_info(jcr, dev, 0); + mark_volume_in_error(jcr, dev); goto mount_next_vol; } /* *****FIXME**** we should do some checking for files too */ @@ -355,9 +354,7 @@ Jmsg(jcr, M_ERROR, 0, _("I canot write on this volume because:\n\ The number of files mismatch! Volume=%u Catalog=%u\n"), dev_file(dev), dev->VolCatInfo.VolCatFiles); - bstrncpy(dev->VolCatInfo.VolCatStatus, "Error", sizeof(dev->VolCatInfo.VolCatStatus)); - Dmsg0(100, "dir_update_vol_info. Set Error.\n"); - dir_update_volume_info(jcr, dev, 0); + mark_volume_in_error(jcr, dev); goto mount_next_vol; } } @@ -372,7 +369,19 @@ return 1; } +static void mark_volume_in_error(JCR *jcr, DEVICE *dev) +{ + Jmsg(jcr, M_INFO, 0, _("Marking Volume \"%s\" in Error in Catalog.\n"), + jcr->VolumeName); + bstrncpy(dev->VolCatInfo.VolCatStatus, "Error", sizeof(dev->VolCatInfo.VolCatStatus)); + Dmsg0(100, "dir_update_vol_info. Set Error.\n"); + dir_update_volume_info(jcr, dev, 0); +} +/* + * If we are reading, we come here at the end of the tape + * and see if there are more volumes to be mounted. + */ int mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) { Dmsg2(90, "NumVolumes=%d CurVolume=%d\n", jcr->NumVolumes, jcr->CurVolume); @@ -399,7 +408,6 @@ */ void release_volume(JCR *jcr, DEVICE *dev) { - if (jcr->WroteVol) { Jmsg0(jcr, M_ERROR, 0, "Hey!!!!! WroteVol non-zero !!!!!\n"); } @@ -411,7 +419,8 @@ memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo)); memset(&jcr->VolCatInfo, 0, sizeof(jcr->VolCatInfo)); memset(&dev->VolHdr, 0, sizeof(dev->VolHdr)); - dev->state &= ~ST_LABEL; /* label not yet read */ + /* Force re-read of label */ + dev->state &= ~(ST_LABEL|ST_READ|ST_APPEND); jcr->VolumeName[0] = 0; if ((dev->state & ST_OPENED) &&