From d815f53d0563401a4a6c557ff4eb0c02f18e56ac Mon Sep 17 00:00:00 2001 From: Philipp Storz Date: Tue, 25 Feb 2014 10:19:16 +0100 Subject: [PATCH] Adds support for different blocksizes. Min- and maxblocksize are now a property of the pool and are promoted to tapes in that pool. Therefore, the media and pool database tables were adapted to hold min and maxblocksize. In order to be able to read the tape label always, the label is always read and written with the DEFAULT_BLOCK_SIZE = 63k/64512 bytes For backward compatibility, the blocksize DEFAULT_BLOCK_SIZE is used if the blocksize for the medium is zero in the database table. The device blocksizes are set to the values of the mounted volume after it was mounted, so all blocks being written after the label block are written with the blocksizes configured in the medium/pool. Moving a tape from one pool to another through the scratch pool mechanism is supported, as then the pool's properties are promoted to the medium. This new feature makes it possible to move from one blocksize to a new one during normal operation while being able to restore the old backups at any time. For disaster recovery (DR) using bscan etc. you need to set the blocksize used during write of the tape for restore. Fixes #267: make blocksize a property of the pool --- src/cats/cats.h | 4 ++ src/cats/sql_create.c | 17 ++--- src/cats/sql_find.c | 6 +- src/cats/sql_get.c | 13 ++-- src/cats/sql_update.c | 24 ++++--- src/dird/catreq.c | 4 +- src/dird/dird_conf.c | 4 ++ src/dird/dird_conf.h | 2 + src/dird/ua_cmds.c | 7 ++- src/dird/ua_label.c | 27 +++++--- src/lib/scan.c | 5 +- src/stored/acquire.c | 12 +++- src/stored/askdir.c | 33 ++++++---- src/stored/block.c | 16 +++-- src/stored/block.h | 4 +- src/stored/bscan.c | 2 +- src/stored/butil.c | 2 +- src/stored/dev.c | 131 +++++++++++++++++++++++++++++++++++++-- src/stored/dev.h | 17 ++++- src/stored/dir_cmd.c | 38 ++++++++---- src/stored/label.c | 54 ++++++++++++++-- src/stored/mount.c | 14 +++++ src/stored/protos.h | 2 +- src/stored/reserve.c | 6 +- src/stored/sd_plugins.c | 2 +- src/stored/spool.c | 2 +- src/stored/stored.c | 2 +- src/stored/stored.h | 1 + src/stored/stored_conf.c | 1 + src/stored/stored_conf.h | 5 +- 30 files changed, 366 insertions(+), 91 deletions(-) diff --git a/src/cats/cats.h b/src/cats/cats.h index cb77d4abc27..9f782ffb167 100644 --- a/src/cats/cats.h +++ b/src/cats/cats.h @@ -247,6 +247,8 @@ struct POOL_DBR { DBId_t ScratchPoolId; /* ScratchPool source when media is needed */ char PoolType[MAX_NAME_LENGTH]; char LabelFormat[MAX_NAME_LENGTH]; + uint32_t MinBlocksize; /* Minimum Block Size */ + uint32_t MaxBlocksize; /* Maximum Block Size */ /* Extra stuff not in DB */ faddr_t rec_addr; }; @@ -330,6 +332,8 @@ class MEDIA_DBR { uint32_t EndFile; /* Last file on volume */ uint32_t EndBlock; /* Last block on volume */ uint32_t RecycleCount; /* Number of times recycled */ + uint32_t MinBlocksize; /* Minimum Block Size */ + uint32_t MaxBlocksize; /* Maximum Block Size */ char VolStatus[20]; /* Volume status */ DBId_t DeviceId; /* Device where Vol last written */ DBId_t LocationId; /* Where Volume is -- user defined */ diff --git a/src/cats/sql_create.c b/src/cats/sql_create.c index fe0851334d6..ea211779e44 100644 --- a/src/cats/sql_create.c +++ b/src/cats/sql_create.c @@ -198,8 +198,8 @@ bool db_create_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr) "INSERT INTO Pool (Name,NumVols,MaxVols,UseOnce,UseCatalog," "AcceptAnyVolume,AutoPrune,Recycle,VolRetention,VolUseDuration," "MaxVolJobs,MaxVolFiles,MaxVolBytes,PoolType,LabelType,LabelFormat," -"RecyclePoolId,ScratchPoolId,ActionOnPurge) " -"VALUES ('%s',%u,%u,%d,%d,%d,%d,%d,%s,%s,%u,%u,%s,'%s',%d,'%s',%s,%s,%d)", +"RecyclePoolId,ScratchPoolId,ActionOnPurge,MinBlocksize,MaxBlocksize) " +"VALUES ('%s',%u,%u,%d,%d,%d,%d,%d,%s,%s,%u,%u,%s,'%s',%d,'%s',%s,%s,%d,%d,%d)", esc_name, pr->NumVols, pr->MaxVols, pr->UseOnce, pr->UseCatalog, @@ -212,8 +212,9 @@ bool db_create_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr) pr->PoolType, pr->LabelType, esc_lf, edit_int64(pr->RecyclePoolId,ed4), edit_int64(pr->ScratchPoolId,ed5), - pr->ActionOnPurge - ); + pr->ActionOnPurge, + pr->MinBlocksize, + pr->MaxBlocksize); Dmsg1(200, "Create Pool: %s\n", mdb->cmd); pr->PoolId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("Pool")); if (pr->PoolId == 0) { @@ -438,9 +439,10 @@ bool db_create_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) "VolCapacityBytes,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles," "VolStatus,Slot,VolBytes,InChanger,VolReadTime,VolWriteTime," "EndFile,EndBlock,LabelType,StorageId,DeviceId,LocationId," -"ScratchPoolId,RecyclePoolId,Enabled,ActionOnPurge,EncryptionKey)" +"ScratchPoolId,RecyclePoolId,Enabled,ActionOnPurge,EncryptionKey," +"MinBlocksize,MaxBlocksize) " "VALUES ('%s','%s',0,%u,%s,%s,%d,%s,%s,%u,%u,'%s',%d,%s,%d,%s,%s,0,0,%d,%s," -"%s,%s,%s,%s,%d,%d,'%s')", +"%s,%s,%s,%s,%d,%d,'%s',%d,%d)", esc_name, esc_mtype, mr->PoolId, edit_uint64(mr->MaxVolBytes,ed1), @@ -463,7 +465,8 @@ bool db_create_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) edit_int64(mr->ScratchPoolId, ed11), edit_int64(mr->RecyclePoolId, ed12), mr->Enabled, mr->ActionOnPurge, - mr->EncrKey); + mr->EncrKey, mr->MinBlocksize, + mr->MaxBlocksize); Dmsg1(500, "Create Volume: %s\n", mdb->cmd); mr->MediaId = sql_insert_autokey_record(mdb, mdb->cmd, NT_("Media")); diff --git a/src/cats/sql_find.c b/src/cats/sql_find.c index b48e4f46af4..0f6a75a7b6f 100644 --- a/src/cats/sql_find.c +++ b/src/cats/sql_find.c @@ -337,7 +337,7 @@ int db_find_next_volume(JCR *jcr, B_DB *mdb, int item, bool InChanger, MEDIA_DBR "EndFile,EndBlock,LabelType,LabelDate,StorageId," "Enabled,LocationId,RecycleCount,InitialWrite," "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime," - "ActionOnPurge,EncryptionKey " + "ActionOnPurge,EncryptionKey,MinBlocksize,MaxBlocksize " "FROM Media WHERE PoolId=%s AND MediaType='%s' AND VolStatus IN ('Full'," "'Recycle','Purged','Used','Append') AND Enabled=1 " "ORDER BY LastWritten LIMIT 1", @@ -363,7 +363,7 @@ int db_find_next_volume(JCR *jcr, B_DB *mdb, int item, bool InChanger, MEDIA_DBR "EndFile,EndBlock,LabelType,LabelDate,StorageId," "Enabled,LocationId,RecycleCount,InitialWrite," "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime," - "ActionOnPurge,EncryptionKey " + "ActionOnPurge,EncryptionKey,MinBlocksize,MaxBlocksize " "FROM Media WHERE PoolId=%s AND MediaType='%s' AND Enabled=1 " "AND VolStatus='%s' " "%s " @@ -443,6 +443,8 @@ int db_find_next_volume(JCR *jcr, B_DB *mdb, int item, bool InChanger, MEDIA_DBR mr->VolWriteTime = str_to_int64(row[35]); mr->ActionOnPurge = str_to_int64(row[36]); bstrncpy(mr->EncrKey, (row[37] != NULL) ? row[37] : "", sizeof(mr->EncrKey)); + mr->MinBlocksize = str_to_int32(row[38]); + mr->MaxBlocksize = str_to_int32(row[39]); sql_free_result(mdb); diff --git a/src/cats/sql_get.c b/src/cats/sql_get.c index 9ac207fe5de..057e5f2dcbd 100644 --- a/src/cats/sql_get.c +++ b/src/cats/sql_get.c @@ -608,7 +608,7 @@ bool db_get_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr) "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,AcceptAnyVolume," "AutoPrune,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles," "MaxVolBytes,PoolType,LabelType,LabelFormat,RecyclePoolId,ScratchPoolId," -"ActionOnPurge FROM Pool WHERE Pool.PoolId=%s", +"ActionOnPurge,MinBlocksize,MaxBlocksize FROM Pool WHERE Pool.PoolId=%s", edit_int64(pdbr->PoolId, ed1)); } else { /* find by name */ mdb->db_escape_string(jcr, esc, pdbr->Name, strlen(pdbr->Name)); @@ -616,7 +616,7 @@ bool db_get_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr) "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,AcceptAnyVolume," "AutoPrune,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles," "MaxVolBytes,PoolType,LabelType,LabelFormat,RecyclePoolId,ScratchPoolId," -"ActionOnPurge FROM Pool WHERE Pool.Name='%s'", esc); +"ActionOnPurge,MinBlocksize,MaxBlocksize FROM Pool WHERE Pool.Name='%s'", esc); } if (QUERY_DB(jcr, mdb, mdb->cmd)) { num_rows = sql_num_rows(mdb); @@ -650,6 +650,8 @@ bool db_get_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr) pdbr->RecyclePoolId = str_to_int64(row[17]); pdbr->ScratchPoolId = str_to_int64(row[18]); pdbr->ActionOnPurge = str_to_int32(row[19]); + pdbr->MinBlocksize = str_to_int32(row[20]); + pdbr->MaxBlocksize = str_to_int32(row[21]); ok = true; } } @@ -1004,7 +1006,7 @@ bool db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) "EndFile,EndBlock,LabelType,LabelDate,StorageId," "Enabled,LocationId,RecycleCount,InitialWrite," "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime," - "ActionOnPurge,EncryptionKey " + "ActionOnPurge,EncryptionKey,MinBlocksize,MaxBlocksize " "FROM Media WHERE MediaId=%s", edit_int64(mr->MediaId, ed1)); } else { /* find by name */ @@ -1016,7 +1018,7 @@ bool db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) "EndFile,EndBlock,LabelType,LabelDate,StorageId," "Enabled,LocationId,RecycleCount,InitialWrite," "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime," - "ActionOnPurge,EncryptionKey " + "ActionOnPurge,EncryptionKey,MinBlocksize,MaxBlocksize " "FROM Media WHERE VolumeName='%s'", esc); } @@ -1075,7 +1077,8 @@ bool db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) mr->VolWriteTime = str_to_int64(row[35]); mr->ActionOnPurge = str_to_int32(row[36]); bstrncpy(mr->EncrKey, (row[37] != NULL) ? row[37] : "", sizeof(mr->EncrKey)); - + mr->MinBlocksize = str_to_int32(row[38]); + mr->MaxBlocksize = str_to_int32(row[39]); retval = true; } } else { diff --git a/src/cats/sql_update.c b/src/cats/sql_update.c index 44bc8f82f5d..18b9c880af8 100644 --- a/src/cats/sql_update.c +++ b/src/cats/sql_update.c @@ -272,7 +272,7 @@ bool db_update_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr) "AcceptAnyVolume=%d,VolRetention='%s',VolUseDuration='%s'," "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,Recycle=%d," "AutoPrune=%d,LabelType=%d,LabelFormat='%s',RecyclePoolId=%s," -"ScratchPoolId=%s,ActionOnPurge=%d WHERE PoolId=%s", +"ScratchPoolId=%s,ActionOnPurge=%d,MinBlockSize=%d,MaxBlockSize=%d WHERE PoolId=%s", pr->NumVols, pr->MaxVols, pr->UseOnce, pr->UseCatalog, pr->AcceptAnyVolume, edit_uint64(pr->VolRetention, ed1), edit_uint64(pr->VolUseDuration, ed2), @@ -282,6 +282,8 @@ bool db_update_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr) esc, edit_int64(pr->RecyclePoolId,ed5), edit_int64(pr->ScratchPoolId,ed6), pr->ActionOnPurge, + pr->MinBlocksize, + pr->MaxBlocksize, ed4); retval = UPDATE_DB(jcr, mdb, mdb->cmd); db_unlock(mdb); @@ -373,7 +375,8 @@ bool db_update_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) "Slot=%d,InChanger=%d,VolReadTime=%s,VolWriteTime=%s," "LabelType=%d,StorageId=%s,PoolId=%s,VolRetention=%s,VolUseDuration=%s," "MaxVolJobs=%d,MaxVolFiles=%d,Enabled=%d,LocationId=%s," - "ScratchPoolId=%s,RecyclePoolId=%s,RecycleCount=%d,Recycle=%d,ActionOnPurge=%d" + "ScratchPoolId=%s,RecyclePoolId=%s,RecycleCount=%d,Recycle=%d,ActionOnPurge=%d," + "MinBlocksize=%u,MaxBlocksize=%u" " WHERE VolumeName='%s'", mr->VolJobs, mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1), mr->VolMounts, mr->VolErrors, mr->VolWrites, @@ -390,7 +393,8 @@ bool db_update_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) mr->Enabled, edit_uint64(mr->LocationId, ed9), edit_uint64(mr->ScratchPoolId, ed10), edit_uint64(mr->RecyclePoolId, ed11), - mr->RecycleCount,mr->Recycle, mr->ActionOnPurge, + mr->RecycleCount, mr->Recycle, mr->ActionOnPurge, + mr->MinBlocksize, mr->MaxBlocksize, esc_name); Dmsg1(400, "%s\n", mdb->cmd); @@ -420,25 +424,31 @@ bool db_update_media_defaults(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) if (mr->VolumeName[0]) { mdb->db_escape_string(jcr, esc, mr->VolumeName, strlen(mr->VolumeName)); Mmsg(mdb->cmd, "UPDATE Media SET " - "ActionOnPurge=%d, Recycle=%d,VolRetention=%s,VolUseDuration=%s," - "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s" + "ActionOnPurge=%d,Recycle=%d,VolRetention=%s,VolUseDuration=%s," + "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s," + "MinBlocksize=%d,MaxBlocksize=%d" " WHERE VolumeName='%s'", mr->ActionOnPurge, mr->Recycle,edit_uint64(mr->VolRetention, ed1), edit_uint64(mr->VolUseDuration, ed2), mr->MaxVolJobs, mr->MaxVolFiles, edit_uint64(mr->MaxVolBytes, ed3), edit_uint64(mr->RecyclePoolId, ed4), + mr->MinBlocksize, + mr->MaxBlocksize, esc); } else { Mmsg(mdb->cmd, "UPDATE Media SET " - "ActionOnPurge=%d, Recycle=%d,VolRetention=%s,VolUseDuration=%s," - "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s" + "ActionOnPurge=%d,Recycle=%d,VolRetention=%s,VolUseDuration=%s," + "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s," + "MinBlocksize=%d,MaxBlocksize=%d" " WHERE PoolId=%s", mr->ActionOnPurge, mr->Recycle,edit_uint64(mr->VolRetention, ed1), edit_uint64(mr->VolUseDuration, ed2), mr->MaxVolJobs, mr->MaxVolFiles, edit_uint64(mr->MaxVolBytes, ed3), edit_int64(mr->RecyclePoolId, ed4), + mr->MinBlocksize, + mr->MaxBlocksize, edit_int64(mr->PoolId, ed5)); } diff --git a/src/dird/catreq.c b/src/dird/catreq.c index cfa9123652f..ec6269831cb 100644 --- a/src/dird/catreq.c +++ b/src/dird/catreq.c @@ -68,7 +68,7 @@ static char OK_media[] = " MaxVolBytes=%s VolCapacityBytes=%s VolStatus=%s Slot=%d" " MaxVolJobs=%u MaxVolFiles=%u InChanger=%d VolReadTime=%s" " VolWriteTime=%s EndFile=%u EndBlock=%u LabelType=%d" - " MediaId=%s EncryptionKey=%s\n"; + " MediaId=%s EncryptionKey=%s MinBlocksize=%d MaxBlocksize=%d\n"; static char OK_create[] = "1000 OK CreateJobMedia\n"; @@ -92,7 +92,7 @@ static int send_volume_info_to_storage_daemon(JCR *jcr, BSOCK *sd, MEDIA_DBR *mr mr->EndFile, mr->EndBlock, mr->LabelType, edit_uint64(mr->MediaId, ed6), - mr->EncrKey); + mr->EncrKey, mr->MinBlocksize, mr->MaxBlocksize); unbash_spaces(mr->VolumeName); Dmsg2(100, "Vol Info for %s: %s", jcr->Job, sd->msg); return status; diff --git a/src/dird/dird_conf.c b/src/dird/dird_conf.c index 80f3a4fd851..97120df5a33 100644 --- a/src/dird/dird_conf.c +++ b/src/dird/dird_conf.c @@ -455,6 +455,8 @@ static RES_ITEM pool_items[] = { { "catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, NULL }, { "fileretention", store_time, ITEM(res_pool.FileRetention), 0, 0, NULL }, { "jobretention", store_time, ITEM(res_pool.JobRetention), 0, 0, NULL }, + { "minimumblocksize", store_pint32, ITEM(res_pool.MinBlocksize), 0, 0, NULL }, + { "maximumblocksize", store_pint32, ITEM(res_pool.MaxBlocksize), 0, 0, NULL }, { NULL, NULL, { 0 }, 0, 0, NULL } }; @@ -1136,6 +1138,8 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"), res->res_pool.max_volumes, res->res_pool.AutoPrune, edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1))); + sendit(sock, _(" minblocksize=%d maxblocksize=%d\n"), + res->res_pool.MinBlocksize, res->res_pool.MaxBlocksize); sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"), edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)), res->res_pool.Recycle, diff --git a/src/dird/dird_conf.h b/src/dird/dird_conf.h index fa7b870accc..99e7898a71a 100644 --- a/src/dird/dird_conf.h +++ b/src/dird/dird_conf.h @@ -607,6 +607,8 @@ class POOLRES { CATRES *catalog; /* Catalog to be used */ utime_t FileRetention; /* file retention period in seconds */ utime_t JobRetention; /* job retention period in seconds */ + uint32_t MinBlocksize; /* Minimum Blocksize */ + uint32_t MaxBlocksize; /* Maximum Blocksize */ /* Methods */ char *name() const; diff --git a/src/dird/ua_cmds.c b/src/dird/ua_cmds.c index 0d5182bb199..75753403bab 100644 --- a/src/dird/ua_cmds.c +++ b/src/dird/ua_cmds.c @@ -309,6 +309,8 @@ void set_pool_dbr_defaults_in_media_dbr(MEDIA_DBR *mr, POOL_DBR *pr) mr->MaxVolFiles = pr->MaxVolFiles; mr->MaxVolBytes = pr->MaxVolBytes; mr->LabelType = pr->LabelType; + mr->MinBlocksize = pr->MinBlocksize; + mr->MaxBlocksize = pr->MaxBlocksize; mr->Enabled = 1; } @@ -555,7 +557,7 @@ static int cancel_cmd(UAContext *ua, const char *cmd) * Pool DB base record from a Pool Resource. We handle * the setting of MaxVols and NumVols slightly differently * depending on if we are creating the Pool or we are - * simply bringing it into agreement with the resource (updage). + * simply bringing it into agreement with the resource (update). * * Caution : RecyclePoolId isn't setup in this function. * You can use set_pooldbr_recyclepoolid(); @@ -585,6 +587,9 @@ void set_pooldbr_from_poolres(POOL_DBR *pr, POOLRES *pool, e_pool_op op) pr->MaxVolBytes = pool->MaxVolBytes; pr->AutoPrune = pool->AutoPrune; pr->ActionOnPurge = pool->action_on_purge; + pr->ActionOnPurge = pool->action_on_purge; + pr->MinBlocksize = pool->MinBlocksize; + pr->MaxBlocksize = pool->MaxBlocksize; pr->Recycle = pool->Recycle; if (pool->label_format) { bstrncpy(pr->LabelFormat, pool->label_format, sizeof(pr->LabelFormat)); diff --git a/src/dird/ua_label.c b/src/dird/ua_label.c index 941efdc5489..c968e20485a 100644 --- a/src/dird/ua_label.c +++ b/src/dird/ua_label.c @@ -412,8 +412,7 @@ static void label_from_barcodes(UAContext *ua, int drive, bool label_encrypt) set_storageid_in_mr(store, &mr); /* - * Deal with creating cleaning tape here. Normal tapes created in - * send_label_request() below + * Deal with creating cleaning tape here. Normal tapes created in send_label_request() below */ if (is_cleaning_tape(ua, &mr, &pr)) { if (media_record_exists) { /* we update it */ @@ -458,7 +457,7 @@ static void label_from_barcodes(UAContext *ua, int drive, bool label_encrypt) } mr.Slot = vl->Slot; - send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists, drive); + send_label_request(ua, &mr, &omr, &pr, false, media_record_exists, drive); } bail_out: @@ -555,20 +554,30 @@ static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr, if (relabel) { bash_spaces(omr->VolumeName); sd->fsend("relabel %s OldName=%s NewName=%s PoolName=%s " - "MediaType=%s Slot=%d drive=%d", + "MediaType=%s Slot=%d drive=%d MinBlocksize=%d MaxBlocksize=%d", dev_name, omr->VolumeName, mr->VolumeName, pr->Name, - mr->MediaType, mr->Slot, drive); + mr->MediaType, mr->Slot, drive, + /* + * if relabeling, keep blocksize settings + */ + omr->MinBlocksize, omr->MaxBlocksize); ua->send_msg(_("Sending relabel command from \"%s\" to \"%s\" ...\n"), omr->VolumeName, mr->VolumeName); } else { sd->fsend("label %s VolumeName=%s PoolName=%s MediaType=%s " - "Slot=%d drive=%d", + "Slot=%d drive=%d MinBlocksize=%d MaxBlocksize=%d", dev_name, mr->VolumeName, pr->Name, mr->MediaType, - mr->Slot, drive); + mr->Slot, drive, + /* + * if labeling, use blocksize defined in pool + */ + pr->MinBlocksize, pr->MaxBlocksize); ua->send_msg(_("Sending label command for Volume \"%s\" Slot %d ...\n"), mr->VolumeName, mr->Slot); - Dmsg6(100, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d drive=%d\n", - dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive); + Dmsg8(100, "label %s VolumeName=%s PoolName=%s MediaType=%s " + "Slot=%d drive=%d MinBlocksize=%d MaxBlocksize=%d\n", + dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive, + pr->MinBlocksize, pr->MaxBlocksize); } /* diff --git a/src/lib/scan.c b/src/lib/scan.c index cf194421b39..6ab48dadb1f 100644 --- a/src/lib/scan.c +++ b/src/lib/scan.c @@ -544,6 +544,8 @@ struct VOLUME_CAT_INFO { uint64_t VolCatCapacityBytes; /* capacity estimate */ uint64_t VolReadTime; /* time spent reading */ uint64_t VolWriteTime; /* time spent writing this Volume */ + uint32_t MinBlocksize; /* Minimum block size */ + uint32_t MaxBlocksize; /* Maximum block size */ char VolCatStatus[20]; /* Volume status */ char VolCatName[MAX_NAME_LENGTH]; /* Desired volume to mount */ }; @@ -569,7 +571,8 @@ struct VOLUME_CAT_INFO { &vol.VolCatWrites, &vol.VolCatMaxBytes, &vol.VolCatCapacityBytes, vol.VolCatStatus, &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles, - &vol.InChanger, &vol.VolReadTime, &vol.VolWriteTime); + &vol.InChanger, &vol.VolReadTime, &vol.VolWriteTime, + &vol.MaxBlocksize, &vol.MinBocksize); printf("cnt=%d Vol=%s\n", cnt, vol.VolCatName); } diff --git a/src/stored/acquire.c b/src/stored/acquire.c index e38434dadf1..84a66671eb7 100644 --- a/src/stored/acquire.c +++ b/src/stored/acquire.c @@ -338,7 +338,9 @@ bool acquire_device_for_read(DCR *dcr) } Dmsg2(rdbglvl, "dcr=%p dev=%p\n", dcr, dcr->dev); Dmsg2(rdbglvl, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type); + dev->Unlock_read_acquire(); + Leave(rdbglvl); return ok; } @@ -606,7 +608,7 @@ bool clean_device(DCR *dcr) * this dcr in the right place * */ -DCR *new_dcr(JCR *jcr, DCR *dcr, DEVICE *dev) +DCR *new_dcr(JCR *jcr, DCR *dcr, DEVICE *dev, BLOCKSIZES *blocksizes) { if (!dcr) { int errstat; @@ -633,6 +635,14 @@ DCR *new_dcr(JCR *jcr, DCR *dcr, DEVICE *dev) * Set device information, possibly change device */ if (dev) { + /* + * Set wanted blocksizes + */ + if (blocksizes) { + dev->min_block_size = blocksizes->min_block_size; + dev->max_block_size = blocksizes->max_block_size; + } + if (dcr->block) { free_block(dcr->block); } diff --git a/src/stored/askdir.c b/src/stored/askdir.c index b65ff7e2ad9..148130181e6 100644 --- a/src/stored/askdir.c +++ b/src/stored/askdir.c @@ -59,7 +59,8 @@ static char OK_media[] = " MaxVolBytes=%lld VolCapacityBytes=%lld VolStatus=%20s" " Slot=%ld MaxVolJobs=%lu MaxVolFiles=%lu InChanger=%ld" " VolReadTime=%lld VolWriteTime=%lld EndFile=%lu EndBlock=%lu" - " LabelType=%ld MediaId=%lld EncryptionKey=%127s\n"; + " LabelType=%ld MediaId=%lld EncryptionKey=%127s" + " MinBlocksize=%lu MaxBlocksize=%lu\n"; static char OK_create[] = "1000 OK CreateJobMedia\n"; @@ -181,8 +182,9 @@ static bool do_get_volume_info(DCR *dcr) &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles, &InChanger, &vol.VolReadTime, &vol.VolWriteTime, &vol.EndFile, &vol.EndBlock, &vol.LabelType, - &vol.VolMediaId, vol.VolEncrKey); - if (n != 22) { + &vol.VolMediaId, vol.VolEncrKey, + &vol.VolMinBlocksize, &vol.VolMaxBlocksize); + if (n != 24) { Dmsg3(dbglvl, "Bad response from Dir fields=%d, len=%d: %s", n, dir->msglen, dir->msg); Mmsg(jcr->errmsg, _("Error getting Volume info: %s"), dir->msg); @@ -195,8 +197,7 @@ static bool do_get_volume_info(DCR *dcr) dcr->VolCatInfo = vol; /* structure assignment */ /* - * If we received a new crypto key update the cache and write - * out the new cache on a change. + * If we received a new crypto key update the cache and write out the new cache on a change. */ if (*vol.VolEncrKey) { if (update_crypto_cache(vol.VolCatName, vol.VolEncrKey)) { @@ -205,12 +206,23 @@ static bool do_get_volume_info(DCR *dcr) } } - Dmsg2(dbglvl, "do_get_volume_info return true slot=%d Volume=%s\n", - vol.Slot, vol.VolCatName); + Dmsg4(dbglvl, "do_get_volume_info return true slot=%d Volume=%s, " + "VolminBlocksize=%u VolMaxBlocksize=%u\n", + vol.Slot, vol.VolCatName, vol.VolMinBlocksize, vol.VolMaxBlocksize); + Dmsg2(dbglvl, "setting dcr->VolMinBlocksize(%u) to vol.VolMinBlocksize(%u)\n", + dcr->VolMinBlocksize, vol.VolMinBlocksize); + Dmsg2(dbglvl, "setting dcr->VolMaxBlocksize(%u) to vol.VolMaxBlocksize(%u)\n", + dcr->VolMaxBlocksize, vol.VolMaxBlocksize); + + /* + * Assign the volcatinfo to the dcr. + */ + dcr->VolMinBlocksize = vol.VolMinBlocksize; + dcr->VolMaxBlocksize = vol.VolMaxBlocksize; + return true; } - /** * Get Volume info for a specific volume from the Director's Database * @@ -238,8 +250,6 @@ bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing) return ok; } - - /** * Get info on the next appendable volume in the Director's database * @@ -316,7 +326,6 @@ bool dir_find_next_appendable_volume(DCR *dcr) return rtn; } - /** * After writing a Volume, send the updated statistics * back to the director. The information comes from the @@ -443,7 +452,6 @@ bool dir_create_jobmedia_record(DCR *dcr, bool zero) return true; } - /** * Update File Attribute data * We do the following: @@ -486,7 +494,6 @@ bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) return dir->send(); } - /** * Request the sysop to create an appendable volume * diff --git a/src/stored/block.c b/src/stored/block.c index 979f226c08c..6462bf5766a 100644 --- a/src/stored/block.c +++ b/src/stored/block.c @@ -42,7 +42,6 @@ static const bool no_tape_write_test = true; static const bool no_tape_write_test = false; #endif - static bool terminate_writing_volume(DCR *dcr); static bool do_new_file_bookkeeping(DCR *dcr); static void reread_last_block(DCR *dcr); @@ -121,13 +120,12 @@ DEV_BLOCK *new_block(DEVICE *dev) memset(block, 0, sizeof(DEV_BLOCK)); - /* - * If the user has specified a max_block_size, use it as the default - */ if (dev->max_block_size == 0) { - block->buf_len = DEFAULT_BLOCK_SIZE; + block->buf_len = dev->device->label_block_size; + Dmsg1(100, "created new block of blocksize %d (dev->device->label_block_size) as dev->max_block_size is zero\n", block->buf_len); } else { block->buf_len = dev->max_block_size; + Dmsg1(100, "created new block of blocksize %d (dev->max_block_size)\n", block->buf_len); } block->dev = dev; block->block_len = block->buf_len; /* default block size */ @@ -502,11 +500,19 @@ bool DCR::write_block_to_dev() wlen = ((wlen + TAPE_BSIZE - 1) / TAPE_BSIZE) * TAPE_BSIZE; } } + + Dmsg4(100, "writing block of size %d to dev=%s with max_block_size %d and min_block_size %d\n", + wlen, dev->print_name(), dev->max_block_size, dev->min_block_size); + if (wlen-blen > 0) { memset(block->bufp, 0, wlen-blen); /* clear garbage */ } } + Dmsg4(100, "writing block of size %d to dev=%s with max_block_size %d and min_block_size %d\n", + wlen, dev->print_name(), dev->max_block_size, dev->min_block_size); + + checksum = ser_block_header(block, dev->do_checksum()); /* diff --git a/src/stored/block.h b/src/stored/block.h index d2ab3f459d6..cc69e25b034 100644 --- a/src/stored/block.h +++ b/src/stored/block.h @@ -28,7 +28,9 @@ #define __BLOCK_H 1 #define MAX_BLOCK_LENGTH 20000000 /* this is a sort of sanity check */ -#define DEFAULT_BLOCK_SIZE (512 * 126) /* 64,512 N.B. do not use 65,636 here */ +#define DEFAULT_BLOCK_SIZE (512 * 126) /* 64,512 N.B. do not use 65,536 here + the POSIX standard defaults the size of a + tape record to 126 blocks (63k). */ /* Block Header definitions. */ #define BLKHDR1_ID "BB01" diff --git a/src/stored/bscan.c b/src/stored/bscan.c index 00041273fe7..94f3de4184b 100644 --- a/src/stored/bscan.c +++ b/src/stored/bscan.c @@ -1391,7 +1391,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->dcr = jobjcr->read_dcr = new_dcr(jobjcr, NULL, dev); + jobjcr->dcr = jobjcr->read_dcr = new_dcr(jobjcr, NULL, dev, NULL); return jobjcr; } diff --git a/src/stored/butil.c b/src/stored/butil.c index deb1abbe172..24d5d35d556 100644 --- a/src/stored/butil.c +++ b/src/stored/butil.c @@ -171,7 +171,7 @@ static DCR *setup_to_access_device(JCR *jcr, char *dev_name, return NULL; } device->dev = dev; - jcr->dcr = dcr = new_dcr(jcr, NULL, dev); + jcr->dcr = dcr = new_dcr(jcr, NULL, dev, NULL); if (VolName[0]) { bstrncpy(dcr->VolumeName, VolName, sizeof(dcr->VolumeName)); } diff --git a/src/stored/dev.c b/src/stored/dev.c index a6670d59366..82f0fb14d29 100644 --- a/src/stored/dev.c +++ b/src/stored/dev.c @@ -118,6 +118,8 @@ m_init_dev(JCR *jcr, DEVRES *device, bool new_init) DEVICE *dev; uint32_t max_bs; + Dmsg1(400, "max_block_size in device res is %u\n", device->max_block_size); + /* If no device type specified, try to guess */ if (!device->dev_type) { /* Check that device is available */ @@ -172,14 +174,23 @@ m_init_dev(JCR *jcr, DEVRES *device, bool new_init) } dev->clear_slot(); /* unknown */ - /* Copy user supplied device parameters from Resource */ + /* + * Copy user supplied device parameters from Resource + */ dev->dev_name = get_memory(strlen(device->device_name)+1); pm_strcpy(dev->dev_name, device->device_name); dev->prt_name = get_memory(strlen(device->device_name) + strlen(device->hdr.name) + 20); - /* We edit "Resource-name" (physical-name) */ + + /* + * We edit "Resource-name" (physical-name) + */ Mmsg(dev->prt_name, "\"%s\" (%s)", device->hdr.name, device->device_name); Dmsg1(400, "Allocate dev=%s\n", dev->print_name()); dev->capabilities = device->cap_bits; + + /* + * current block sizes + */ dev->min_block_size = device->min_block_size; dev->max_block_size = device->max_block_size; dev->max_volume_size = device->max_volume_size; @@ -196,7 +207,10 @@ m_init_dev(JCR *jcr, DEVRES *device, bool new_init) dev->norewindonclose = device->norewindonclose; dev->dev_type = device->dev_type; dev->device = device; - /* Sanity check */ + + /* + * Sanity check + */ if (dev->vol_poll_interval && dev->vol_poll_interval < 60) { dev->vol_poll_interval = 60; } @@ -206,7 +220,8 @@ m_init_dev(JCR *jcr, DEVRES *device, bool new_init) dev->capabilities |= CAP_STREAM; /* set stream device */ } - /* If the device requires mount : + /* + * If the device requires mount : * - Check that the mount point is available * - Check that (un)mount commands are defined */ @@ -223,7 +238,9 @@ m_init_dev(JCR *jcr, DEVRES *device, bool new_init) } } - /* Sanity check */ + /* + * Sanity check + */ if (dev->max_block_size == 0) { max_bs = DEFAULT_BLOCK_SIZE; } else { @@ -289,7 +306,6 @@ m_init_dev(JCR *jcr, DEVRES *device, bool new_init) dev->set_mutex_priorities(); - #ifdef xxx if ((errstat = rwl_init(&dev->lock)) != 0) { berrno be; @@ -303,10 +319,113 @@ m_init_dev(JCR *jcr, DEVRES *device, bool new_init) dev->attached_dcrs = New(dlist(dcr, &dcr->dev_link)); Dmsg2(100, "init_dev: tape=%d dev_name=%s\n", dev->is_tape(), dev->dev_name); dev->initiated = true; + Dmsg3(100, "dev=%s dev_max_bs=%u max_bs=%u\n", dev->dev_name, dev->device->max_block_size, dev->max_block_size); return dev; } +/* + * Set the block size of the device. + * If the volume block size is zero, we set the max block size to what is + * configured in the device resource i.e. dev->device->max_block_size. + */ +void DEVICE::set_blocksizes(DCR *dcr) { + + DEVICE* dev = this; + JCR* jcr = dcr->jcr; + uint32_t max_bs; + + Dmsg3(100, "Device %s has dev_max_block_size of %u and max_block_size of %u\n", + dev->print_name(), dev->device->max_block_size, dev->max_block_size); + + if (dcr->VolMaxBlocksize == 0) { + Dmsg2(100, "setting dev->max_block_size to dev_max_block_size=%u " + "on device %s because dcr->VolMaxBlocksize is 0\n", + dev->device->max_block_size, dev->print_name()); + dev->min_block_size = dev->device->min_block_size; + dev->max_block_size = dev->device->max_block_size; + } else { + dev->min_block_size = dcr->VolMinBlocksize; + dev->max_block_size = dcr->VolMaxBlocksize; + } + + /* + * Sanity check + */ + if (dev->max_block_size == 0) { + max_bs = DEFAULT_BLOCK_SIZE; + } else { + max_bs = dev->max_block_size; + } + + if (dev->min_block_size > max_bs) { + Jmsg(jcr, M_ERROR_TERM, 0, _("Min block size > max on device %s\n"), dev->print_name()); + } + + if (dev->max_block_size > MAX_BLOCK_LENGTH) { + Jmsg3(jcr, M_ERROR, 0, _("Block size %u on device %s is too large, using default %u\n"), + dev->max_block_size, dev->print_name(), DEFAULT_BLOCK_SIZE); + dev->max_block_size = 0; + } + + if (dev->max_block_size % TAPE_BSIZE != 0) { + Jmsg3(jcr, M_WARNING, 0, _("Max block size %u not multiple of device %s block size=%d.\n"), + dev->max_block_size, dev->print_name(), TAPE_BSIZE); + } + + if (dev->max_volume_size != 0 && dev->max_volume_size < (dev->max_block_size << 4)) { + Jmsg(jcr, M_ERROR_TERM, 0, _("Max Vol Size < 8 * Max Block Size for device %s\n"), dev->print_name()); + } + + Dmsg3(100, "set minblocksize to %d, maxblocksize to %d on device %s\n", + dev->min_block_size, dev->max_block_size, dev->print_name()); + + /* + * If blocklen is not dev->max_block_size create a new block with the right size. + * (as header is always dev->label_block_size which is preset with DEFAULT_BLOCK_SIZE) + */ + if (dcr->block) { + if (dcr->block->buf_len != dev->max_block_size) { + Dmsg2(100, "created new block of buf_len: %u on device %s\n", + dev->max_block_size, dev->print_name()); + free_block(dcr->block); + dcr->block = new_block(dev); + Dmsg2(100, "created new block of buf_len: %u on device %s, freeing block\n", + dcr->block->buf_len, dev->print_name()); + } + } +} + +/* + * Set the block size of the device to the label_block_size + * to read labels as we want to always use that blocksize when + * writing volume labels + */ +void DEVICE::set_label_blocksize(DCR *dcr) +{ + DEVICE *dev = this; + + Dmsg3(100, "setting minblocksize to %u, " + "maxblocksize to label_block_size=%u, on device %s\n", + 0, dev->device->label_block_size, dev->print_name()); + + dev->min_block_size = 0; + + dev->max_block_size = dev->device->label_block_size; + /* + * If blocklen is not dev->max_block_size create a new block with the right size + * (as header is always label_block_size) + */ + if (dcr->block) { + if (dcr->block->buf_len != dev->max_block_size) { + free_block(dcr->block); + dcr->block = new_block(dev); + Dmsg2(100, "created new block of buf_len: %u on device %s\n", + dcr->block->buf_len, dev->print_name()); + } + } +} + /* * Open the device with the operating system and * initialize buffer pointers. diff --git a/src/stored/dev.h b/src/stored/dev.h index b499c71e79f..fa2061397da 100644 --- a/src/stored/dev.h +++ b/src/stored/dev.h @@ -192,6 +192,13 @@ struct VOLUME_CAT_INFO { char VolCatStatus[20]; /* Volume status */ char VolCatName[MAX_NAME_LENGTH]; /* Desired volume to mount */ char VolEncrKey[MAX_NAME_LENGTH]; /* Encryption Key needed to read the media */ + uint32_t VolMinBlocksize; /* Volume Minimum Blocksize */ + uint32_t VolMaxBlocksize; /* Volume Maximum Blocksize */ +}; + +struct BLOCKSIZES { + uint32_t max_block_size; + uint32_t min_block_size; }; class DEVRES; /* Device resource defined in stored_conf.h */ @@ -251,8 +258,8 @@ class DEVICE: public SMARTALLOC { uint64_t file_size; /* Current file size */ uint32_t EndBlock; /* last block written */ uint32_t EndFile; /* last file written */ - uint32_t min_block_size; /* min block size */ - uint32_t max_block_size; /* max block size */ + uint32_t min_block_size; /* min block size currently set */ + uint32_t max_block_size; /* max block size currently set */ uint32_t max_concurrent_jobs; /* maximum simultaneous jobs this drive */ uint64_t max_volume_size; /* max bytes to put on one volume */ uint64_t max_file_size; /* max file size to put in one file on volume */ @@ -415,6 +422,9 @@ class DEVICE: public SMARTALLOC { void set_slot(int32_t slot); /* in dev.c */ void clear_slot(); /* in dev.c */ + void set_blocksizes(DCR* dcr); /* in dev.c */ + void set_label_blocksize(DCR* dcr); /* in dev.c */ + uint32_t get_file() const { return file; }; uint32_t get_block_num() const { return block_num; }; int fd() const { return m_fd; }; @@ -538,6 +548,8 @@ class DCR { int64_t VolMediaId; /* MediaId */ int64_t job_spool_size; /* Current job spool size */ int64_t max_job_spool_size; /* Max job spool size */ + uint32_t VolMinBlocksize; /* Minimum Blocksize */ + uint32_t VolMaxBlocksize; /* Maximum Blocksize */ char VolumeName[MAX_NAME_LENGTH]; /* Volume name */ char pool_name[MAX_NAME_LENGTH]; /* Pool name */ char pool_type[MAX_NAME_LENGTH]; /* Pool type */ @@ -610,7 +622,6 @@ class DCR { /* Methods in label.c */ bool rewrite_volume_label(bool recycle); - }; /* Get some definition of function to position diff --git a/src/stored/dir_cmd.c b/src/stored/dir_cmd.c index 0a7babcb48d..50a16cfdca8 100644 --- a/src/stored/dir_cmd.c +++ b/src/stored/dir_cmd.c @@ -58,10 +58,10 @@ static char cancelcmd[] = "cancel Job=%127s"; static char relabelcmd[] = "relabel %127s OldName=%127s NewName=%127s PoolName=%127s " - "MediaType=%127s Slot=%d drive=%d"; + "MediaType=%127s Slot=%d drive=%d MinBlocksize=%d MaxBlocksize=%d"; static char labelcmd[] = "label %127s VolumeName=%127s PoolName=%127s " - "MediaType=%127s Slot=%d drive=%d"; + "MediaType=%127s Slot=%d drive=%d MinBlocksize=%d MaxBlocksize=%d"; static char mountslotcmd[] = "mount %127s drive=%d slot=%d"; static char mountcmd[] = @@ -136,7 +136,7 @@ static bool setbandwidth_cmd(JCR *jcr); static bool setdebug_cmd(JCR *jcr); static bool unmount_cmd(JCR *jcr); -static DCR *find_device(JCR *jcr, POOL_MEM &dev_name, int drive); +static DCR *find_device(JCR *jcr, POOL_MEM &dev_name, int drive, BLOCKSIZES *blocksizes); 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, @@ -578,8 +578,10 @@ static bool do_label(JCR *jcr, bool relabel) BSOCK *dir = jcr->dir_bsock; DCR *dcr; DEVICE *dev; + BLOCKSIZES blocksizes; bool ok = false; int32_t slot, drive; + //, max_block_size, min_block_size; /* * Determine the length of the temporary buffers. @@ -600,25 +602,35 @@ static bool do_label(JCR *jcr, bool relabel) mediatype = get_memory(len); if (relabel) { if (sscanf(dir->msg, relabelcmd, dev_name.c_str(), oldname, - newname, poolname, mediatype, &slot, &drive) == 7) { + newname, poolname, mediatype, &slot, &drive, + &blocksizes.min_block_size, &blocksizes.max_block_size) == 9) { ok = true; } } else { *oldname = 0; if (sscanf(dir->msg, labelcmd, dev_name.c_str(), newname, - poolname, mediatype, &slot, &drive) == 6) { + poolname, mediatype, &slot, &drive, + &blocksizes.min_block_size, &blocksizes.max_block_size) == 8) { ok = true; } } + if (ok) { unbash_spaces(newname); unbash_spaces(oldname); unbash_spaces(poolname); unbash_spaces(mediatype); - dcr = find_device(jcr, dev_name, drive); + + dcr = find_device(jcr, dev_name, drive, &blocksizes); if (dcr) { dev = dcr->dev; + + dev->Lock(); /* Use P to avoid indefinite block */ + dcr->VolMinBlocksize = blocksizes.min_block_size; + dcr->VolMaxBlocksize = blocksizes.max_block_size; + dev->set_blocksizes(dcr); /* apply blocksizes from dcr to dev */ + if (!dev->is_open() && !dev->is_busy()) { Dmsg1(400, "Can %slabel. Device is not open\n", relabel ? "re" : ""); label_volume_if_ok(dcr, oldname, newname, poolname, slot, relabel); @@ -801,7 +813,7 @@ static bool read_label(DCR *dcr) /* * Searches for device by name, and if found, creates a dcr and returns it. */ -static DCR *find_device(JCR *jcr, POOL_MEM &devname, int drive) +static DCR *find_device(JCR *jcr, POOL_MEM &devname, int drive, BLOCKSIZES *blocksizes) { DEVRES *device; AUTOCHANGERRES *changer; @@ -862,7 +874,7 @@ 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, NULL, device->dev); + dcr = new_dcr(jcr, NULL, device->dev, blocksizes); dcr->device = device; } return dcr; @@ -888,7 +900,7 @@ static bool mount_cmd(JCR *jcr) Dmsg3(100, "ok=%d drive=%d slot=%d\n", ok, drive, slot); if (ok) { - dcr = find_device(jcr, devname, drive); + dcr = find_device(jcr, devname, drive, NULL); if (dcr) { dev = dcr->dev; dev->Lock(); /* Use P to avoid indefinite block */ @@ -1038,7 +1050,7 @@ static bool unmount_cmd(JCR *jcr) int32_t drive; if (sscanf(dir->msg, unmountcmd, devname.c_str(), &drive) == 2) { - dcr = find_device(jcr, devname, drive); + dcr = find_device(jcr, devname, drive, NULL); if (dcr) { dev = dcr->dev; dev->Lock(); /* Use P to avoid indefinite block */ @@ -1173,7 +1185,7 @@ static bool release_cmd(JCR *jcr) int32_t drive; if (sscanf(dir->msg, releasecmd, devname.c_str(), &drive) == 2) { - dcr = find_device(jcr, devname, drive); + dcr = find_device(jcr, devname, drive, NULL); if (dcr) { dev = dcr->dev; dev->Lock(); /* Use P to avoid indefinite block */ @@ -1328,7 +1340,7 @@ static bool changer_cmd(JCR *jcr) is_transfer = true; } if (ok) { - dcr = find_device(jcr, devname, -1); + dcr = find_device(jcr, devname, -1, NULL); if (dcr) { dev = dcr->dev; dev->Lock(); /* Use P to avoid indefinite block */ @@ -1378,7 +1390,7 @@ static bool readlabel_cmd(JCR *jcr) if (sscanf(dir->msg, readlabelcmd, devname.c_str(), &Slot, &drive) == 3) { - dcr = find_device(jcr, devname, drive); + dcr = find_device(jcr, devname, drive, NULL); if (dcr) { dev = dcr->dev; dev->Lock(); /* Use P to avoid indefinite block */ diff --git a/src/stored/label.c b/src/stored/label.c index 90a6feba4c6..cb95cfca28b 100644 --- a/src/stored/label.c +++ b/src/stored/label.c @@ -67,9 +67,19 @@ int read_dev_volume_label(DCR *dcr) bool want_ansi_label; bool have_ansi_label = false; - Dmsg4(100, "Enter read_volume_label res=%d device=%s vol=%s dev_Vol=%s\n", + /* + * We always write the label in an 64512 byte / 63k block. + * so we never have problems reading the volume label. + */ + + /* + * Set the default blocksize to read the label + */ + dev->set_label_blocksize(dcr); + + Dmsg5(100, "Enter read_volume_label res=%d device=%s vol=%s dev_Vol=%s max_blocksize=%u\n", dev->num_reserved(), dev->print_name(), VolName, - dev->VolHdr.VolumeName[0]?dev->VolHdr.VolumeName:"*NULL*"); + dev->VolHdr.VolumeName[0]?dev->VolHdr.VolumeName:"*NULL*", dev->max_block_size); if (!dev->is_open()) { if (!dev->open(dcr, OPEN_READ_ONLY)) { @@ -259,7 +269,7 @@ int read_dev_volume_label(DCR *dcr) * the return value e.g. although we think the volume label is ok the plugin * has reasons to override that. So when the plugin returns something else * then bRC_OK it want to tell us the volume is not OK to use and as - * such we return VOL_NAME_ERROR as error although it might not be te + * such we return VOL_NAME_ERROR as error although it might not be the * best error it should be sufficient. */ if (generate_plugin_event(jcr, bsdEventLabelVerified, dcr) != bRC_OK) { @@ -268,6 +278,13 @@ int read_dev_volume_label(DCR *dcr) goto bail_out; } empty_block(block); + + /* + * reset blocksizes from volinfo to device as we set blocksize to + * DEFAULT_BLOCK_SIZE to read the label + */ + dev->set_blocksizes(dcr); + return VOL_OK; bail_out: @@ -328,12 +345,16 @@ bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, DEVICE *dev = dcr->dev; DEV_BLOCK *block = dcr->block; + /* + * Set the default blocksize to read the label + */ + dev->set_label_blocksize(dcr); + Dmsg0(150, "write_volume_label()\n"); if (*VolName == 0) { Pmsg0(0, "=== ERROR: write_new_volume_label_to_dev called with NULL VolName\n"); goto bail_out; } - if (relabel) { volume_unused(dcr); /* mark current volume unused */ /* Truncate device */ @@ -349,6 +370,8 @@ bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, dev->setVolCatName(VolName); dcr->setVolCatName(VolName); Dmsg1(150, "New VolName=%s\n", VolName); + + if (!dev->open(dcr, OPEN_READ_WRITE)) { /* If device is not tape, attempt to create it */ if (dev->is_tape() || !dev->open(dcr, CREATE_READ_WRITE)) { @@ -379,6 +402,7 @@ bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, /* Temporarily mark in append state to enable writing */ dev->set_append(); + /* Create PRE_LABEL */ create_volume_label(dev, VolName, PoolName); @@ -400,6 +424,11 @@ bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, dcr->rec->Stream = 0; dcr->rec->maskedStream = 0; + /* + * Set the label blocksize to read the label + */ + dev->set_label_blocksize(dcr); + if (!write_record_to_block(dcr, dcr->rec)) { Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg()); goto bail_out; @@ -436,6 +465,12 @@ bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, dev = dcr->dev; /* may have changed in reserve_volume */ dev->clear_append(); /* remove append since this is PRE_LABEL */ + + /* + * Reset blocksizes from volinfo to device as we set blocksize to DEFAULT_BLOCK_SIZE to read the label. + */ + dev->set_blocksizes(dcr); + return true; bail_out: @@ -456,6 +491,11 @@ bool DCR::rewrite_volume_label(bool recycle) { DCR *dcr = this; + /* + * Set the label blocksize to write the label + */ + dev->set_label_blocksize(dcr); + if (!dev->open(dcr, OPEN_READ_WRITE)) { Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"), dev->print_name(), dcr->VolumeName, dev->bstrerror()); @@ -572,6 +612,12 @@ bool DCR::rewrite_volume_label(bool recycle) */ Dmsg1(150, "OK from rewrite vol label. Vol=%s\n", dcr->VolumeName); + /* + * reset blocksizes from volinfo to device as we set blocksize to + * DEFAULT_BLOCK_SIZE to write the label + */ + dev->set_blocksizes(dcr); + /* * Let any stored plugin know the label was rewritten and as such is verified . */ diff --git a/src/stored/mount.c b/src/stored/mount.c index fea6178a3a3..ff376564d04 100644 --- a/src/stored/mount.c +++ b/src/stored/mount.c @@ -237,7 +237,21 @@ bool DCR::mount_next_write_volume() if (!find_a_volume()) { goto mount_next_vol; } + dev->VolCatInfo = VolCatInfo; /* structure assignment */ + + /* + * Apply the Volume Blocksizes to device + */ + dcr->VolMinBlocksize = VolCatInfo.VolMinBlocksize; + dcr->VolMaxBlocksize = VolCatInfo.VolMaxBlocksize; + Dmsg3(200, "applying vol block sizes to device %s: dcr->VolMinBlocksize set to %u, dcr->VolMaxBlocksize set to %u\n", + dev->print_name(), dcr->VolMinBlocksize, dcr->VolMaxBlocksize); + + /* + * Set the block sizes of the dcr in the device. + */ + dev->set_blocksizes(dcr); } /* diff --git a/src/stored/protos.h b/src/stored/protos.h index dafdf0af0c6..29f4b5917f9 100644 --- a/src/stored/protos.h +++ b/src/stored/protos.h @@ -32,7 +32,7 @@ DCR *acquire_device_for_append(DCR *dcr); bool acquire_device_for_read(DCR *dcr); bool release_device(DCR *dcr); bool clean_device(DCR *dcr); -DCR *new_dcr(JCR *jcr, DCR *dcr, DEVICE *dev); +DCR *new_dcr(JCR *jcr, DCR *dcr, DEVICE *dev, BLOCKSIZES *blocksizes); void free_dcr(DCR *dcr); /* append.c */ diff --git a/src/stored/reserve.c b/src/stored/reserve.c index dfac4eb2ed7..eb6ea1e925b 100644 --- a/src/stored/reserve.c +++ b/src/stored/reserve.c @@ -247,7 +247,7 @@ static bool use_device_cmd(JCR *jcr) #endif init_jcr_device_wait_timers(jcr); - jcr->dcr = new_dcr(jcr, NULL, NULL); /* get a dcr */ + jcr->dcr = new_dcr(jcr, NULL, NULL, NULL); /* get a dcr */ if (!jcr->dcr) { BSOCK *dir = jcr->dir_bsock; dir->fsend(_("3939 Could not get dcr\n")); @@ -645,9 +645,9 @@ static int reserve_device(RCTX &rctx) rctx.suitable_device = true; Dmsg1(dbglvl, "try reserve %s\n", rctx.device->hdr.name); if (rctx.store->append) { - dcr = new_dcr(rctx.jcr, rctx.jcr->dcr, rctx.device->dev); + dcr = new_dcr(rctx.jcr, rctx.jcr->dcr, rctx.device->dev, NULL); } else { - dcr = new_dcr(rctx.jcr, rctx.jcr->read_dcr, rctx.device->dev); + dcr = new_dcr(rctx.jcr, rctx.jcr->read_dcr, rctx.device->dev, NULL); } if (!dcr) { BSOCK *dir = rctx.jcr->dir_bsock; diff --git a/src/stored/sd_plugins.c b/src/stored/sd_plugins.c index 4de52080bee..55d27758ca1 100644 --- a/src/stored/sd_plugins.c +++ b/src/stored/sd_plugins.c @@ -30,7 +30,7 @@ #include "sd_plugins.h" #include "lib/crypto_cache.h" -const int dbglvl = 150; +const int dbglvl = 250; const char *plugin_type = "-sd.so"; static alist *sd_plugin_list = NULL; diff --git a/src/stored/spool.c b/src/stored/spool.c index 4b28468dd40..840dec345eb 100644 --- a/src/stored/spool.c +++ b/src/stored/spool.c @@ -262,7 +262,7 @@ 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, NULL, rdev); + rdcr = new_dcr(jcr, NULL, rdev, NULL); rdcr->spool_fd = dcr->spool_fd; block = dcr->block; /* save block */ dcr->block = rdcr->block; /* make read and write block the same */ diff --git a/src/stored/stored.c b/src/stored/stored.c index 202c1f2fed6..039419eed8f 100644 --- a/src/stored/stored.c +++ b/src/stored/stored.c @@ -629,7 +629,7 @@ void *device_initialization(void *arg) continue; } - jcr->dcr = dcr = new_dcr(jcr, NULL, dev); + jcr->dcr = dcr = new_dcr(jcr, NULL, dev, NULL); generate_plugin_event(jcr, bsdEventDeviceInit, dcr); if (dev->is_autochanger()) { /* If autochanger set slot in dev structure */ diff --git a/src/stored/stored.h b/src/stored/stored.h index 9d3b6395115..eff5c969d5e 100644 --- a/src/stored/stored.h +++ b/src/stored/stored.h @@ -62,6 +62,7 @@ const int sd_dbglvl = 300; #include "jcr.h" #include "vol_mgr.h" #include "reserve.h" + #include "protos.h" #ifdef HAVE_FNMATCH #include diff --git a/src/stored/stored_conf.c b/src/stored/stored_conf.c index 9bd13b0f0d2..91436bfcc61 100644 --- a/src/stored/stored_conf.c +++ b/src/stored/stored_conf.c @@ -196,6 +196,7 @@ static RES_ITEM dev_items[] = { { "maximumnetworkbuffersize", store_pint32, ITEM(res_dev.max_network_buffer_size), 0, 0, NULL }, { "volumepollinterval", store_time, ITEM(res_dev.vol_poll_interval), 0, ITEM_DEFAULT, "300" /* 5 minutes */ }, { "maximumrewindwait", store_time, ITEM(res_dev.max_rewind_wait), 0, ITEM_DEFAULT, "300" /* 5 minutes */ }, + { "labelblocksize", store_pint32, ITEM(res_dev.label_block_size), 0, ITEM_DEFAULT, "64512"/* DEFAULT_BLOCK_SIZE */ }, { "minimumblocksize", store_pint32, ITEM(res_dev.min_block_size), 0, 0, NULL }, { "maximumblocksize", store_maxblocksize, ITEM(res_dev.max_block_size), 0, 0, NULL }, { "maximumvolumesize", store_size64, ITEM(res_dev.max_volume_size), 0, ITEM_DEPRECATED, NULL }, diff --git a/src/stored/stored_conf.h b/src/stored/stored_conf.h index 04dea0f9901..a134be47bad 100644 --- a/src/stored/stored_conf.h +++ b/src/stored/stored_conf.h @@ -157,8 +157,9 @@ class DEVRES { utime_t max_rewind_wait; /* Maximum secs to wait for rewind */ utime_t max_open_wait; /* Maximum secs to wait for open */ uint32_t max_open_vols; /* Maximum simultaneous open volumes */ - uint32_t min_block_size; /* Min block size */ - uint32_t max_block_size; /* Max block size */ + uint32_t label_block_size; /* block size of the label block*/ + uint32_t min_block_size; /* Current Minimum block size */ + uint32_t max_block_size; /* Current Maximum block size */ uint32_t max_volume_jobs; /* Max jobs to put on one volume */ uint32_t max_network_buffer_size; /* Max network buf size */ uint32_t max_concurrent_jobs; /* Maximum concurrent jobs this drive */