2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from many
7 others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 Bacula® is a registered trademark of Kern Sibbald.
18 * dev.c -- low level operations on device (storage device)
20 * written by, Kern Sibbald, MM
22 * NOTE!!!! None of these routines are reentrant. You must
23 * use dev->rLock() and dev->Unlock() at a higher level,
24 * or use the xxx_device() equivalents. By moving the
25 * thread synchronization to a higher level, we permit
26 * the higher level routines to "seize" the device and
27 * to carry out operations without worrying about who
28 * set what lock (i.e. race conditions).
30 * Note, this is the device dependent code, and may have
31 * to be modified for each system, but is meant to
32 * be as "generic" as possible.
34 * The purpose of this code is to develop a SIMPLE Storage
35 * daemon. More complicated coding (double buffering, writer
36 * thread, ...) is left for a later version.
41 * Handling I/O errors and end of tape conditions are a bit tricky.
42 * This is how it is currently done when writing.
43 * On either an I/O error or end of tape,
44 * we will stop writing on the physical device (no I/O recovery is
45 * attempted at least in this daemon). The state flag will be sent
46 * to include ST_EOT, which is ephemeral, and ST_WEOT, which is
47 * persistent. Lots of routines clear ST_EOT, but ST_WEOT is
48 * cleared only when the problem goes away. Now when ST_WEOT
49 * is set all calls to write_block_to_device() call the fix_up
50 * routine. In addition, all threads are blocked
51 * from writing on the tape by calling lock_dev(), and thread other
52 * than the first thread to hit the EOT will block on a condition
53 * variable. The first thread to hit the EOT will continue to
54 * be able to read and write the tape (he sort of tunnels through
55 * the locking mechanism -- see lock_dev() for details).
57 * Now presumably somewhere higher in the chain of command
58 * (device.c), someone will notice the EOT condition and
59 * get a new tape up, get the tape label read, and mark
60 * the label for rewriting. Then this higher level routine
61 * will write the unwritten buffer to the new volume.
62 * Finally, he will release
63 * any blocked threads by doing a broadcast on the condition
64 * variable. At that point, we should be totally back in
65 * business with no lost data.
75 /* Imported functions */
76 extern void set_os_device_parameters(DCR *dcr);
77 extern bool dev_get_os_pos(DEVICE *dev, struct mtget *mt_stat);
78 extern uint32_t status_dev(DEVICE *dev);
80 /* Forward referenced functions */
81 const char *mode_to_str(int mode);
82 DEVICE *m_init_dev(JCR *jcr, DEVRES *device, bool alt);
84 * Device types for printing
86 static const char *prt_dev_types[] = {
99 * Allocate and initialize the DEVICE structure
100 * Note, if dev is non-NULL, it is already allocated,
101 * thus we neither allocate it nor free it. This allows
102 * the caller to put the packet in shared memory.
104 * Note, for a tape, the device->device_name is the device name
105 * (e.g. /dev/nst0), and for a file, the device name
106 * is the directory in which the file will be placed.
109 DEVICE *init_dev(JCR *jcr, DEVRES *device)
111 generate_global_plugin_event(bsdGlobalEventDeviceInit, device);
112 DEVICE *dev = m_init_dev(jcr, device, false);
116 DEVICE *m_init_dev(JCR *jcr, DEVRES *device, bool alt)
124 /* If no device type specified, try to guess */
125 if (!device->dev_type) {
126 /* Check that device is available */
127 if (stat(device->device_name, &statp) < 0) {
129 Jmsg2(jcr, M_ERROR, 0, _("Unable to stat device %s: ERR=%s\n"),
130 device->device_name, be.bstrerror());
133 if (S_ISDIR(statp.st_mode)) {
134 device->dev_type = B_FILE_DEV;
135 } else if (S_ISCHR(statp.st_mode)) {
136 device->dev_type = B_TAPE_DEV;
137 } else if (S_ISFIFO(statp.st_mode)) {
138 device->dev_type = B_FIFO_DEV;
140 /* must set DeviceType = Vtape
141 * in normal mode, autodetection is disabled
143 } else if (S_ISREG(statp.st_mode)) {
144 device->dev_type = B_VTAPE_DEV;
146 } else if (!(device->cap_bits & CAP_REQMOUNT)) {
147 Jmsg2(jcr, M_ERROR, 0, _("%s is an unknown device type. Must be tape or directory\n"
148 " or have RequiresMount=yes for DVD. st_mode=%x\n"),
149 device->device_name, statp.st_mode);
152 device->dev_type = B_DVD_DEV;
155 switch (device->dev_type) {
157 Jmsg0(jcr, M_FATAL, 0, _("DVD support is now deprecated.\n"));
160 Jmsg0(jcr, M_FATAL, 0, _("Aligned device not supported. Please use \"DeviceType = File\"\n"));
167 dev = New(ftp_device);
171 /* TODO: defined in src/win32/stored/mtops.cpp */
173 dev = New(win_tape_dev);
176 dev = New(win_file_dev);
191 dev->clear_slot(); /* unknown */
193 /* Copy user supplied device parameters from Resource */
194 dev->dev_name = get_memory(strlen(device->device_name)+1);
195 pm_strcpy(dev->dev_name, device->device_name);
196 dev->prt_name = get_memory(strlen(device->device_name) + strlen(device->hdr.name) + 20);
197 /* We edit "Resource-name" (physical-name) */
198 Mmsg(dev->prt_name, "\"%s\" (%s)", device->hdr.name, device->device_name);
199 Dmsg1(400, "Allocate dev=%s\n", dev->print_name());
200 dev->capabilities = device->cap_bits;
201 dev->min_block_size = device->min_block_size;
202 dev->max_block_size = device->max_block_size;
203 dev->max_volume_size = device->max_volume_size;
204 dev->max_file_size = device->max_file_size;
205 dev->max_concurrent_jobs = device->max_concurrent_jobs;
206 dev->volume_capacity = device->volume_capacity;
207 dev->max_rewind_wait = device->max_rewind_wait;
208 dev->max_open_wait = device->max_open_wait;
209 dev->vol_poll_interval = device->vol_poll_interval;
210 dev->max_spool_size = device->max_spool_size;
211 dev->drive_index = device->drive_index;
212 dev->autoselect = device->autoselect;
213 dev->read_only = device->read_only;
214 dev->dev_type = device->dev_type;
215 dev->device = device;
216 if (dev->is_tape()) { /* No parts on tapes */
217 dev->max_part_size = 0;
219 dev->max_part_size = device->max_part_size;
222 if (dev->vol_poll_interval && dev->vol_poll_interval < 60) {
223 dev->vol_poll_interval = 60;
226 * ***FIXME*** remove this when we implement write device
229 * We limit aligned Jobs to run one at a time.
230 * This is required because:
231 * 1. BlockAddr must be local for each JCR, today it
233 * 2. When flushing buffers, all other processes must
234 * be locked out, and they currently are not.
235 * 3. We need to reserve the full space for a job, but
236 * currently space for only one block is reserved.
237 * 4. In the case that the file grows, we must be able
238 * to create multiple references to the correct data
239 * blocks, if they are not contiguous.
244 if (dev->is_fifo()) {
245 dev->capabilities |= CAP_STREAM; /* set stream device */
248 /* If the device requires mount :
249 * - Check that the mount point is available
250 * - Check that (un)mount commands are defined
252 if (dev->is_file() && dev->requires_mount()) {
253 if (!device->mount_point || stat(device->mount_point, &statp) < 0) {
255 dev->dev_errno = errno;
256 Jmsg2(jcr, M_ERROR_TERM, 0, _("Unable to stat mount point %s: ERR=%s\n"),
257 device->mount_point, be.bstrerror());
260 if (!device->mount_command || !device->unmount_command) {
261 Jmsg0(jcr, M_ERROR_TERM, 0, _("Mount and unmount commands must defined for a device which requires mount.\n"));
266 if (dev->max_block_size == 0) {
267 max_bs = DEFAULT_BLOCK_SIZE;
269 max_bs = dev->max_block_size;
271 if (dev->min_block_size > max_bs) {
272 Jmsg(jcr, M_ERROR_TERM, 0, _("Min block size > max on device %s\n"),
275 if (dev->max_block_size > 4096000) {
276 Jmsg3(jcr, M_ERROR, 0, _("Block size %u on device %s is too large, using default %u\n"),
277 dev->max_block_size, dev->print_name(), DEFAULT_BLOCK_SIZE);
278 dev->max_block_size = 0;
280 if (dev->max_block_size % TAPE_BSIZE != 0) {
281 Jmsg3(jcr, M_WARNING, 0, _("Max block size %u not multiple of device %s block size=%d.\n"),
282 dev->max_block_size, dev->print_name(), TAPE_BSIZE);
284 if (dev->max_volume_size != 0 && dev->max_volume_size < (dev->max_block_size << 4)) {
285 Jmsg(jcr, M_ERROR_TERM, 0, _("Max Vol Size < 8 * Max Block Size for device %s\n"),
289 dev->errmsg = get_pool_memory(PM_EMSG);
292 if ((errstat = dev->init_mutex()) != 0) {
294 dev->dev_errno = errstat;
295 Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat));
296 Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
298 if ((errstat = pthread_cond_init(&dev->wait, NULL)) != 0) {
300 dev->dev_errno = errstat;
301 Mmsg1(dev->errmsg, _("Unable to init cond variable: ERR=%s\n"), be.bstrerror(errstat));
302 Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
304 if ((errstat = pthread_cond_init(&dev->wait_next_vol, NULL)) != 0) {
306 dev->dev_errno = errstat;
307 Mmsg1(dev->errmsg, _("Unable to init cond variable: ERR=%s\n"), be.bstrerror(errstat));
308 Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
310 if ((errstat = pthread_mutex_init(&dev->spool_mutex, NULL)) != 0) {
312 dev->dev_errno = errstat;
313 Mmsg1(dev->errmsg, _("Unable to init spool mutex: ERR=%s\n"), be.bstrerror(errstat));
314 Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
316 if ((errstat = dev->init_acquire_mutex()) != 0) {
318 dev->dev_errno = errstat;
319 Mmsg1(dev->errmsg, _("Unable to init acquire mutex: ERR=%s\n"), be.bstrerror(errstat));
320 Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
322 if ((errstat = dev->init_read_acquire_mutex()) != 0) {
324 dev->dev_errno = errstat;
325 Mmsg1(dev->errmsg, _("Unable to init read acquire mutex: ERR=%s\n"), be.bstrerror(errstat));
326 Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
328 if ((errstat = dev->init_volcat_mutex()) != 0) {
330 dev->dev_errno = errstat;
331 Mmsg1(dev->errmsg, _("Unable to init volcat mutex: ERR=%s\n"), be.bstrerror(errstat));
332 Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
334 if ((errstat = dev->init_dcrs_mutex()) != 0) {
336 dev->dev_errno = errstat;
337 Mmsg1(dev->errmsg, _("Unable to init dcrs mutex: ERR=%s\n"), be.bstrerror(errstat));
338 Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
341 dev->set_mutex_priorities();
344 if ((errstat = rwl_init(&dev->lock)) != 0) {
346 dev->dev_errno = errstat;
347 Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat));
348 Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
353 dev->attached_dcrs = New(dlist(dcr, &dcr->dev_link));
354 Dmsg2(100, "init_dev: tape=%d dev_name=%s\n", dev->is_tape(), dev->dev_name);
355 dev->initiated = true;
361 * Open the device with the operating system and
362 * initialize buffer pointers.
364 * Returns: true on success
367 * Note, for a tape, the VolName is the name we give to the
368 * volume (not really used here), but for a file, the
369 * VolName represents the name of the file to be created/opened.
370 * In the case of a file, the full name is the device name
371 * (archive_name) with the VolName concatenated.
373 bool DEVICE::open(DCR *dcr, int omode)
377 if (openmode == omode) {
380 Dmsg1(200, "Close fd=%d for mode change in open().\n", m_fd);
383 preserve = state & (ST_LABEL|ST_APPEND|ST_READ);
387 dcr->setVolCatName(dcr->VolumeName);
388 VolCatInfo = dcr->VolCatInfo; /* structure assign */
391 state &= ~(ST_NOSPACE|ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF);
392 label_type = B_BACULA_LABEL;
394 if (is_tape() || is_fifo()) {
395 open_tape_device(dcr, omode);
396 } else if (is_ftp()) {
397 this->open_device(dcr, omode);
399 Dmsg1(100, "call open_file_device mode=%s\n", mode_to_str(omode));
400 open_file_device(dcr, omode);
402 state |= preserve; /* reset any important state info */
403 Dmsg2(100, "preserve=0x%x fd=%d\n", preserve, m_fd);
405 Dmsg7(100, "open dev: fd=%d dev=%p dcr=%p vol=%s type=%d dev_name=%s mode=%s\n",
406 m_fd, getVolCatName(), this, dcr, dev_type, print_name(), mode_to_str(omode));
410 void DEVICE::set_mode(int new_mode)
413 case CREATE_READ_WRITE:
414 mode = O_CREAT | O_RDWR | O_BINARY;
416 case OPEN_READ_WRITE:
417 mode = O_RDWR | O_BINARY;
420 mode = O_RDONLY | O_BINARY;
422 case OPEN_WRITE_ONLY:
423 mode = O_WRONLY | O_BINARY;
426 Emsg0(M_ABORT, 0, _("Illegal mode given to open dev.\n"));
431 void DEVICE::open_device(DCR *dcr, int omode)
433 /* do nothing waiting to split open_file/tape_device */
438 * Called to indicate that we have just read an
439 * EOF from the device.
441 void DEVICE::set_ateof()
453 * Called to indicate we are now at the end of the tape, and
454 * writing is not possible.
456 void DEVICE::set_ateot()
458 /* Make tape effectively read-only */
459 Dmsg0(200, "==== Set AtEof\n");
460 state |= (ST_EOF|ST_EOT|ST_WEOT);
466 * Set the position of the device -- only for files and DVD
467 * For other devices, there is no generic way to do it.
468 * Returns: true on succes
471 bool DEVICE::update_pos(DCR *dcr)
478 Mmsg0(errmsg, _("Bad device call. Device not open\n"));
479 Emsg1(M_FATAL, 0, "%s", errmsg);
486 pos = lseek(dcr, (boffset_t)0, SEEK_CUR);
490 Pmsg1(000, _("Seek error: ERR=%s\n"), be.bstrerror());
491 Mmsg2(errmsg, _("lseek error on %s. ERR=%s.\n"),
492 print_name(), be.bstrerror());
496 block_num = (uint32_t)pos;
497 file = (uint32_t)(pos >> 32);
503 void DEVICE::set_slot(int32_t slot)
506 if (vol) vol->clear_slot();
509 void DEVICE::clear_slot()
512 if (vol) vol->set_slot(-1);
515 const char *DEVICE::print_type() const
517 return prt_dev_types[device->dev_type];
521 * Set to unload the current volume in the drive
523 void DEVICE::set_unload()
525 if (!m_unload && VolHdr.VolumeName[0] != 0) {
527 memcpy(UnloadVolName, VolHdr.VolumeName, sizeof(UnloadVolName));
528 notify_newvol_in_attached_dcrs(NULL);
533 * Clear volume header
535 void DEVICE::clear_volhdr()
537 Dmsg1(100, "Clear volhdr vol=%s\n", VolHdr.VolumeName);
538 memset(&VolHdr, 0, sizeof(VolHdr));
539 setVolCatInfo(false);
548 Dmsg4(40, "close_dev vol=%s fd=%d dev=%p dev=%s\n",
549 VolHdr.VolumeName, m_fd, this, print_name());
553 Dmsg2(200, "device %s already closed vol=%s\n", print_name(),
555 return; /* already closed */
563 /* Fall through wanted */
569 unmount(1); /* do unmount if required */
571 /* Clean up device packet so it can be reused */
575 * Be careful not to clear items needed by the DVD driver
576 * when it is closing a single part.
578 state &= ~(ST_LABEL|ST_READ|ST_APPEND|ST_EOT|ST_WEOT|ST_EOF|
579 ST_NOSPACE|ST_MOUNTED|ST_MEDIA|ST_SHORT);
580 label_type = B_BACULA_LABEL;
581 file = block_num = 0;
584 EndFile = EndBlock = 0;
587 memset(&VolCatInfo, 0, sizeof(VolCatInfo));
589 stop_thread_timer(tid);
595 * This call closes the device, but it is used in DVD handling
596 * where we close one part and then open the next part. The
597 * difference between close_part() and close() is that close_part()
598 * saves the state information of the device (e.g. the Volume lable,
599 * the Volume Catalog record, ... This permits opening and closing
600 * the Volume parts multiple times without losing track of what the
601 * main Volume parameters are.
603 void DEVICE::close_part(DCR * /*dcr*/)
605 VOLUME_LABEL saveVolHdr;
606 VOLUME_CAT_INFO saveVolCatInfo; /* Volume Catalog Information */
609 saveVolHdr = VolHdr; /* structure assignment */
610 saveVolCatInfo = VolCatInfo; /* structure assignment */
611 close(); /* close current part */
612 VolHdr = saveVolHdr; /* structure assignment */
613 VolCatInfo = saveVolCatInfo; /* structure assignment */
618 * If timeout, wait until the mount command returns 0.
619 * If !timeout, try to mount the device only once.
621 bool DEVICE::mount(int timeout)
623 Dmsg0(190, "Enter mount\n");
633 if (device->mount_command) {
634 return do_tape_mount(1, timeout);
638 if (requires_mount() && device->mount_command) {
639 return do_file_mount(1, timeout);
651 * If timeout, wait until the unmount command returns 0.
652 * If !timeout, try to unmount the device only once.
654 bool DEVICE::unmount(int timeout)
656 Dmsg0(100, "Enter unmount\n");
666 if (device->unmount_command) {
667 return do_tape_mount(0, timeout);
672 if (requires_mount() && device->unmount_command) {
673 return do_file_mount(0, timeout);
685 * Edit codes into (Un)MountCommand, Write(First)PartCommand
687 * %a = archive device name
688 * %e = erase (set if cannot mount and first part)
691 * %v = last part name
693 * omsg = edited output message
694 * imsg = input string containing edit codes (%x)
697 void DEVICE::edit_mount_codes(POOL_MEM &omsg, const char *imsg)
703 POOL_MEM archive_name(PM_FNAME);
706 Dmsg1(800, "edit_mount_codes: %s\n", imsg);
707 for (p=imsg; *p; p++) {
717 if (num_dvd_parts == 0) {
718 if (truncating || blank_dvd) {
728 bsnprintf(add, sizeof(add), "%d", part);
732 str = device->mount_point;
746 Dmsg1(1900, "add_str %s\n", str);
747 pm_strcat(omsg, (char *)str);
748 Dmsg1(1800, "omsg=%s\n", omsg.c_str());
752 /* return the last timer interval (ms)
753 * or 0 if something goes wrong
755 btime_t DEVICE::get_timer_count()
757 btime_t temp = last_timer;
758 last_timer = get_current_btime();
759 temp = last_timer - temp; /* get elapsed time */
760 return (temp>0)?temp:0; /* take care of skewed clock */
764 ssize_t DEVICE::read(void *buf, size_t len)
770 read_len = d_read(m_fd, buf, len);
772 last_tick = get_timer_count();
774 DevReadTime += last_tick;
775 VolCatInfo.VolReadTime += last_tick;
777 if (read_len > 0) { /* skip error */
778 DevReadBytes += read_len;
785 ssize_t DEVICE::write(const void *buf, size_t len)
791 write_len = d_write(m_fd, buf, len);
793 last_tick = get_timer_count();
795 DevWriteTime += last_tick;
796 VolCatInfo.VolWriteTime += last_tick;
798 if (write_len > 0) { /* skip error */
799 DevWriteBytes += write_len;
805 /* Return the resource name for the device */
806 const char *DEVICE::name() const
808 return device->hdr.name;
811 uint32_t DEVICE::get_file()
813 if (is_dvd() || is_tape()) {
816 uint64_t bytes = VolCatInfo.VolCatAmetaBytes;
817 return (uint32_t)(bytes >> 32);
821 uint32_t DEVICE::get_block_num()
823 if (is_dvd() || is_tape()) {
826 return VolCatInfo.VolCatAmetaBlocks;
831 * Walk through all attached jcrs indicating the volume has changed
832 * Note: If you have the new VolumeName, it is passed here,
833 * otherwise pass a NULL.
836 DEVICE::notify_newvol_in_attached_dcrs(const char *newVolumeName)
838 Dmsg2(140, "Notify dcrs of vol change. oldVolume=%s NewVolume=%s\n",
839 getVolCatName(), newVolumeName?"*None*":newVolumeName);
842 foreach_dlist(mdcr, attached_dcrs) {
843 if (mdcr->jcr->JobId == 0) {
844 continue; /* ignore console */
847 mdcr->NewFile = true;
848 if (newVolumeName && mdcr->VolumeName != newVolumeName) {
849 bstrncpy(mdcr->VolumeName, newVolumeName, sizeof(mdcr->VolumeName));
850 Dmsg2(140, "Set NewVol=%s in JobId=%d\n", mdcr->VolumeName, mdcr->jcr->JobId);
857 * Walk through all attached jcrs indicating the File has changed
860 DEVICE::notify_newfile_in_attached_dcrs()
862 Dmsg1(140, "Notify dcrs of file change. Volume=%s\n", getVolCatName());
865 foreach_dlist(mdcr, attached_dcrs) {
866 if (mdcr->jcr->JobId == 0) {
867 continue; /* ignore console */
869 Dmsg1(140, "Notify JobI=%d\n", mdcr->jcr->JobId);
870 mdcr->NewFile = true;
878 * Free memory allocated for the device
880 void DEVICE::term(void)
883 Dmsg1(900, "term dev: %s\n", print_name());
886 free_memory(dev_name);
890 free_memory(prt_name);
894 free_pool_memory(errmsg);
897 pthread_mutex_destroy(&m_mutex);
898 pthread_cond_destroy(&wait);
899 pthread_cond_destroy(&wait_next_vol);
900 pthread_mutex_destroy(&spool_mutex);
902 delete attached_dcrs;
903 attached_dcrs = NULL;
915 * This routine initializes the device wait timers
917 void init_device_wait_timers(DCR *dcr)
919 DEVICE *dev = dcr->dev;
922 /* ******FIXME******* put these on config variables */
923 dev->min_wait = 60 * 60;
924 dev->max_wait = 24 * 60 * 60;
925 dev->max_num_wait = 9; /* 5 waits =~ 1 day, then 1 day at a time */
926 dev->wait_sec = dev->min_wait;
927 dev->rem_wait_sec = dev->wait_sec;
931 jcr->min_wait = 60 * 60;
932 jcr->max_wait = 24 * 60 * 60;
933 jcr->max_num_wait = 9; /* 5 waits =~ 1 day, then 1 day at a time */
934 jcr->wait_sec = jcr->min_wait;
935 jcr->rem_wait_sec = jcr->wait_sec;
940 void init_jcr_device_wait_timers(JCR *jcr)
942 /* ******FIXME******* put these on config variables */
943 jcr->min_wait = 60 * 60;
944 jcr->max_wait = 24 * 60 * 60;
945 jcr->max_num_wait = 9; /* 5 waits =~ 1 day, then 1 day at a time */
946 jcr->wait_sec = jcr->min_wait;
947 jcr->rem_wait_sec = jcr->wait_sec;
953 * The dev timers are used for waiting on a particular device
955 * Returns: true if time doubled
956 * false if max time expired
958 bool double_dev_wait_time(DEVICE *dev)
960 dev->wait_sec *= 2; /* double wait time */
961 if (dev->wait_sec > dev->max_wait) { /* but not longer than maxtime */
962 dev->wait_sec = dev->max_wait;
965 dev->rem_wait_sec = dev->wait_sec;
966 if (dev->num_wait >= dev->max_num_wait) {
972 static const char *modes[] = {
980 const char *mode_to_str(int mode)
982 static char buf[100];
983 if (mode < 1 || mode > 4) {
984 bsnprintf(buf, sizeof(buf), "BAD mode=%d", mode);
987 return modes[mode-1];