/*
Bacula® - The Network Backup Solution
- Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
+ Copyright (C) 2000-2012 Free Software Foundation Europe e.V.
The main author of Bacula is Kern Sibbald, with contributions from
many others, a complete list can be found in the file AUTHORS.
This program is Free Software; you can redistribute it and/or
- modify it under the terms of version two of the GNU General Public
+ modify it under the terms of version three of the GNU Affero General Public
License as published by the Free Software Foundation and included
in the file LICENSE.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
- You should have received a copy of the GNU General Public License
+ You should have received a copy of the GNU Affero General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*
* Kern Sibbald, MM
*
- * Version $Id$
- *
*/
/*
*
*/
-
#ifndef __DEV_H
#define __DEV_H 1
B_DVD_DEV,
B_FIFO_DEV,
B_VTAPE_DEV, /* change to B_TAPE_DEV after init */
+ B_FTP_DEV,
B_VTL_DEV
};
#define CAP_CLOSEONPOLL (1<<18) /* Close device on polling */
#define CAP_POSITIONBLOCKS (1<<19) /* Use block positioning */
#define CAP_MTIOCGET (1<<20) /* Basic support for fileno and blkno */
-#define CAP_REQMOUNT (1<<21) /* Require mount to read files back (typically: DVD) */
+#define CAP_REQMOUNT (1<<21) /* Require mount/unmount */
#define CAP_CHECKLABELS (1<<22) /* Check for ANSI/IBM labels */
+#define CAP_BLOCKCHECKSUM (1<<23) /* Create/test block checksum */
/* Test state */
#define dev_state(dev, st_state) ((dev)->state & (st_state))
utime_t VolFirstWritten; /* Time of first write */
utime_t VolLastWritten; /* Time of last write */
bool InChanger; /* Set if vol in current magazine */
+ bool is_valid; /* set if this data is valid */
char VolCatStatus[20]; /* Volume status */
char VolCatName[MAX_NAME_LENGTH]; /* Desired volume to mount */
};
-
class DEVRES; /* Device resource defined in stored_conf.h */
class DCR; /* forward reference */
class VOLRES; /* forward reference */
* each physical device. Everything here is "global" to
* that device and effects all jobs using the device.
*/
-class DEVICE {
-private:
+class DEVICE: public SMARTALLOC {
+protected:
int m_fd; /* file descriptor */
+private:
int m_blocked; /* set if we must wait (i.e. change tape) */
int m_count; /* Mutex use count -- DEBUG only */
+ int m_num_reserved; /* counter of device reservations */
+ int32_t m_slot; /* slot loaded in drive or -1 if none */
pthread_t m_pid; /* Thread that locked -- DEBUG only */
bool m_unload; /* set when Volume must be unloaded */
bool m_load; /* set when Volume must be loaded */
- int m_num_reserved; /* counter of device reservations */
- int32_t m_slot; /* slot loaded in drive or -1 if none */
public:
+ DEVICE() {};
+ virtual ~DEVICE() {};
DEVICE * volatile swap_dev; /* Swap vol from this device */
dlist *attached_dcrs; /* attached DCR list */
- pthread_mutex_t m_mutex; /* access control */
- pthread_mutex_t spool_mutex; /* mutex for updating spool_size */
+ bthread_mutex_t m_mutex; /* access control */
+ bthread_mutex_t spool_mutex; /* mutex for updating spool_size */
+ bthread_mutex_t acquire_mutex; /* mutex for acquire code */
+ pthread_mutex_t read_acquire_mutex; /* mutex for acquire read code */
pthread_cond_t wait; /* thread wait variable */
pthread_cond_t wait_next_vol; /* wait for tape to be mounted */
pthread_t no_wait_id; /* this thread must not wait */
uint32_t EndFile; /* last file written */
uint32_t min_block_size; /* min block size */
uint32_t max_block_size; /* max block size */
+ 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 */
uint64_t volume_capacity; /* advisory capacity */
int has_cap(int cap) const { return capabilities & cap; }
void clear_cap(int cap) { capabilities &= ~cap; }
void set_cap(int cap) { capabilities |= cap; }
+ bool do_checksum() const { return (capabilities & CAP_BLOCKCHECKSUM) != 0; }
int is_autochanger() const { return capabilities & CAP_AUTOCHANGER; }
int requires_mount() const { return capabilities & CAP_REQMOUNT; }
int is_removable() const { return capabilities & CAP_REM; }
int is_tape() const { return (dev_type == B_TAPE_DEV ||
dev_type == B_VTAPE_DEV); }
+ int is_ftp() const { return dev_type == B_FTP_DEV; }
int is_file() const { return dev_type == B_FILE_DEV; }
int is_fifo() const { return dev_type == B_FIFO_DEV; }
int is_dvd() const { return dev_type == B_DVD_DEV; }
char *bstrerror(void) { return errmsg; };
char *print_errmsg() { return errmsg; };
int32_t get_slot() const { return m_slot; };
+ void setVolCatInfo(bool valid) { VolCatInfo.is_valid = valid; };
+ bool haveVolCatInfo() const { return VolCatInfo.is_valid; };
+ void setVolCatName(const char *name) {
+ bstrncpy(VolCatInfo.VolCatName, name, sizeof(VolCatInfo.VolCatName));
+ setVolCatInfo(false);
+ };
+ char *getVolCatName() { return VolCatInfo.VolCatName; };
void set_unload(); /* in dev.c */
void clear_volhdr(); /* in dev.c */
void close(); /* in dev.c */
void close_part(DCR *dcr); /* in dev.c */
- bool truncate(DCR *dcr); /* in dev.c */
int open(DCR *dcr, int mode); /* in dev.c */
void term(void); /* in dev.c */
ssize_t read(void *buf, size_t len); /* in dev.c */
ssize_t write(const void *buf, size_t len); /* in dev.c */
- bool rewind(DCR *dcr); /* in dev.c */
bool mount(int timeout); /* in dev.c */
bool unmount(int timeout); /* in dev.c */
void edit_mount_codes(POOL_MEM &omsg, const char *imsg); /* in dev.c */
bool scan_dir_for_volume(DCR *dcr); /* in scan.c */
bool reposition(DCR *dcr, uint32_t rfile, uint32_t rblock); /* in dev.c */
void clrerror(int func); /* in dev.c */
- boffset_t lseek(DCR *dcr, boffset_t offset, int whence); /* in dev.c */
- bool update_pos(DCR *dcr); /* in dev.c */
void set_slot(int32_t slot); /* in dev.c */
void clear_slot(); /* in dev.c */
int fd() const { return m_fd; };
/* low level operations */
- void init_backend();
- int (*d_open)(const char *pathname, int flags, ...);
- int (*d_close)(int fd);
- int (*d_ioctl)(int fd, ioctl_req_t request, ...);
- ssize_t (*d_read)(int fd, void *buffer, size_t count);
- ssize_t (*d_write)(int fd, const void *buffer, size_t count);
-
+ virtual int d_ioctl(int fd, ioctl_req_t request, char *mt_com=NULL);
+ virtual int d_open(const char *pathname, int flags);
+ virtual int d_close(int fd);
+ virtual ssize_t d_read(int fd, void *buffer, size_t count);
+ virtual ssize_t d_write(int fd, const void *buffer, size_t count);
+ virtual boffset_t lseek(DCR *dcr, boffset_t offset, int whence);
+ virtual bool update_pos(DCR *dcr);
+ virtual bool rewind(DCR *dcr);
+ virtual bool truncate(DCR *dcr);
+ virtual void open_device(DCR *dcr, int omode);
/*
* Locking and blocking calls
*/
#ifdef SD_DEBUG_LOCK
- void _r_dlock(const char *, int); /* in lock.c */
+ void _r_dlock(const char *, int, bool locked=false); /* in lock.c */
void _r_dunlock(const char *, int); /* in lock.c */
void _dlock(const char *, int); /* in lock.c */
void _dunlock(const char *, int); /* in lock.c */
#else
- void r_dlock(); /* 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); }
#endif
void dblock(int why); /* in lock.c */
void dunblock(bool locked=false); /* in lock.c */
+ bool is_device_unmounted(); /* in lock.c */
void set_blocked(int block) { m_blocked = block; };
int blocked() const { return m_blocked; };
bool is_blocked() const { return m_blocked != BST_NOT_BLOCKED; };
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 */
};
inline const char *DEVICE::strerror() const { return errmsg; }
* the device. Items in this record are "local" to the Job and
* do not affect other Jobs. Note, a job can have multiple
* DCRs open, each pointing to a different device.
+ * Normally, there is only one JCR thread per DCR. However, the
+ * big and important exception to this is when a Job is being
+ * canceled. At that time, there may be two threads using the
+ * same DCR. Consequently, when creating/attaching/detaching
+ * and freeing the DCR we must lock it (m_mutex).
*/
class DCR {
private:
public:
dlink dev_link; /* link to attach to dev */
JCR *jcr; /* pointer to JCR */
+ bthread_mutex_t m_mutex; /* access control */
DEVICE * volatile dev; /* pointer to device */
DEVRES *device; /* pointer to device resource */
DEV_BLOCK *block; /* pointer to block */
void clear_found_in_use() { m_found_in_use = false; };
bool is_reserved() const { return m_reserved; };
bool is_dev_locked() { return m_dev_locked; }
+#ifdef SD_DEBUG_LOCK
+ void _dlock(const char *, int); /* in lock.c */
+ void _dunlock(const char *, int); /* in lock.c */
+#else
void dlock() { dev->dlock(); m_dev_locked = true; }
void dunlock() { m_dev_locked = false; dev->dunlock(); }
+#endif
void dblock(int why) { dev->dblock(why); }
+ void setVolCatInfo(bool valid) { VolCatInfo.is_valid = valid; };
+ bool haveVolCatInfo() const { return VolCatInfo.is_valid; };
+ void setVolCatName(const char *name) {
+ bstrncpy(VolCatInfo.VolCatName, name, sizeof(VolCatInfo.VolCatName));
+ setVolCatInfo(false);
+ };
+ char *getVolCatName() { return VolCatInfo.VolCatName; };
/* Methods in reserve.c */