From: Kern Sibbald Date: Tue, 15 Feb 2005 22:04:34 +0000 (+0000) Subject: - Fix Media LabelDate and FirstWritten to be correctly set. X-Git-Tag: Release-1.38.0~643 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=31324722fa6a602c0f97fe47deb3ed2b69dead4b;p=bacula%2Fbacula - Fix Media LabelDate and FirstWritten to be correctly set. - Fix deadlock in multiple simultaneous jobs. - Fix tape truncation/number of files after restore bug. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1826 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/kernstodo b/bacula/kernstodo index dade3954dd..f5c584c413 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -30,6 +30,16 @@ Suggestions for Preben: - Optimized bootstrap. For 1.37: +- Windows restore: + data-fd: RestoreFiles.2004-12-07_15.56.42 Error: + > ..\findlib\../../findlib/create_file.c:275 Could not open e:/: ERR=Der + > Prozess kann nicht auf die Datei zugreifen, da sie von einem anderen + > Prozess verwendet wird. + Restore restores all files, but then fails at the end. +- Add better documentation on how restores can be done + from failed jobs. +- Resolve the problem between Device name and Archive name, + and fix SD messages. - Make sure SD deletes spool files on error exit. - Delete old spool files when SD starts. - When Python creates a new label, the tape is immediately diff --git a/bacula/patches/1.36.1-truncate.patch b/bacula/patches/1.36.1-truncate.patch new file mode 100644 index 0000000000..a66a1e5a12 --- /dev/null +++ b/bacula/patches/1.36.1-truncate.patch @@ -0,0 +1,24 @@ + + This patch fixes a bug where a tape gets "truncated" after + doing a restore. The number of files in the catalog do not + agree with what Bacula thinks is on tape, then the tape is + marked in error. + Apply this patch to version 1.36.1 with: + + cd + patch -p0 <1.36.1-truncate.patch + make + ... + + +--- src/stored/read_record.c.orig 2004-09-29 21:11:17.000000000 +0200 ++++ src/stored/read_record.c 2005-02-15 13:22:12.723140229 +0100 +@@ -266,7 +266,7 @@ + Dmsg2(300, "Current postion (file:block) %d:%d\n", + dev->file, dev->block_num); + jcr->bsr->mount_next_volume = false; +- dev->state |= ST_EOT; ++// dev->state |= ST_EOT; + rec->Block = 0; + return 1; + } diff --git a/bacula/patches/patches-1.36.1 b/bacula/patches/patches-1.36.1 index d339716528..1a41d7c87f 100644 --- a/bacula/patches/patches-1.36.1 +++ b/bacula/patches/patches-1.36.1 @@ -32,3 +32,9 @@ in the incorrect name being used for the check. This could lead to security problems with unwanted access by restricted consoles. + +15Feb05 1.36.1-truncate.patch + This patch fixes a bug where a tape gets "truncated" after + doing a restore. The number of files in the catalog do not + agree with what Bacula thinks is on tape, then the tape is + marked in error. diff --git a/bacula/src/cats/cats.h b/bacula/src/cats/cats.h index a912098ce6..bcbffd5276 100644 --- a/bacula/src/cats/cats.h +++ b/bacula/src/cats/cats.h @@ -728,7 +728,9 @@ struct MEDIA_DBR { */ char cFirstWritten[MAX_TIME_LENGTH]; /* FirstWritten returned from DB */ char cLastWritten[MAX_TIME_LENGTH]; /* LastWritten returned from DB */ - char cLabelData[MAX_TIME_LENGTH]; /* LabelData returned from DB */ + char cLabelDate[MAX_TIME_LENGTH]; /* LabelData returned from DB */ + bool set_first_written; + bool set_label_date; }; /* Client record -- same as the database */ diff --git a/bacula/src/cats/make_mysql_tables.in b/bacula/src/cats/make_mysql_tables.in index 425382102b..8877617421 100644 --- a/bacula/src/cats/make_mysql_tables.in +++ b/bacula/src/cats/make_mysql_tables.in @@ -45,6 +45,8 @@ CREATE TABLE File ( # INDEX (FilenameId), # INDEX (JobId, PathId, FilenameId) # +# Adding an index on JobId can speed up pruning +# CREATE TABLE Job ( JobId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, diff --git a/bacula/src/cats/sql_create.c b/bacula/src/cats/sql_create.c index 4dd809878a..1265d78a05 100644 --- a/bacula/src/cats/sql_create.c +++ b/bacula/src/cats/sql_create.c @@ -415,8 +415,11 @@ db_create_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) } else { mr->MediaId = sql_insert_id(mdb, _("Media")); stat = 1; - if (mr->LabelDate) { + if (mr->set_label_date) { char dt[MAX_TIME_LENGTH]; + if (mr->LabelDate == 0) { + mr->LabelDate = time(NULL); + } localtime_r(&mr->LabelDate, &tm); strftime(dt, sizeof(dt), "%Y-%m-%d %T", &tm); Mmsg(mdb->cmd, "UPDATE Media SET LabelDate='%s' " diff --git a/bacula/src/cats/sql_get.c b/bacula/src/cats/sql_get.c index 9d707d71b2..968ebd865d 100644 --- a/bacula/src/cats/sql_get.c +++ b/bacula/src/cats/sql_get.c @@ -835,7 +835,7 @@ int db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes," "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs," "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger," - "EndFile,EndBlock,VolParts,LabelType " + "EndFile,EndBlock,VolParts,LabelType,LabelDate " "FROM Media WHERE MediaId=%s", edit_int64(mr->MediaId, ed1)); } else { /* find by name */ @@ -843,7 +843,7 @@ int db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes," "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs," "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger," - "EndFile,EndBlock,VolParts,LabelType " + "EndFile,EndBlock,VolParts,LabelType,LabelDate " "FROM Media WHERE VolumeName='%s'", mr->VolumeName); } @@ -889,6 +889,8 @@ int db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) mr->EndBlock = str_to_uint64(row[24]); mr->VolParts = str_to_int64(row[25]); mr->LabelType = str_to_int64(row[26]); + bstrncpy(mr->cLabelDate, row[27]!=NULL?row[27]:"", sizeof(mr->cLabelDate)); + mr->LabelDate = (time_t)str_to_utime(mr->cLabelDate); stat = mr->MediaId; } } else { diff --git a/bacula/src/cats/sql_update.c b/bacula/src/cats/sql_update.c index 7557d5f759..f02578ff05 100644 --- a/bacula/src/cats/sql_update.c +++ b/bacula/src/cats/sql_update.c @@ -276,7 +276,7 @@ db_update_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) Dmsg1(100, "update_media: FirstWritten=%d\n", mr->FirstWritten); db_lock(mdb); - if (mr->VolJobs == 1) { + if (mr->set_first_written) { Dmsg1(400, "Set FirstWritten Vol=%s\n", mr->VolumeName); ttime = mr->FirstWritten; localtime_r(&ttime, &tm); @@ -284,11 +284,11 @@ db_update_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) Mmsg(mdb->cmd, "UPDATE Media SET FirstWritten='%s'" " WHERE VolumeName='%s'", dt, mr->VolumeName); stat = UPDATE_DB(jcr, mdb, mdb->cmd); - Dmsg1(400, "Firstwritten stat=%d\n", stat); + Dmsg1(400, "Firstwritten=%d\n", mr->FirstWritten); } /* Label just done? */ - if (mr->VolBytes == 1) { + if (mr->set_label_date) { ttime = mr->LabelDate; if (ttime == 0) { ttime = time(NULL); diff --git a/bacula/src/cats/update_mysql_tables.in b/bacula/src/cats/update_mysql_tables.in index 0ff6b4146d..d088d83469 100755 --- a/bacula/src/cats/update_mysql_tables.in +++ b/bacula/src/cats/update_mysql_tables.in @@ -17,7 +17,7 @@ ALTER TABLE Pool ADD COLUMN LabelType INTEGER UNSIGNED NOT NULL DEFAULT 0; ALTER TABLE Media ADD COLUMN VolParts INTEGER UNSIGNED NOT NULL DEFAULT 0; CREATE TABLE MediaType ( - MediaTypeId INTERGER UNSIGNED NOT NULL AUTO_INCREMENT, + MediaTypeId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, MediaType VARCHAR(128) NOT NULL, ReadOnly TINYINT DEFAULT 0, PRIMARY KEY(MediaTypeId) @@ -26,7 +26,7 @@ CREATE TABLE MediaType ( CREATE TABLE Device ( DeviceId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, Name VARCHAR(128) NOT NULL, - MediaTypeId INTEGER UNSIGNED REFERENCES MediaType NOT NULL, + MediaTypeId INTEGER UNSIGNED NOT NULL REFERENCES MediaType, StorageId INTEGER UNSIGNED REFERENCES Storage, DevMounts INTEGER UNSIGNED DEFAULT 0, DevReadBytes BIGINT UNSIGNED DEFAULT 0, diff --git a/bacula/src/dird/catreq.c b/bacula/src/dird/catreq.c index 21d759e6e4..a1eb4fc926 100644 --- a/bacula/src/dird/catreq.c +++ b/bacula/src/dird/catreq.c @@ -106,6 +106,14 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) * Request to find next appendable Volume for this Job */ Dmsg1(400, "catreq %s", bs->msg); + if (!jcr->db) { + omsg = get_memory(bs->msglen+1); + pm_strcpy(omsg, bs->msg); + bnet_fsend(bs, "1990 Invalid Catalog Request: %s", omsg); + Jmsg1(jcr, M_FATAL, 0, _("Invalid Catalog request; DB not open: %s"), omsg); + free_memory(omsg); + return; + } if (sscanf(bs->msg, Find_media, &Job, &index) == 2) { ok = find_next_volume_for_append(jcr, &mr, true /*permit create new vol*/); /* @@ -177,7 +185,6 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) bnet_fsend(bs, "1997 Volume \"%s\" not in catalog.\n", mr.VolumeName); } - /* * Request to update Media record. Comes typically at the end * of a Storage daemon Job Session, when labeling/relabeling a @@ -203,13 +210,15 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) return; } /* Set first written time if this is first job */ - if (mr.VolJobs == 0 || sdmr.VolJobs == 1) { + if (mr.FirstWritten == 0) { mr.FirstWritten = jcr->start_time; /* use Job start time as first write */ + mr.set_first_written = true; } /* If we just labeled the tape set time */ - Dmsg2(400, "label=%d labeldate=%d\n", label, mr.LabelDate); if (label || mr.LabelDate == 0) { - mr.LabelDate = time(NULL); + mr.LabelDate = jcr->start_time; + mr.set_label_date = true; + Dmsg2(400, "label=%d labeldate=%d\n", label, mr.LabelDate); } else { /* * Insanity check for VolFiles get set to a smaller value @@ -246,7 +255,7 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) } else if (db_update_media_record(jcr, jcr->db, &mr)) { send_volume_info_to_storage_daemon(jcr, bs, &mr); } else { - Jmsg(jcr, M_ERROR, 0, _("Catalog error updating Media record. %s"), + Jmsg(jcr, M_FATAL, 0, _("Catalog error updating Media record. %s"), db_strerror(jcr->db)); bnet_fsend(bs, "1992 Update Media error\n"); Dmsg0(400, "send error\n"); @@ -265,7 +274,7 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) Dmsg6(400, "create_jobmedia JobId=%d MediaId=%d SF=%d EF=%d FI=%d LI=%d\n", jm.JobId, jm.MediaId, jm.StartFile, jm.EndFile, jm.FirstIndex, jm.LastIndex); if (!db_create_jobmedia_record(jcr, jcr->db, &jm)) { - Jmsg(jcr, M_ERROR, 0, _("Catalog error creating JobMedia record. %s"), + Jmsg(jcr, M_FATAL, 0, _("Catalog error creating JobMedia record. %s"), db_strerror(jcr->db)); bnet_fsend(bs, "1991 Update JobMedia error\n"); } else { @@ -277,7 +286,7 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) omsg = get_memory(bs->msglen+1); pm_strcpy(omsg, bs->msg); bnet_fsend(bs, "1990 Invalid Catalog Request: %s", omsg); - Jmsg1(jcr, M_ERROR, 0, _("Invalid Catalog request: %s"), omsg); + Jmsg1(jcr, M_FATAL, 0, _("Invalid Catalog request: %s"), omsg); free_memory(omsg); } Dmsg1(400, ">CatReq response: %s", bs->msg); diff --git a/bacula/src/dird/jobq.c b/bacula/src/dird/jobq.c index eea66c004a..1a9954c8c3 100755 --- a/bacula/src/dird/jobq.c +++ b/bacula/src/dird/jobq.c @@ -437,12 +437,7 @@ void *jobq_server(void *arg) Dmsg1(2300, "Took jobid=%d from ready and appended to run\n", jcr->JobId); /* Release job queue lock */ - if ((stat = pthread_mutex_unlock(&jq->mutex)) != 0) { - berrno be; - Jmsg1(NULL, M_ERROR, 0, "pthread_mutex_unlock: ERR=%s\n", be.strerror(stat)); - jq->num_workers--; - return NULL; - } + V(jq->mutex); /* Call user's routine here */ Dmsg1(2300, "Calling user engine for jobid=%d\n", jcr->JobId); @@ -451,13 +446,7 @@ void *jobq_server(void *arg) Dmsg1(2300, "Back from user engine jobid=%d.\n", jcr->JobId); /* Reacquire job queue lock */ - if ((stat = pthread_mutex_lock(&jq->mutex)) != 0) { - berrno be; - Jmsg1(NULL, M_ERROR, 0, "pthread_mutex_lock: ERR=%s\n", be.strerror(stat)); - jq->num_workers--; - free(je); /* release job entry */ - return NULL; - } + P(jq->mutex); Dmsg0(200, "Done lock mutex after running job. Release locks.\n"); jq->running_jobs->remove(je); /* @@ -467,9 +456,6 @@ void *jobq_server(void *arg) */ if (jcr->acquired_resource_locks) { jcr->store->NumConcurrentJobs--; - if (jcr->JobType == JT_RESTORE || jcr->JobType == JT_VERIFY) { - jcr->store->MaxConcurrentJobs = jcr->saveMaxConcurrentJobs; - } jcr->client->NumConcurrentJobs--; jcr->job->NumConcurrentJobs--; } @@ -574,9 +560,7 @@ void *jobq_server(void *arg) if (jcr->JobType == JT_RESTORE || jcr->JobType == JT_VERIFY) { /* Let only one Restore/verify job run at a time regardless of MaxConcurrentJobs */ if (jcr->store->NumConcurrentJobs == 0) { - jcr->store->NumConcurrentJobs++; - jcr->saveMaxConcurrentJobs = jcr->store->MaxConcurrentJobs; - jcr->store->MaxConcurrentJobs = 1; + jcr->store->NumConcurrentJobs = 1; } else { set_jcr_job_status(jcr, JS_WaitStoreRes); je = jn; /* point to next waiting job */ @@ -609,6 +593,8 @@ void *jobq_server(void *arg) if (!skip_this_jcr) { jcr->store->NumConcurrentJobs++; } + } else { + skip_this_jcr = true; } if (skip_this_jcr) { set_jcr_job_status(jcr, JS_WaitStoreRes); @@ -621,9 +607,6 @@ void *jobq_server(void *arg) } else { /* Back out previous locks */ jcr->store->NumConcurrentJobs--; - if (jcr->JobType == JT_RESTORE || jcr->JobType == JT_VERIFY) { - jcr->store->MaxConcurrentJobs = jcr->saveMaxConcurrentJobs; - } set_jcr_job_status(jcr, JS_WaitClientRes); je = jn; /* point to next waiting job */ continue; @@ -633,9 +616,6 @@ void *jobq_server(void *arg) } else { /* Back out previous locks */ jcr->store->NumConcurrentJobs--; - if (jcr->JobType == JT_RESTORE || jcr->JobType == JT_VERIFY) { - jcr->store->MaxConcurrentJobs = jcr->saveMaxConcurrentJobs; - } jcr->client->NumConcurrentJobs--; set_jcr_job_status(jcr, JS_WaitJobRes); je = jn; /* Point to next waiting job */ diff --git a/bacula/src/dird/recycle.c b/bacula/src/dird/recycle.c index bb6c7987f9..a4e15bb906 100644 --- a/bacula/src/dird/recycle.c +++ b/bacula/src/dird/recycle.c @@ -119,5 +119,6 @@ int recycle_volume(JCR *jcr, MEDIA_DBR *mr) mr->VolJobs = mr->VolFiles = mr->VolBlocks = mr->VolErrors = 0; mr->VolBytes = 1; mr->FirstWritten = mr->LastWritten = 0; + mr->set_first_written = true; return db_update_media_record(jcr, jcr->db, mr); } diff --git a/bacula/src/dird/sql_cmds.c b/bacula/src/dird/sql_cmds.c index 0aa0720ecd..b33bbd24d1 100644 --- a/bacula/src/dird/sql_cmds.c +++ b/bacula/src/dird/sql_cmds.c @@ -359,7 +359,6 @@ const char *uar_jobids_fileindex = "ORDER BY Job.StartTime DESC LIMIT 1"; /* Query to get all files in a directory -- no recursing */ -// cleanup needed -- add client, ... const char *uar_jobid_fileindex_from_dir = "SELECT Job.JobId,File.FileIndex FROM Job,File,Path,Filename,Client " "WHERE Job.JobId IN (%s) " diff --git a/bacula/src/dird/ua_label.c b/bacula/src/dird/ua_label.c index f73e192b68..423678c933 100644 --- a/bacula/src/dird/ua_label.c +++ b/bacula/src/dird/ua_label.c @@ -621,6 +621,7 @@ static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr, unbash_spaces(mr->MediaType); unbash_spaces(pr->Name); mr->LabelDate = time(NULL); + mr->set_label_date = true; if (ok) { if (media_record_exists) { /* we update it */ mr->VolBytes = 1; diff --git a/bacula/src/stored/block.c b/bacula/src/stored/block.c index c1317da712..47efa0ff00 100644 --- a/bacula/src/stored/block.c +++ b/bacula/src/stored/block.c @@ -34,6 +34,8 @@ extern int debug_level; static bool terminate_writing_volume(DCR *dcr); +static bool do_new_file_bookkeeping(DCR *dcr); +static bool do_dvd_size_checks(DCR *dcr); /* * Dump the block header, then walk through @@ -477,99 +479,21 @@ bool write_block_to_dev(DCR *dcr) (dev->file_size+block->binbuf) >= dev->max_file_size) { dev->file_size = 0; /* reset file size */ - if (dev->is_tape() && weof_dev(dev, 1) != 0) { /* write eof */ + if (weof_dev(dev, 1) != 0) { /* write eof */ Dmsg0(190, "WEOF error in max file size.\n"); terminate_writing_volume(dcr); dev->dev_errno = ENOSPC; return false; } - /* Create a JobMedia record so restore can seek */ - if (!dir_create_jobmedia_record(dcr)) { - Dmsg0(190, "Error from create_job_media.\n"); - dev->dev_errno = EIO; - Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"), - dcr->VolCatInfo.VolCatName, jcr->Job); - terminate_writing_volume(dcr); - dev->dev_errno = EIO; - return false; - } - dev->VolCatInfo.VolCatFiles = dev->file; - if (!dir_update_volume_info(dcr, false)) { - Dmsg0(190, "Error from update_vol_info.\n"); - terminate_writing_volume(dcr); - dev->dev_errno = EIO; - return false; - } - Dmsg0(100, "dir_update_volume_info max file size -- OK\n"); - - - /* - * Walk through all attached dcrs setting flag to call - * set_new_file_parameters() when that dcr is next used. - */ - DCR *mdcr; - foreach_dlist(mdcr, dev->attached_dcrs) { - if (mdcr->jcr->JobId == 0) { - continue; - } - mdcr->NewFile = true; /* set reminder to do set_new_file_params */ - } - /* Set new file/block parameters for current dcr */ - set_new_file_parameters(dcr); - } - - /* Limit maximum part size to value specified by user (not applicable to tapes/fifos) */ - if (!(dev->state & (ST_TAPE|ST_FIFO)) && - (dev->max_part_size > 0) && - ((dev->part_size + block->binbuf) >= dev->max_part_size)) { - if (dev->part < dev->num_parts) { - Jmsg3(dcr->jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"), - dev->part, dev->num_parts, dev_name(dev)); - dev->dev_errno = EIO; - return false; - } - - if (open_next_part(dev) < 0) { - Jmsg2(dcr->jcr, M_FATAL, 0, _("Unable to open device next part %s. ERR=%s\n"), - dev_name(dev), strerror_dev(dev)); - dev->dev_errno = EIO; - return false; - } - - dev->VolCatInfo.VolCatParts = dev->num_parts; - - if (!dir_update_volume_info(dcr, false)) { - Dmsg0(190, "Error from update_vol_info.\n"); - dev->dev_errno = EIO; + if (!do_new_file_bookkeeping(dcr)) { return false; } } - if (dev->free_space_errno < 0) { /* Error while getting free space */ - char ed1[50], ed2[50]; - Dmsg1(10, "Cannot get free space on the device ERR=%s.\n", dev->errmsg); - Jmsg(jcr, M_FATAL, 0, _("End of Volume \"%s\" at %u:%u on device %s (part_size=%s, free_space=%s, free_space_errno=%d, errmsg=%s).\n"), - dev->VolCatInfo.VolCatName, - dev->file, dev->block_num, dev->dev_name, - edit_uint64_with_commas(dev->part_size, ed1), edit_uint64_with_commas(dev->free_space, ed2), - dev->free_space_errno, dev->errmsg); - dev->dev_errno = -dev->free_space_errno; + if (!do_dvd_size_checks(dcr)) { return false; } - - if (((dev->free_space_errno > 0) && ((dev->part_size + block->binbuf) >= dev->free_space))) { - char ed1[50], ed2[50]; - Dmsg0(10, "==== Just enough free space on the device to write the current part...\n"); - Jmsg(jcr, M_INFO, 0, _("End of Volume \"%s\" at %u:%u on device %s (part_size=%s, free_space=%s, free_space_errno=%d).\n"), - dev->VolCatInfo.VolCatName, - dev->file, dev->block_num, dev->dev_name, - edit_uint64_with_commas(dev->part_size, ed1), edit_uint64_with_commas(dev->free_space, ed2), - dev->free_space_errno); - terminate_writing_volume(dcr); - dev->dev_errno = ENOSPC; - return false; - } dev->VolCatInfo.VolCatWrites++; Dmsg1(300, "Write block of %u bytes\n", wlen); @@ -766,12 +690,118 @@ static bool terminate_writing_volume(DCR *dcr) Jmsg(dcr->jcr, M_ERROR, 0, "%s", dev->errmsg); } bail_out: - dev->state |= (ST_EOF|ST_EOT|ST_WEOT); - dev->state &= ~ST_APPEND; /* make tape read-only */ + dev->set_eot(); Dmsg1(100, "Leave terminate_writing_volume -- %s\n", ok?"OK":"ERROR"); return ok; } +/* + * Do bookkeeping when a new file is created on a Volume. This is + * also done for disk files to generate the jobmedia records for + * quick seeking. + */ +static bool do_new_file_bookkeeping(DCR *dcr) +{ + DEVICE *dev = dcr->dev; + JCR *jcr = dcr->jcr; + + /* Create a JobMedia record so restore can seek */ + if (!dir_create_jobmedia_record(dcr)) { + Dmsg0(190, "Error from create_job_media.\n"); + dev->dev_errno = EIO; + Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"), + dcr->VolCatInfo.VolCatName, jcr->Job); + terminate_writing_volume(dcr); + dev->dev_errno = EIO; + return false; + } + dev->VolCatInfo.VolCatFiles = dev->file; + if (!dir_update_volume_info(dcr, false)) { + Dmsg0(190, "Error from update_vol_info.\n"); + terminate_writing_volume(dcr); + dev->dev_errno = EIO; + return false; + } + Dmsg0(100, "dir_update_volume_info max file size -- OK\n"); + + /* + * Walk through all attached dcrs setting flag to call + * set_new_file_parameters() when that dcr is next used. + */ + DCR *mdcr; + foreach_dlist(mdcr, dev->attached_dcrs) { + if (mdcr->jcr->JobId == 0) { + continue; + } + mdcr->NewFile = true; /* set reminder to do set_new_file_params */ + } + /* Set new file/block parameters for current dcr */ + set_new_file_parameters(dcr); + return true; +} + +/* + * Do all checks for DVD sizes during writing. + */ +static bool do_dvd_size_checks(DCR *dcr) +{ + DEVICE *dev = dcr->dev; + JCR *jcr = dcr->jcr; + DEV_BLOCK *block = dcr->block; + + /* Limit maximum part size to value specified by user (not applicable to tapes/fifos) */ + if (!(dev->state & (ST_TAPE|ST_FIFO)) && dev->max_part_size > 0 && + (dev->part_size + block->binbuf) >= dev->max_part_size) { + if (dev->part < dev->num_parts) { + Jmsg3(dcr->jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"), + dev->part, dev->num_parts, dev_name(dev)); + dev->dev_errno = EIO; + return false; + } + + if (open_next_part(dev) < 0) { + Jmsg2(dcr->jcr, M_FATAL, 0, _("Unable to open device next part %s. ERR=%s\n"), + dev_name(dev), strerror_dev(dev)); + dev->dev_errno = EIO; + return false; + } + + dev->VolCatInfo.VolCatParts = dev->num_parts; + + if (!dir_update_volume_info(dcr, false)) { + Dmsg0(190, "Error from update_vol_info.\n"); + dev->dev_errno = EIO; + return false; + } + } + + if (dev->free_space_errno < 0) { /* Error while getting free space */ + char ed1[50], ed2[50]; + Dmsg1(10, "Cannot get free space on the device ERR=%s.\n", dev->errmsg); + Jmsg(jcr, M_FATAL, 0, _("End of Volume \"%s\" at %u:%u on device %s (part_size=%s, free_space=%s, free_space_errno=%d, errmsg=%s).\n"), + dev->VolCatInfo.VolCatName, + dev->file, dev->block_num, dev->dev_name, + edit_uint64_with_commas(dev->part_size, ed1), edit_uint64_with_commas(dev->free_space, ed2), + dev->free_space_errno, dev->errmsg); + dev->dev_errno = -dev->free_space_errno; + return false; + } + + if ((dev->free_space_errno > 0 && (dev->part_size + block->binbuf) >= dev->free_space)) { + char ed1[50], ed2[50]; + Dmsg0(10, "==== Just enough free space on the device to write the current part...\n"); + Jmsg(jcr, M_INFO, 0, _("End of Volume \"%s\" at %u:%u on device %s (part_size=%s, free_space=%s, free_space_errno=%d).\n"), + dev->VolCatInfo.VolCatName, + dev->file, dev->block_num, dev->dev_name, + edit_uint64_with_commas(dev->part_size, ed1), edit_uint64_with_commas(dev->free_space, ed2), + dev->free_space_errno); + terminate_writing_volume(dcr); + dev->dev_errno = ENOSPC; + return false; + } + return true; +} + /* * Read block with locking diff --git a/bacula/src/stored/bls.c b/bacula/src/stored/bls.c index 68474d9cb8..0711259833 100644 --- a/bacula/src/stored/bls.c +++ b/bacula/src/stored/bls.c @@ -257,7 +257,7 @@ static void do_blocks(char *infname) for ( ;; ) { if (!read_block_from_device(dcr, NO_BLOCK_NUMBER_CHECK)) { Dmsg1(100, "!read_block(): ERR=%s\n", dev->strerror()); - if (dev->at_eom()) { + if (dev->at_eot()) { if (!mount_next_read_volume(dcr)) { Jmsg(jcr, M_INFO, 0, _("Got EOM at file %u on device %s, Volume \"%s\"\n"), dev->file, dev_name(dev), dcr->VolumeName); diff --git a/bacula/src/stored/btape.c b/bacula/src/stored/btape.c index dad98ef739..c59f8dfef2 100644 --- a/bacula/src/stored/btape.c +++ b/bacula/src/stored/btape.c @@ -562,7 +562,7 @@ static void capcmd() printf("%sMALLOC ", dev->state & ST_MALLOC ? "" : "!"); printf("%sAPPEND ", dev->can_append() ? "" : "!"); printf("%sREAD ", dev->can_read() ? "" : "!"); - printf("%sEOT ", dev->at_eom() ? "" : "!"); + printf("%sEOT ", dev->at_eot() ? "" : "!"); printf("%sWEOT ", dev->state & ST_WEOT ? "" : "!"); printf("%sEOF ", dev->at_eof() ? "" : "!"); printf("%sNEXTVOL ", dev->state & ST_NEXTVOL ? "" : "!"); diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index 6397ba7451..32017d375c 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -458,7 +458,7 @@ open_dev(DEVICE *dev, char *VolName, int mode) } Dmsg4(29, "open_dev: disk fd=%d opened, part=%d/%d, part_size=%u\n", dev->fd, dev->part, dev->num_parts, dev->part_size); if (dev->is_dvd() && (dev->mode != OPEN_READ_ONLY) && - ((dev->free_space_errno == 0) || (dev->num_parts == dev->part))) { + (dev->free_space_errno == 0 || dev->num_parts == dev->part)) { update_free_space_dev(dev); } } @@ -1102,6 +1102,16 @@ void DEVICE::set_eof() block_num = 0; } +/* + * Called to indicate we are now at the end of the tape, and + * writing is not possible. + */ +void DEVICE::set_eot() +{ + state |= (ST_EOF|ST_EOT|ST_WEOT); + state &= ~ST_APPEND; /* make tape read-only */ +} + /* * Position device to end of medium (end of data) * Returns: 1 on succes diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index abf48beb3f..6c7fde3ff5 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -257,6 +257,7 @@ public: const char *strerror() const; const char *archive_name() const; void set_eof(); + void set_eot(); }; /* Note, these return int not bool! */ @@ -268,7 +269,6 @@ inline int DEVICE::is_open() const { return state & ST_OPENED; } inline int DEVICE::is_labeled() const { return state & ST_LABEL; } inline int DEVICE::is_busy() const { return state & ST_READ || num_writers; } inline int DEVICE::at_eof() const { return state & ST_EOF; } -inline int DEVICE::at_eom() const { return state & ST_EOT; } inline int DEVICE::at_eot() const { return state & ST_EOT; } inline int DEVICE::can_append() const { return state & ST_APPEND; } inline int DEVICE::can_read() const { return state & ST_READ; } diff --git a/bacula/src/stored/read_record.c b/bacula/src/stored/read_record.c index 4a4d91ef22..54d355c165 100644 --- a/bacula/src/stored/read_record.c +++ b/bacula/src/stored/read_record.c @@ -64,7 +64,7 @@ bool read_records(DCR *dcr, break; } if (!read_block_from_device(dcr, CHECK_BLOCK_NUMBERS)) { - if (dev_state(dev, ST_EOT)) { + if (dev->at_eot()) { DEV_RECORD *trec = new_record(); Jmsg(jcr, M_INFO, 0, "End of Volume at file %u on device %s, Volume \"%s\"\n", @@ -97,7 +97,7 @@ bool read_records(DCR *dcr, /* After reading label, we must read first data block */ continue; - } else if (dev_state(dev, ST_EOF)) { + } else if (dev->at_eof()) { if (verbose) { Jmsg(jcr, M_INFO, 0, "Got EOF at file %u on device %s, Volume \"%s\"\n", dev->file, dev_name(dev), dcr->VolumeName); @@ -259,7 +259,7 @@ static int try_repositioning(JCR *jcr, DEV_RECORD *rec, DEVICE *dev) Dmsg2(300, "Current postion (file:block) %d:%d\n", dev->file, dev->block_num); jcr->bsr->mount_next_volume = false; - dev->state |= ST_EOT; +// dev->state |= ST_EOT; rec->Block = 0; return 1; } diff --git a/bacula/src/stored/status.c b/bacula/src/stored/status.c index 875c32b8af..d09b93cf65 100644 --- a/bacula/src/stored/status.c +++ b/bacula/src/stored/status.c @@ -211,7 +211,7 @@ static void send_blocked_status(JCR *jcr, DEVICE *dev) bnet_fsend(user, "%sMALLOC ", dev->state & ST_MALLOC ? "" : "!"); bnet_fsend(user, "%sAPPEND ", dev->can_append() ? "" : "!"); bnet_fsend(user, "%sREAD ", dev->can_read() ? "" : "!"); - bnet_fsend(user, "%sEOT ", dev->at_eom() ? "" : "!"); + bnet_fsend(user, "%sEOT ", dev->at_eot() ? "" : "!"); bnet_fsend(user, "%sWEOT ", dev->state & ST_WEOT ? "" : "!"); bnet_fsend(user, "%sEOF ", dev->at_eof() ? "" : "!"); bnet_fsend(user, "%sNEXTVOL ", dev->state & ST_NEXTVOL ? "" : "!");