]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/dvd.c
dvd.c:dvd_write_part: Increase timeout when writing the first part (see the code...
[bacula/bacula] / bacula / src / stored / dvd.c
index 21f1d992bb6e63455e8cdaf27c9ac7fab9c32ce0..578cbaaaf8b664a03f22862d9ad202719638a0b9 100644 (file)
@@ -182,15 +182,21 @@ static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout)
                   dev->device->mount_point, dev->print_name());
             break;
          }
-         count++;
+         if ((strcmp(result->d_name, ".")) && (strcmp(result->d_name, "..")) && (strcmp(result->d_name, ".keep"))) {
+            count++; /* result->d_name != ., .. or .keep (Gentoo-specific) */
+         }
+         else {
+            Dmsg2(129, "open_mounted_dev: ignoring %s in %s\n", 
+                  result->d_name, dev->device->mount_point);
+         }
       }
       free(entry);
       closedir(dp);
       
-      Dmsg1(29, "open_mounted_dev: got %d files in the mount point\n", count);
+      Dmsg1(29, "open_mounted_dev: got %d files in the mount point (not counting ., .. and .keep)\n", count);
       
-      if (count > 2) {
-         mount = 1;                      /* If we got more than . and .. */
+      if (count > 0) {
+         mount = 1;                      /* If we got more than ., .. and .keep */
          break;                          /*   there must be something mounted */
       }
 get_out:
@@ -203,7 +209,7 @@ get_out:
    
    dev->set_mounted(mount);              /* set/clear mounted flag */
    free_pool_memory(results);
-   /* Do not check free space when unmounting (otherwise it will mount it again) */
+   /* Do not check free space when unmounting */
    if (mount) {
       update_free_space_dev(dev);
    }
@@ -298,7 +304,35 @@ void update_free_space_dev(DEVICE* dev)
 bool dvd_write_part(DCR *dcr) 
 {
    DEVICE *dev = dcr->dev;
+   POOL_MEM archive_name(PM_FNAME);
+   
+   /* Don't write empty part files.
+    * This is only useful when growisofs does not support write beyond
+    * the 4GB boundary.
+    * Example :
+    *   - 3.9 GB on the volume, dvd-freespace reports 0.4 GB free
+    *   - Write 0.2 GB on the volume, Bacula thinks it could still
+    *     append data, it creates a new empty part.
+    *   - dvd-freespace reports 0 GB free, as the 4GB boundary has
+    *     been crossed
+    *   - Bacula thinks he must finish to write to the device, so it
+    *     tries to write the last part (0-byte), but dvd-writepart fails...
+    *
+    * There is one exception: when recycling a volume, we write a blank part
+    * file, so, then, we need to accept to write it.
+    */
+   if ((dev->part_size == 0) && (dev->part > 0)) {
+      Dmsg2(29, "dvd_write_part: device is %s, won't write blank part %d\n", dev->print_name(), dev->part);
+      /* Delete spool file */
+      make_spooled_dvd_filename(dev, archive_name);
+      unlink(archive_name.c_str());
+      Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
+      sm_check(__FILE__, __LINE__, false);
+      return true;
+   }
+   
    POOL_MEM ocmd(PM_FNAME);
+   POOL_MEM results(PM_MESSAGE);
    char* icmd;
    int status;
    int timeout;
@@ -316,34 +350,43 @@ bool dvd_write_part(DCR *dcr)
     * I modified this for a longer timeout; pre-formatting, blanking and
     * writing can take quite a while
     */
-   timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024)*8);
+
+   /* Explanation of the timeout value, when writing the first part,
+    *  by Arno Lehmann :
+    * 9 GB, write speed 1x: 6990 seconds (almost 2 hours...)
+    * Overhead: 900 seconds (starting, initializing, finalizing,probably 
+    *   reloading 15 minutes)
+    * Sum: 15780.
+    * A reasonable last-exit timeout would be 16000 seconds. Quite long - 
+    * almost 4.5 hours, but hopefully, that timeout will only ever be needed 
+    * in case of a serious emergency.
+    */
+
+   if (dev->part == 0)
+      timeout = 16000;
+   else
+      timeout = dev->max_open_wait + (dev->part_size/(1350*1024/4));
 
    Dmsg2(29, "dvd_write_part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
       
-   {
-      POOL_MEM results(PM_MESSAGE);
-      sm_check(__FILE__, __LINE__, false);
-      status = run_program_full_output(ocmd.c_str(), timeout, results.c_str());
-      sm_check(__FILE__, __LINE__, false);
-      if (status != 0) {
-         Mmsg1(dev->errmsg, _("Error while writing current part to the DVD: %s"), 
-               results.c_str());
-         Dmsg1(000, "%s", dev->errmsg);
-         dev->dev_errno = EIO;
-         mark_volume_in_error(dcr);
-         return false;
-      }
+   status = run_program_full_output(ocmd.c_str(), timeout, results.c_str());
+   if (status != 0) {
+      Mmsg1(dev->errmsg, _("Error while writing current part to the DVD: %s"), 
+            results.c_str());
+      Dmsg1(000, "%s", dev->errmsg);
+      dev->dev_errno = EIO;
+      mark_volume_in_error(dcr);
       sm_check(__FILE__, __LINE__, false);
+      return false;
+   } else {
+      dev->num_parts++;            /* there is now one more part on DVD */
    }
 
-   {
-      POOL_MEM archive_name(PM_FNAME);
-      /* Delete spool file */
-      make_spooled_dvd_filename(dev, archive_name);
-      unlink(archive_name.c_str());
-      Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
-      sm_check(__FILE__, __LINE__, false);
-   }
+   /* Delete spool file */
+   make_spooled_dvd_filename(dev, archive_name);
+   unlink(archive_name.c_str());
+   Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
+   sm_check(__FILE__, __LINE__, false);
    
    /* growisofs umounted the device, so remount it (it will update the free space) */
    dev->clear_mounted();
@@ -391,6 +434,7 @@ int dvd_open_next_part(DCR *dcr)
     */
    if (dev->is_dvd() && (dev->part >= dev->num_parts) && dev->can_append()) {
       if (!dvd_write_part(dcr)) {
+         Dmsg0(29, "Error in dvd_write part.\n");
          return -1;
       }
    }
@@ -423,8 +467,7 @@ int dvd_open_next_part(DCR *dcr)
          }
       }
 
