From: Kern Sibbald Date: Mon, 18 Jun 2007 19:29:26 +0000 (+0000) Subject: kes Add some additional locking in the cats directory in subroutines X-Git-Tag: Release-7.0.0~6119 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=0e794438e5b1afd88ba96f584541e2731ab9cc23;p=bacula%2Fbacula kes Add some additional locking in the cats directory in subroutines that modify packet variables called from batch insert. kes Rework how dcrs are allocated. new_dcr() can now be called with an existing pointer, and it will simply clean it up. This allows the reservation system to test various different devices, and will permit easy device changes. kes A bunch of changes all over to handle new new_dcr() calling sequence. kes Work more on the Volume management in the SD. Remember Volumes for tape drives and for autochangers (even virtual disk changers). kes When looking at the Volume list to reserve a drive, handle autochanger names correctly by interating through the changer devices. Also call the Director to see if a Volume is suitable for the current job. kes Fix some bugs in bscan. Make sure all media records are written. Make sure that valid JobMedia records are written for disk files. Previously they were completely wrong. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@5038 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/src/cats/mysql.c b/bacula/src/cats/mysql.c index aade9955f9..6242fc3753 100644 --- a/bacula/src/cats/mysql.c +++ b/bacula/src/cats/mysql.c @@ -395,10 +395,12 @@ int db_sql_query(B_DB *mdb, const char *query, DB_RESULT_HANDLER *result_handler void my_mysql_free_result(B_DB *mdb) { + db_lock(mdb); if (mdb->result) { mysql_free_result(mdb->result); mdb->result = NULL; } + db_unlock(mdb); } char *my_mysql_batch_lock_path_query = "LOCK TABLES Path write, " diff --git a/bacula/src/cats/postgresql.c b/bacula/src/cats/postgresql.c index 8d4deb4e02..d7010647e9 100644 --- a/bacula/src/cats/postgresql.c +++ b/bacula/src/cats/postgresql.c @@ -511,6 +511,8 @@ bail_out: void my_postgresql_free_result(B_DB *mdb) { + + db_lock(mdb); if (mdb->result) { PQclear(mdb->result); mdb->result = NULL; @@ -525,6 +527,7 @@ void my_postgresql_free_result(B_DB *mdb) free(mdb->fields); mdb->fields = NULL; } + db_unlock(mdb); } int my_postgresql_currval(B_DB *mdb, char *table_name) diff --git a/bacula/src/cats/sql_create.c b/bacula/src/cats/sql_create.c index d4a1d71d6e..95d4afdf85 100644 --- a/bacula/src/cats/sql_create.c +++ b/bacula/src/cats/sql_create.c @@ -686,7 +686,10 @@ bool db_create_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr) */ bool my_batch_start(JCR *jcr, B_DB *mdb) { - return db_sql_query(mdb, + bool ok; + + db_lock(mdb); + ok = db_sql_query(mdb, " CREATE TEMPORARY TABLE batch " " (fileindex integer, " " jobid integer, " @@ -694,6 +697,8 @@ bool my_batch_start(JCR *jcr, B_DB *mdb) " name blob, " " lstat tinyblob, " " md5 tinyblob) ",NULL, NULL); + db_unlock(mdb); + return ok; } /* diff --git a/bacula/src/dird/ua_output.c b/bacula/src/dird/ua_output.c index c6744370d9..01c76f1a20 100644 --- a/bacula/src/dird/ua_output.c +++ b/bacula/src/dird/ua_output.c @@ -473,6 +473,10 @@ static bool list_nextvol(UAContext *ua, int ndays) if (!complete_jcr_for_job(jcr, job, run->pool)) { return false; } + if (!jcr->jr.PoolId) { + ua->error_msg(_("Could not Pool Job %s\n"), job->name()); + continue; + } memset(&pr, 0, sizeof(pr)); pr.PoolId = jcr->jr.PoolId; if (!db_get_pool_record(ua->jcr, ua->db, &pr)) { @@ -482,12 +486,12 @@ static bool list_nextvol(UAContext *ua, int ndays) get_job_storage(&store, job, run); mr.StorageId = store.store->StorageId; if (!find_next_volume_for_append(jcr, &mr, 1, fnv_no_create_vol, fnv_prune)) { - ua->error_msg(_("Could not find next Volume for Job %s (%s, %s).\n"), - job->hdr.name, pr.Name, level_to_str(run->level)); + ua->error_msg(_("Could not find next Volume for Job %s (Pool=%s, Level=%s).\n"), + job->name(), pr.Name, level_to_str(run->level)); } else { ua->send_msg( - _("The next Volume to be used by Job \"%s\" (%s, %s) will be %s\n"), - job->hdr.name, pr.Name, level_to_str(run->level), mr.VolumeName); + _("The next Volume to be used by Job \"%s\" (Pool=%s, Level=%s) will be %s\n"), + job->name(), pr.Name, level_to_str(run->level), mr.VolumeName); found = true; } if (jcr->db && jcr->db != ua->db) { diff --git a/bacula/src/stored/acquire.c b/bacula/src/stored/acquire.c index cc32c6bb1a..0f6a89017a 100644 --- a/bacula/src/stored/acquire.c +++ b/bacula/src/stored/acquire.c @@ -125,24 +125,24 @@ bool acquire_device_for_read(DCR *dcr) rctx.store = store; /* - * Note, if search_for_device() succeeds, we get a new_dcr, + * Note, if search_for_device() succeeds, we get a new dcr, * which we do not use except for the dev info. */ stat = search_res_for_device(rctx); release_msgs(jcr); /* release queued messages */ unlock_reservations(); if (stat == 1) { - DCR *new_dcr = jcr->read_dcr; + DCR *ndcr = jcr->read_dcr; dev->unblock(dev_unlocked); detach_dcr_from_dev(dcr); /* release old device */ /* Copy important info from the new dcr */ - dev = dcr->dev = new_dcr->dev; + dev = dcr->dev = ndcr->dev; jcr->read_dcr = dcr; - dcr->device = new_dcr->device; + dcr->device = ndcr->device; dcr->max_job_spool_size = dcr->device->max_job_spool_size; attach_dcr_to_dev(dcr); - new_dcr->VolumeName[0] = 0; - free_dcr(new_dcr); + ndcr->VolumeName[0] = 0; + free_dcr(ndcr); dev->block(BST_DOING_ACQUIRE); Jmsg(jcr, M_INFO, 0, _("Media Type change. New device %s chosen.\n"), dev->print_name()); @@ -577,23 +577,43 @@ bool release_device(DCR *dcr) /* * Create a new Device Control Record and attach * it to the device (if this is a real job). + * Note, this has been updated so that it can be called first + * without a DEVICE, then a second or third time with a DEVICE, + * and each time, it should cleanup and point to the new device. + * This should facilitate switching devices. + * Note, each dcr must point to the controlling job (jcr). However, + * a job can have multiple dcrs, so we must not store in the jcr's + * structure as previously. The higher level routine must store + * this dcr in the right place + * */ -DCR *new_dcr(JCR *jcr, DEVICE *dev) +DCR *new_dcr(JCR *jcr, DCR *dcr, DEVICE *dev) { - if (jcr) Dmsg2(100, "enter new_dcr JobId=%u dev=%p\n", (uint32_t)jcr->JobId, dev); - DCR *dcr = (DCR *)malloc(sizeof(DCR)); - memset(dcr, 0, sizeof(DCR)); - dcr->jcr = jcr; - if (dev) { + if (!dcr) { + dcr = (DCR *)malloc(sizeof(DCR)); + memset(dcr, 0, sizeof(DCR)); dcr->tid = pthread_self(); - dcr->dev = dev; - dcr->device = dev->device; + dcr->spool_fd = -1; + } + dcr->jcr = jcr; /* point back to jcr */ + /* Set device information, possibly change device */ + if (dev) { + if (dcr->block) { + free_block(dcr->block); + } dcr->block = new_block(dev); + if (dcr->rec) { + free_record(dcr->rec); + } dcr->rec = new_record(); + if (dcr->attached_to_dev) { + detach_dcr_from_dev(dcr); + } dcr->max_job_spool_size = dev->device->max_job_spool_size; + dcr->device = dev->device; + dcr->dev = dev; attach_dcr_to_dev(dcr); } - dcr->spool_fd = -1; return dcr; } @@ -639,10 +659,10 @@ static void attach_dcr_to_dev(DCR *dcr) void detach_dcr_from_dev(DCR *dcr) { Dmsg1(500, "JobId=%u enter detach_dcr_from_dev\n", (uint32_t)dcr->jcr->JobId); - unreserve_device(dcr); /* Detach this dcr only if attached */ - if (dcr->attached_to_dev) { + if (dcr->attached_to_dev && dcr->dev) { + unreserve_device(dcr); dcr->dev->attached_dcrs->remove(dcr); /* detach dcr from device */ dcr->attached_to_dev = false; // remove_dcr_from_dcrs(dcr); /* remove dcr from jcr list */ @@ -657,9 +677,7 @@ void free_dcr(DCR *dcr) { JCR *jcr = dcr->jcr; - if (dcr->dev) { - detach_dcr_from_dev(dcr); - } + detach_dcr_from_dev(dcr); if (dcr->block) { free_block(dcr->block); diff --git a/bacula/src/stored/autochanger.c b/bacula/src/stored/autochanger.c index 8f2ac0c00d..2edd3f66c3 100644 --- a/bacula/src/stored/autochanger.c +++ b/bacula/src/stored/autochanger.c @@ -251,7 +251,7 @@ int get_autochanger_loaded_slot(DCR *dcr) return dev->Slot; } /* Virtual disk autochanger */ - if (dcr->device->changer_command[0] ==0) { + if (dcr->device->changer_command[0] == 0) { return 1; } diff --git a/bacula/src/stored/bscan.c b/bacula/src/stored/bscan.c index d097fc4559..f68ef04296 100644 --- a/bacula/src/stored/bscan.c +++ b/bacula/src/stored/bscan.c @@ -1,18 +1,7 @@ -/* - * - * Program to scan a Bacula Volume and compare it with - * the catalog and optionally synchronize the catalog - * with the tape. - * - * Kern E. Sibbald, December 2001 - * - * - * Version $Id$ - */ /* Bacula® - The Network Backup Solution - Copyright (C) 2001-2006 Free Software Foundation Europe e.V. + Copyright (C) 2001-2007 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. @@ -36,6 +25,17 @@ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, Switzerland, email:ftf@fsfeurope.org. */ +/* + * + * Program to scan a Bacula Volume and compare it with + * the catalog and optionally synchronize the catalog + * with the tape. + * + * Kern E. Sibbald, December 2001 + * + * + * Version $Id$ + */ #include "bacula.h" #include "stored.h" @@ -315,25 +315,26 @@ static bool bscan_mount_next_read_volume(DCR *dcr) Dmsg1(100, "Walk attached jcrs. Volume=%s\n", dev->VolCatInfo.VolCatName); foreach_dlist(mdcr, dev->attached_dcrs) { JCR *mjcr = mdcr->jcr; + Dmsg1(000, "========== JobId=%u ========\n", mjcr->JobId); if (mjcr->JobId == 0) { continue; } if (verbose) { Pmsg1(000, _("Create JobMedia for Job %s\n"), mjcr->Job); } - if (dev->is_tape()) { - mdcr->EndBlock = dcr->EndBlock; - mdcr->EndFile = dcr->EndFile; -// } else { -// mdcr->EndBlock = (uint32_t)dcr->file_addr; -// mdcr->EndFile = (uint32_t)(dcr->file_addr >> 32); - } + mdcr->StartBlock = dcr->StartBlock; + mdcr->StartFile = dcr->StartFile; + mdcr->EndBlock = dcr->EndBlock; + mdcr->EndFile = dcr->EndFile; mjcr->read_dcr->VolLastIndex = dcr->VolLastIndex; if (!create_jobmedia_record(db, mjcr)) { Pmsg2(000, _("Could not create JobMedia record for Volume=%s Job=%s\n"), dev->VolCatInfo.VolCatName, mjcr->Job); } } + + update_media_record(db, &mr); + /* Now let common read routine get up next tape. Note, * we call mount_next... with bscan's jcr because that is where we * have the Volume list, but we get attached. @@ -890,6 +891,12 @@ static int create_media_record(B_DB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl) mr->LabelDate = mktime(&tm); } lasttime = mr->LabelDate; + if (mr->VolJobs == 0) { + mr->VolJobs = 1; + } + if (mr->VolMounts == 0) { + mr->VolMounts = 1; + } if (!update_db) { return 1; @@ -1168,15 +1175,8 @@ static int create_jobmedia_record(B_DB *db, JCR *mjcr) JOBMEDIA_DBR jmr; DCR *dcr = mjcr->read_dcr; - if (dev->is_tape()) { - dcr->EndBlock = dev->EndBlock; - dcr->EndFile = dev->EndFile; -#ifdef needed - } else { - dcr->EndBlock = (uint32_t)dev->file_addr; - dcr->EndFile = (uint32_t)(dev->file_addr >> 32); -#endif - } + dcr->EndBlock = dev->EndBlock; + dcr->EndFile = dev->EndFile; memset(&jmr, 0, sizeof(jmr)); jmr.JobId = mjcr->JobId; @@ -1261,7 +1261,7 @@ static JCR *create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId) jobjcr->VolSessionId = rec->VolSessionId; jobjcr->VolSessionTime = rec->VolSessionTime; jobjcr->ClientId = jr->ClientId; - jobjcr->read_dcr = new_dcr(jobjcr, dev); + jobjcr->dcr = jobjcr->read_dcr = new_dcr(jobjcr, NULL, dev); return jobjcr; } diff --git a/bacula/src/stored/butil.c b/bacula/src/stored/butil.c index 9cfe48e48b..ed91e0497f 100644 --- a/bacula/src/stored/butil.c +++ b/bacula/src/stored/butil.c @@ -1,20 +1,7 @@ -/* - * - * Utility routines for "tool" programs such as bscan, bls, - * bextract, ... Some routines also used by Bacula. - * - * Kern Sibbald, MM - * - * Normally nothing in this file is called by the Storage - * daemon because we interact more directly with the user - * i.e. printf, ... - * - * Version $Id$ - */ /* Bacula® - The Network Backup Solution - Copyright (C) 2000-2006 Free Software Foundation Europe e.V. + Copyright (C) 2000-2007 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. @@ -38,6 +25,19 @@ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, Switzerland, email:ftf@fsfeurope.org. */ +/* + * + * Utility routines for "tool" programs such as bscan, bls, + * bextract, ... Some routines also used by Bacula. + * + * Kern Sibbald, MM + * + * Normally nothing in this file is called by the Storage + * daemon because we interact more directly with the user + * i.e. printf, ... + * + * Version $Id$ + */ #include "bacula.h" #include "stored.h" @@ -175,8 +175,7 @@ static DCR *setup_to_access_device(JCR *jcr, char *dev_name, return NULL; } device->dev = dev; - dcr = new_dcr(jcr, dev); - jcr->dcr = dcr; + jcr->dcr = dcr = new_dcr(jcr, NULL, dev); if (VolName[0]) { bstrncpy(dcr->VolumeName, VolName, sizeof(dcr->VolumeName)); } diff --git a/bacula/src/stored/dircmd.c b/bacula/src/stored/dircmd.c index a35a1370c0..1c31bf233a 100644 --- a/bacula/src/stored/dircmd.c +++ b/bacula/src/stored/dircmd.c @@ -87,11 +87,11 @@ static bool bootstrap_cmd(JCR *jcr); static bool changer_cmd(JCR *sjcr); static bool do_label(JCR *jcr, int relabel); static DCR *find_device(JCR *jcr, POOL_MEM &dev_name, int drive); -static void read_volume_label(JCR *jcr, DEVICE *dev, int Slot); +static void read_volume_label(JCR *jcr, DCR *dcr, DEVICE *dev, int Slot); static void label_volume_if_ok(DCR *dcr, char *oldname, char *newname, char *poolname, int Slot, int relabel); -static bool try_autoload_device(JCR *jcr, int slot, const char *VolName); +static bool try_autoload_device(JCR *jcr, DCR *dcr, int slot, const char *VolName); static void send_dir_busy_message(BSOCK *dir, DEVICE *dev); struct s_cmds { @@ -398,7 +398,6 @@ static bool do_label(JCR *jcr, int relabel) } dev->dunlock(); free_dcr(dcr); - jcr->dcr = NULL; } else { bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), dev_name.c_str()); } @@ -438,7 +437,7 @@ static void label_volume_if_ok(DCR *dcr, char *oldname, Dmsg0(90, "try_autoload_device - looking for volume_info\n"); - if (!try_autoload_device(dcr->jcr, slot, volname)) { + if (!try_autoload_device(dcr->jcr, dcr, slot, volname)) { goto bail_out; /* error */ } @@ -615,9 +614,8 @@ static DCR *find_device(JCR *jcr, POOL_MEM &devname, int drive) if (found) { Dmsg1(100, "Found device %s\n", device->hdr.name); - dcr = new_dcr(jcr, device->dev); + dcr = new_dcr(jcr, NULL, device->dev); dcr->device = device; - jcr->dcr = dcr; } return dcr; } @@ -663,7 +661,7 @@ static bool mount_cmd(JCR *jcr) case BST_UNMOUNTED_WAITING_FOR_SYSOP: case BST_UNMOUNTED: if (dev->is_autochanger() && slot > 0) { - try_autoload_device(jcr, slot, ""); + try_autoload_device(jcr, dcr, slot, ""); } /* We freed the device, so reopen it and wake any waiting threads */ if (dev->open(dcr, OPEN_READ_ONLY) < 0) { @@ -711,7 +709,7 @@ static bool mount_cmd(JCR *jcr) case BST_NOT_BLOCKED: if (dev->is_autochanger() && slot > 0) { - try_autoload_device(jcr, slot, ""); + try_autoload_device(jcr, dcr, slot, ""); } if (dev->is_open()) { if (dev->is_labeled()) { @@ -756,7 +754,6 @@ static bool mount_cmd(JCR *jcr) } dev->dunlock(); free_dcr(dcr); - jcr->dcr = NULL; } else { bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str()); } @@ -847,7 +844,6 @@ static bool unmount_cmd(JCR *jcr) } dev->dunlock(); free_dcr(dcr); - jcr->dcr = NULL; } else { bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str()); } @@ -920,7 +916,6 @@ static bool release_cmd(JCR *jcr) } dev->dunlock(); free_dcr(dcr); - jcr->dcr = NULL; } else { bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str()); } @@ -984,7 +979,6 @@ static bool changer_cmd(JCR *jcr) } dev->dunlock(); free_dcr(dcr); - jcr->dcr = NULL; } else { bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str()); } @@ -1016,19 +1010,18 @@ static bool readlabel_cmd(JCR *jcr) dev = dcr->dev; dev->dlock(); /* Use P to avoid indefinite block */ if (!dev->is_open()) { - read_volume_label(jcr, dev, Slot); + read_volume_label(jcr, dcr, dev, Slot); dev->close(); /* Under certain "safe" conditions, we can steal the lock */ } else if (dev->can_steal_lock()) { - read_volume_label(jcr, dev, Slot); + read_volume_label(jcr, dcr, dev, Slot); } else if (dev->is_busy() || dev->is_blocked()) { send_dir_busy_message(dir, dev); } else { /* device not being used */ - read_volume_label(jcr, dev, Slot); + read_volume_label(jcr, dcr, dev, Slot); } dev->dunlock(); free_dcr(dcr); - jcr->dcr = NULL; } else { bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str()); } @@ -1046,16 +1039,15 @@ static bool readlabel_cmd(JCR *jcr) * * Enter with the mutex set */ -static void read_volume_label(JCR *jcr, DEVICE *dev, int Slot) +static void read_volume_label(JCR *jcr, DCR *dcr, DEVICE *dev, int Slot) { BSOCK *dir = jcr->dir_bsock; bsteal_lock_t hold; - DCR *dcr = jcr->dcr; dcr->dev = dev; steal_device_lock(dev, &hold, BST_WRITING_LABEL); - if (!try_autoload_device(jcr, Slot, "")) { + if (!try_autoload_device(jcr, dcr, Slot, "")) { goto bail_out; /* error */ } @@ -1077,9 +1069,8 @@ bail_out: return; } -static bool try_autoload_device(JCR *jcr, int slot, const char *VolName) +static bool try_autoload_device(JCR *jcr, DCR *dcr, int slot, const char *VolName) { - DCR *dcr = jcr->dcr; BSOCK *dir = jcr->dir_bsock; bstrncpy(dcr->VolumeName, VolName, sizeof(dcr->VolumeName)); diff --git a/bacula/src/stored/job.c b/bacula/src/stored/job.c index fe8c4b732e..8215000b83 100644 --- a/bacula/src/stored/job.c +++ b/bacula/src/stored/job.c @@ -356,6 +356,10 @@ void stored_free_jcr(JCR *jcr) } jcr->dcrs = NULL; + /* Avoid a double free */ + if (jcr->dcr == jcr->read_dcr) { + jcr->read_dcr = NULL; + } if (jcr->dcr) { free_dcr(jcr->dcr); jcr->dcr = NULL; diff --git a/bacula/src/stored/protos.h b/bacula/src/stored/protos.h index d417274290..1fd5355f14 100644 --- a/bacula/src/stored/protos.h +++ b/bacula/src/stored/protos.h @@ -38,7 +38,7 @@ uint32_t new_VolSessionId(); DCR *acquire_device_for_append(DCR *dcr); bool acquire_device_for_read(DCR *dcr); bool release_device(DCR *dcr); -DCR *new_dcr(JCR *jcr, DEVICE *dev); +DCR *new_dcr(JCR *jcr, DCR *dcr, DEVICE *dev); void free_dcr(DCR *dcr); void detach_dcr_from_dev(DCR *dcr); diff --git a/bacula/src/stored/reserve.c b/bacula/src/stored/reserve.c index 9f301629c0..17a74d7d59 100644 --- a/bacula/src/stored/reserve.c +++ b/bacula/src/stored/reserve.c @@ -463,7 +463,7 @@ bool volume_unused(DCR *dcr) * explicitly read in this drive. This allows the SD to remember * where the tapes are or last were. */ - if (dev->is_tape()) { + if (dev->is_tape() || dev->is_autochanger()) { return true; } else { return free_volume(dev); @@ -511,7 +511,13 @@ void free_volume_list() } lock_volumes(); foreach_dlist(vol, vol_list) { - Dmsg3(dbglvl, "jid=%u Unreleased Volume=%s dev=%p\n", jid(), vol->vol_name, vol->dev); + if (vol->dev) { + Dmsg3(dbglvl, "jid=%u free vol_list Volume=%s dev=%s\n", jid(), + vol->vol_name, vol->dev->print_name()); + } else { + Dmsg3(dbglvl, "jid=%u free vol_list Volume=%s dev=%p\n", jid(), + vol->vol_name, vol->dev); + } free(vol->vol_name); vol->vol_name = NULL; } @@ -634,6 +640,13 @@ static bool use_storage_cmd(JCR *jcr) } init_jcr_device_wait_timers(jcr); + jcr->dcr = new_dcr(jcr, NULL, NULL); /* get a dcr */ + if (!jcr->dcr) { + BSOCK *dir = jcr->dir_bsock; + dir->fsend(_("3939 Could not get dcr\n")); + Dmsg1(dbglvl, ">dird: %s", dir->msg); + ok = false; + } /* * At this point, we have a list of all the Director's Storage * resources indicated for this Job, which include Pool, PoolType, @@ -648,6 +661,7 @@ static bool use_storage_cmd(JCR *jcr) int repeat = 0; bool fail = false; rctx.notify_dir = true; + lock_reservations(); for ( ; !fail && !job_canceled(jcr); ) { while ((msg = (char *)msgs->pop())) { @@ -658,7 +672,11 @@ static bool use_storage_cmd(JCR *jcr) rctx.VolumeName[0] = 0; rctx.any_drive = false; if (!jcr->PreferMountedVols) { - /* Look for unused drives in autochangers */ + /* + * Here we try to find a drive that is not used. + * This will maximize the use of available drives. + * + */ rctx.num_writers = 20000000; /* start with impossible number */ rctx.low_use_drive = NULL; rctx.PreferMountedVols = false; @@ -688,7 +706,11 @@ static bool use_storage_cmd(JCR *jcr) break; } } - /* Look for an exact match all drives */ + /* + * Now we look for a drive that may or may not be in + * use. + */ + /* Look for an exact Volume match all drives */ rctx.PreferMountedVols = true; rctx.exact_match = true; rctx.autochanger_only = false; @@ -783,6 +805,39 @@ void release_msgs(JCR *jcr) unlock_reservations(); } +/* + * Walk through the autochanger resources and check if + * the volume is in one of them. + * + * Returns: true if volume is in device + * false otherwise + */ +static bool is_vol_in_autochanger(RCTX &rctx, VOLRES *vol) +{ + AUTOCHANGER *changer; + Dmsg2(dbglvl, "jid=%u search changers for %s\n", (int)rctx.jcr->JobId, + rctx.device_name); + foreach_res(changer, R_AUTOCHANGER) { + Dmsg2(dbglvl, "jid=%u Try match changer res=%s\n", + (int)rctx.jcr->JobId, changer->hdr.name); + /* Find resource, and make sure we were able to open it */ + if (fnmatch(rctx.device_name, changer->hdr.name, 0) == 0) { + DEVRES *device; + /* Try each device in this AutoChanger */ + foreach_alist(device, changer->device) { + Dmsg2(dbglvl, "jid=%u Try changer device %s\n", + (int)rctx.jcr->JobId, device->hdr.name); + if (device->dev == vol->dev) { + Dmsg2(dbglvl, "jid=%u Found changer device %s\n", + (int)rctx.jcr->JobId, device->hdr.name); + return true; + } + } + } + } + return false; +} + /* * Search for a device suitable for this job. */ @@ -792,6 +847,7 @@ bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx) DIRSTORE *store; char *device_name; alist *dirstore; + DCR *dcr = jcr->dcr; if (rctx.append) { dirstore = jcr->write_store; @@ -803,6 +859,12 @@ bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx) rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device, rctx.autochanger_only); + /* + * If the appropriate conditions of this if are met, namely that + * we are appending and the user wants mounted drive (or we + * force try a mounted drive because they are all busy), we + * start by looking at all the Volumes in the volume list. + */ if (!vol_list->empty() && rctx.append && rctx.PreferMountedVols) { dlist *temp_vol_list, *save_vol_list; VOLRES *vol = NULL; @@ -836,19 +898,37 @@ bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx) unlock_volumes(); /* Look through reserved volumes for one we can use */ + Dmsg1(dbglvl, "jid=%u look for vol in vol list\n", (int)rctx.jcr->JobId); foreach_dlist(vol, temp_vol_list) { if (!vol->dev) { + Dmsg2(dbglvl, "jid=%u vol=%s no dev\n", (int)rctx.jcr->JobId, vol->vol_name); + continue; + } + /* Check with Director if this Volume is OK */ + bstrncpy(dcr->VolumeName, vol->vol_name, sizeof(dcr->VolumeName)); + if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE)) { continue; } + + Dmsg2(dbglvl, "jid=%u vol=%s\n", (int)rctx.jcr->JobId, vol->vol_name); foreach_alist(store, dirstore) { + int stat; rctx.store = store; foreach_alist(device_name, store->device) { - int stat; - if (strcmp(device_name, vol->dev->device->hdr.name) != 0) { - continue; - } + /* Found a device, try to use it */ rctx.device_name = device_name; rctx.device = vol->dev->device; + + if (!vol->dev->is_autochanger()) { + if (!is_vol_in_autochanger(rctx, vol)) { + continue; + } + } else if (strcmp(device_name, vol->dev->device->hdr.name) != 0) { + Dmsg3(dbglvl, "jid=%u device=%s not suitable want %s\n", (int)rctx.jcr->JobId, + vol->dev->device->hdr.name, device_name); + continue; + } + bstrncpy(rctx.VolumeName, vol->vol_name, sizeof(rctx.VolumeName)); rctx.have_volume = true; /* Try reserving this device and volume */ @@ -874,6 +954,7 @@ bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx) } } } /* end for loop over reserved volumes */ + lock_volumes(); save_vol_list = vol_list; vol_list = temp_vol_list; @@ -1025,7 +1106,7 @@ static int reserve_device(RCTX &rctx) rctx.suitable_device = true; Dmsg2(dbglvl, "jid=%u try reserve %s\n", rctx.jcr->JobId, rctx.device->hdr.name); - dcr = new_dcr(rctx.jcr, rctx.device->dev); + rctx.jcr->dcr = dcr = new_dcr(rctx.jcr, rctx.jcr->dcr, rctx.device->dev); if (!dcr) { BSOCK *dir = rctx.jcr->dir_bsock; dir->fsend(_("3926 Could not get dcr for device: %s\n"), rctx.device_name); @@ -1099,7 +1180,7 @@ static int reserve_device(RCTX &rctx) bail_out: rctx.have_volume = false; - free_dcr(dcr); +// free_dcr(dcr); Dmsg1(dbglvl, "jid=%u Not OK.\n", (int)rctx.jcr->JobId); return 0; } diff --git a/bacula/src/stored/spool.c b/bacula/src/stored/spool.c index 2611e30b91..1c8be6c8e2 100644 --- a/bacula/src/stored/spool.c +++ b/bacula/src/stored/spool.c @@ -257,9 +257,8 @@ static bool despool_data(DCR *dcr, bool commit) rdev->max_block_size = dcr->dev->max_block_size; rdev->min_block_size = dcr->dev->min_block_size; rdev->device = dcr->dev->device; - rdcr = new_dcr(jcr, rdev); + rdcr = new_dcr(jcr, NULL, rdev); rdcr->spool_fd = dcr->spool_fd; - rdcr->jcr = jcr; /* set a valid jcr */ block = dcr->block; /* save block */ dcr->block = rdcr->block; /* make read and write block the same */ diff --git a/bacula/src/stored/stored.c b/bacula/src/stored/stored.c index ab44f067fe..8eff4fc495 100644 --- a/bacula/src/stored/stored.c +++ b/bacula/src/stored/stored.c @@ -483,7 +483,7 @@ void *device_initialization(void *arg) continue; } - jcr->dcr = dcr = new_dcr(jcr, dev); + jcr->dcr = dcr = new_dcr(jcr, NULL, dev); if (dev->is_autochanger()) { /* If autochanger set slot in dev sturcture */ get_autochanger_loaded_slot(dcr); diff --git a/bacula/src/version.h b/bacula/src/version.h index 56374a7608..1e8013f975 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -3,9 +3,9 @@ */ #undef VERSION -#define VERSION "2.1.18" -#define BDATE "16 June 2007" -#define LSMDATE "16Jun07" +#define VERSION "2.1.19" +#define BDATE "18 June 2007" +#define LSMDATE "18Jun07" #define PROG_COPYRIGHT "Copyright (C) %d-2007 Free Software Foundation Europe e.V.\n" #define BYEAR "2007" /* year for copyright messages in progs */ diff --git a/bacula/technotes-2.1 b/bacula/technotes-2.1 index 1fd184c2cf..0fb9a1dcfb 100644 --- a/bacula/technotes-2.1 +++ b/bacula/technotes-2.1 @@ -1,6 +1,28 @@ Technical notes on version 2.1 General: +18Jun08 +kes Add some additional locking in the cats directory in subroutines + that modify packet variables called from batch insert. +kes Rework how dcrs are allocated. new_dcr() can now be called + with an existing pointer, and it will simply clean it up. + This allows the reservation system to test various different + devices, and will permit easy device changes. +kes A bunch of changes all over to handle new new_dcr() calling + sequence. +kes Work more on the Volume management in the SD. Remember Volumes + for tape drives and for autochangers (even virtual disk changers). +kes When looking at the Volume list to reserve a drive, handle + autochanger names correctly by interating through the changer + devices. Also call the Director to see if a Volume is suitable + for the current job. +kes Fix some bugs in bscan. Make sure all media records are written. + Make sure that valid JobMedia records are written for disk files. + Previously they were completely wrong. +kes Move source tar files for depkgs-mingw32 to www.bacula.org so + that the URLs don't change and so that the developers will all + work off the same copy. Rebuild from scrach. +kes Upgrade Win32 SQLite3 from 3.3.8 to 3.3.17. Release: 2.1.18 beta 16Jun07 kes Fix seg fault in FD from incorrect digest size.