X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=bacula%2Fsrc%2Fstored%2Fautochanger.c;h=653b6502ca9a4b55eec81ec86c3ea260d17fc99b;hb=7f4f08eb20a0e6d851e906ca2bbba24396ddc729;hp=07596604de08243cb8509afc3e2d5cb7fba2417e;hpb=b4b5081b4303c7d1f1d6cbbfb080ff8e23dd7f91;p=bacula%2Fbacula diff --git a/bacula/src/stored/autochanger.c b/bacula/src/stored/autochanger.c index 07596604de..653b6502ca 100644 --- a/bacula/src/stored/autochanger.c +++ b/bacula/src/stored/autochanger.c @@ -1,12 +1,12 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2002-2007 Free Software Foundation Europe e.V. + Copyright (C) 2002-2011 Free Software Foundation Europe e.V. The main author of Bacula is Kern Sibbald, with contributions from many others, a complete list can be found in the file AUTHORS. This program is Free Software; you can redistribute it and/or - modify it under the terms of version two of the GNU General Public + modify it under the terms of version three of the GNU Affero General Public License as published by the Free Software Foundation and included in the file LICENSE. @@ -15,12 +15,12 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Affero General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Bacula® is a registered trademark of John Walker. + Bacula® is a registered trademark of Kern Sibbald. The licensor of Bacula is the Free Software Foundation Europe (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, Switzerland, email:ftf@fsfeurope.org. @@ -31,7 +31,6 @@ * * Kern Sibbald, August MMII * - * Version $Id$ */ #include "bacula.h" /* pull in global headers */ @@ -118,16 +117,19 @@ int autoload_device(DCR *dcr, int writing, BSOCK *dir) POOLMEM *changer; if (!dev->is_autochanger()) { - Dmsg1(200, "Device %s is not an autochanger\n", dev->print_name()); + Dmsg1(100, "Device %s is not an autochanger\n", dev->print_name()); return 0; } /* An empty ChangerCommand => virtual disk autochanger */ if (dcr->device->changer_command && dcr->device->changer_command[0] == 0) { + Dmsg0(100, "ChangerCommand=0, virtual disk changer\n"); return 1; /* nothing to load */ } slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0; + Dmsg3(100, "autoload: slot=%d InChgr=%d Vol=%s\n", dcr->VolCatInfo.Slot, + dcr->VolCatInfo.InChanger, dcr->getVolCatName()); /* * Handle autoloaders here. If we cannot autoload it, we * will return 0 so that the sysop will be asked to load it. @@ -136,6 +138,7 @@ int autoload_device(DCR *dcr, int writing, BSOCK *dir) if (dir) { return 0; /* For user, bail out right now */ } + /* ***FIXME*** this really should not be here */ if (dir_find_next_appendable_volume(dcr)) { slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0; } else { @@ -146,17 +149,26 @@ int autoload_device(DCR *dcr, int writing, BSOCK *dir) changer = get_pool_memory(PM_FNAME); if (slot <= 0) { - Jmsg(jcr, M_INFO, 0, _("Invalid slot=%d defined in catalog for Volume \"%s\" " - "on %s. Manual load may be required.\n"), slot, dcr->VolCatInfo.VolCatName, - dev->print_name()); + /* Suppress info when polling */ + if (!dev->poll) { + Jmsg(jcr, M_INFO, 0, _("No slot defined in catalog (slot=%d) for Volume \"%s\" on %s.\n"), + slot, dcr->getVolCatName(), dev->print_name()); + Jmsg(jcr, M_INFO, 0, _("Cartridge change or \"update slots\" may be required.\n")); + } rtn_stat = 0; } else if (!dcr->device->changer_name) { - Jmsg(jcr, M_INFO, 0, _("No \"Changer Device\" for %s. Manual load of Volume may be required.\n"), - dev->print_name()); + /* Suppress info when polling */ + if (!dev->poll) { + Jmsg(jcr, M_INFO, 0, _("No \"Changer Device\" for %s. Manual load of Volume may be required.\n"), + dev->print_name()); + } rtn_stat = 0; } else if (!dcr->device->changer_command) { - Jmsg(jcr, M_INFO, 0, _("No \"Changer Command\" for %s. Manual load of Volume may be requird.\n"), - dev->print_name()); + /* Suppress info when polling */ + if (!dev->poll) { + Jmsg(jcr, M_INFO, 0, _("No \"Changer Command\" for %s. Manual load of Volume may be requird.\n"), + dev->print_name()); + } rtn_stat = 0; } else { /* Attempt to load the Volume */ @@ -183,7 +195,7 @@ int autoload_device(DCR *dcr, int writing, BSOCK *dir) * Load the desired cassette */ lock_changer(dcr); - Dmsg1(100, "Doing changer load slot %d\n", slot); + Dmsg2(100, "Doing changer load slot %d %s\n", slot, dev->print_name()); Jmsg(jcr, M_INFO, 0, _("3304 Issuing autochanger \"load slot %d, drive %d\" command.\n"), slot, drive); @@ -196,7 +208,7 @@ int autoload_device(DCR *dcr, int writing, BSOCK *dir) Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"), slot, drive); Dmsg2(100, "load slot %d, drive %d, status is OK.\n", slot, drive); - dev->Slot = slot; /* set currently loaded slot */ + dev->set_slot(slot); /* set currently loaded slot */ } else { berrno be; be.set_errno(status); @@ -206,13 +218,13 @@ int autoload_device(DCR *dcr, int writing, BSOCK *dir) "ERR=%s.\nResults=%s\n"), slot, drive, be.bstrerror(), results.c_str()); rtn_stat = -1; /* hard error */ - dev->Slot = -1; /* mark unknown */ + dev->set_slot(-1); /* mark unknown */ } Dmsg2(100, "load slot %d status=%d\n", slot, status); unlock_changer(dcr); } else { status = 0; /* we got what we want */ - dev->Slot = slot; /* set currently loaded slot */ + dev->set_slot(slot); /* set currently loaded slot */ } Dmsg1(100, "After changer, status=%d\n", status); if (status == 0) { /* did we succeed? */ @@ -248,12 +260,13 @@ int get_autochanger_loaded_slot(DCR *dcr) return -1; } if (!dcr->device->changer_command) { - Jmsg(jcr, M_FATAL, 0, _("3992 Missing Changer command.\n")); +// Jmsg(jcr, M_FATAL, 0, _("3992 Missing Changer command.\n")); return -1; } - if (dev->Slot > 0) { - return dev->Slot; + if (dev->get_slot() > 0) { + return dev->get_slot(); } + /* Virtual disk autochanger */ if (dcr->device->changer_command[0] == 0) { return 1; @@ -262,8 +275,11 @@ int get_autochanger_loaded_slot(DCR *dcr) /* Find out what is loaded, zero means device is unloaded */ changer = get_pool_memory(PM_FNAME); lock_changer(dcr); - Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded? drive %d\" command.\n"), - drive); + /* Suppress info when polling */ + if (!dev->poll) { + Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded? drive %d\" command.\n"), + drive); + } changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded"); Dmsg1(100, "Run program=%s\n", changer); status = run_program_full_output(changer, timeout, results.addr()); @@ -271,13 +287,23 @@ int get_autochanger_loaded_slot(DCR *dcr) if (status == 0) { loaded = str_to_int32(results.c_str()); if (loaded > 0) { - Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result is Slot %d.\n"), - drive, loaded); - dev->Slot = loaded; + /* Suppress info when polling */ + if (!dev->poll) { + Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result is Slot %d.\n"), + drive, loaded); + } + dev->set_slot(loaded); } else { - Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result: nothing loaded.\n"), - drive); - dev->Slot = -1; /* unknown */ + /* Suppress info when polling */ + if (!dev->poll) { + Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result: nothing loaded.\n"), + drive); + } + if (loaded == 0) { /* no slot loaded */ + dev->set_slot(0); + } else { /* probably some error */ + dev->clear_slot(); /* unknown */ + } } } else { berrno be; @@ -295,8 +321,13 @@ static void lock_changer(DCR *dcr) { AUTOCHANGER *changer_res = dcr->device->changer_res; if (changer_res) { + int errstat; Dmsg1(200, "Locking changer %s\n", changer_res->hdr.name); - P(changer_res->changer_mutex); /* Lock changer script */ + if ((errstat=rwl_writelock(&changer_res->changer_lock)) != 0) { + berrno be; + Jmsg(dcr->jcr, M_ERROR_TERM, 0, _("Lock failure on autochanger. ERR=%s\n"), + be.bstrerror(errstat)); + } } } @@ -304,8 +335,13 @@ static void unlock_changer(DCR *dcr) { AUTOCHANGER *changer_res = dcr->device->changer_res; if (changer_res) { + int errstat; Dmsg1(200, "Unlocking changer %s\n", changer_res->hdr.name); - V(changer_res->changer_mutex); /* Unlock changer script */ + if ((errstat=rwl_writeunlock(&changer_res->changer_lock)) != 0) { + berrno be; + Jmsg(dcr->jcr, M_ERROR_TERM, 0, _("Unlock failure on autochanger. ERR=%s\n"), + be.bstrerror(errstat)); + } } } @@ -334,9 +370,11 @@ bool unload_autochanger(DCR *dcr, int loaded) /* Virtual disk autochanger */ if (dcr->device->changer_command[0] == 0) { + dev->clear_unload(); return true; } + lock_changer(dcr); if (loaded < 0) { loaded = get_autochanger_loaded_slot(dcr); } @@ -344,7 +382,6 @@ bool unload_autochanger(DCR *dcr, int loaded) if (loaded > 0) { POOL_MEM results(PM_MESSAGE); POOLMEM *changer = get_pool_memory(PM_FNAME); - lock_changer(dcr); Jmsg(jcr, M_INFO, 0, _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"), loaded, dev->drive_index); @@ -363,13 +400,21 @@ bool unload_autochanger(DCR *dcr, int loaded) "ERR=%s\nResults=%s\n"), loaded, dev->drive_index, be.bstrerror(), results.c_str()); ok = false; - dev->Slot = -1; /* unknown */ + dev->clear_slot(); /* unknown */ } else { - dev->Slot = 0; /* nothing loaded */ + dev->set_slot(0); /* nothing loaded */ } - free_volume(dev); /* Free any volume associated with this drive */ + free_pool_memory(changer); - unlock_changer(dcr); + } + unlock_changer(dcr); + + if (loaded > 0) { /* free_volume outside from changer lock */ + free_volume(dev); /* Free any volume associated with this drive */ + } + + if (ok) { + dev->clear_unload(); } return ok; } @@ -380,14 +425,10 @@ bool unload_autochanger(DCR *dcr, int loaded) static bool unload_other_drive(DCR *dcr, int slot) { DEVICE *dev = NULL; - DEVICE *save_dev; - JCR *jcr = dcr->jcr; - int save_slot; - uint32_t timeout = dcr->device->max_changer_wait; - bool ok = true; + DEVICE *dev_save; + bool found = false; AUTOCHANGER *changer = dcr->dev->device->changer_res; DEVRES *device; - bool found = false; int retries = 0; /* wait for device retries */ if (!changer) { @@ -397,16 +438,35 @@ static bool unload_other_drive(DCR *dcr, int slot) return true; } + /* + * We look for the slot number corresponding to the tape + * we want in other drives, and if possible, unload + * it. + */ + Dmsg0(100, "Wiffle through devices looking for slot\n"); foreach_alist(device, changer->device) { - if (device->dev && device->dev->Slot == slot) { + dev = device->dev; + if (!dev) { + continue; + } + dev_save = dcr->dev; + dcr->dev = dev; + if (dev->get_slot() <= 0 && get_autochanger_loaded_slot(dcr) <= 0) { + dcr->dev = dev_save; + continue; + } + dcr->dev = dev_save; + if (dev->get_slot() == slot) { found = true; - dev = device->dev; break; } } if (!found) { + Dmsg1(100, "Slot=%d not found in another device\n", slot); return true; - } + } else { + Dmsg1(100, "Slot=%d found in another device\n", slot); + } /* The Volume we want is on another device. */ if (dev->is_busy()) { @@ -421,36 +481,68 @@ static bool unload_other_drive(DCR *dcr, int slot) } break; } - dev->dlock(); if (dev->is_busy()) { - Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" is in use by device %s\n"), - dcr->VolumeName, dev->print_name()); + Jmsg(dcr->jcr, M_WARNING, 0, _("Volume \"%s\" wanted on %s is in use by device %s\n"), + dcr->VolumeName, dcr->dev->print_name(), dev->print_name()); Dmsg4(100, "Vol %s for dev=%s is busy dev=%s slot=%d\n", - dcr->VolumeName, dcr->dev->print_name(), dev->print_name(), slot); - Dmsg2(100, "num_writ=%d reserv=%d\n", dev->num_writers, dev->reserved_device); - dev->dunlock(); + dcr->VolumeName, dcr->dev->print_name(), dev->print_name(), dev->get_slot()); + Dmsg2(100, "num_writ=%d reserv=%d\n", dev->num_writers, dev->num_reserved()); + volume_unused(dcr); + return false; + } + return unload_dev(dcr, dev); +} + +/* + * Unconditionally unload a specified drive + */ +bool unload_dev(DCR *dcr, DEVICE *dev) +{ + JCR *jcr = dcr->jcr; + bool ok = true; + uint32_t timeout = dcr->device->max_changer_wait; + AUTOCHANGER *changer = dcr->dev->device->changer_res; + DEVICE *save_dev; + int save_slot; + + if (!changer) { + return false; + } + + save_dev = dcr->dev; /* save dcr device */ + dcr->dev = dev; /* temporarily point dcr at other device */ + + /* Update slot if not set or not always_open */ + if (dev->get_slot() <= 0 || !dev->has_cap(CAP_ALWAYSOPEN)) { + get_autochanger_loaded_slot(dcr); + } + + /* Fail if we have no slot to unload */ + if (dev->get_slot() <= 0) { + dcr->dev = save_dev; return false; } + + save_slot = dcr->VolCatInfo.Slot; + dcr->VolCatInfo.Slot = dev->get_slot(); + +// dev->dlock(); POOLMEM *changer_cmd = get_pool_memory(PM_FNAME); POOL_MEM results(PM_MESSAGE); lock_changer(dcr); Jmsg(jcr, M_INFO, 0, _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"), - slot, dev->drive_index); + dev->get_slot(), dev->drive_index); Dmsg2(100, "Issuing autochanger \"unload slot %d, drive %d\" command.\n", - slot, dev->drive_index); + dev->get_slot(), dev->drive_index); - save_dev = dcr->dev; - dcr->dev = dev; - save_slot = dcr->VolCatInfo.Slot; - dcr->VolCatInfo.Slot = slot; changer_cmd = edit_device_codes(dcr, changer_cmd, dcr->device->changer_command, "unload"); dev->close(); Dmsg2(200, "close dev=%s reserve=%d\n", dev->print_name(), - dev->reserved_device); + dev->num_reserved()); Dmsg1(100, "Run program=%s\n", changer_cmd); int stat = run_program_full_output(changer_cmd, timeout, results.addr()); dcr->VolCatInfo.Slot = save_slot; @@ -458,20 +550,25 @@ static bool unload_other_drive(DCR *dcr, int slot) if (stat != 0) { berrno be; be.set_errno(stat); - Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"), - slot, dev->drive_index, be.bstrerror()); + Jmsg(jcr, M_INFO, 0, _("3997 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"), + dev->get_slot(), dev->drive_index, be.bstrerror()); Dmsg3(100, "Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n", - slot, dev->drive_index, be.bstrerror()); + dev->get_slot(), dev->drive_index, be.bstrerror()); ok = false; - dev->Slot = -1; /* unknown */ + dev->clear_slot(); /* unknown */ } else { - dev->Slot = 0; /* nothing loaded */ - Dmsg0(100, "Slot unloaded\n"); + Dmsg2(100, "Slot %d unloaded %s\n", dev->get_slot(), dev->print_name()); + dev->set_slot(0); /* nothing loaded */ + } + if (ok) { + dev->clear_unload(); } - free_volume(dev); /* Free any volume associated with this drive */ unlock_changer(dcr); - dev->dunlock(); + +// dev->dunlock(); + + free_volume(dev); /* Free any volume associated with this drive */ free_pool_memory(changer_cmd); return ok; } @@ -490,7 +587,6 @@ bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd) POOLMEM *changer; BPIPE *bpipe; int len = sizeof_pool_memory(dir->msg) - 1; - bool ok = false; int stat; if (!dev->is_autochanger() || !dcr->device->changer_name || @@ -523,9 +619,9 @@ bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd) bpipe = open_bpipe(changer, timeout, "r"); if (!bpipe) { dir->fsend(_("3996 Open bpipe failed.\n")); - goto bail_out; + goto bail_out; /* TODO: check if we need to return false */ } - if (strcmp(cmd, "list") == 0) { + if (bstrcmp(cmd, "list") || bstrcmp(cmd, "listall")) { /* Get output from changer */ while (fgets(dir->msg, len, bpipe->rfd)) { dir->msglen = strlen(dir->msg); @@ -551,8 +647,6 @@ bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd) be.set_errno(stat); dir->fsend(_("Autochanger error: ERR=%s\n"), be.bstrerror()); } - bnet_sig(dir, BNET_EOD); - ok = true; bail_out: unlock_changer(dcr); @@ -619,7 +713,15 @@ char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd) str = dcr->jcr->Job; break; case 'v': - str = NPRT(dcr->VolumeName); + if (dcr->VolCatInfo.VolCatName[0]) { + str = dcr->VolCatInfo.VolCatName; + } else if (dcr->VolumeName[0]) { + str = dcr->VolumeName; + } else if (dcr->dev->vol && dcr->dev->vol->vol_name) { + str = dcr->dev->vol->vol_name; + } else { + str = dcr->dev->VolHdr.VolumeName; + } break; case 'f': str = NPRT(dcr->jcr->client_name);