From aefed13b75f8f1a167f700c482b660b7c38e9f82 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Wed, 9 Apr 2008 14:59:59 +0000 Subject: [PATCH] kes Correct error string numbers in dird/catreq.c kes Restructure reserving, acquiring, and mounting volumes. Calls to autochanger are deferred for mount.c -- simplifes the code. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@6779 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/dird/catreq.c | 4 +- bacula/src/dird/ua_prune.c | 24 +++- bacula/src/stored/acquire.c | 133 ++++++----------- bacula/src/stored/askdir.c | 2 +- bacula/src/stored/dev.h | 4 + bacula/src/stored/device.c | 5 +- bacula/src/stored/dvd.c | 2 +- bacula/src/stored/label.c | 9 +- bacula/src/stored/mount.c | 275 ++++++++++++++++++------------------ bacula/src/stored/protos.h | 4 +- bacula/src/stored/reserve.c | 36 ++--- bacula/src/version.h | 4 +- bacula/technotes-2.3 | 9 ++ 13 files changed, 239 insertions(+), 272 deletions(-) diff --git a/bacula/src/dird/catreq.c b/bacula/src/dird/catreq.c index ee1d059c06..e04a1e7b43 100644 --- a/bacula/src/dird/catreq.c +++ b/bacula/src/dird/catreq.c @@ -331,7 +331,7 @@ void catalog_request(JCR *jcr, BSOCK *bs) if (!db_create_jobmedia_record(jcr, jcr->db, &jm)) { Jmsg(jcr, M_FATAL, 0, _("Catalog error creating JobMedia record. %s"), db_strerror(jcr->db)); - bs->fsend(_("1991 Update JobMedia error\n")); + bs->fsend(_("1992 Create JobMedia error\n")); } else { Dmsg0(400, "JobMedia record created\n"); bs->fsend(OK_create); @@ -377,7 +377,7 @@ void catalog_update(JCR *jcr, BSOCK *bs) if (!jcr->db) { omsg = get_memory(bs->msglen+1); pm_strcpy(omsg, bs->msg); - bs->fsend(_("1991 Invalid Catalog Update: %s"), omsg); + bs->fsend(_("1994 Invalid Catalog Update: %s"), omsg); Jmsg1(jcr, M_FATAL, 0, _("Invalid Catalog Update; DB not open: %s"), omsg); free_memory(omsg); goto bail_out; diff --git a/bacula/src/dird/ua_prune.c b/bacula/src/dird/ua_prune.c index 7299155d16..546477f9b0 100644 --- a/bacula/src/dird/ua_prune.c +++ b/bacula/src/dird/ua_prune.c @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2002-2007 Free Software Foundation Europe e.V. + Copyright (C) 2002-2008 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. @@ -169,11 +169,11 @@ int prunecmd(UAContext *ua, const char *cmd) case 3: /* prune stats */ dir = (DIRRES *)GetNextRes(R_DIRECTOR, NULL); if (!dir->stats_retention) { - return false; + return false; } retention = dir->stats_retention; if (!confirm_retention(ua, &retention, "Statistics")) { - return false; + return false; } prune_stats(ua, retention); return true; @@ -195,7 +195,7 @@ int prune_stats(UAContext *ua, utime_t retention) db_lock(ua->db); Mmsg(query, "DELETE FROM JobStat WHERE JobTDate < %s", - edit_uint64(now - retention, ed1)); + edit_uint64(now - retention, ed1)); db_sql_query(ua->db, query.c_str(), NULL, NULL); db_unlock(ua->db); @@ -468,6 +468,8 @@ int get_prune_list_for_volume(UAContext *ua, MEDIA_DBR *mr, del_ctx *del) int i; utime_t now, period; char ed1[50], ed2[50]; + JCR *jcr; + bool skip; if (mr->Enabled == 2) { return 0; /* cannot prune Archived volumes */ @@ -495,10 +497,18 @@ int get_prune_list_for_volume(UAContext *ua, MEDIA_DBR *mr, del_ctx *del) goto bail_out; } + /* Do not prune any job currently running */ for (i=0; i < del->num_ids; i++) { - if (ua->jcr->JobId == del->JobId[i]) { - Dmsg2(150, "skip same job JobId[%d]=%d\n", i, (int)del->JobId[i]); - del->JobId[i] = 0; + skip = false; + foreach_jcr(jcr) { + if (jcr->JobId == del->JobId[i]) { + Dmsg2(150, "skip same job JobId[%d]=%d\n", i, (int)del->JobId[i]); + del->JobId[i] = 0; + skip = true; + break; + } + } + if (skip) { continue; } Dmsg2(150, "accept JobId[%d]=%d\n", i, (int)del->JobId[i]); diff --git a/bacula/src/stored/acquire.c b/bacula/src/stored/acquire.c index b930e64974..4ab57d2178 100644 --- a/bacula/src/stored/acquire.c +++ b/bacula/src/stored/acquire.c @@ -39,6 +39,7 @@ /* Forward referenced functions */ static void attach_dcr_to_dev(DCR *dcr); static bool is_suitable_volume_mounted(DCR *dcr); +static bool is_tape_position_ok(JCR *jcr, DEVICE *dev); /********************************************************************* @@ -315,10 +316,7 @@ get_out: */ DCR *acquire_device_for_append(DCR *dcr) { - bool do_mount = false; - bool release = false; - bool have_vol; - DEVICE * volatile dev = dcr->dev; + DEVICE *dev = dcr->dev; JCR *jcr = dcr->jcr; init_device_wait_timers(dcr); @@ -340,92 +338,23 @@ DCR *acquire_device_for_append(DCR *dcr) * have_vol defines whether or not mount_next_write_volume should * ask the Director again about what Volume to use. */ - have_vol = is_suitable_volume_mounted(dcr); - if (dev->can_append()) { - Dmsg0(100, "device already in append.\n"); + if (dev->can_append() && is_suitable_volume_mounted(dcr) && + strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") != 0) { + Dmsg0(190, "device already in append.\n"); /* - * Device already in append mode - * - * Check if we have the right Volume mounted - * OK if current volume info OK - * OK if next volume matches current volume - * otherwise mount desired volume obtained from - * dir_find_next_appendable_volume - * dev->VolHdr.VolumeName is what is in the drive - * dcr->VolumeName is what we pass into the routines, or - * get back from the subroutines. + * At this point, the correct tape is already mounted, so + * we do not need to do mount_next_write_volume(), unless + * we need to recycle the tape. */ - /* If we do not have a volume, see if we can find one */ - if (!have_vol) { - Dmsg0(100, "call dir_find_next_appendable_volume\n"); - have_vol = dir_find_next_appendable_volume(dcr); - dev = dcr->dev; - Dmsg2(100, "devVol=%s dcrVol=%s\n", dev->VolHdr.VolumeName, dcr->VolumeName); - } - if (have_vol) { - do_mount = true; - /* Make sure it is what we we have on the drive */ - if (dev->VolHdr.VolumeName[0]) { - Dmsg2(100, "devVol=%s dcrVol=%s\n", dev->VolHdr.VolumeName, dcr->VolumeName); - /* If we already have the volume, mount/release are not needed */ - do_mount = strcmp(dev->VolHdr.VolumeName, dcr->VolumeName) != 0; - if (do_mount) { - release = true; - Dmsg0(100, "Set release\n"); - } - } - } - if (have_vol && !do_mount) { - /* - * At this point, the correct tape is already mounted, so - * we do not need to do mount_next_write_volume(), unless - * we need to recycle the tape. - */ - Dmsg2(100, "devVol=%s dcrVol=%s\n", dev->VolHdr.VolumeName, dcr->VolumeName); - do_mount = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0; - Dmsg2(190, "jid=%u Correct tape mounted. recycle=%d\n", - (uint32_t)jcr->JobId, do_mount); - if (dev->num_writers == 0) { - memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo)); - } - - /* - * Insanity check - * - * Check to see if the tape position as defined by the OS is - * the same as our concept. If it is not, we bail out, because - * it means the user has probably manually rewound the tape. - * Note, we check only if num_writers == 0, but this code will - * also work fine for any number of writers. If num_writers > 0, - * we probably should cancel all jobs using this device, or - * perhaps even abort the SD, or at a minimum, mark the tape - * in error. Another strategy with num_writers == 0, would be - * to rewind the tape and do a new eod() request. - */ - if (dev->is_tape() && dev->num_writers == 0) { - int32_t file = dev->get_os_tape_file(); - if (file >= 0 && file != (int32_t)dev->get_file()) { - Jmsg(jcr, M_FATAL, 0, _("Invalid tape position on volume \"%s\"" - " on device %s. Expected %d, got %d\n"), - dev->VolHdr.VolumeName, dev->print_name(), dev->get_file(), file); - goto get_out; - } - } - } + if (dev->num_writers == 0) { + memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo)); + } + if (!is_tape_position_ok(jcr, dev)) { + goto get_out; + } } else { - /* Not already in append mode, so mount the device */ - Dmsg2(190, "jid=%u Not in append mode, try mount have_vol=%d\n", - (uint32_t)jcr->JobId, have_vol); - - ASSERT(dev->num_writers == 0); - do_mount = true; - } - - if (do_mount || !have_vol) { Dmsg1(190, "jid=%u Do mount_next_write_vol\n", (uint32_t)jcr->JobId); - Dmsg2(100, "devVol=%s dcrVol=%s\n", dev->VolHdr.VolumeName, dcr->VolumeName); - bool mounted = mount_next_write_volume(dcr, have_vol, release); - if (!mounted) { + if (!dcr->mount_next_write_volume()) { if (!job_canceled(jcr)) { /* Reduce "noise" -- don't print if job canceled */ Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"), @@ -469,13 +398,39 @@ get_out: return NULL; } +/* + * Insanity check + * + * Check to see if the tape position as defined by the OS is + * the same as our concept. If it is not, we bail out, because + * it means the user has probably manually rewound the tape. + * Note, we check only if num_writers == 0, but this code will + * also work fine for any number of writers. If num_writers > 0, + * we probably should cancel all jobs using this device, or + * perhaps even abort the SD, or at a minimum, mark the tape + * in error. Another strategy with num_writers == 0, would be + * to rewind the tape and do a new eod() request. + */ +static bool is_tape_position_ok(JCR *jcr, DEVICE *dev) +{ + if (dev->is_tape() && dev->num_writers == 0) { + int32_t file = dev->get_os_tape_file(); + if (file >= 0 && file != (int32_t)dev->get_file()) { + Jmsg(jcr, M_FATAL, 0, _("Invalid tape position on volume \"%s\"" + " on device %s. Expected %d, got %d\n"), + dev->VolHdr.VolumeName, dev->print_name(), dev->get_file(), file); + return false; + } + } + return true; +} static bool is_suitable_volume_mounted(DCR *dcr) { DEVICE *dev = dcr->dev; /* Volume mounted? */ - if (dev->VolHdr.VolumeName[0] == 0) { + if (dev->VolHdr.VolumeName[0] == 0 || dcr->swap_dev || dcr->unload_device) { return false; /* no */ } bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName)); @@ -500,6 +455,7 @@ bool release_device(DCR *dcr) if (!dcr->is_dev_locked()) { dev->r_dlock(); } + lock_volumes(); Dmsg2(100, "release_device device %s is %s\n", dev->print_name(), dev->is_tape()?"tape":"disk"); /* if device is reserved, job never started, so release the reserve here */ @@ -554,6 +510,7 @@ bool release_device(DCR *dcr) */ volume_unused(dcr); } + unlock_volumes(); /* If no writers, close if file or !CAP_ALWAYS_OPEN */ if (dev->num_writers == 0 && (!dev->is_tape() || !dev->has_cap(CAP_ALWAYSOPEN))) { @@ -712,7 +669,7 @@ static void attach_dcr_to_dev(DCR *dcr) void detach_dcr_from_dev(DCR *dcr) { DEVICE *dev = dcr->dev; - Dmsg0(500, "Enter detach_dcr_from_dev\n"); + Dmsg0(500, "Enter detach_dcr_from_dev\n"); /* jcr is NULL in some cases */ /* Detach this dcr only if attached */ if (dcr->attached_to_dev && dev) { diff --git a/bacula/src/stored/askdir.c b/bacula/src/stored/askdir.c index 96ba8d1de0..8d993457e0 100644 --- a/bacula/src/stored/askdir.c +++ b/bacula/src/stored/askdir.c @@ -258,7 +258,7 @@ bool dir_find_next_appendable_volume(DCR *dcr) dcr->reserved_device, dcr->VolumeName); /* - * Try the fourty oldest or most available volumes. Note, + * Try the forty oldest or most available volumes. Note, * the most available could already be mounted on another * drive, so we continue looking for a not in use Volume. */ diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index 7162dde092..be8d184747 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -426,6 +426,7 @@ public: dlink dev_link; /* link to attach to dev */ JCR *jcr; /* pointer to JCR */ DEVICE * volatile dev; /* pointer to device */ + DEVICE * volatile swap_dev; /* Swap vol from this device */ DEVRES *device; /* pointer to device resource */ DEV_BLOCK *block; /* pointer to block */ DEV_RECORD *rec; /* pointer to record */ @@ -444,6 +445,7 @@ public: bool attached_to_dev; /* set when attached to dev */ bool volume_in_use; /* set in dir_find_next_appendable_volume() */ bool keep_dcr; /* do not free dcr in release_dcr */ + bool unload_device; /* set if device must be unloaded */ uint32_t VolFirstIndex; /* First file index this Volume */ uint32_t VolLastIndex; /* Last file index this Volume */ uint32_t FileIndex; /* Current File Index */ @@ -468,6 +470,8 @@ public: void dlock() { dev->dlock(); m_dev_locked = true; } void dunlock() { m_dev_locked = false; dev->dunlock(); } void dblock(int why) { dev->dblock(why); } + bool mount_next_write_volume(); + void mark_volume_in_error(); }; diff --git a/bacula/src/stored/device.c b/bacula/src/stored/device.c index 50ab5dab1a..0d84404ea7 100644 --- a/bacula/src/stored/device.c +++ b/bacula/src/stored/device.c @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2000-2007 Free Software Foundation Europe e.V. + Copyright (C) 2000-2008 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. @@ -123,7 +123,8 @@ bool fixup_device_block_write_error(DCR *dcr) bstrftime(dt, sizeof(dt), time(NULL))); /* Called with have_vol=false, release=true */ - if (!mount_next_write_volume(dcr, false, true)) { + dcr->unload_device = true; + if (!dcr->mount_next_write_volume()) { free_block(label_blk); dcr->block = block; dev->dlock(); diff --git a/bacula/src/stored/dvd.c b/bacula/src/stored/dvd.c index f798098bd0..0cfa2a5c09 100644 --- a/bacula/src/stored/dvd.c +++ b/bacula/src/stored/dvd.c @@ -266,7 +266,7 @@ bool dvd_write_part(DCR *dcr) Dmsg1(100, "%s\n", dev->errmsg); dev->dev_errno = EIO; if (!dev->truncating) { - mark_volume_in_error(dcr); + dcr->mark_volume_in_error(); } sm_check(__FILE__, __LINE__, false); return false; diff --git a/bacula/src/stored/label.c b/bacula/src/stored/label.c index ccf657c5ea..9f47dbe88f 100644 --- a/bacula/src/stored/label.c +++ b/bacula/src/stored/label.c @@ -212,14 +212,16 @@ int read_dev_volume_label(DCR *dcr) } dev->set_labeled(); /* set has Bacula label */ - Dmsg0(100, "Call reserve_volume\n"); + Dmsg1(100, "Call reserve_volume=%s\n", dev->VolHdr.VolumeName); + Dmsg2(100, "=== dcr->dev=%p dev=%p\n", dcr->dev, dev); if (reserve_volume(dcr, dev->VolHdr.VolumeName) == NULL) { Mmsg2(jcr->errmsg, _("Could not reserve volume %s on %s\n"), dev->VolHdr.VolumeName, dev->print_name()); stat = VOL_NAME_ERROR; goto bail_out; } - dev = dcr->dev; /* may have changed in reserve volume */ + Dmsg2(100, "=== dcr->dev=%p dev=%p\n", dcr->dev, dev); +// dev = dcr->dev; /* may have changed in reserve volume */ /* Compare Volume Names */ Dmsg2(130, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName); @@ -236,6 +238,7 @@ int read_dev_volume_label(DCR *dcr) } Dmsg0(150, "return VOL_NAME_ERROR\n"); stat = VOL_NAME_ERROR; + volume_unused(dcr); /* mark volume "released" */ goto bail_out; } Dmsg1(130, "Copy vol_name=%s\n", dev->VolHdr.VolumeName); @@ -251,6 +254,7 @@ int read_dev_volume_label(DCR *dcr) stat = read_ansi_ibm_label(dcr); /* If we want a label and didn't find it, return error */ if (stat != VOL_OK) { + volume_unused(dcr); /* mark volume "released" */ goto bail_out; } } @@ -259,7 +263,6 @@ int read_dev_volume_label(DCR *dcr) return VOL_OK; bail_out: - volume_unused(dcr); /* mark volume "released" */ empty_block(block); dev->rewind(dcr); Dmsg1(150, "return %d\n", stat); diff --git a/bacula/src/stored/mount.c b/bacula/src/stored/mount.c index 08381715bd..79edb8affb 100644 --- a/bacula/src/stored/mount.c +++ b/bacula/src/stored/mount.c @@ -40,6 +40,7 @@ static void mark_volume_not_inchanger(DCR *dcr); static int try_autolabel(DCR *dcr, bool opened); +static bool is_eod_valid(DCR *dcr); enum { try_next_vol = 1, @@ -60,21 +61,20 @@ enum { * impossible to get the requested Volume. * */ -bool mount_next_write_volume(DCR *dcr, bool have_vol, bool release) +bool DCR::mount_next_write_volume() { int retry = 0; bool ask = false, recycle, autochanger; int vol_label_status; - DEVICE *dev = dcr->dev; - JCR *jcr = dcr->jcr; - DEV_BLOCK *block = dcr->block; int mode; + DCR *dcr = this; - Dmsg2(150, "Enter mount_next_volume(release=%d) dev=%s\n", release, + Dmsg2(150, "Enter mount_next_volume(release=%d) dev=%s\n", unload_device, dev->print_name()); init_device_wait_timers(dcr); - + lock_volumes(); + /* * Attempt to mount the next volume. If something non-fatal goes * wrong, we come back here to re-try (new op messages, re-read @@ -85,21 +85,23 @@ mount_next_vol: /* Ignore retry if this is poll request */ if (!dev->poll && retry++ > 4) { /* Last ditch effort before giving up, force operator to respond */ - dcr->VolCatInfo.Slot = 0; + VolCatInfo.Slot = 0; if (!dir_ask_sysop_to_mount_volume(dcr, ST_APPEND)) { Jmsg(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"), dev->print_name()); - return false; + goto bail_out; } } if (job_canceled(jcr)) { Jmsg(jcr, M_FATAL, 0, _("Job %d canceled.\n"), jcr->JobId); - return false; + goto bail_out; } recycle = false; - if (release) { + if (unload_device) { Dmsg0(150, "mount_next_volume release=1\n"); release_volume(dcr); + unload_autochanger(dcr, -1); + unload_device = false; ask = true; /* ask operator to mount tape */ } @@ -108,22 +110,18 @@ mount_next_vol: * in dcr->VolCatInfo */ Dmsg0(200, "Before dir_find_next_appendable_volume.\n"); - if (!have_vol) { - while (!dir_find_next_appendable_volume(dcr)) { - Dmsg0(200, "not dir_find_next\n"); - if (!dir_ask_sysop_to_create_appendable_volume(dcr)) { - return false; - } - Dmsg0(200, "Again dir_find_next_append...\n"); + while (!dir_find_next_appendable_volume(dcr)) { + Dmsg0(200, "not dir_find_next\n"); + if (!dir_ask_sysop_to_create_appendable_volume(dcr)) { + goto bail_out; } - } else { - have_vol = false; /* set false for next pass if any */ + Dmsg0(200, "Again dir_find_next_append...\n"); } if (job_canceled(jcr)) { - return false; + goto bail_out; } Dmsg3(150, "After find_next_append. Vol=%s Slot=%d Parts=%d\n", - dcr->VolCatInfo.VolCatName, dcr->VolCatInfo.Slot, dcr->VolCatInfo.VolCatParts); + VolCatInfo.VolCatName, VolCatInfo.Slot, VolCatInfo.VolCatParts); /* * Get next volume and ready it for append @@ -136,12 +134,18 @@ mount_next_vol: * and move the tape to the end of data. * */ + if (swap_dev) { + dev->vol = swap_dev->vol; /* take its volume */ + swap_dev->vol = NULL; + unload_dev(dcr, swap_dev); + swap_dev = NULL; + } if (autoload_device(dcr, 1, NULL) > 0) { autochanger = true; ask = false; } else { autochanger = false; - dcr->VolCatInfo.Slot = 0; + VolCatInfo.Slot = 0; } Dmsg1(200, "autoload_dev returns %d\n", autochanger); /* @@ -150,7 +154,7 @@ mount_next_vol: * and read the label. If there is no tape in the drive, * we will fail, recurse and ask the operator the next time. */ - if (!release && dev->is_tape() && dev->has_cap(CAP_AUTOMOUNT)) { + if (!unload_device && dev->is_tape() && dev->has_cap(CAP_AUTOMOUNT)) { Dmsg0(150, "(1)Ask=0\n"); ask = false; /* don't ask SYSOP this time */ } @@ -160,16 +164,17 @@ mount_next_vol: ask = false; } Dmsg2(150, "Ask=%d autochanger=%d\n", ask, autochanger); - release = true; /* release next time if we "recurse" */ + unload_device = true; /* release next time if we "recurse" */ if (ask && !dir_ask_sysop_to_mount_volume(dcr, ST_APPEND)) { Dmsg0(150, "Error return ask_sysop ...\n"); - return false; /* error return */ + goto bail_out; /* error return */ } if (job_canceled(jcr)) { - return false; + goto bail_out; } - Dmsg2(150, "want vol=%s dev=%s\n", dcr->VolumeName, dev->VolHdr.VolumeName); + Dmsg3(150, "want vol=%s devvol=%s dev=%s\n", VolumeName, + dev->VolHdr.VolumeName, dev->print_name()); if (dev->poll && dev->has_cap(CAP_CLOSEONPOLL)) { dev->close(); @@ -214,7 +219,7 @@ mount_next_vol: } else { Jmsg(jcr, M_ERROR, 0, _("Could not open device %s: ERR=%s\n"), dev->print_name(), dev->print_errmsg()); - return false; + goto bail_out; } } @@ -228,25 +233,25 @@ read_volume: */ if (dev->has_cap(CAP_STREAM)) { vol_label_status = VOL_OK; - create_volume_label(dev, dcr->VolumeName, "Default", false /* not DVD */); + create_volume_label(dev, VolumeName, "Default", false /* not DVD */); dev->VolHdr.LabelType = PRE_LABEL; } else { vol_label_status = read_dev_volume_label(dcr); } if (job_canceled(jcr)) { - return false; + goto bail_out; } - Dmsg2(150, "Want dirVol=%s dirStat=%s\n", dcr->VolumeName, - dcr->VolCatInfo.VolCatStatus); + Dmsg2(150, "Want dirVol=%s dirStat=%s\n", VolumeName, + VolCatInfo.VolCatStatus); /* * At this point, dev->VolCatInfo has what is in the drive, if anything, * and dcr->VolCatInfo has what the Director wants. */ switch (vol_label_status) { case VOL_OK: - Dmsg1(150, "Vol OK name=%s\n", dcr->VolumeName); - dev->VolCatInfo = dcr->VolCatInfo; /* structure assignment */ + Dmsg1(150, "Vol OK name=%s\n", VolumeName); + dev->VolCatInfo = VolCatInfo; /* structure assignment */ recycle = strcmp(dev->VolCatInfo.VolCatStatus, "Recycle") == 0; break; /* got a Volume */ case VOL_NAME_ERROR: @@ -256,16 +261,16 @@ read_volume: /* If not removable, Volume is broken */ if (!dev->is_removable()) { Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" not on device %s.\n"), - dcr->VolumeName, dev->print_name()); - mark_volume_in_error(dcr); + VolumeName, dev->print_name()); + dcr->mark_volume_in_error(); goto mount_next_vol; } - Dmsg1(150, "Vol NAME Error Name=%s\n", dcr->VolumeName); + Dmsg1(150, "Vol NAME Error Name=%s\n", VolumeName); /* If polling and got a previous bad name, ignore it */ if (dev->poll && strcmp(dev->BadVolName, dev->VolHdr.VolumeName) == 0) { ask = true; - Dmsg1(200, "Vol Name error supress due to poll. Name=%s\n", dcr->VolumeName); + Dmsg1(200, "Vol Name error supress due to poll. Name=%s\n", VolumeName); goto mount_next_vol; } /* @@ -274,17 +279,17 @@ read_volume: * this volume is really OK. If not, put back the desired * volume name, mark it not in changer and continue. */ - dcrVolCatInfo = dcr->VolCatInfo; /* structure assignment */ + dcrVolCatInfo = VolCatInfo; /* structure assignment */ devVolCatInfo = dev->VolCatInfo; /* structure assignment */ /* Check if this is a valid Volume in the pool */ - bstrncpy(VolumeName, dcr->VolumeName, sizeof(VolumeName)); - bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName)); + bstrncpy(VolumeName, VolumeName, sizeof(VolumeName)); + bstrncpy(VolumeName, dev->VolHdr.VolumeName, sizeof(VolumeName)); if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE)) { POOL_MEM vol_info_msg; pm_strcpy(vol_info_msg, jcr->dir_bsock->msg); /* save error message */ /* Restore desired volume name, note device info out of sync */ /* This gets the info regardless of the Pool */ - bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName)); + bstrncpy(VolumeName, dev->VolHdr.VolumeName, sizeof(VolumeName)); if (autochanger && !dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) { /* * If we get here, we know we cannot write on the Volume, @@ -302,16 +307,16 @@ read_volume: vol_info_msg.c_str()); ask = true; /* Restore saved DCR before continuing */ - bstrncpy(dcr->VolumeName, VolumeName, sizeof(dcr->VolumeName)); - dcr->VolCatInfo = dcrVolCatInfo; /* structure assignment */ + bstrncpy(VolumeName, VolumeName, sizeof(VolumeName)); + VolCatInfo = dcrVolCatInfo; /* structure assignment */ goto mount_next_vol; } /* * This was not the volume we expected, but it is OK with * the Director, so use it. */ - Dmsg1(150, "want new name=%s\n", dcr->VolumeName); - dev->VolCatInfo = dcr->VolCatInfo; /* structure assignment */ + Dmsg1(150, "want new name=%s\n", VolumeName); + dev->VolCatInfo = VolCatInfo; /* structure assignment */ recycle = strcmp(dev->VolCatInfo.VolCatStatus, "Recycle") == 0; break; /* got a Volume */ /* @@ -320,8 +325,8 @@ read_volume: case VOL_IO_ERROR: if (dev->is_dvd()) { Jmsg(jcr, M_FATAL, 0, "%s", jcr->errmsg); - mark_volume_in_error(dcr); - return false; /* we could not write on DVD */ + dcr->mark_volume_in_error(); + goto bail_out; /* we could not write on DVD */ } /* Fall through wanted */ case VOL_NO_LABEL: @@ -331,7 +336,7 @@ read_volume: case try_read_vol: goto read_volume; case try_error: - return false; + goto bail_out; case try_default: break; } @@ -368,7 +373,7 @@ read_volume: */ if (dev->VolHdr.LabelType == PRE_LABEL || recycle) { if (!rewrite_volume_label(dcr, recycle)) { - mark_volume_in_error(dcr); + dcr->mark_volume_in_error(); goto mount_next_vol; } } else { @@ -379,95 +384,23 @@ read_volume: */ Dmsg0(200, "Device previously written, moving to end of data\n"); Jmsg(jcr, M_INFO, 0, _("Volume \"%s\" previously written, moving to end of data.\n"), - dcr->VolumeName); + VolumeName); + if (!dev->eod(dcr)) { Jmsg(jcr, M_ERROR, 0, _("Unable to position to end of data on device %s: ERR=%s\n"), dev->print_name(), dev->bstrerror()); - mark_volume_in_error(dcr); + dcr->mark_volume_in_error(); goto mount_next_vol; } - if (dev->is_dvd()) { - char ed1[50], ed2[50]; - if (dev->VolCatInfo.VolCatBytes == dev->part_start + dev->part_size) { - Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume \"%s\"" - " part=%d size=%s\n"), dcr->VolumeName, - dev->part, edit_uint64(dev->VolCatInfo.VolCatBytes,ed1)); - } else { - Jmsg(jcr, M_ERROR, 0, _("Bacula cannot write on DVD Volume \"%s\" because: " - "The sizes do not match! Volume=%s Catalog=%s\n"), - dcr->VolumeName, - edit_uint64(dev->part_start + dev->part_size, ed1), - edit_uint64(dev->VolCatInfo.VolCatBytes, ed2)); - mark_volume_in_error(dcr); - goto mount_next_vol; - } - } else if (dev->is_tape()) { - /* - * Check if we are positioned on the tape at the same place - * that the database says we should be. - */ - if (dev->VolCatInfo.VolCatFiles == dev->get_file()) { - Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume \"%s\" at file=%d.\n"), - dcr->VolumeName, dev->get_file()); - } else { - Jmsg(jcr, M_ERROR, 0, _("Bacula cannot write on tape Volume \"%s\" because:\n" - "The number of files mismatch! Volume=%u Catalog=%u\n"), - dcr->VolumeName, dev->get_file(), dev->VolCatInfo.VolCatFiles); - mark_volume_in_error(dcr); - goto mount_next_vol; - } - } else if (dev->is_file()) { - char ed1[50], ed2[50]; - boffset_t pos; - pos = dev->lseek(dcr, (boffset_t)0, SEEK_END); - if (dev->VolCatInfo.VolCatBytes == (uint64_t)pos) { - Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume \"%s\"" - " size=%s\n"), dcr->VolumeName, - edit_uint64(dev->VolCatInfo.VolCatBytes, ed1)); - } else { - Jmsg(jcr, M_ERROR, 0, _("Bacula cannot write on disk Volume \"%s\" because: " - "The sizes do not match! Volume=%s Catalog=%s\n"), - dcr->VolumeName, - edit_uint64(pos, ed1), - edit_uint64(dev->VolCatInfo.VolCatBytes, ed2)); - mark_volume_in_error(dcr); - goto mount_next_vol; - } + if (!is_eod_valid(dcr)) { + goto mount_next_vol; } + dev->VolCatInfo.VolCatMounts++; /* Update mounts */ Dmsg1(150, "update volinfo mounts=%d\n", dev->VolCatInfo.VolCatMounts); if (!dir_update_volume_info(dcr, false, false)) { - return false; - } - - /* - * DVD : check if the last part was removed or truncated, or if a written - * part was overwritten. - * We need to do it after dir_update_volume_info, so we have the EndBlock - * info. (nb: I don't understand why VolCatFiles is set (used to check - * tape file number), but not EndBlock) - * Maybe could it be changed "dev->is_file()" (would remove the fixme above) - * - * Disabled: I had problems with this code... - * (maybe is it related to the seek bug ?) - */ -#ifdef xxx - if (dev->is_dvd()) { - Dmsg2(150, "DVD/File sanity check addr=%u vs endblock=%u\n", (unsigned int)dev->file_addr, (unsigned int)dev->VolCatInfo.EndBlock); - if (dev->file_addr == dev->VolCatInfo.EndBlock+1) { - Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume \"%s\" at file address=%u.\n"), - dcr->VolumeName, (unsigned int)dev->file_addr); - } - else { - Jmsg(jcr, M_ERROR, 0, _("Bacula cannot write on Volume \"%s\" because:\n" - "The EOD file address is wrong: Volume file address=%u != Catalog Endblock=%u(+1)\n" - "Perhaps You removed the DVD last part in spool directory.\n"), - dcr->VolumeName, (unsigned int)dev->file_addr, (unsigned int)dev->VolCatInfo.EndBlock); - mark_volume_in_error(dcr); - goto mount_next_vol; - } + goto bail_out; } -#endif /* Return an empty block */ empty_block(block); /* we used it for reading so set for write */ @@ -476,9 +409,76 @@ read_volume: Dmsg1(150, "set APPEND, normal return from mount_next_write_volume. dev=%s\n", dev->print_name()); + unlock_volumes(); + return true; + +bail_out: + unlock_volumes(); + return false; +} + + +/* + * Check if the current position on the volume corresponds to + * what is in the catalog. + */ +static bool is_eod_valid(DCR *dcr) +{ + DEVICE *dev = dcr->dev; + JCR *jcr = dcr->jcr; + + if (dev->is_dvd()) { + char ed1[50], ed2[50]; + if (dev->VolCatInfo.VolCatBytes == dev->part_start + dev->part_size) { + Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume \"%s\"" + " part=%d size=%s\n"), dcr->VolumeName, + dev->part, edit_uint64(dev->VolCatInfo.VolCatBytes,ed1)); + } else { + Jmsg(jcr, M_ERROR, 0, _("Bacula cannot write on DVD Volume \"%s\" because: " + "The sizes do not match! Volume=%s Catalog=%s\n"), + dcr->VolumeName, + edit_uint64(dev->part_start + dev->part_size, ed1), + edit_uint64(dev->VolCatInfo.VolCatBytes, ed2)); + dcr->mark_volume_in_error(); + return false; + } + } else if (dev->is_tape()) { + /* + * Check if we are positioned on the tape at the same place + * that the database says we should be. + */ + if (dev->VolCatInfo.VolCatFiles == dev->get_file()) { + Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume \"%s\" at file=%d.\n"), + dcr->VolumeName, dev->get_file()); + } else { + Jmsg(jcr, M_ERROR, 0, _("Bacula cannot write on tape Volume \"%s\" because:\n" + "The number of files mismatch! Volume=%u Catalog=%u\n"), + dcr->VolumeName, dev->get_file(), dev->VolCatInfo.VolCatFiles); + dcr->mark_volume_in_error(); + return false; + } + } else if (dev->is_file()) { + char ed1[50], ed2[50]; + boffset_t pos; + pos = dev->lseek(dcr, (boffset_t)0, SEEK_END); + if (dev->VolCatInfo.VolCatBytes == (uint64_t)pos) { + Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume \"%s\"" + " size=%s\n"), dcr->VolumeName, + edit_uint64(dev->VolCatInfo.VolCatBytes, ed1)); + } else { + Jmsg(jcr, M_ERROR, 0, _("Bacula cannot write on disk Volume \"%s\" because: " + "The sizes do not match! Volume=%s Catalog=%s\n"), + dcr->VolumeName, + edit_uint64(pos, ed1), + edit_uint64(dev->VolCatInfo.VolCatBytes, ed2)); + dcr->mark_volume_in_error(); + return false; + } + } return true; } + /* * If permitted, we label the device, make sure we can do * it by checking that the VolCatBytes is zero => not labeled, @@ -516,7 +516,7 @@ static int try_autolabel(DCR *dcr, bool opened) dcr->pool_name, false, /* no relabel */ false /* defer DVD label */)) { Dmsg0(150, "!write_vol_label\n"); if (opened) { - mark_volume_in_error(dcr); + dcr->mark_volume_in_error(); } return try_next_vol; } @@ -538,7 +538,7 @@ static int try_autolabel(DCR *dcr, bool opened) if (!dev->is_removable()) { Jmsg(dcr->jcr, M_WARNING, 0, _("Volume \"%s\" not on device %s.\n"), dcr->VolumeName, dev->print_name()); - mark_volume_in_error(dcr); + dcr->mark_volume_in_error(); return try_next_vol; } return try_default; @@ -548,16 +548,15 @@ static int try_autolabel(DCR *dcr, bool opened) /* * Mark volume in error in catalog */ -void mark_volume_in_error(DCR *dcr) +void DCR::mark_volume_in_error() { - DEVICE *dev = dcr->dev; - Jmsg(dcr->jcr, M_INFO, 0, _("Marking Volume \"%s\" in Error in Catalog.\n"), - dcr->VolumeName); - dev->VolCatInfo = dcr->VolCatInfo; /* structure assignment */ + Jmsg(jcr, M_INFO, 0, _("Marking Volume \"%s\" in Error in Catalog.\n"), + VolumeName); + dev->VolCatInfo = VolCatInfo; /* structure assignment */ bstrncpy(dev->VolCatInfo.VolCatStatus, "Error", sizeof(dev->VolCatInfo.VolCatStatus)); Dmsg0(150, "dir_update_vol_info. Set Error.\n"); - dir_update_volume_info(dcr, false, false); - volume_unused(dcr); + dir_update_volume_info(this, false, false); + volume_unused(this); } /* diff --git a/bacula/src/stored/protos.h b/bacula/src/stored/protos.h index b6aca7b9ff..2d0d37814f 100644 --- a/bacula/src/stored/protos.h +++ b/bacula/src/stored/protos.h @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2000-2007 Free Software Foundation Europe e.V. + Copyright (C) 2000-20087 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. @@ -185,9 +185,7 @@ BSR *find_next_bsr(BSR *root_bsr, DEVICE *dev); bool is_this_bsr_done(BSR *bsr, DEV_RECORD *rec); /* From mount.c */ -bool mount_next_write_volume(DCR *dcr, bool have_vol, bool release); bool mount_next_read_volume(DCR *dcr); -void mark_volume_in_error(DCR *dcr); /* From parse_bsr.c */ BSR *parse_bsr(JCR *jcr, char *lf); diff --git a/bacula/src/stored/reserve.c b/bacula/src/stored/reserve.c index 90a81e6dd3..2880fb500f 100644 --- a/bacula/src/stored/reserve.c +++ b/bacula/src/stored/reserve.c @@ -320,7 +320,8 @@ VOLRES *reserve_volume(DCR *dcr, const char *VolumeName) ASSERT(dev != NULL); - Dmsg1(dbglvl, "enter reserve_volume %s\n", VolumeName); + Dmsg2(dbglvl, "enter reserve_volume=%s drive=%s\n", VolumeName, + dcr->dev->print_name()); /* * We lock the reservations system here to ensure * when adding a new volume that no newly scheduled @@ -355,8 +356,9 @@ VOLRES *reserve_volume(DCR *dcr, const char *VolumeName) goto get_out; } Dmsg2(dbglvl, "reserve_vol free vol=%s at %p\n", vol->vol_name, vol->vol_name); - unload_autochanger(dcr, -1); /* unload the volume */ free_volume(dev); + dcr->unload_device = true; /* have to unload current volume */ +// unload_autochanger(dcr, -1); /* unload the volume */ debug_list_volumes("reserve_vol free"); } } @@ -381,40 +383,22 @@ VOLRES *reserve_volume(DCR *dcr, const char *VolumeName) * Clear dev pointer so that free_vol_item() doesn't * take away our volume. */ - nvol->dev = NULL; /* don't zap dev entry */ + nvol->dev = NULL; /* don't zap dev entry */ free_vol_item(nvol); /* Check if we are trying to use the Volume on a different drive */ if (dev != vol->dev) { /* Caller wants to switch Volume to another device */ -#ifdef xxx - Dmsg2(dbglvl, "==== Swap from dev=%s to %s\n", - dev->print_name(), vol->dev->print_name()); - vol->dev->vol = NULL; /* take vol from old drive */ - switch_device(dcr, vol->dev); - dev = vol->dev; - bstrncpy(dcr->VolumeName, VolumeName, sizeof(dcr->VolumeName)); -#else if (!vol->dev->is_busy()) { - vol->dev->vol = NULL; /* take vol from old drive */ - if (vol->dev->Slot > 0) { - Dmsg1(dbglvl, "Unload dev=%s\n", vol->dev->print_name()); - unload_dev(dcr, vol->dev); - } - /* OK to move it -- I'm not sure this will work */ - Dmsg3(dbglvl, "==== Swap vol=%s from dev=%s to %s\n", VolumeName, - vol->dev->print_name(), dev->print_name()); - vol->dev->VolHdr.VolumeName[0] = 0; - vol->dev = dev; /* point vol at new drive */ - dev->vol = vol; /* point dev at vol */ - dev->VolHdr.VolumeName[0] = 0; + dcr->swap_dev = vol->dev; /* remember to get this vol */ + Dmsg3(dbglvl, "==== Swap vol=%s from dev=%s to %s\n", + VolumeName, vol->dev->print_name(), dev->print_name()); } else { Dmsg3(dbglvl, "==== Swap not possible Vol busy vol=%s from dev=%s to %s\n", VolumeName, vol->dev->print_name(), dev->print_name()); - vol = NULL; /* device busy */ + vol = NULL; /* device busy */ goto get_out; } -#endif } } dev->vol = vol; @@ -487,6 +471,7 @@ VOLRES *find_volume(DCR *dcr) void unreserve_device(DCR *dcr) { DEVICE *dev = dcr->dev; + lock_volumes(); if (dcr->reserved_device) { dcr->reserved_device = false; dcr->reserved_volume = false; @@ -504,6 +489,7 @@ void unreserve_device(DCR *dcr) volume_unused(dcr); } } + unlock_volumes(); } /* diff --git a/bacula/src/version.h b/bacula/src/version.h index 58c829d608..95579a4335 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -4,8 +4,8 @@ #undef VERSION #define VERSION "2.3.16" -#define BDATE "07 April 2008" -#define LSMDATE "07Apr08" +#define BDATE "09 April 2008" +#define LSMDATE "09Apr08" #define PROG_COPYRIGHT "Copyright (C) %d-2008 Free Software Foundation Europe e.V.\n" #define BYEAR "2008" /* year for copyright messages in progs */ diff --git a/bacula/technotes-2.3 b/bacula/technotes-2.3 index e034899c83..724940a656 100644 --- a/bacula/technotes-2.3 +++ b/bacula/technotes-2.3 @@ -24,6 +24,15 @@ Add long term statistics job table General: +09Apr08 +kes Correct error string numbers in dird/catreq.c +kes Restructure reserving, acquiring, and mounting volumes. Calls to + autochanger are deferred for mount.c -- simplifes the code. +08Apr08 +kes Do not prune any running job. It just fails the job. +kes Lock the volumes when changing dev->reserved_device and marking + the volume unused otherwise the device can get reserved by + another job before the volume is released, thus blocking it. 06Apr08 kes Correctly detect Ubuntu systems, and add ubuntu platform directory. kes Fix bug #1063, reuse of freed ptr in list nextvol. -- 2.39.5