src/stored/device.c
bool fixup_device_block_write_error(DCR *dcr, int retries)
{
   char PrevVolName[MAX_NAME_LENGTH];
   DEV_BLOCK *block = dcr->block;
   DEV_BLOCK *ameta_block = dcr->ameta_block;
   DEV_BLOCK *adata_block = dcr->adata_block;
   char b1[30], b2[30];
   time_t wait_time;
   char dt[MAX_TIME_LENGTH];
   JCR *jcr = dcr->jcr;
   DEVICE *dev;
   int blocked;              /* save any previous blocked status */
   bool ok = false;
   bool save_adata = dcr->dev->adata;

   Enter(100);
   if (save_adata) {
      dcr->set_ameta();      /* switch to working with ameta */
   }
   dev = dcr->dev;
   blocked = dev->blocked();

   wait_time = time(NULL);

   /*
    * If we are blocked at entry, unblock it, and set our own block status
    */
   if (blocked != BST_NOT_BLOCKED) {
      unblock_device(dev);
   }
   block_device(dev, BST_DOING_ACQUIRE);

   /* Continue unlocked, but leave BLOCKED */
   dev->Unlock();

   bstrncpy(PrevVolName, dev->getVolCatName(), sizeof(PrevVolName));
   bstrncpy(dev->VolHdr.PrevVolumeName, PrevVolName, sizeof(dev->VolHdr.PrevVolumeName));

   /* create temporary block, that will be released at the end, current blocks
    * have been saved in local DEV_BLOCK above and will be restored before to
    * leave the function
    */
   dev->new_dcr_blocks(dcr);

   /* Inform User about end of medium */
   Jmsg(jcr, M_INFO, 0, _("End of medium on Volume \"%s\" Bytes=%s Blocks=%s at %s.\n"),
        PrevVolName, edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, b1),
        edit_uint64_with_commas(dev->VolCatInfo.VolCatBlocks, b2),
        bstrftime(dt, sizeof(dt), time(NULL)));

   Dmsg1(150, "set_unload dev=%s\n", dev->print_name());
   dev->set_unload();

   /* Clear DCR Start/End Block/File positions */
   dcr->VolFirstIndex = dcr->VolLastIndex = 0;
   dcr->StartAddr = dcr->EndAddr = 0;
   dcr->VolMediaId = 0;
   dcr->WroteVol = false;

   if (!dcr->mount_next_write_volume()) {
      dev->free_dcr_blocks(dcr);
      dcr->block = block;
      dcr->ameta_block = ameta_block;
      dcr->adata_block = adata_block;
      dev->Lock();
      goto bail_out;
   }
   Dmsg2(150, "must_unload=%d dev=%s\n", dev->must_unload(), dev->print_name());

   dev->notify_newvol_in_attached_dcrs(dcr->VolumeName);
   dev->Lock();                    /* lock again */

   dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs on vol */
   if (!dir_update_volume_info(dcr, false, false)) { /* send Volume info to Director */
      goto bail_out;
   }

   Jmsg(jcr, M_INFO, 0, _("New volume \"%s\" mounted on device %s at %s.\n"),
      dcr->VolumeName, dev->print_name(), bstrftime(dt, sizeof(dt), time(NULL)));

   /*
    * If this is a new tape, the label_blk will contain the
    *  label, so write it now. If this is a previously
    *  used tape, mount_next_write_volume() will return an
    *  empty label_blk, and nothing will be written.
    */
   Dmsg0(190, "write label block to dev\n");
   if (!dcr->write_block_to_dev()) {
      berrno be;
      Pmsg1(0, _("write_block_to_device Volume label failed. ERR=%s"),
        be.bstrerror(dev->dev_errno));
      dev->free_dcr_blocks(dcr);
      dcr->block = block;
      dcr->ameta_block = ameta_block;
      dcr->adata_block = adata_block;
      goto bail_out;
   }
   dev->free_dcr_blocks(dcr);
   dcr->block = block;
   dcr->ameta_block = ameta_block;
   dcr->adata_block = adata_block;

   /* Clear NewVol now because dir_get_volume_info() already done */
   jcr->dcr->NewVol = false;
   set_new_volume_parameters(dcr);

   jcr->run_time += time(NULL) - wait_time; /* correct run time for mount wait */

   /* Write overflow block to device */
   Dmsg0(190, "Write overflow block to dev\n");
   if (save_adata) {
      dcr->set_adata();      /* try to write block we entered with */
   }
   if (!dcr->write_block_to_dev()) {
      berrno be;
      Dmsg1(0, _("write_block_to_device overflow block failed. ERR=%s"),
        be.bstrerror(dev->dev_errno));
      /* Note: recursive call */
      if (retries-- <= 0 || !fixup_device_block_write_error(dcr, retries)) {
         Jmsg2(jcr, M_FATAL, 0,
              _("Catastrophic error. Cannot write overflow block to device %s. ERR=%s"),
              dev->print_name(), be.bstrerror(dev->dev_errno));
         goto bail_out;
      }
   }
   ok = true;

