#ifndef lint
static const char rcsid[] =
- "$Id: tape.c,v 1.78 2003/10/26 16:05:47 stelian Exp $";
+ "$Id: tape.c,v 1.91 2009/06/18 09:50:54 stelian Exp $";
#endif /* not lint */
#include <config.h>
#ifdef __linux__
#include <sys/types.h>
#include <sys/time.h>
-#include <linux/fs.h> /* for definition of BLKFLSBUF */
+#include <sys/ioctl.h>
+#include <sys/mount.h> /* for definition of BLKFLSBUF */
+#ifndef BLKFLSBUF /* last resort... */
+#define BLKFLSBUF _IO(0x12, 97) /* Flush buffer cache. */
+#endif
#include <time.h>
#endif
#include <sys/param.h>
int writesize; /* size of malloc()ed buffer for tape */
long lastspclrec = -1; /* tape block number of last written header */
int trecno = 0; /* next record to write in current block */
-extern long blocksperfile; /* number of blocks per output file */
+extern long *blocksperfiles; /* number of blocks per output file(s) */
+long blocksperfiles_current; /* current position in blocksperfiles */
long blocksthisvol; /* number of blocks on current output file */
extern int ntrec; /* blocking factor on tape */
extern int cartridge;
long long tapea_bytes = 0; /* bytes_written at start of current volume */
static int magtapeout; /* output is really a tape */
-static ssize_t dump_atomic_read __P((int, void *, size_t));
-static ssize_t dump_atomic_write __P((int, const void *, size_t));
+static ssize_t dump_atomic_read __P((int, char *, size_t));
+static ssize_t dump_atomic_write __P((int, const char *, size_t));
#ifdef WRITEDEBUG
static void doslave __P((int, int, int));
#else
* The following structure defines the instruction packets sent to slaves.
*/
struct req {
- daddr_t dblk;
+ ext2_loff_t dblk;
int count;
};
int reqsiz;
static int gtperr = 0;
#endif
+/*
+ * Determine if we can use Linux' clone system call. If so, call it
+ * with the CLONE_IO flag so that all processes will share the same I/O
+ * context, allowing the I/O schedulers to make better scheduling decisions.
+ */
+#ifdef __linux__
+/* first, pull in the header files that define sys_clone and CLONE_IO */
+#include <syscall.h>
+#define _GNU_SOURCE
+#include <sched.h>
+#include <unistd.h>
+#undef _GNU_SOURCE
+
+/* If either is not present, fall back on the fork behaviour */
+#if ! defined(SYS_clone) || ! defined (CLONE_IO)
+#define fork_clone_io fork
+#else /* SYS_clone */
+/* CLONE_IO is available, determine which version of sys_clone to use */
+#include <linux/version.h>
+/*
+ * Kernel 2.5.49 introduced two extra parameters to the clone system call.
+ * Neither is useful in our case, so this is easy to handle.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,49)
+/* clone_flags, child_stack, parent_tidptr, child_tidptr */
+#define CLONE_ARGS SIGCHLD|CLONE_IO, 0, NULL, NULL
+#else
+#define CLONE_ARGS SIGCHLD|CLONE_IO, 0
+#endif /* LINUX_VERSION_CODE */
+pid_t fork_clone_io(void);
+#endif /* SYS_clone */
+#else /* __linux__ not defined */
+#define fork_clone_io fork
+#endif /* __linux__ */
+
int
alloctape(void)
{
* repositioning after stopping, i.e, streaming mode, where the gap is
* variable, 0.30" to 0.45". The gap is maximal when the tape stops.
*/
- if (blocksperfile == 0 && !unlimited)
+ if (!blocksperfiles && !unlimited)
tenths = (cartridge ? 16 : density == 625 ? 5 : 8);
else {
tenths = 0;
writerec(const void *dp, int isspcl)
{
- slp->req[trecno].dblk = (daddr_t)0;
+ slp->req[trecno].dblk = (ext2_loff_t)0;
slp->req[trecno].count = 1;
/* XXX post increment triggers an egcs-1.1.2-12 bug on alpha/sparc */
*(union u_spcl *)(*(nextblock)) = *(union u_spcl *)dp;
/* Need to write it to the archive file */
if (! AfileActive && isspcl && (spcl.c_type == TS_END))
AfileActive = 1;
- if (AfileActive && Afile >= 0) {
+ if (AfileActive && Afile >= 0 && !(spcl.c_flags & DR_EXTATTRIBUTES)) {
/* When we dump an inode which is not a directory,
* it means we ended the archive contents */
if (isspcl && (spcl.c_type == TS_INODE) &&
}
void
-dumpblock(daddr_t blkno, int size)
+dumpblock(blk_t blkno, int size)
{
- int avail, tpblks, dblkno;
+ int avail, tpblks;
+ ext2_loff_t dblkno;
dblkno = fsbtodb(sblock, blkno);
tpblks = size >> tp_bshift;
int siz = (char *)nextblock - (char *)slp->req;
+ /* make sure returned has sane values in case we don't read
+ * them from the slave in this pass */
+ returned.unclen = returned.clen = writesize;
+
slp->req[trecno].count = 0; /* Sentinel */
if (dump_atomic_write( slp->fd, (char *)slp->req, siz) != siz)
}
blks = 0;
- if (spcl.c_type != TS_END) {
- for (i = 0; i < spcl.c_count; i++)
- if (spcl.c_addr[i] != 0)
- blks++;
+ if (spcl.c_type == TS_CLRI || spcl.c_type == TS_BITS)
+ blks = spcl.c_count;
+ else {
+ if (spcl.c_type != TS_END) {
+ for (i = 0; i < spcl.c_count; i++)
+ if (spcl.c_addr[i] != 0)
+ blks++;
+ }
}
slp->count = lastspclrec + blks + 1 - spcl.c_tapea;
slp->tapea = spcl.c_tapea;
blockswritten += ntrec;
blocksthisvol += ntrec;
if (!pipeout && !unlimited) {
- if (blocksperfile) {
- if ( compressed ? (bytes_written - tapea_bytes + SLAVES * (writesize + sizeof(struct tapebuf))) >= (((long long)blocksperfile) * 1024)
- : blocksthisvol >= blocksperfile ) {
+ if (blocksperfiles && blocksperfiles[blocksperfiles_current]) {
+ if ( compressed ? (bytes_written - tapea_bytes + SLAVES * (writesize + sizeof(struct tapebuf))) >= (((long long)blocksperfiles[blocksperfiles_current]) * 1024)
+ : blocksthisvol >= blocksperfiles[blocksperfiles_current] ) {
close_rewind();
startnewtape(0);
}
{
int eot_code = 1;
(void)trewind();
- if (nexttape || Mflag)
- return;
if (eot_script) {
msg("Launching %s\n", eot_script);
eot_code = system_command(eot_script, tape, tapeno);
}
if (eot_code == 0)
return;
+ if (nexttape || Mflag)
+ return;
if (!nogripe) {
msg("Change Volumes: Mount volume #%d\n", tapeno+1);
broadcast("CHANGE DUMP VOLUMES!\7\7\n");
tslp = &slaves[SLAVES];
ntb = (union u_spcl *)tslp->tblock[1];
+ /* make sure returned has sane values in case we don't read
+ * them from the slave in this pass */
+ returned.unclen = returned.clen = writesize;
+
/*
* Each of the N slaves should have requests that need to
* be replayed on the next tape. Use the extra slave buffers
#endif
}
+#ifdef __linux__
+#if defined(SYS_clone) && defined(CLONE_IO)
+pid_t
+fork_clone_io(void)
+{
+ return syscall(SYS_clone, CLONE_ARGS);
+}
+#endif
+#endif
+
/*
* We implement taking and restoring checkpoints on the tape level.
* When each tape is opened, a new process is created by forking; this
/*
* All signals are inherited...
*/
- childpid = fork();
+ childpid = fork_clone_io();
if (childpid < 0) {
msg("Context save fork fails in parent %d\n", parentpid);
Exit(X_ABORT);
tape[MAXPATHLEN - 1] = '\0';
msg("Dumping volume %d on %s\n", tapeno, tape);
}
+ if (blocksperfiles && blocksperfiles_current < *blocksperfiles)
+ blocksperfiles_current++;
#ifdef RDUMP
while ((tapefd = (host ? rmtopen(tape, O_WRONLY|O_CREAT|O_TRUNC) : pipeout ?
fileno(stdout) :
}
if (socketpair(AF_UNIX, SOCK_STREAM, 0, cmd) < 0 ||
- (slaves[i].pid = fork()) < 0)
+ (slaves[i].pid = fork_clone_io()) < 0)
quit("too many slaves, %d (recompile smaller): %s\n",
i, strerror(errno));
int compresult;
volatile int do_compress = !first;
unsigned long worklen;
-#ifdef HAVE_BZLIB
- unsigned int worklen2;
-#endif
#ifdef HAVE_LZO
lzo_align_t __LZO_MMODEL *LZO_WorkMem;
#endif
#endif /* HAVE_ZLIB */
#ifdef HAVE_BZLIB
if (zipflag == COMPRESS_BZLIB) {
- worklen2 = worklen;
+ unsigned int worklen2 = worklen;
compresult = BZ2_bzBuffToBuffCompress(
comp_buf->buf,
&worklen2,
#endif /* HAVE_BZLIB */
#ifdef HAVE_LZO
if (zipflag == COMPRESS_LZO) {
+ lzo_uint worklen2 = worklen;
compresult = lzo1x_1_compress((char *)slp->tblock[0],writesize,
comp_buf->buf,
- (lzo_uintp)&worklen,
+ &worklen2,
LZO_WorkMem);
+ worklen = worklen2;
if (compresult == LZO_E_OK)
compresult = 1;
else
if ((spclptr->c_magic == NFS_MAGIC) &&
(spclptr->c_type == TS_INODE) &&
(spclptr->c_date == gThisDumpDate) &&
- !(spclptr->c_dinode.di_mode & S_IFDIR)
+ !(spclptr->c_dinode.di_mode & S_IFDIR) &&
+ !(spclptr->c_flags & DR_EXTATTRIBUTES)
) {
foundone = 1;
/* if (cntntrecs >= maxntrecs) { only write every maxntrecs amount of data */
* loop until the count is satisfied (or error).
*/
static ssize_t
-dump_atomic_read(int fd, void *buf, size_t count)
+dump_atomic_read(int fd, char *buf, size_t count)
{
int got, need = count;
do {
while ((got = read(fd, buf, need)) > 0 && (need -= got) > 0)
- (char *)buf += got;
+ buf += got;
} while (got == -1 && errno == EINTR);
return (got < 0 ? got : (ssize_t)count - need);
}
* loop until the count is satisfied (or error).
*/
static ssize_t
-dump_atomic_write(int fd, const void *buf, size_t count)
+dump_atomic_write(int fd, const char *buf, size_t count)
{
int got, need = count;
do {
while ((got = write(fd, buf, need)) > 0 && (need -= got) > 0)
- (char *)buf += got;
+ buf += got;
} while (got == -1 && errno == EINTR);
- return (got < 0 ? got : count - need);
+ return (got < 0 ? got : (ssize_t)count - need);
}