Suggestions for Preben:
- Look at adding Client run command that will use the
port opened by the client.
-- Implement WildFile and WildDir to solve problem of
- saving only *.doc files.
-- Bootstrap from JobMedia records.
- Optimized bootstrap.
Autochangers:
-- Locking (done)
-- Key on Storage rather than Pool (done)
-- Allow multiple drives to use same Pool
-- Synchronize multiple drives so that no more
- than one loads a tape and any time.
+- Copy Changer Device and Changer Command from Autochanger
+ to Device resource in SD if none given in Device resource.
- Doc the following
to activate, check or disable the hardware compression feature on my
exb-8900 i use the exabyte "MammothTool" you can get it here:
There is a solaris version of this tool. With option -C 0 or 1 you can
disable or activate compression. Start this tool without any options for
a small reference.
+- 3.Prevent two drives requesting the same Volume in any given
+ autochanger.
+- 4. Use Changer Device and Changer Command specified in the
+ Autochanger resource, if none is found in the Device resource.
+ You can continue to specify them in the Device resource if you want
+ or need them to be different for each device.
+- 5. Implement a new Device directive (perhaps "Autoselect = yes/no")
+ that can allow a Device be part of an Autochanger, and hence the changer
+ script protected, but if set to no, will prevent the Device from being
+ automatically selected from the changer. This allows the device to
+ be directly accessed through its Device name, but not through the
+ AutoChanger name.
+- 7. Implement new Console commands to allow offlining/reserving drives,
+ and possibly manipulating the autochanger (much asked for).
+- 8. Automatic updating of Drive status from SD to DIR when something
+ changes (Volume, offline, append, read, ...).
+
+Autochangers Done:
+- 1. Automatic use of more than one drive in an autochanger (done)
+- 2. Automatic selection of the correct drive for each Job (i.e.
+ selects a drive with an appropriate Volume for the Job) (done)
+- 6. Allow multiple simultaneous Jobs referencing the same pool write
+ to several tapes (some new directive(s) are are probably needed for
+ this) (done)
+- Locking (done)
+- Key on Storage rather than Pool (done)
+- Allow multiple drives to use same Pool (change jobq.c DIR) (done).
+- Synchronize multiple drives so that not more
+ than one loads a tape and any time (done)
For 1.37:
> ..\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.
+ Restore restores all files, but then fails at the end trying
+ to set the attributes of e:
- Add better documentation on how restores can be done
from failed jobs.
- Resolve the problem between Device name and Archive name,
for operator intervention.
- Cancel command should include JobId in list of Jobs.
- Add performance testing hooks
+- Bootstrap from JobMedia records.
+- Implement WildFile and WildDir to solve problem of
+ saving only *.doc files.
+
bool labeled;
bool autochanger;
bool offline;
+ bool autoselect;
+ char ChangerName[MAX_NAME_LENGTH];
char VolumeName[MAX_NAME_LENGTH];
char MediaType[MAX_NAME_LENGTH];
};
int64_t StorageId; /* Set from Storage DB record */
+ /* Methods */
char *dev_name() const;
char *name() const;
};
/* Simple case, first job */
jcr->store->NumConcurrentJobs = 1;
} else if (jcr->store->NumConcurrentJobs < jcr->store->MaxConcurrentJobs) {
- /*
- * At this point, we already have at least one Job running
- * for this Storage daemon, so we must ensure that there
- * is no Volume conflict. In general, it should be OK, if
- * all Jobs pull from the same Pool, so we check the Pools.
- */
- JCR *njcr;
- lock_jcr_chain();
- for (njcr=jobs; njcr; njcr=njcr->next) {
- if (njcr->JobId == 0 || njcr == jcr) {
- continue;
- }
- if (njcr->pool != jcr->pool) {
- skip_this_jcr = true;
- break;
- }
- }
- unlock_jcr_chain();
- if (!skip_this_jcr) {
- jcr->store->NumConcurrentJobs++;
- }
+ jcr->store->NumConcurrentJobs++;
} else {
skip_this_jcr = true;
}
set_jcr_job_status(jcr, JS_WaitJobRes);
return false;
}
+ /* Check actual device availability */
+ /* ***FIXME****/
return true;
}
/* Response from Storage daemon */
static char OKjob[] = "3000 OK Job SDid=%d SDtime=%d Authorization=%100s\n";
-static char OK_device[] = "3000 OK use device\n";
+static char OK_device[] = "3000 OK use device device=%s\n";
static char OK_query[] = "3001 OK query append=%d read=%d num_writers=%d "
- "num_waiting=%d open=%d use_count=%d labeled=%d offline=%d autochanger=%d "
- "media_type=%127s volume_name=%127s";
+ "num_waiting=%d open=%d use_count=%d labeled=%d offline=%d "
+ "autoselect=%d autochanger=%d "
+ "changer_name=%127s media_type=%127s volume_name=%127s";
/* Storage Daemon requests */
static char Job_start[] = "3010 Job %127s start\n";
*/
bool update_device_res(JCR *jcr, DEVICE *dev)
{
- POOL_MEM device_name, media_type, volume_name;
+ POOL_MEM device_name, changer_name, media_type, volume_name;
int dev_open, dev_append, dev_read, dev_labeled;
- int dev_offline, dev_autochanger;
+ int dev_offline, dev_autochanger, dev_autoselect;
BSOCK *sd;
if (!connect_to_storage_daemon(jcr, 5, 30, 0)) {
return false;
Dmsg1(400, "<stored: %s", sd->msg);
if (sscanf(sd->msg, OK_query, &dev_append, &dev_read,
&dev->num_writers, &dev->num_waiting, &dev_open,
- &dev->use_count, &dev_labeled, &dev_offline,
- &dev_autochanger, media_type.c_str(),
- volume_name.c_str()) != 11) {
+ &dev->use_count, &dev_labeled, &dev_offline, &dev_autoselect,
+ &dev_autochanger, changer_name.c_str(), media_type.c_str(),
+ volume_name.c_str()) != 13) {
return false;
}
+ unbash_spaces(changer_name);
unbash_spaces(media_type);
unbash_spaces(volume_name);
+ bstrncpy(dev->ChangerName, changer_name.c_str(), sizeof(dev->ChangerName));
bstrncpy(dev->MediaType, media_type.c_str(), sizeof(dev->MediaType));
bstrncpy(dev->VolumeName, volume_name.c_str(), sizeof(dev->VolumeName));
dev->open = dev_open;
dev->read = dev_read;
dev->labeled = dev_labeled;
dev->offline = dev_offline;
+ dev->autoselect = dev_autoselect;
dev->autochanger = dev_autochanger;
dev->found = true;
} else {
media_type.c_str(), pool_name.c_str(), pool_type.c_str(),
append);
Dmsg1(200, ">stored: %s", sd->msg);
- ok = response(jcr, sd, OK_device, "Use Device", NO_DISPLAY);
- if (!ok) {
- pm_strcpy(pool_type, sd->msg); /* save message */
+ if (bget_dirmsg(sd) > 0) {
+ Dmsg1(400, "<stored: %s", sd->msg);
+ ok = sscanf(sd->msg, OK_device, device_name.c_str()) == 1;
+ } else {
+ POOL_MEM err_msg;
+ ok = false;
+ pm_strcpy(err_msg, sd->msg); /* save message */
Jmsg(jcr, M_FATAL, 0, _("\n"
" Storage daemon didn't accept Device \"%s\" because:\n %s"),
- device_name.c_str(), pool_type.c_str()/* sd->msg */);
+ device_name.c_str(), err_msg.c_str()/* sd->msg */);
}
// }
if (ok) {
/*
* At user request modify parameters of job to be run.
*/
- if (ua->cmd[0] == 0) {
- goto bail_out;
- }
- if (strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
+ if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
FILE *fd;
start_prompt(ua, _("Parameters to modify:\n"));
goto bail_out;
}
- if (strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
+ if (ua->cmd[0] == 0 || strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
JobId_t JobId;
Dmsg1(800, "Calling run_job job=%x\n", jcr->job);
start_job:
if (dev) {
dev->dev_errno = errno;
}
- Jmsg2(jcr, M_FATAL, 0, _("Unable to stat device %s: ERR=%s\n"),
+ Jmsg2(jcr, M_ERROR, 0, _("Unable to stat device %s: ERR=%s\n"),
device->device_name, be.strerror());
return NULL;
}
if (dev) {
dev->dev_errno = ENODEV;
}
- Jmsg2(jcr, M_FATAL, 0, _("%s is an unknown device type. Must be tape or directory. st_mode=%x\n"),
+ Jmsg2(jcr, M_ERROR, 0, _("%s is an unknown device type. Must be tape or directory. st_mode=%x\n"),
device->device_name, statp.st_mode);
return NULL;
}
if (stat(device->mount_point, &statp) < 0) {
berrno be;
dev->dev_errno = errno;
- Jmsg2(jcr, M_FATAL, 0, _("Unable to stat mount point %s: ERR=%s\n"),
+ Jmsg2(jcr, M_ERROR, 0, _("Unable to stat mount point %s: ERR=%s\n"),
device->mount_point, be.strerror());
return NULL;
}
int dev_errno; /* Our own errno */
int mode; /* read/write modes */
int openmode; /* parameter passed to open_dev (useful to reopen the device) */
+ bool autoselect; /* Autoselect in autochanger */
int label_type; /* Bacula/ANSI/IBM label types */
uint32_t drive_index; /* Autochanger drive index */
POOLMEM *dev_name; /* device name */
int rem_wait_sec;
int num_wait;
+ /* Methods */
int is_tape() const;
int is_file() const;
int is_fifo() const;
/* Responses sent to Director daemon */
static char OKjob[] = "3000 OK Job SDid=%u SDtime=%u Authorization=%s\n";
-static char OK_device[] = "3000 OK use device\n";
+static char OK_device[] = "3000 OK use device device=%s\n";
static char NO_device[] = "3924 Device \"%s\" not in SD Device resources.\n";
static char NOT_open[] = "3925 Device \"%s\" could not be opened or does not exist.\n";
static char BAD_use[] = "3913 Bad use command: %s\n";
static char BAD_job[] = "3915 Bad Job command: %s\n";
static char OK_query[] = "3001 OK query append=%d read=%d num_writers=%d "
- "num_waiting=%d open=%d use_count=%d labeled=%d offline=%d autochanger=%d "
- "media_type=%s volume_name=%s";
+ "num_waiting=%d open=%d use_count=%d labeled=%d offline=%d "
+ "autoselect=%d autochanger=%d "
+ "changer_name=%s media_type=%s volume_name=%s";
static char BAD_query[] = "3917 Bad query command: %s\n";
/*
/*
* Wait for the device, media, and pool information
*/
+ Dmsg1(100, "Use_cmd: %s\n", jcr->dir_bsock->msg);
if (!use_device_cmd(jcr)) {
set_jcr_job_status(jcr, JS_ErrorTerminated);
memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
struct timespec timeout;
int errstat;
+ Dmsg1(100, "Run_cmd: %s\n", jcr->dir_bsock->msg);
/* The following jobs don't need the FD */
switch (jcr->JobType) {
case JT_MIGRATION:
POOL_MEM dev_name, media_type, pool_name, pool_type;
BSOCK *dir = jcr->dir_bsock;
DEVRES *device;
+ AUTOCHANGER *changer;
int append;
bool ok;
- Dmsg1(120, "Use device: %s", dir->msg);
+ Dmsg1(100, "Use_device_cmd: %s", jcr->dir_bsock->msg);
/*
* If there are multiple devices, the director sends us
* use_device for each device that it wants to use.
}
if (!device->dev) {
Jmsg(jcr, M_FATAL, 0, _("\n"
- " Archive \"%s\" requested by DIR could not be opened or does not exist.\n"),
+ " Device \"%s\" requested by DIR could not be opened or does not exist.\n"),
dev_name.c_str());
bnet_fsend(dir, NOT_open, dev_name.c_str());
return false;
bnet_fsend(dir, _("3926 Could not get dcr for device: %s\n"), dev_name.c_str());
return false;
}
- Dmsg1(120, "Found device %s\n", device->hdr.name);
+ Dmsg1(100, "Found device %s\n", device->hdr.name);
bstrncpy(dcr->pool_name, pool_name, name_len);
bstrncpy(dcr->pool_type, pool_type, name_len);
bstrncpy(dcr->media_type, media_type, name_len);
return false;
}
Dmsg1(220, "Got: %s", dir->msg);
- return bnet_fsend(dir, OK_device);
+ bash_spaces(dev_name);
+ return bnet_fsend(dir, OK_device, dev_name.c_str());
}
}
+
+ foreach_res(changer, R_AUTOCHANGER) {
+ /* Find resource, and make sure we were able to open it */
+ if (fnmatch(dev_name.c_str(), changer->hdr.name, 0) == 0) {
+ const int name_len = MAX_NAME_LENGTH;
+ DCR *dcr;
+ /* Try each device in this AutoChanger */
+ foreach_alist(device, changer->device) {
+ Dmsg1(100, "Try changer device %s\n", device->hdr.name);
+ if (!device->dev) {
+ device->dev = init_dev(jcr, NULL, device);
+ }
+ if (!device->dev) {
+ Dmsg1(100, "Device %s could not be opened. Skipped\n", dev_name.c_str());
+ Jmsg(jcr, M_WARNING, 0, _("\n"
+ " Device \"%s\" in changer \"%s\" requested by DIR could not be opened or does not exist.\n"),
+ device->hdr.name, dev_name.c_str());
+ continue;
+ }
+ dcr = new_dcr(jcr, device->dev);
+ if (!dcr) {
+ bnet_fsend(dir, _("3926 Could not get dcr for device: %s\n"), dev_name.c_str());
+ UnlockRes();
+ return false;
+ }
+ Dmsg1(100, "Found changer device %s\n", device->hdr.name);
+ bstrncpy(dcr->pool_name, pool_name, name_len);
+ bstrncpy(dcr->pool_type, pool_type, name_len);
+ bstrncpy(dcr->media_type, media_type, name_len);
+ bstrncpy(dcr->dev_name, dev_name, name_len);
+ jcr->dcr = dcr;
+ if (append == SD_APPEND) {
+ ok = reserve_device_for_append(jcr, device->dev);
+ } else {
+ ok = reserve_device_for_read(jcr, device->dev);
+ }
+ if (!ok) {
+ Jmsg(jcr, M_WARNING, 0, _("Could not reserve device: %s\n"), dev_name.c_str());
+ free_dcr(jcr->dcr);
+ continue;
+ }
+ Dmsg1(100, "Device %s opened.\n", dev_name.c_str());
+ UnlockRes();
+ pm_strcpy(dev_name, device->hdr.name);
+ bash_spaces(dev_name);
+ return bnet_fsend(dir, OK_device, dev_name.c_str());
+ }
+ break; /* we found it but could not open a device */
+ }
+ }
+
UnlockRes();
if (verbose) {
unbash_spaces(dir->msg);
*/
bool query_cmd(JCR *jcr)
{
- POOL_MEM dev_name;
+ POOL_MEM dev_name;
BSOCK *dir = jcr->dir_bsock;
DEVRES *device;
+ AUTOCHANGER *changer;
bool ok;
- Dmsg1(120, "Query: %s", dir->msg);
+ Dmsg1(100, "Query_cmd: %s", dir->msg);
ok = sscanf(dir->msg, query_device, dev_name.c_str()) == 1;
if (ok) {
break;
}
DEVICE *dev = device->dev;
- POOL_MEM VolumeName, MediaType;
+ POOL_MEM VolumeName, MediaType, ChangerName;
UnlockRes();
if (dev->is_labeled()) {
pm_strcpy(VolumeName, dev->VolHdr.VolName);
bash_spaces(VolumeName);
pm_strcpy(MediaType, device->media_type);
bash_spaces(MediaType);
+ if (device->changer_res) {
+ pm_strcpy(ChangerName, device->changer_res->hdr.name);
+ bash_spaces(ChangerName);
+ } else {
+ pm_strcpy(ChangerName, "");
+ }
return bnet_fsend(dir, OK_query, dev->can_append()!=0,
dev->can_read()!=0, dev->num_writers, dev->num_waiting,
dev->is_open()!=0, dev->use_count, dev->is_labeled()!=0,
- dev->is_offline()!=0, device->changer_res!=NULL,
- MediaType.c_str(), VolumeName.c_str());
+ dev->is_offline()!=0, 0, dev->autoselect,
+ ChangerName.c_str(), MediaType.c_str(), VolumeName.c_str());
}
}
+ foreach_res(changer, R_AUTOCHANGER) {
+ /* Find resource, and make sure we were able to open it */
+ if (fnmatch(dev_name.c_str(), changer->hdr.name, 0) == 0) {
+ UnlockRes();
+ /* This is mostly to indicate that we are here */
+ return bnet_fsend(dir, OK_query, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 1, "*", /* Set AutoChanger = 1 */
+ "*", "*");
+ }
+ }
+ /* If we get here, the device/autochanger was not found */
UnlockRes();
unbash_spaces(dir->msg);
pm_strcpy(jcr->errmsg, dir->msg);
pm_strcpy(jcr->errmsg, dir->msg);
bnet_fsend(dir, BAD_query, jcr->errmsg);
}
+
return true;
}
/* */
#undef VERSION
#define VERSION "1.37.4"
-#define BDATE "28 February 2005"
-#define LSMDATE "28Feb05"
+#define BDATE "01 March 2005"
+#define LSMDATE "01Mar05"
/* Debug flags */
#undef DEBUG