bail_out:
   if (save_adata) {
      dcr->set_ameta();   /* Do unblock ... on ameta */
   }
   /*
    * At this point, the device is locked and blocked.
    * Unblock the device, restore any entry blocked condition, then
    *   return leaving the device locked (as it was on entry).
    */
   unblock_device(dev);
   if (blocked != BST_NOT_BLOCKED) {
      block_device(dev, blocked);
   }
   if (save_adata) {
      dcr->set_adata();      /* switch back to what we entered with */
   }
   return ok;                               /* device locked */
}
/*
 * This is the dreaded moment. We either have an end of
 * medium condition or worse, and error condition.
 * Attempt to "recover" by obtaining a new Volume.
 *
 * Here are a few things to know:
 *  dcr->VolCatInfo contains the info on the "current" tape for this job.
 *  dev->VolCatInfo contains the info on the tape in the drive.
 *    The tape in the drive could have changed several times since
 *    the last time the job used it (jcr->VolCatInfo).
 *  dcr->VolumeName is the name of the current/desired tape in the drive.
 *
 * We enter with device locked, and
 *     exit with device locked.
 *
 * Note, we are called only from one place in block.c for the daemons.
 *     The btape utility calls it from btape.c.
 *
 *  Returns: true  on success
 *           false on failure
 */
This is the dreaded moment. We either have an end of
medium condition or worse, and error condition.
Attempt to "recover" by obtaining a new Volume.

Here are a few things to know:
dcr->VolCatInfo contains the info on the "current" tape for this job.
dev->VolCatInfo contains the info on the tape in the drive.
The tape in the drive could have changed several times since
the last time the job used it (jcr->VolCatInfo).
dcr->VolumeName is the name of the current/desired tape in the drive.

We enter with device locked, and
exit with device locked.

Note, we are called only from one place in block.c for the daemons.
The btape utility calls it from btape.c.

