Author: mckusick
Date: Mon Aug  7 19:40:03 2017
New Revision: 322179
URL: https://svnweb.freebsd.org/changeset/base/322179

Log:
  gjournal is broken in handling its flush_queue. If we have 10 bio's
  in the flush_queue:
           1 2 3 4 5 6 7 8 9 10
  and another 10 bio's go into the flush queue after only the first five
  bio's are removed from the flush queue, the queue should look like:
           6 7 8 9 10 11 12 13 14 15 16 17 18 19 20,
  but because of the bug we end up with
           6 11 12 13 14  15 16 17 18 19 20 7 8 9 10.
  So the sequence of the bio's is damaged in the flush queue (and
  therefore in the journal on disk !). This error can be triggered by
  ffs_snapshot() when a block is read with readblock() and gjournal finds
  this block in the broken flush queue before it goes to the correct
  active queue.
  
  The fix is to place all new blocks at the end of the queue.
  
  Submitted by: Dr. Andreas Longwitz <longw...@incore.de>
  Discussed with: kib
  MFC after: 1 week

Modified:
  head/sys/geom/journal/g_journal.c
  head/sys/geom/journal/g_journal.h

Modified: head/sys/geom/journal/g_journal.c
==============================================================================
--- head/sys/geom/journal/g_journal.c   Mon Aug  7 19:18:27 2017        
(r322178)
+++ head/sys/geom/journal/g_journal.c   Mon Aug  7 19:40:03 2017        
(r322179)
@@ -1261,7 +1261,7 @@ g_journal_flush(struct g_journal_softc *sc)
        strlcpy(hdr.jrh_magic, GJ_RECORD_HEADER_MAGIC, sizeof(hdr.jrh_magic));
 
        bioq = &sc->sc_active.jj_queue;
-       pbp = sc->sc_flush_queue;
+       GJQ_LAST(sc->sc_flush_queue, pbp);
 
        fbp = g_alloc_bio();
        fbp->bio_parent = NULL;

Modified: head/sys/geom/journal/g_journal.h
==============================================================================
--- head/sys/geom/journal/g_journal.h   Mon Aug  7 19:18:27 2017        
(r322178)
+++ head/sys/geom/journal/g_journal.h   Mon Aug  7 19:40:03 2017        
(r322179)
@@ -182,6 +182,17 @@ struct g_journal_softc {
                (pbp)->bio_next = (bp);                                 \
        }                                                               \
 } while (0)
+#define GJQ_LAST(head, bp) do {                                                
\
+       struct bio *_bp;                                                \
+                                                                       \
+       if ((head) == NULL) {                                           \
+               (bp) = (head);                                          \
+               break;                                                  \
+       }                                                               \
+       for (_bp = (head); _bp->bio_next != NULL; _bp = _bp->bio_next)  \
+               continue;                                               \
+       (bp) = (_bp);                                                   \
+} while (0)
 #define        GJQ_FIRST(head) (head)
 #define        GJQ_REMOVE(head, bp)    do {                                    
\
        struct bio *_bp;                                                \
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to