From ff7ee8f1fed361263f9e377aceb5c76a5ca73d56 Mon Sep 17 00:00:00 2001 From: Marco van Wieringen Date: Sat, 24 Oct 2009 11:13:16 +0200 Subject: [PATCH] First go at supporting a mount and unmount wrapper for tape devices. Initial cleanup of the existing code for file/dvd based mount and unmount. --- bacula/src/stored/dev.c | 186 ++++++++++++++++++++++++++++------------ bacula/src/stored/dev.h | 13 +-- 2 files changed, 137 insertions(+), 62 deletions(-) diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index 29e4c8cff2..f6db91c261 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -402,6 +402,7 @@ void DEVICE::open_tape_device(DCR *dcr, int omode) utime_t start_time = time(NULL); #endif + mount(1); /* do mount if required */ Dmsg0(100, "Open dev: device is tape\n"); @@ -1927,18 +1928,13 @@ void DEVICE::close() case B_VTAPE_DEV: case B_TAPE_DEV: unlock_door(); - d_close(m_fd); - break; - case B_FILE_DEV: - case B_DVD_DEV: - d_close(m_fd); - unmount(1); /* do unmount if required */ - break; default: d_close(m_fd); break; } + unmount(1); /* do unmount if required */ + /* Clean up device packet so it can be reused */ clear_opened(); /* @@ -2074,74 +2070,165 @@ bool DEVICE::truncate(DCR *dcr) /* We need the DCR for DVD-writing */ return false; } -/* Mount the device. +/* + * Mount the device. * If timeout, wait until the mount command returns 0. * If !timeout, try to mount the device only once. */ bool DEVICE::mount(int timeout) { Dmsg0(190, "Enter mount\n"); + if (is_mounted()) { return true; - } else if (requires_mount()) { - return do_mount(1, timeout); - } + } + + switch (dev_type) { + case B_VTL_DEV: + case B_VTAPE_DEV: + case B_TAPE_DEV: + if (device->mount_command) { + return do_tape_mount(1, timeout); + } + break; + case B_FILE_DEV: + case B_DVD_DEV: + if (requires_mount() && device->mount_command) { + return do_file_mount(1, timeout); + } + break; + default: + break; + } + return true; } -/* Unmount the device +/* + * Unmount the device * If timeout, wait until the unmount command returns 0. * If !timeout, try to unmount the device only once. */ bool DEVICE::unmount(int timeout) { Dmsg0(100, "Enter unmount\n"); - if (requires_mount() && is_mounted()) { - return do_mount(0, timeout); + + if (!is_mounted()) { + return true; + } + + switch (dev_type) { + case B_VTL_DEV: + case B_VTAPE_DEV: + case B_TAPE_DEV: + if (device->unmount_command) { + return do_tape_mount(0, timeout); + } + break; + case B_FILE_DEV: + case B_DVD_DEV: + if (requires_mount() && device->unmount_command) { + return do_file_mount(0, timeout); + } + break; + default: + break; } + return true; } -/* (Un)mount the device */ -bool DEVICE::do_mount(int mount, int dotimeout) +/* + * (Un)mount the device (for tape devices) + */ +bool DEVICE::do_tape_mount(int mount, int dotimeout) { POOL_MEM ocmd(PM_FNAME); POOLMEM *results; char *icmd; - int status, timeout; - + int status, tries; + berrno be; + Dsm_check(1); if (mount) { - if (is_mounted()) { - Dmsg0(200, "======= mount=1\n"); - return true; - } icmd = device->mount_command; } else { - if (!is_mounted()) { - Dmsg0(200, "======= mount=0\n"); - return true; + icmd = device->unmount_command; + } + + edit_mount_codes(ocmd, icmd); + + Dmsg2(100, "do_tape_mount: cmd=%s mounted=%d\n", ocmd.c_str(), !!is_mounted()); + + if (dotimeout) { + /* Try at most 10 times to (un)mount the device. This should perhaps be configurable. */ + tries = 10; + } else { + tries = 0; + } + results = get_memory(4000); + + /* If busy retry each second */ + Dmsg1(100, "do_tape_mount run_prog=%s\n", ocmd.c_str()); + while ((status = run_program_full_output(ocmd.c_str(), max_open_wait/2, results)) != 0) { + if (tries-- > 0) { + continue; } + + Dmsg5(100, "Device %s cannot be %smounted. stat=%d result=%s ERR=%s\n", print_name(), + (mount ? "" : "un"), status, results, be.bstrerror(status)); + Mmsg(errmsg, _("Device %s cannot be %smounted. ERR=%s\n"), + print_name(), (mount ? "" : "un"), be.bstrerror(status)); + + set_mounted(false); + free_pool_memory(results); + Dmsg0(200, "============ mount=0\n"); + Dsm_check(1); + return false; + } + + set_mounted(mount); /* set/clear mounted flag */ + free_pool_memory(results); + Dmsg1(200, "============ mount=%d\n", mount); + return true; +} + +/* + * (Un)mount the device (either a FILE or DVD device) + */ +bool DEVICE::do_file_mount(int mount, int dotimeout) +{ + POOL_MEM ocmd(PM_FNAME); + POOLMEM *results; + DIR* dp; + char *icmd; + struct dirent *entry, *result; + int status, tries, name_max, count; + berrno be; + + Dsm_check(1); + if (mount) { + icmd = device->mount_command; + } else { icmd = device->unmount_command; } clear_freespace_ok(); edit_mount_codes(ocmd, icmd); - Dmsg2(100, "do_mount: cmd=%s mounted=%d\n", ocmd.c_str(), !!is_mounted()); + Dmsg2(100, "do_file_mount: cmd=%s mounted=%d\n", ocmd.c_str(), !!is_mounted()); if (dotimeout) { /* Try at most 10 times to (un)mount the device. This should perhaps be configurable. */ - timeout = 10; + tries = 10; } else { - timeout = 0; + tries = 0; } results = get_memory(4000); /* If busy retry each second */ - Dmsg1(100, "do_mount run_prog=%s\n", ocmd.c_str()); - while ((status = run_program_full_output(ocmd.c_str(), - max_open_wait/2, results)) != 0) { + Dmsg1(100, "do_file_mount run_prog=%s\n", ocmd.c_str()); + while ((status = run_program_full_output(ocmd.c_str(), max_open_wait/2, results)) != 0) { /* Doesn't work with internationalization (This is not a problem) */ if (mount && fnmatch("*is already mounted on*", results, 0) == 0) { break; @@ -2149,37 +2236,24 @@ bool DEVICE::do_mount(int mount, int dotimeout) if (!mount && fnmatch("* not mounted*", results, 0) == 0) { break; } - if (timeout-- > 0) { + if (tries-- > 0) { /* Sometimes the device cannot be mounted because it is already mounted. * Try to unmount it, then remount it */ if (mount) { Dmsg1(400, "Trying to unmount the device %s...\n", print_name()); - do_mount(0, 0); + do_file_mount(0, 0); } bmicrosleep(1, 0); continue; } - if (status != 0) { - berrno be; - Dmsg5(100, "Device %s cannot be %smounted. stat=%d result=%s ERR=%s\n", print_name(), - (mount ? "" : "un"), status, results, be.bstrerror(status)); - Mmsg(errmsg, _("Device %s cannot be %smounted. ERR=%s\n"), - print_name(), (mount ? "" : "un"), be.bstrerror(status)); - } else { - Dmsg4(100, "Device %s cannot be %smounted. stat=%d ERR=%s\n", print_name(), - (mount ? "" : "un"), status, results); - Mmsg(errmsg, _("Device %s cannot be %smounted. ERR=%s\n"), - print_name(), (mount ? "" : "un"), results); - } + Dmsg5(100, "Device %s cannot be %smounted. stat=%d result=%s ERR=%s\n", print_name(), + (mount ? "" : "un"), status, results, be.bstrerror(status)); + Mmsg(errmsg, _("Device %s cannot be %smounted. ERR=%s\n"), + print_name(), (mount ? "" : "un"), be.bstrerror(status)); + /* - * Now, just to be sure it is not mounted, try to read the - * filesystem. + * Now, just to be sure it is not mounted, try to read the filesystem. */ - DIR* dp; - struct dirent *entry, *result; - int name_max; - int count; - name_max = pathconf(".", _PC_NAME_MAX); if (name_max < 1024) { name_max = 1024; @@ -2188,7 +2262,7 @@ bool DEVICE::do_mount(int mount, int dotimeout) if (!(dp = opendir(device->mount_point))) { berrno be; dev_errno = errno; - Dmsg3(100, "do_mount: failed to open dir %s (dev=%s), ERR=%s\n", + Dmsg3(100, "do_file_mount: failed to open dir %s (dev=%s), ERR=%s\n", device->mount_point, print_name(), be.bstrerror()); goto get_out; } @@ -2198,7 +2272,7 @@ bool DEVICE::do_mount(int mount, int dotimeout) while (1) { if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) { dev_errno = EIO; - Dmsg2(129, "do_mount: failed to find suitable file in dir %s (dev=%s)\n", + Dmsg2(129, "do_file_mount: failed to find suitable file in dir %s (dev=%s)\n", device->mount_point, print_name()); break; } @@ -2206,13 +2280,13 @@ bool DEVICE::do_mount(int mount, int dotimeout) count++; /* result->d_name != ., .. or .keep (Gentoo-specific) */ break; } else { - Dmsg2(129, "do_mount: ignoring %s in %s\n", result->d_name, device->mount_point); + Dmsg2(129, "do_file_mount: ignoring %s in %s\n", result->d_name, device->mount_point); } } free(entry); closedir(dp); - Dmsg1(100, "do_mount: got %d files in the mount point (not counting ., .. and .keep)\n", count); + Dmsg1(100, "do_file_mount: got %d files in the mount point (not counting ., .. and .keep)\n", count); if (count > 0) { /* If we got more than ., .. and .keep */ diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index e7085c5056..b2c6793456 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -451,7 +451,7 @@ public: void _dlock(const char *, int); /* in lock.c */ void _dunlock(const char *, int); /* in lock.c */ #else - void r_dlock(bool locked=false); /* in lock.c */ + void r_dlock(bool locked=false); /* in lock.c */ void r_dunlock() { dunlock(); } void dlock() { P(m_mutex); } void dunlock() { V(m_mutex); } @@ -465,11 +465,12 @@ public: const char *print_blocked() const; /* in dev.c */ private: - bool do_mount(int mount, int timeout); /* in dev.c */ - void set_mode(int omode); /* in dev.c */ - void open_tape_device(DCR *dcr, int omode); /* in dev.c */ - void open_file_device(DCR *dcr, int omode); /* in dev.c */ - void open_dvd_device(DCR *dcr, int omode); /* in dev.c */ + bool do_tape_mount(int mount, int dotimeout); /* in dev.c */ + bool do_file_mount(int mount, int dotimeout); /* in dev.c */ + void set_mode(int omode); /* in dev.c */ + void open_tape_device(DCR *dcr, int omode); /* in dev.c */ + void open_file_device(DCR *dcr, int omode); /* in dev.c */ + void open_dvd_device(DCR *dcr, int omode); /* in dev.c */ }; inline const char *DEVICE::strerror() const { return errmsg; } -- 2.39.5