true  on success
false on failure
This is the dreaded moment . We either have an end of medium condition or worse and error condition . Attempt to " recover " by obtaining a new Volume . Here are a few things to know : dcr - > VolCatInfo contains the info on the " current " tape for this job . dev - > VolCatInfo contains the info on the tape in the drive . The tape in the drive could have changed several times since the last time the job used it ( jcr - > VolCatInfo ) . dcr - > VolumeName is the name of the current / desired tape in the drive . We enter with device locked and exit with device locked . Note we are called only from one place in block . c for the daemons . The btape utility calls it from btape . c . true on success false on failure
bool fixup_device_block_write_error(DCR *dcr, int retries)
{
   char PrevVolName[MAX_NAME_LENGTH];
   DEV_BLOCK *block = dcr->block;
   DEV_BLOCK *ameta_block = dcr->ameta_block;
   DEV_BLOCK *adata_block = dcr->adata_block;
   char b1[30], b2[30];
   time_t wait_time;
   char dt[MAX_TIME_LENGTH];
   JCR *jcr = dcr->jcr;
   DEVICE *dev;
   int blocked;              
   bool ok = false;
   bool save_adata = dcr->dev->adata;
   Enter(100);
   if (save_adata) {
      dcr->set_ameta();      
   }
   dev = dcr->dev;
   blocked = dev->blocked();
   wait_time = time(NULL);
   if (blocked != BST_NOT_BLOCKED) {
      unblock_device(dev);
   }
   block_device(dev, BST_DOING_ACQUIRE);
   dev->Unlock();
   bstrncpy(PrevVolName, dev->getVolCatName(), sizeof(PrevVolName));
   bstrncpy(dev->VolHdr.PrevVolumeName, PrevVolName, sizeof(dev->VolHdr.PrevVolumeName));
   dev->new_dcr_blocks(dcr);
   Jmsg(jcr, M_INFO, 0, _("End of medium on Volume \"%s\" Bytes=%s Blocks=%s at %s.\n"),
        PrevVolName, edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, b1),
        edit_uint64_with_commas(dev->VolCatInfo.VolCatBlocks, b2),
        bstrftime(dt, sizeof(dt), time(NULL)));
   Dmsg1(150, "set_unload dev=%s\n", dev->print_name());
   dev->set_unload();
   dcr->VolFirstIndex = dcr->VolLastIndex = 0;
   dcr->StartAddr = dcr->EndAddr = 0;
   dcr->VolMediaId = 0;
   dcr->WroteVol = false;
   if (!dcr->mount_next_write_volume()) {
      dev->free_dcr_blocks(dcr);
      dcr->block = block;
      dcr->ameta_block = ameta_block;
      dcr->adata_block = adata_block;
      dev->Lock();
      goto bail_out;
   }
   Dmsg2(150, "must_unload=%d dev=%s\n", dev->must_unload(), dev->print_name());
   dev->notify_newvol_in_attached_dcrs(dcr->VolumeName);
   dev->Lock();                    
   dev->VolCatInfo.VolCatJobs++;              
   if (!dir_update_volume_info(dcr, false, false)) { 
      goto bail_out;
   }
   Jmsg(jcr, M_INFO, 0, _("New volume \"%s\" mounted on device %s at %s.\n"),
      dcr->VolumeName, dev->print_name(), bstrftime(dt, sizeof(dt), time(NULL)));
   Dmsg0(190, "write label block to dev\n");
   if (!dcr->write_block_to_dev()) {
      berrno be;
      Pmsg1(0, _("write_block_to_device Volume label failed. ERR=%s"),
        be.bstrerror(dev->dev_errno));
      dev->free_dcr_blocks(dcr);
      dcr->block = block;
      dcr->ameta_block = ameta_block;
      dcr->adata_block = adata_block;
      goto bail_out;
   }
   dev->free_dcr_blocks(dcr);
   dcr->block = block;
   dcr->ameta_block = ameta_block;
   dcr->adata_block = adata_block;
   jcr->dcr->NewVol = false;
   set_new_volume_parameters(dcr);
   jcr->run_time += time(NULL) - wait_time; 
   Dmsg0(190, "Write overflow block to dev\n");
   if (save_adata) {
      dcr->set_adata();      
   }
   if (!dcr->write_block_to_dev()) {
      berrno be;
      Dmsg1(0, _("write_block_to_device overflow block failed. ERR=%s"),
        be.bstrerror(dev->dev_errno));
      if (retries-- <= 0 || !fixup_device_block_write_error(dcr, retries)) {
         Jmsg2(jcr, M_FATAL, 0,
              _("Catastrophic error. Cannot write overflow block to device %s. ERR=%s"),
              dev->print_name(), be.bstrerror(dev->dev_errno));
         goto bail_out;
      }
   }
   ok = true;
