+ alist *dirstore;
+ DCR *dcr = jcr->dcr;
+
+ if (rctx.append) {
+ dirstore = jcr->write_store;
+ } else {
+ dirstore = jcr->read_store;
+ }
+ Dmsg5(dbglvl, "Start find_suit_dev PrefMnt=%d exact=%d suitable=%d chgronly=%d any=%d\n",
+ rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
+ rctx.autochanger_only, rctx.any_drive);
+
+ /*
+ * If the appropriate conditions of this if are met, namely that
+ * we are appending and the user wants mounted drive (or we
+ * force try a mounted drive because they are all busy), we
+ * start by looking at all the Volumes in the volume list.
+ */
+ if (!vol_list->empty() && rctx.append && rctx.PreferMountedVols) {
+ dlist *temp_vol_list, *save_vol_list;
+ VOLRES *vol = NULL;
+ lock_volumes();
+ Dmsg0(dbglvl, "lock volumes\n");
+
+ /*
+ * Create a temporary copy of the volume list. We do this,
+ * to avoid having the volume list locked during the
+ * call to reserve_device(), which would cause a deadlock.
+ * Note, we may want to add an update counter on the vol_list
+ * so that if it is modified while we are traversing the copy
+ * we can take note and act accordingly (probably redo the
+ * search at least a few times).
+ */
+ Dmsg0(dbglvl, "duplicate vol list\n");
+ temp_vol_list = New(dlist(vol, &vol->link));
+ foreach_dlist(vol, vol_list) {
+ VOLRES *nvol;
+ VOLRES *tvol = (VOLRES *)malloc(sizeof(VOLRES));
+ memset(tvol, 0, sizeof(VOLRES));
+ tvol->vol_name = bstrdup(vol->vol_name);
+ tvol->dev = vol->dev;
+ nvol = (VOLRES *)temp_vol_list->binary_insert(tvol, my_compare);
+ if (tvol != nvol) {
+ tvol->dev = NULL; /* don't zap dev entry */
+ free_vol_item(tvol);
+ Pmsg0(000, "Logic error. Duplicating vol list hit duplicate.\n");
+ Jmsg(jcr, M_WARNING, 0, "Logic error. Duplicating vol list hit duplicate.\n");
+ }
+ }
+ Dmsg0(dbglvl, "unlock volumes\n");
+ unlock_volumes();
+
+ /* Look through reserved volumes for one we can use */
+ Dmsg0(dbglvl, "look for vol in vol list\n");
+ foreach_dlist(vol, temp_vol_list) {
+ if (!vol->dev) {
+ Dmsg1(dbglvl, "vol=%s no dev\n", vol->vol_name);
+ continue;
+ }
+ /* Check with Director if this Volume is OK */
+ bstrncpy(dcr->VolumeName, vol->vol_name, sizeof(dcr->VolumeName));
+ if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE)) {
+ continue;
+ }
+
+ Dmsg1(dbglvl, "vol=%s OK for this job\n", vol->vol_name);
+ foreach_alist(store, dirstore) {
+ int stat;
+ rctx.store = store;
+ foreach_alist(device_name, store->device) {
+ /* Found a device, try to use it */
+ rctx.device_name = device_name;
+ rctx.device = vol->dev->device;
+
+ if (vol->dev->is_autochanger()) {
+ Dmsg1(dbglvl, "vol=%s is in changer\n", vol->vol_name);
+ if (!is_vol_in_autochanger(rctx, vol)) {
+ continue;
+ }
+ } else if (strcmp(device_name, vol->dev->device->hdr.name) != 0) {
+ Dmsg2(dbglvl, "device=%s not suitable want %s\n",
+ vol->dev->device->hdr.name, device_name);
+ continue;
+ }
+
+ bstrncpy(rctx.VolumeName, vol->vol_name, sizeof(rctx.VolumeName));
+ rctx.have_volume = true;
+ /* Try reserving this device and volume */
+ Dmsg2(dbglvl, "try vol=%s on device=%s\n", rctx.VolumeName, device_name);
+ stat = reserve_device(rctx);
+ if (stat == 1) { /* found available device */
+ Dmsg1(dbglvl, "Suitable device found=%s\n", device_name);
+ ok = true;
+ break;
+ } else if (stat == 0) { /* device busy */
+ Dmsg1(dbglvl, "Suitable device=%s, busy: not use\n", device_name);
+ } else {
+ /* otherwise error */
+ Dmsg0(dbglvl, "No suitable device found.\n");
+ }
+ rctx.have_volume = false;
+ rctx.VolumeName[0] = 0;
+ }
+ if (ok) {
+ break;
+ }
+ }
+ if (ok) {
+ break;
+ }
+ } /* end for loop over reserved volumes */
+
+ Dmsg0(dbglvl, "lock volumes\n");
+ lock_volumes();
+ save_vol_list = vol_list;
+ vol_list = temp_vol_list;
+ free_volume_list(); /* release temp_vol_list */
+ vol_list = save_vol_list;
+ Dmsg0(dbglvl, "deleted temp vol list\n");
+ Dmsg0(dbglvl, "unlock volumes\n");
+ unlock_volumes();
+ debug_list_volumes("after free temp table");
+ }
+ if (ok) {
+ Dmsg1(dbglvl, "OK dev found. Vol=%s from in-use vols list\n", rctx.VolumeName);
+ return true;
+ }