-      Dmsg2(100, "Set npart=%d to part=%d\n", dev->num_parts, dev->part);
-      dev->num_parts = dev->part;
+      Dmsg2(100, "num_parts=%d part=%d\n", dev->num_parts, dev->part);
       dev->VolCatInfo.VolCatParts = dev->part;
       make_spooled_dvd_filename(dev, archive_name);   /* makes spool name */
       
@@ -441,6 +484,11 @@ int dvd_open_next_part(DCR *dcr)
          }
       }
    }
+   /* KES.  It seems to me that this if should not be
+    *  needed. If num_parts represents what is on the DVD
+    *  we should only need to change it when writing a part
+    *  to the DVD.
+    */
    if (dev->num_parts < dev->part) {
       Dmsg2(100, "Set npart=%d to part=%d\n", dev->num_parts, dev->part);
       dev->num_parts = dev->part;
@@ -470,8 +518,8 @@ int dvd_open_first_part(DCR *dcr, int mode)
 {
    DEVICE *dev = dcr->dev;
 
-   Dmsg4(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_parts=%d\n", dev->print_name(), 
-         dev->VolCatInfo.VolCatName, dev->openmode, dev->num_parts);
+   Dmsg5(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_parts=%d append=%d\n", dev->print_name(), 
+         dev->VolCatInfo.VolCatName, dev->openmode, dev->num_parts, dev->can_append());
 
    if (dev->fd >= 0) {
       close(dev->fd);
@@ -484,11 +532,16 @@ int dvd_open_first_part(DCR *dcr, int mode)
    
    Dmsg2(50, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName, 
          mode);
+   int append = dev->can_append();
    if (dev->open(dcr, mode) < 0) {
       Dmsg0(50, "open dev() failed\n");
       return -1;
    }
-   Dmsg1(50, "Leave open_first_part state=%s\n", dev->is_open()?"open":"not open");
+   if (append && (dev->part == dev->num_parts)) { /* If needed, set the append flag back */
+      dev->set_append();
+   }
+   Dmsg2(50, "Leave open_first_part state=%s append=%d\n", dev->is_open()?"open":"not open", dev->can_append());
+   
    return dev->fd;
 }
 
@@ -692,6 +745,11 @@ bool truncate_dvd_dev(DCR *dcr) {
       return false;
    }
    
+   /* Set num_parts to zero (on disk) */
+   dev->num_parts = 0;
+   dcr->VolCatInfo.VolCatParts = 0;
+   dev->VolCatInfo.VolCatParts = 0;
+   
    if (dvd_open_first_part(dcr, OPEN_READ_WRITE) < 0) {
       Dmsg0(100, "truncate_dvd_dev: Error while opening first part (2).\n");
       return false;
@@ -716,7 +774,7 @@ bool check_can_write_on_non_blank_dvd(DCR *dcr) {
    if (name_max < 1024) {
       name_max = 1024;
    }
-         
+   
    if (!(dp = opendir(dev->device->mount_point))) {
       berrno be;
       dev->dev_errno = errno;