bail_out:
   if (save_adata) {
      dcr->set_ameta();   
   }
   unblock_device(dev);
   if (blocked != BST_NOT_BLOCKED) {
      block_device(dev, blocked);
   }
   if (save_adata) {
      dcr->set_adata();      
   }
   return ok;                               
}
bool fixup_device_block_write_error ( DCR * dcr , int retries ) { char PrevVolName [ MAX_NAME_LENGTH ] ; DEV_BLOCK * block = dcr -> block ; DEV_BLOCK * ameta_block = dcr -> ameta_block ; DEV_BLOCK * adata_block = dcr -> adata_block ; char b1 [ 30 ] , b2 [ 30 ] ; time_t wait_time ; char dt [ MAX_TIME_LENGTH ] ; JCR * jcr = dcr -> jcr ; DEVICE * dev ; int blocked ; bool ok = false ; bool save_adata = dcr -> dev -> adata ; Enter ( 100 ) ; if ( save_adata ) { dcr -> set_ameta ( ) ; } dev = dcr -> dev ; blocked = dev -> blocked ( ) ; wait_time = time ( NULL ) ; if ( blocked != BST_NOT_BLOCKED ) { unblock_device ( dev ) ; } block_device ( dev , BST_DOING_ACQUIRE ) ; dev -> Unlock ( ) ; bstrncpy ( PrevVolName , dev -> getVolCatName ( ) , sizeof ( PrevVolName ) ) ; bstrncpy ( dev -> VolHdr . PrevVolumeName , PrevVolName , sizeof ( dev -> VolHdr . PrevVolumeName ) ) ; dev -> new_dcr_blocks ( dcr ) ; Jmsg ( jcr , M_INFO , 0 , _ ( " \" \" \n " ) , PrevVolName , edit_uint64_with_commas ( dev -> VolCatInfo . VolCatBytes , b1 ) , edit_uint64_with_commas ( dev -> VolCatInfo . VolCatBlocks , b2 ) , bstrftime ( dt , sizeof ( dt ) , time ( NULL ) ) ) ; Dmsg1 ( 150 , " \n " , dev -> print_name ( ) ) ; dev -> set_unload ( ) ; dcr -> VolFirstIndex = dcr -> VolLastIndex = 0 ; dcr -> StartAddr = dcr -> EndAddr = 0 ; dcr -> VolMediaId = 0 ; dcr -> WroteVol = false ; if ( ! dcr -> mount_next_write_volume ( ) ) { dev -> free_dcr_blocks ( dcr ) ; dcr -> block = block ; dcr -> ameta_block = ameta_block ; dcr -> adata_block = adata_block ; dev -> Lock ( ) ; goto bail_out ; } Dmsg2 ( 150 , " \n " , dev -> must_unload ( ) , dev -> print_name ( ) ) ; dev -> notify_newvol_in_attached_dcrs ( dcr -> VolumeName ) ; dev -> Lock ( ) ; dev -> VolCatInfo . VolCatJobs ++ ; if ( ! dir_update_volume_info ( dcr , false , false ) ) { goto bail_out ; } Jmsg ( jcr , M_INFO , 0 , _ ( " \" \" \n " ) , dcr -> VolumeName , dev -> print_name ( ) , bstrftime ( dt , sizeof ( dt ) , time ( NULL ) ) ) ; Dmsg0 ( 190 , " \n " ) ; if ( ! dcr -> write_block_to_dev ( ) ) { berrno be ; Pmsg1 ( 0 , _ ( " " ) , be . bstrerror ( dev -> dev_errno ) ) ; dev -> free_dcr_blocks ( dcr ) ; dcr -> block = block ; dcr -> ameta_block = ameta_block ; dcr -> adata_block = adata_block ; goto bail_out ; } dev -> free_dcr_blocks ( dcr ) ; dcr -> block = block ; dcr -> ameta_block = ameta_block ; dcr -> adata_block = adata_block ; jcr -> dcr -> NewVol = false ; set_new_volume_parameters ( dcr ) ; jcr -> run_time += time ( NULL ) - wait_time ; Dmsg0 ( 190 , " \n " ) ; if ( save_adata ) { dcr -> set_adata ( ) ; } if ( ! dcr -> write_block_to_dev ( ) ) { berrno be ; Dmsg1 ( 0 , _ ( " " ) , be . bstrerror ( dev -> dev_errno ) ) ; if ( retries -- <= 0 || ! fixup_device_block_write_error ( dcr , retries ) ) { Jmsg2 ( jcr , M_FATAL , 0 , _ ( " " ) , dev -> print_name ( ) , be . bstrerror ( dev -> dev_errno ) ) ; goto bail_out ; } } ok = true ; bail_out : if ( save_adata ) { dcr -> set_ameta ( ) ; } unblock_device ( dev ) ; if ( blocked != BST_NOT_BLOCKED ) { block_device ( dev , blocked ) ; } if ( save_adata ) { dcr -> set_adata ( ) ; } return ok ; }
This is the dreaded moment.
This is the dreaded moment .
/* save any previous blocked status */ /* switch to working with ameta */ /*
    * If we are blocked at entry, unblock it, and set our own block status
    */ /* Continue unlocked, but leave BLOCKED */ /* create temporary block, that will be released at the end, current blocks
    * have been saved in local DEV_BLOCK above and will be restored before to
    * leave the function
    */ /* Inform User about end of medium */ /* Clear DCR Start/End Block/File positions */ /* lock again */ /* increment number of jobs on vol */ /* send Volume info to Director */ /*
    * If this is a new tape, the label_blk will contain the
    *  label, so write it now. If this is a previously
    *  used tape, mount_next_write_volume() will return an
    *  empty label_blk, and nothing will be written.
    */ /* Clear NewVol now because dir_get_volume_info() already done */ /* correct run time for mount wait */ /* Write overflow block to device */ /* try to write block we entered with */ /* Note: recursive call */ /* Do unblock ... on ameta */ /*
    * At this point, the device is locked and blocked.
    * Unblock the device, restore any entry blocked condition, then
    *   return leaving the device locked (as it was on entry).
    */ /* switch back to what we entered with */ /* device locked */