]> git.sur5r.net Git - bacula/bacula/commitdiff
ebl tweak faketape with variable file length
authorEric Bollengier <eric@eb.homelinux.org>
Mon, 2 Jun 2008 22:15:40 +0000 (22:15 +0000)
committerEric Bollengier <eric@eb.homelinux.org>
Mon, 2 Jun 2008 22:15:40 +0000 (22:15 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@7096 91ce42f0-d328-0410-95d8-f526ca767f89

bacula/patches/testing/faketape2.patch [new file with mode: 0644]

diff --git a/bacula/patches/testing/faketape2.patch b/bacula/patches/testing/faketape2.patch
new file mode 100644 (file)
index 0000000..34ebb51
--- /dev/null
@@ -0,0 +1,645 @@
+Index: src/stored/faketape.c
+===================================================================
+--- src/stored/faketape.c      (révision 7092)
++++ src/stored/faketape.c      (copie de travail)
+@@ -170,6 +170,7 @@
+ int faketape::tape_op(struct mtop *mt_com)
+ {
+    int result=0;
++   int count = mt_com->mt_count;
+    if (!online) {
+       errno = ENOMEDIUM;
+@@ -193,11 +194,15 @@
+       break;
+    case MTFSF:                  /* Forward space over mt_count filemarks. */
+-      result = fsf(mt_com->mt_count);
++      do {
++       result = fsf();
++      } while (--count > 0 && result == 0);
+       break;
+    case MTBSF:                  /* Backward space over mt_count filemarks. */
+-      result = bsf(mt_com->mt_count);
++      do {
++       result = bsf();
++      } while (--count > 0 && result == 0);
+       break;
+    case MTFSR:      /* Forward space over mt_count records (tape blocks). */
+@@ -222,16 +227,20 @@
+       break;
+    case MTWEOF:                 /* Write mt_count filemarks. */
+-      result = weof(mt_com->mt_count);
++      do {
++       result = weof();
++      } while (result == 0 && --count > 0);
+       break;
+    case MTREW:                  /* Rewind. */
+       Dmsg0(dbglevel, "rewind faketape\n");
++      check_eof();
+       atEOF = atEOD = false;
+       atBOT = true;
+       current_file = 0;
+       current_block = 0;
+-      seek_file();
++      lseek(fd, 0, SEEK_SET);
++      read_next_fm(true);
+       break;
+    case MTOFFL:                 /* put tape offline */
+@@ -253,19 +262,28 @@
+       break;
+    case MTEOM:/* Go to the end of the recorded media (for appending files). */
++      while (next_FM) {
++       lseek(fd, next_FM, SEEK_SET);
++       read_next_fm(true);
++      }
++      off_t l;
++      while (::read(fd, &l, sizeof(l)) > 0) {
++       if (l) {
++          lseek(fd, l, SEEK_CUR);
++       } else {
++          ASSERT(0);
++       }
++       Dmsg0(dbglevel, "skip 1 block\n");
++      }
++      current_block = -1;
++      atEOF = false;
++      atEOD = true;
++
+ /*
+    file number = 3
+    block number = -1
+ */
+       /* Can be at EOM */
+-      atBOT = false;
+-      atEOF = false;
+-      atEOD = true;
+-      atEOT = false;
+-
+-      current_file = last_file;
+-      current_block = -1;
+-      seek_file();
+       break;
+    case MTERASE:                /* not used by bacula */
+@@ -275,7 +293,8 @@
+       current_file = 0;
+       current_block = -1;
+-      seek_file();
++      lseek(fd, 0, SEEK_SET);
++      read_next_fm(true);
+       truncate_file();
+       break;
+@@ -405,8 +424,8 @@
+    atEOT = false;
+    atEOD = false;
+    online = false;
+-   inplace = false;
+    needEOF = false;
++   eot_count = 0;
+    file_block = 0;
+    last_file = 0;
+@@ -444,8 +463,6 @@
+       return -1;
+    }
+-   check_inplace();
+-
+    if (!atEOD) {                /* if not at the end of the data */
+       truncate_file();
+    }
+@@ -460,14 +477,6 @@
+    needEOF = true;              /* next operation need EOF mark */
+-//   if ((count + file_size) > max_size) {
+-//      Dmsg2(dbglevel, 
+-//          "EOT writing only %i of %i requested\n", 
+-//          max_size - file_size, count);
+-//      count = max_size - file_size;
+-//      atEOT = true;
+-//   }
+-
+    uint32_t size = count;
+    ::write(fd, &size, sizeof(uint32_t));
+    nb = ::write(fd, buffer, count);
+@@ -484,43 +493,68 @@
+    return nb;
+ }
+-int faketape::weof(int count)
++/*
++ *  +---+---------+---+------------------+---+-------------------+
++ *  |00N|  DATA   |0LN|   DATA           |0LC|     DATA          |
++ *  +---+---------+---+------------------+---+-------------------+
++ *
++ *  0 : zero
++ *  L : Last FileMark offset
++ *  N : Next FileMark offset
++ *  C : Current FileMark Offset
++ */
++int faketape::weof()
+ {
+    ASSERT(online);
+    ASSERT(current_file >= 0);
+    Dmsg3(dbglevel, "Writing EOF %i:%i last=%i\n", 
+          current_file, current_block,last_file);
++
++   off_t cur_FM;
++
+    if (atEOT) {
+       errno = ENOSPC;
+       current_block = -1;
+       return -1;
+    }
+-   needEOF = false;
+-   check_inplace();
+-   truncate_file();             /* nothing after this point */
++   if (!atEOD) {
++      truncate_file();             /* nothing after this point */
++   }
++   
++   cur_FM = lseek(fd, 0, SEEK_CUR); // current position
++   /* update previous next_FM  */
++   lseek(fd, last_FM + sizeof(uint32_t)+sizeof(off_t), SEEK_SET);
++   ::write(fd, &cur_FM, sizeof(off_t));
++   lseek(fd, cur_FM, SEEK_SET);
++
++   prev_FM = last_FM;
++   last_FM = cur_FM;
++   next_FM = 0;
++
+    uint32_t c=0;
+-   ::write(fd, &c, sizeof(uint32_t));
++   ::write(fd, &c,       sizeof(uint32_t)); // EOF
++   ::write(fd, &last_FM, sizeof(last_FM));  // F-1
++   ::write(fd, &next_FM, sizeof(next_FM));  // F   (will be updated next time)
+-   current_file += count;
++   current_file++;
+    current_block = 0;
+-   seek_file();
+-   c=0;
+-   ::write(fd, &c, sizeof(uint32_t));   
+-   lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
+-
++   needEOF = false;
+    atEOD = false;
+    atBOT = false;
+    atEOF = true;
+-   update_pos();
++   last_file = MAX(current_file, last_file);
+    return 0;
+ }
+-int faketape::fsf(int count)
++/*
++ * Go to next FM
++ */
++int faketape::fsf()
+ {   
+    ASSERT(online);
+    ASSERT(current_file >= 0);
+@@ -528,24 +562,33 @@
+ /*
+  * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
+  */
+-   check_inplace();
+-   check_eof();
+-   int ret;
++   int ret=0;
+    if (atEOT || atEOD) {
+       errno = EIO;
+       current_block = -1;
+       return -1;
+    }
+-   atBOT = atEOF = false;
+-   Dmsg3(dbglevel+1, "fsf %i+%i <= %i\n", current_file, count, last_file);
++   atBOT = false;
++   Dmsg2(dbglevel+1, "fsf %i <= %i\n", current_file, last_file);
+-   if ((current_file + count) <= last_file) {
+-      current_file += count;
+-      current_block = 0;
++   if (next_FM > last_FM) {   /* not the last file */
++      lseek(fd, next_FM, SEEK_SET);
++      read_next_fm(true);
++      current_file++;
++      atEOF = true;
+       ret = 0;
+-   } else {
++
++   } else if (atEOF) {                /* last file mark */
++      current_block=-1;
++      errno = EIO;
++      atEOF = false;
++      atEOD = true;
++
++   } else {                   /* last file, but no at the end */
++      fsr(100000);
++
+       Dmsg0(dbglevel, "Try to FSF after EOT\n");
+       errno = EIO;
+       current_file = last_file ;
+@@ -553,10 +596,44 @@
+       atEOD=true;
+       ret = -1;
+    }
+-   seek_file();
+    return ret;
+ }
++/* /------------\ /---------------\
++ * +---+------+---+---------------+-+
++ * |OLN|      |0LN|               | |
++ * +---+------+---+---------------+-+
++ */
++bool faketape::read_next_fm(bool read_all /* read the 0 byte */)
++{
++   prev_FM = last_FM;
++   return read_fm(read_all);
++}
++
++bool faketape::read_fm(bool read_all /* read the 0 byte */)
++{
++   int ret;
++   uint32_t c;
++   if (read_all) {
++      ::read(fd, &c, sizeof(c));
++      if (c != 0) {
++       lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(c), SEEK_SET);
++       return false;
++      }
++   }
++   ::read(fd, &last_FM, sizeof(last_FM));
++   ret = ::read(fd, &next_FM, sizeof(next_FM));
++
++   current_block=0;
++   
++   Dmsg1(dbglevel, "Read FM next=%lli\n", next_FM);
++
++   return (ret == sizeof(next_FM));
++}
++
++/*
++ * TODO: Check fsr with EOF
++ */
+ int faketape::fsr(int count)
+ {
+    ASSERT(online);
+@@ -568,7 +645,6 @@
+    uint32_t s;
+    Dmsg3(dbglevel, "fsr %i:%i count=%i\n", current_file,current_block, count);
+-   check_inplace();
+    check_eof();
+    if (atEOT) {
+@@ -595,20 +671,23 @@
+                current_file, current_block, nb,s);
+          errno = EIO;
+          ret = -1;
+-         if (current_file < last_file) {
++       if (next_FM) {
+             current_block = 0;
+             current_file++;
+-            seek_file();
+-         }
++          read_next_fm(false);
++       }
+          atEOF = true;          /* stop the loop */
+       }
+    }
+-   find_maxfile();              /* refresh stats */
+-
+    return ret;
+ }
++/*
++ * BSR + EOF => begin of EOF + EIO
++ * BSR + BSR + EOF => last block
++ * current_block = -1
++ */
+ int faketape::bsr(int count)
+ {
+    Dmsg2(dbglevel, "bsr current_block=%i count=%i\n", 
+@@ -619,7 +698,6 @@
+    ASSERT(count == 1);
+    ASSERT(fd >= 0);
+-   check_inplace();
+    check_eof();
+    if (!count) {
+@@ -641,22 +719,21 @@
+       return -1;
+    }
++   /* at EOF 0:-1 BOT=0 EOD=0 EOF=0 ERR: Input/output error  */
+    if (atEOF) {
+-      if (!current_block) {
+-       if (current_file > 0) {
+-          current_file--;
+-       }
+-       current_block=-1;
+-       errno = EIO;
+-       return -1;
+-
+-      } else {
+-       atEOF=false;
+-      }
++      lseek(fd, last_FM, SEEK_CUR);
++      atEOF = false;
++      current_block=-1;
++      errno = EIO;
++      return -1;
+    }
+-   current_block=0;
+-   seek_file();
++   /*
++    * First, go to last_FM and read all blocks to find the good one
++    */
++   
++   lseek(fd, last_FM, SEEK_CUR);
++   read_fm(true);
+    do {
+       if (!atEOF) {
+@@ -700,31 +777,35 @@
+    return 0;
+ }
+-int faketape::bsf(int count)
++/* BSF => just before last EOF
++ * EOF + BSF => just before EOF
++ * file 0 + BSF => BOT + errno
++ */
++int faketape::bsf()
+ {
+    ASSERT(online);
+    ASSERT(current_file >= 0);
+-   Dmsg3(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block, count);
++   Dmsg2(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block);
+    int ret = 0;
+-   check_inplace();
+    check_eof();
+    atBOT = atEOF = atEOT = atEOD = false;
+-   if (current_file - count < 0) {
++   if (current_file == 0) {/* BOT + errno */      
++      lseek(fd, 0, SEEK_SET);
++      read_fm(true);
++      prev_FM = 0;
+       current_file = 0;
+       current_block = 0;
+       atBOT = true;
+       errno = EIO;
+       ret = -1;
+    } else {
+-      current_file = current_file - count + 1;
+-      current_block = -1;
+-      seek_file();
++      Dmsg1(dbglevel, "bfs last=%lli\n", last_FM);
++      lseek(fd, last_FM, SEEK_SET);
+       current_file--;
+-      /* go just before last EOF */
+-      lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
++      current_block=-1;
+    }
+    return ret;
+ }
+@@ -749,6 +830,9 @@
+    return 0;
+ }
++/* A filemark is automatically written to tape if the last tape operation
++ * before close was a write.
++ */
+ int faketape::close()
+ {
+    check_eof();
+@@ -756,18 +840,15 @@
+    fd = -1;
+    return 0;
+ }
++
+ /*
+- **rb
+- **status
+- * EOF Bacula status: file=2 block=0
+- * Device status: EOF ONLINE IM_REP_EN file=2 block=0
+- **rb
+- **status
+- * EOD EOF Bacula status: file=2 block=0
+- * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
+- *
++ * When a filemark is encountered while reading, the following happens.  If
++ * there are data remaining in the buffer when the filemark is found, the
++ * buffered data is returned.  The next read returns zero bytes.  The following
++ * read returns data from the next file.  The end of recorded data is sig‐
++ * naled by returning zero bytes for two consecutive read calls.  The third
++ * read returns an error.
+  */
+-
+ int faketape::read(void *buffer, unsigned int count)
+ {
+    ASSERT(online);
+@@ -778,6 +859,10 @@
+    Dmsg2(dbglevel, "read %i:%i\n", current_file, current_block);
+    if (atEOT || atEOD) {
++      if (eot_count < 2) {    // first two reads return 0, after EIO
++       eot_count++;
++       return 0;
++      }
+       errno = EIO;
+       return -1;
+    }
+@@ -792,10 +877,10 @@
+       atEOF=false;
+    }
+-   check_inplace();
+    check_eof();
+    atEOD = atBOT = false;
++   eot_count = 0;
+    /* reading size of data */
+    nb = ::read(fd, &s, sizeof(uint32_t));
+@@ -813,11 +898,10 @@
+    if (!s) {                    /* EOF */
+       atEOF = true;
+-      if (current_file < last_file) { /* move to next file if possible */
+-         current_file++;
+-         current_block = 0;
+-         inplace=false;
++      if (read_next_fm(false)) {
++       current_file++;
+       }
++
+       return 0;
+    }
+@@ -825,7 +909,7 @@
+    nb = ::read(fd, buffer, s);
+    if (s != nb) {             /* read error */
+       errno=EIO;
+-      atEOT = true;
++      set_eot();
+       current_block = -1;
+       Dmsg0(dbglevel, "EOT during reading\n");
+       return -1;
+@@ -860,36 +944,25 @@
+       return -1;
+    }
+-   /* open volume descriptor and get this->fd */
+-   find_maxfile();
+-
+    file_block = 0;
+    current_block = 0;
+    current_file = 0;
++   prev_FM = next_FM = last_FM = 0;
++   eot_count = 0;
+    needEOF = false;
+-   inplace = true;
+    atBOT = true;
+    atEOT = atEOD = false;
+-   return fd;
+-}
+-
+-/*
+- * read volume to get the last file number
+- */
+-int faketape::find_maxfile()
+-{
+-   struct stat statp;
+-   if (fstat(fd, &statp) != 0) {
+-      return 0;
++   
++   if (!read_fm(true)) {
++      weof();
++      last_file = current_file=0;
+    }
+-   last_file = statp.st_size>>FILE_OFFSET;
+-      
+-   Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
+-   return last_file;
++   return fd;
+ }
++/* use this to track file usage */
+ void faketape::update_pos()
+ {
+    ASSERT(online);
+@@ -901,32 +974,12 @@
+    Dmsg1(dbglevel+1, "update_pos=%i\n", file_block);
+    if (file_block > max_block) {
+-      atEOT = true;
++      set_eot();
+    } else {
+       atEOT = false;
+    }
+ }
+-int faketape::seek_file()
+-{
+-   ASSERT(online);
+-   ASSERT(current_file >= 0);
+-   Dmsg2(dbglevel, "seek_file %i:%i\n", current_file, current_block);
+-   inplace = true;
+-
+-   off_t pos = ((off_t)current_file)<<FILE_OFFSET;
+-   if(lseek(fd, pos, SEEK_SET) == -1) {
+-      return -1;
+-   }
+-
+-   last_file = MAX(last_file, current_file);
+-   if (current_block > 0) {
+-      fsr(current_block);
+-   }
+-
+-   return 0;
+-}
+-
+ void faketape::dump()
+ {
+    Dmsg0(dbglevel+1, "===================\n");
+Index: src/stored/faketape.h
+===================================================================
+--- src/stored/faketape.h      (révision 7084)
++++ src/stored/faketape.h      (copie de travail)
+@@ -56,35 +56,39 @@
+ private:
+    int         fd;              /* Our file descriptor */
+-   off_t       file_block;       /* size */
++   off_t       file_block;    /* size */
+    off_t       max_block;
++   off_t       prev_FM;               /* previous file mark */
++   off_t       last_FM;               /* last file mark (current file) */
++   off_t       next_FM;
++
+    bool        atEOF;           /* End of file */
+    bool        atEOT;           /* End of media */
+    bool        atEOD;           /* End of data */
+    bool        atBOT;           /* Begin of tape */
+    bool        online;          /* volume online */
+-   bool        inplace;         /* have to seek before writing ? */
+    bool        needEOF;         /* check if last operation need eof */
+    int32_t     last_file;       /* last file of the volume */
+    int32_t     current_file;    /* current position */
+    int32_t     current_block;   /* current position */
++   int         eot_count;     /* count eot reads */
+    void destroy();
+-   int find_maxfile();
+    int offline();
+    int truncate_file();
+-   int seek_file();
+-   void check_eof() { if(needEOF) weof(1);};
+-   void check_inplace() { if (!inplace) seek_file();};
++   void check_eof() { if(needEOF) weof();};
+    void update_pos();
++   bool read_fm(bool readfirst);
++   bool read_next_fm(bool readfirst);
++   void set_eot() { eot_count=0; atEOT=true;};
+ public:
+-   int fsf(int count);
++   int fsf();
+    int fsr(int count);
+-   int weof(int count);
+-   int bsf(int count);
++   int weof();
++   int bsf();
+    int bsr(int count);
+    faketape();