]> git.wh0rd.org - dump.git/blobdiff - dump/tape.c
Use sys_clone under Linux to share I/O contexts between dump processes.
[dump.git] / dump / tape.c
index f55334b1206af6c8f2468449bbc23c7be6a8099b..edcf5d691925a6532dd71e8b30f75514d8190109 100644 (file)
@@ -37,7 +37,7 @@
 
 #ifndef lint
 static const char rcsid[] =
-       "$Id: tape.c,v 1.79 2003/11/22 16:52:16 stelian Exp $";
+       "$Id: tape.c,v 1.91 2009/06/18 09:50:54 stelian Exp $";
 #endif /* not lint */
 
 #include <config.h>
@@ -60,7 +60,11 @@ int    write(), read();
 #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>
@@ -105,7 +109,8 @@ int    write(), read();
 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;
@@ -115,8 +120,8 @@ int         eot_code = 1;
 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
@@ -141,7 +146,7 @@ static int MkTapeString __P((struct s_spcl *, long long));
  * The following structure defines the instruction packets sent to slaves.
  */
 struct req {
-       daddr_t dblk;
+       ext2_loff_t dblk;
        int count;
 };
 int reqsiz;
@@ -182,6 +187,41 @@ static sigjmp_buf jmpbuf;  /* where to jump to if we are ready when the */
 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)
 {
@@ -197,7 +237,7 @@ 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;
@@ -233,7 +273,7 @@ void
 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;
@@ -241,7 +281,7 @@ writerec(const void *dp, int isspcl)
        /* 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) &&
@@ -271,9 +311,10 @@ writerec(const void *dp, int isspcl)
 }
 
 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;
@@ -414,6 +455,10 @@ flushtape(void)
 
        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)
@@ -469,10 +514,14 @@ flushtape(void)
        }
 
        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;
@@ -484,9 +533,9 @@ flushtape(void)
        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);
                        }
@@ -572,8 +621,6 @@ close_rewind(void)
 {
        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);
@@ -584,6 +631,8 @@ close_rewind(void)
        }
        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");
@@ -610,6 +659,10 @@ rollforward(void)
        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
@@ -737,6 +790,16 @@ rollforward(void)
 #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
@@ -783,7 +846,7 @@ restore_check_point:
        /*
         *      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);
@@ -871,6 +934,8 @@ restore_check_point:
                        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) : 
@@ -997,7 +1062,7 @@ enslave(void)
                }
 
                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));
 
@@ -1084,9 +1149,6 @@ doslave(int cmd,
        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
@@ -1223,7 +1285,7 @@ doslave(int cmd,
 #endif /* HAVE_ZLIB */
 #ifdef HAVE_BZLIB
                        if (zipflag == COMPRESS_BZLIB) {
-                               worklen2 = worklen;
+                               unsigned int worklen2 = worklen;
                                compresult = BZ2_bzBuffToBuffCompress(
                                                       comp_buf->buf,
                                                       &worklen2,
@@ -1241,10 +1303,12 @@ doslave(int cmd,
 #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
@@ -1291,7 +1355,8 @@ doslave(int cmd,
                                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 */
@@ -1379,13 +1444,13 @@ doslave(int cmd,
  * 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);
 }
@@ -1396,13 +1461,13 @@ dump_atomic_read(int fd, void *buf, size_t count)
  * 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 : (ssize_t)count - need);
 }