/*
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_file() const { return dev_type == B_FILE_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; }
int is_vtl() const { return dev_type == B_VTL_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 */
+ bool 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_dunlock(const char *, int); /* in lock.c */
- void _dlock(const char *, int); /* in lock.c */
- void _dunlock(const char *, int); /* in lock.c */
+ void dbg_rLock(const char *, int, bool locked=false); /* in lock.c */
+ void dbg_rUnlock(const char *, int); /* in lock.c */
+ void dbg_Lock(const char *, int); /* in lock.c */
+ void dbg_Unlock(const char *, int); /* in lock.c */
+ void dbg_Lock_acquire(const char *, int); /* in lock.c */
+ void dbg_Unlock_acquire(const char *, int); /* in lock.c */
+ void dbg_Lock_read_acquire(const char *, int); /* in lock.c */
+ void dbg_Unlock_read_acquire(const char *, int); /* in lock.c */
#else
- void r_dlock(); /* in lock.c */
- void r_dunlock() { dunlock(); }
- void dlock() { P(m_mutex); }
- void dunlock() { V(m_mutex); }
+ void rLock(bool locked=false); /* in lock.c */
+ void rUnlock(); /* in lock.c */
+ void Lock(); /* in lock.c */
+ void Unlock(); /* in lock.c */
+ void Lock_acquire(); /* in lock.c */
+ void Unlock_acquire(); /* in lock.c */
+ void Lock_read_acquire(); /* in lock.c */
+ void Unlock_read_acquire(); /* in lock.c */
+ void Lock_VolCatInfo(); /* in lock.c */
+ void Unlock_VolCatInfo(); /* in lock.c */
#endif
+ int init_mutex(); /* in lock.c */
+ int init_acquire_mutex(); /* in lock.c */
+ int init_read_acquire_mutex(); /* in lock.c */
+ int init_volcat_mutex(); /* in lock.c */
+ void set_mutex_priorities(); /* in lock.c */
+ int next_vol_timedwait(const struct timespec *timeout); /* in lock.c */
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; }
inline const char *DEVICE::archive_name() const { return dev_name; }
inline const char *DEVICE::print_name() const { return prt_name; }
+
+#define CHECK_BLOCK_NUMBERS true
+#define NO_BLOCK_NUMBER_CHECK false
+
/*
* Device Context (or Control) Record.
* There is one of these records for each Job that is using
* 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:
bool m_dev_locked; /* set if dev already locked */
+ int m_dev_lock; /* non-zero if rLock already called */
bool m_reserved; /* set if reserved device */
bool m_found_in_use; /* set if a volume found in use */
public:
dlink dev_link; /* link to attach to dev */
JCR *jcr; /* pointer to JCR */
+ bthread_mutex_t m_mutex; /* access control */
+ pthread_mutex_t r_mutex; /* rLock pre-mutex */
DEVICE * volatile dev; /* pointer to device */
DEVRES *device; /* pointer to device resource */
DEV_BLOCK *block; /* pointer to block */
VOLUME_CAT_INFO VolCatInfo; /* Catalog info for desired volume */
/* Methods */
+ void set_dev(DEVICE *ndev) { dev = ndev; };
+ void inc_dev_lock() { m_dev_lock++; };
+ void dec_dev_lock() { m_dev_lock--; };
bool found_in_use() const { return m_found_in_use; };
void set_found_in_use() { m_found_in_use = true; };
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; }
- void dlock() { dev->dlock(); m_dev_locked = true; }
- void dunlock() { m_dev_locked = false; dev->dunlock(); }
+ 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 lock.c */
void dblock(int why) { dev->dblock(why); }
+#ifdef SD_DEBUG_LOCK
+ void dbg_mLock(const char *, int, bool locked); /* in lock.c */
+ void dbg_mUnlock(const char *, int); /* in lock.c */
+#else
+ void mLock(bool locked);
+ void mUnlock();
+#endif
+ /* Methods in record.c */
+ bool write_record(DEV_RECORD *rec);
/* Methods in reserve.c */
void clear_reserved();
void set_reserved();
void unreserve_device();
+
+ /* Methods in vol_mgr.c */
bool can_i_use_volume();
+ bool can_i_write_volume();
/* Methods in mount.c */
bool mount_next_write_volume();
bool do_unload();
bool do_load(bool is_writing);
bool is_tape_position_ok();
+
+ /* Methods in block.c */
+ bool write_block_to_device();
+ bool write_block_to_dev();
+ bool read_block_from_device(bool check_block_numbers);
+ bool read_block_from_dev(bool check_block_numbers);
+
+ /* Methods in label.c */
+ bool rewrite_volume_label(bool recycle);
+
};
/*
bool m_swapping; /* set when swapping to another drive */
bool m_in_use; /* set when volume reserved or in use */
int32_t m_slot; /* slot of swapping volume */
+ uint32_t m_JobId; /* JobId for read volumes */
public:
dlink link;
char *vol_name; /* Volume name */
void set_slot(int32_t slot) { m_slot = slot; };
void clear_slot() { m_slot = -1; };
int32_t get_slot() const { return m_slot; };
+ uint32_t get_jobid() const { return m_JobId; };
+ void set_jobid(uint32_t JobId) { m_JobId = JobId; };
};