[BACK]Return to vfs_wapbl.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/kern/vfs_wapbl.c between version 1.61.2.2 and 1.61.2.3

version 1.61.2.2, 2015/12/27 12:10:05 version 1.61.2.3, 2016/05/29 08:44:37
Line 40  __KERNEL_RCSID(0, "$NetBSD$");
Line 40  __KERNEL_RCSID(0, "$NetBSD$");
   
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/bitops.h>  #include <sys/bitops.h>
   #include <sys/time.h>
   #include <sys/wapbl.h>
   #include <sys/wapbl_replay.h>
   
 #ifdef _KERNEL  #ifdef _KERNEL
 #include <sys/param.h>  
   #include <sys/atomic.h>
   #include <sys/conf.h>
   #include <sys/file.h>
   #include <sys/kauth.h>
   #include <sys/kernel.h>
   #include <sys/module.h>
   #include <sys/mount.h>
   #include <sys/mutex.h>
 #include <sys/namei.h>  #include <sys/namei.h>
 #include <sys/proc.h>  #include <sys/proc.h>
   #include <sys/resourcevar.h>
 #include <sys/sysctl.h>  #include <sys/sysctl.h>
 #include <sys/uio.h>  #include <sys/uio.h>
 #include <sys/vnode.h>  #include <sys/vnode.h>
 #include <sys/file.h>  
 #include <sys/module.h>  
 #include <sys/resourcevar.h>  
 #include <sys/conf.h>  
 #include <sys/mount.h>  
 #include <sys/kernel.h>  
 #include <sys/kauth.h>  
 #include <sys/mutex.h>  
 #include <sys/atomic.h>  
 #include <sys/wapbl.h>  
 #include <sys/wapbl_replay.h>  
   
 #include <miscfs/specfs/specdev.h>  #include <miscfs/specfs/specdev.h>
   
Line 73  static int wapbl_verbose_commit = 0;
Line 74  static int wapbl_verbose_commit = 0;
 static inline size_t wapbl_space_free(size_t, off_t, off_t);  static inline size_t wapbl_space_free(size_t, off_t, off_t);
   
 #else /* !_KERNEL */  #else /* !_KERNEL */
   
 #include <assert.h>  #include <assert.h>
 #include <errno.h>  #include <errno.h>
 #include <stdio.h>  
 #include <stdbool.h>  #include <stdbool.h>
   #include <stdio.h>
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  #include <string.h>
   
 #include <sys/time.h>  
 #include <sys/wapbl.h>  
 #include <sys/wapbl_replay.h>  
   
 #define KDASSERT(x) assert(x)  #define KDASSERT(x) assert(x)
 #define KASSERT(x) assert(x)  #define KASSERT(x) assert(x)
 #define wapbl_alloc(s) malloc(s)  #define wapbl_alloc(s) malloc(s)
Line 129  struct wapbl {
Line 127  struct wapbl {
         off_t wl_head;          /* l:   Byte offset of log head */          off_t wl_head;          /* l:   Byte offset of log head */
         off_t wl_tail;          /* l:   Byte offset of log tail */          off_t wl_tail;          /* l:   Byte offset of log tail */
         /*          /*
          * head == tail == 0 means log is empty           * WAPBL log layout, stored on wl_devvp at wl_logpbn:
          * head == tail != 0 means log is full           *
          * see assertions in wapbl_advance() for other boundary conditions.           *  ___________________ wl_circ_size __________________
          * only truncate moves the tail, except when flush sets it to           * /                                                   \
          * wl_header_size only flush moves the head, except when truncate           * +---------+---------+-------+--------------+--------+
          * sets it to 0.           * [ commit0 | commit1 | CCWCW | EEEEEEEEEEEE | CCCWCW ]
            * +---------+---------+-------+--------------+--------+
            *       wl_circ_off --^       ^-- wl_head    ^-- wl_tail
            *
            * commit0 and commit1 are commit headers.  A commit header has
            * a generation number, indicating which of the two headers is
            * more recent, and an assignment of head and tail pointers.
            * The rest is a circular queue of log records, starting at
            * the byte offset wl_circ_off.
            *
            * E marks empty space for records.
            * W marks records for block writes issued but waiting.
            * C marks completed records.
            *
            * wapbl_flush writes new records to empty `E' spaces after
            * wl_head from the current transaction in memory.
            *
            * wapbl_truncate advances wl_tail past any completed `C'
            * records, freeing them up for use.
            *
            * head == tail == 0 means log is empty.
            * head == tail != 0 means log is full.
            *
            * See assertions in wapbl_advance() for other boundary
            * conditions.
            *
            * Only wapbl_flush moves the head, except when wapbl_truncate
            * sets it to 0 to indicate that the log is empty.
            *
            * Only wapbl_truncate moves the tail, except when wapbl_flush
            * sets it to wl_circ_off to indicate that the log is full.
          */           */
   
         struct wapbl_wc_header *wl_wc_header;   /* l    */          struct wapbl_wc_header *wl_wc_header;   /* l    */
Line 241  int wapbl_replay_verify(struct wapbl_rep
Line 269  int wapbl_replay_verify(struct wapbl_rep
   
 static int wapbl_replay_isopen1(struct wapbl_replay *);  static int wapbl_replay_isopen1(struct wapbl_replay *);
   
 /*  
  * This is useful for debugging.  If set, the log will  
  * only be truncated when necessary.  
  */  
 int wapbl_lazy_truncate = 0;  
   
 struct wapbl_ops wapbl_ops = {  struct wapbl_ops wapbl_ops = {
         .wo_wapbl_discard       = wapbl_discard,          .wo_wapbl_discard       = wapbl_discard,
         .wo_wapbl_replay_isopen = wapbl_replay_isopen1,          .wo_wapbl_replay_isopen = wapbl_replay_isopen1,
Line 309  wapbl_init(void)
Line 331  wapbl_init(void)
 }  }
   
 static int  static int
 wapbl_fini(bool interface)  wapbl_fini(void)
 {  {
   
         if (wapbl_sysctl != NULL)          if (wapbl_sysctl != NULL)
Line 723  wapbl_stop(struct wapbl *wl, int force)
Line 745  wapbl_stop(struct wapbl *wl, int force)
         return 0;          return 0;
 }  }
   
   /****************************************************************/
   /*
    * Unbuffered disk I/O
    */
   
 static int  static int
 wapbl_doio(void *data, size_t len, struct vnode *devvp, daddr_t pbn, int flags)  wapbl_doio(void *data, size_t len, struct vnode *devvp, daddr_t pbn, int flags)
 {  {
Line 773  wapbl_doio(void *data, size_t len, struc
Line 800  wapbl_doio(void *data, size_t len, struc
         return error;          return error;
 }  }
   
   /*
    * wapbl_write(data, len, devvp, pbn)
    *
    *      Synchronously write len bytes from data to physical block pbn
    *      on devvp.
    */
 int  int
 wapbl_write(void *data, size_t len, struct vnode *devvp, daddr_t pbn)  wapbl_write(void *data, size_t len, struct vnode *devvp, daddr_t pbn)
 {  {
Line 780  wapbl_write(void *data, size_t len, stru
Line 813  wapbl_write(void *data, size_t len, stru
         return wapbl_doio(data, len, devvp, pbn, B_WRITE);          return wapbl_doio(data, len, devvp, pbn, B_WRITE);
 }  }
   
   /*
    * wapbl_read(data, len, devvp, pbn)
    *
    *      Synchronously read len bytes into data from physical block pbn
    *      on devvp.
    */
 int  int
 wapbl_read(void *data, size_t len, struct vnode *devvp, daddr_t pbn)  wapbl_read(void *data, size_t len, struct vnode *devvp, daddr_t pbn)
 {  {
Line 787  wapbl_read(void *data, size_t len, struc
Line 826  wapbl_read(void *data, size_t len, struc
         return wapbl_doio(data, len, devvp, pbn, B_READ);          return wapbl_doio(data, len, devvp, pbn, B_READ);
 }  }
   
   /****************************************************************/
   /*
    * Buffered disk writes -- try to coalesce writes and emit
    * MAXPHYS-aligned blocks.
    */
   
 /*  /*
  * Flush buffered data if any.   * wapbl_buffered_flush(wl)
    *
    *      Flush any buffered writes from wapbl_buffered_write.
  */   */
 static int  static int
 wapbl_buffered_flush(struct wapbl *wl)  wapbl_buffered_flush(struct wapbl *wl)
Line 806  wapbl_buffered_flush(struct wapbl *wl)
Line 853  wapbl_buffered_flush(struct wapbl *wl)
 }  }
   
 /*  /*
  * Write data to the log.   * wapbl_buffered_write(data, len, wl, pbn)
  * Try to coalesce writes and emit MAXPHYS aligned blocks.   *
    *      Write len bytes from data to physical block pbn on
    *      wl->wl_devvp.  The write may not complete until
    *      wapbl_buffered_flush.
  */   */
 static int  static int
 wapbl_buffered_write(void *data, size_t len, struct wapbl *wl, daddr_t pbn)  wapbl_buffered_write(void *data, size_t len, struct wapbl *wl, daddr_t pbn)
Line 863  wapbl_buffered_write(void *data, size_t 
Line 913  wapbl_buffered_write(void *data, size_t 
 }  }
   
 /*  /*
  * Off is byte offset returns new offset for next write   * wapbl_circ_write(wl, data, len, offp)
  * handles log wraparound   *
    *      Write len bytes from data to the circular queue of wl, starting
    *      at linear byte offset *offp, and returning the new linear byte
    *      offset in *offp.
    *
    *      If the starting linear byte offset precedes wl->wl_circ_off,
    *      the write instead begins at wl->wl_circ_off.  XXX WTF?  This
    *      should be a KASSERT, not a conditional.
    *
    *      The write is buffered in wl and must be flushed with
    *      wapbl_buffered_flush before it will be submitted to the disk.
  */   */
 static int  static int
 wapbl_circ_write(struct wapbl *wl, void *data, size_t len, off_t *offp)  wapbl_circ_write(struct wapbl *wl, void *data, size_t len, off_t *offp)
Line 907  wapbl_circ_write(struct wapbl *wl, void 
Line 967  wapbl_circ_write(struct wapbl *wl, void 
 }  }
   
 /****************************************************************/  /****************************************************************/
   /*
    * WAPBL transactions: entering, adding/removing bufs, and exiting
    */
   
 int  int
 wapbl_begin(struct wapbl *wl, const char *file, int line)  wapbl_begin(struct wapbl *wl, const char *file, int line)
Line 976  wapbl_end(struct wapbl *wl)
Line 1039  wapbl_end(struct wapbl *wl)
               wl->wl_bufbytes, wl->wl_bcount));                wl->wl_bufbytes, wl->wl_bcount));
 #endif  #endif
   
 #ifdef DIAGNOSTIC          /*
         size_t flushsize = wapbl_transaction_len(wl);           * XXX this could be handled more gracefully, perhaps place
         if (flushsize > (wl->wl_circ_size - wl->wl_reserved_bytes)) {           * only a partial transaction in the log and allow the
                 /*           * remaining to flush without the protection of the journal.
                  * XXX this could be handled more gracefully, perhaps place           */
                  * only a partial transaction in the log and allow the          KASSERTMSG((wapbl_transaction_len(wl) <=
                  * remaining to flush without the protection of the journal.                  (wl->wl_circ_size - wl->wl_reserved_bytes)),
                  */              "wapbl_end: current transaction too big to flush");
                 panic("wapbl_end: current transaction too big to flush\n");  
         }  
 #endif  
   
         mutex_enter(&wl->wl_mtx);          mutex_enter(&wl->wl_mtx);
         KASSERT(wl->wl_lock_count > 0);          KASSERT(wl->wl_lock_count > 0);
Line 1112  wapbl_resize_buf(struct wapbl *wl, struc
Line 1172  wapbl_resize_buf(struct wapbl *wl, struc
 /****************************************************************/  /****************************************************************/
 /* Some utility inlines */  /* Some utility inlines */
   
   /*
    * wapbl_space_used(avail, head, tail)
    *
    *      Number of bytes used in a circular queue of avail total bytes,
    *      from tail to head.
    */
 static inline size_t  static inline size_t
 wapbl_space_used(size_t avail, off_t head, off_t tail)  wapbl_space_used(size_t avail, off_t head, off_t tail)
 {  {
Line 1124  wapbl_space_used(size_t avail, off_t hea
Line 1190  wapbl_space_used(size_t avail, off_t hea
 }  }
   
 #ifdef _KERNEL  #ifdef _KERNEL
 /* This is used to advance the pointer at old to new value at old+delta */  /*
    * wapbl_advance(size, off, oldoff, delta)
    *
    *      Given a byte offset oldoff into a circular queue of size bytes
    *      starting at off, return a new byte offset oldoff + delta into
    *      the circular queue.
    */
 static inline off_t  static inline off_t
 wapbl_advance(size_t size, size_t off, off_t oldoff, size_t delta)  wapbl_advance(size_t size, size_t off, off_t oldoff, size_t delta)
 {  {
Line 1153  wapbl_advance(size_t size, size_t off, o
Line 1225  wapbl_advance(size_t size, size_t off, o
         return newoff;          return newoff;
 }  }
   
   /*
    * wapbl_space_free(avail, head, tail)
    *
    *      Number of bytes free in a circular queue of avail total bytes,
    *      in which everything from tail to head is used.
    */
 static inline size_t  static inline size_t
 wapbl_space_free(size_t avail, off_t head, off_t tail)  wapbl_space_free(size_t avail, off_t head, off_t tail)
 {  {
Line 1160  wapbl_space_free(size_t avail, off_t hea
Line 1238  wapbl_space_free(size_t avail, off_t hea
         return avail - wapbl_space_used(avail, head, tail);          return avail - wapbl_space_used(avail, head, tail);
 }  }
   
   /*
    * wapbl_advance_head(size, off, delta, headp, tailp)
    *
    *      In a circular queue of size bytes starting at off, given the
    *      old head and tail offsets *headp and *tailp, store the new head
    *      and tail offsets in *headp and *tailp resulting from adding
    *      delta bytes of data to the head.
    */
 static inline void  static inline void
 wapbl_advance_head(size_t size, size_t off, size_t delta, off_t *headp,  wapbl_advance_head(size_t size, size_t off, size_t delta, off_t *headp,
                    off_t *tailp)                     off_t *tailp)
Line 1175  wapbl_advance_head(size_t size, size_t o
Line 1261  wapbl_advance_head(size_t size, size_t o
         *tailp = tail;          *tailp = tail;
 }  }
   
   /*
    * wapbl_advance_tail(size, off, delta, headp, tailp)
    *
    *      In a circular queue of size bytes starting at off, given the
    *      old head and tail offsets *headp and *tailp, store the new head
    *      and tail offsets in *headp and *tailp resulting from removing
    *      delta bytes of data from the tail.
    */
 static inline void  static inline void
 wapbl_advance_tail(size_t size, size_t off, size_t delta, off_t *headp,  wapbl_advance_tail(size_t size, size_t off, size_t delta, off_t *headp,
                    off_t *tailp)                     off_t *tailp)
Line 1195  wapbl_advance_tail(size_t size, size_t o
Line 1289  wapbl_advance_tail(size_t size, size_t o
 /****************************************************************/  /****************************************************************/
   
 /*  /*
  * Remove transactions whose buffers are completely flushed to disk.   * wapbl_truncate(wl, minfree)
  * Will block until at least minfree space is available.   *
  * only intended to be called from inside wapbl_flush and therefore   *      Wait until at least minfree bytes are available in the log.
  * does not protect against commit races with itself or with flush.   *
    *      If it was necessary to wait for writes to complete,
    *      advance the circular queue tail to reflect the new write
    *      completions and issue a write commit to the log.
    *
    *      => Caller must hold wl->wl_rwlock writer lock.
  */   */
 static int  static int
 wapbl_truncate(struct wapbl *wl, size_t minfree, int waitonly)  wapbl_truncate(struct wapbl *wl, size_t minfree)
 {  {
         size_t delta;          size_t delta;
         size_t avail;          size_t avail;
Line 1260  wapbl_truncate(struct wapbl *wl, size_t 
Line 1359  wapbl_truncate(struct wapbl *wl, size_t 
         if (error)          if (error)
                 return error;                  return error;
   
         if (waitonly)  
                 return 0;  
   
         /*          /*
          * This is where head, tail and delta are unprotected           * This is where head, tail and delta are unprotected
          * from races against itself or flush.  This is ok since           * from races against itself or flush.  This is ok since
Line 1335  wapbl_biodone(struct buf *bp)
Line 1431  wapbl_biodone(struct buf *bp)
 #endif  #endif
   
         if (bp->b_error) {          if (bp->b_error) {
 #ifdef notyet /* Can't currently handle possible dirty buffer reuse */  
                 /*  
                  * XXXpooka: interfaces not fully updated  
                  * Note: this was not enabled in the original patch  
                  * against netbsd4 either.  I don't know if comment  
                  * above is true or not.  
                  */  
   
                 /*                  /*
                  * If an error occurs, report the error and leave the                   * If an error occurs, it would be nice to leave the buffer
                  * buffer as a delayed write on the LRU queue.                   * as a delayed write on the LRU queue so that we can retry
                  * restarting the write would likely result in                   * it later. But buffercache(9) can't handle dirty buffer
                  * an error spinloop, so let it be done harmlessly                   * reuse, so just mark the log permanently errored out.
                  * by the syncer.  
                  */                   */
                 bp->b_flags &= ~(B_DONE);  
                 simple_unlock(&bp->b_interlock);  
   
                 if (we->we_error == 0) {  
                         mutex_enter(&wl->wl_mtx);  
                         wl->wl_error_count++;  
                         mutex_exit(&wl->wl_mtx);  
                         cv_broadcast(&wl->wl_reclaimable_cv);  
                 }  
                 we->we_error = bp->b_error;  
                 bp->b_error = 0;  
                 brelse(bp);  
                 return;  
 #else  
                 /* For now, just mark the log permanently errored out */  
   
                 mutex_enter(&wl->wl_mtx);                  mutex_enter(&wl->wl_mtx);
                 if (wl->wl_error_count == 0) {                  if (wl->wl_error_count == 0) {
                         wl->wl_error_count++;                          wl->wl_error_count++;
                         cv_broadcast(&wl->wl_reclaimable_cv);                          cv_broadcast(&wl->wl_reclaimable_cv);
                 }                  }
                 mutex_exit(&wl->wl_mtx);                  mutex_exit(&wl->wl_mtx);
 #endif  
         }          }
   
         /*          /*
Line 1430  wapbl_biodone(struct buf *bp)
Line 1500  wapbl_biodone(struct buf *bp)
 }  }
   
 /*  /*
  * Write transactions to disk + start I/O for contents   * wapbl_flush(wl, wait)
    *
    *      Flush pending block writes, deallocations, and inodes from
    *      the current transaction in memory to the log on disk:
    *
    *      1. Call the file system's wl_flush callback to flush any
    *         per-file-system pending updates.
    *      2. Wait for enough space in the log for the current transaction.
    *      3. Synchronously write the new log records, advancing the
    *         circular queue head.
    *      4. Issue the pending block writes asynchronously, now that they
    *         are recorded in the log and can be replayed after crash.
    *      5. If wait is true, wait for all writes to complete and for the
    *         log to become empty.
    *
    *      On failure, call the file system's wl_flush_abort callback.
  */   */
 int  int
 wapbl_flush(struct wapbl *wl, int waitfor)  wapbl_flush(struct wapbl *wl, int waitfor)
Line 1471  wapbl_flush(struct wapbl *wl, int waitfo
Line 1556  wapbl_flush(struct wapbl *wl, int waitfo
             wl->wl_dealloccnt);              wl->wl_dealloccnt);
   
         /*          /*
          * Now that we are fully locked and flushed,           * Now that we are exclusively locked and the file system has
          * do another check for nothing to do.           * issued any deferred block writes for this transaction, check
            * whether there are any blocks to write to the log.  If not,
            * skip waiting for space or writing any log entries.
            *
            * XXX Shouldn't this also check wl_dealloccnt and
            * wl_inohashcnt?  Perhaps wl_dealloccnt doesn't matter if the
            * file system didn't produce any blocks as a consequence of
            * it, but the same does not seem to be so of wl_inohashcnt.
          */           */
         if (wl->wl_bufcount == 0) {          if (wl->wl_bufcount == 0) {
                 goto out;                  goto wait_out;
         }          }
   
 #if 0  #if 0
Line 1502  wapbl_flush(struct wapbl *wl, int waitfo
Line 1594  wapbl_flush(struct wapbl *wl, int waitfo
                  * only a partial transaction in the log and allow the                   * only a partial transaction in the log and allow the
                  * remaining to flush without the protection of the journal.                   * remaining to flush without the protection of the journal.
                  */                   */
                 panic("wapbl_flush: current transaction too big to flush\n");                  panic("wapbl_flush: current transaction too big to flush");
         }          }
   
         error = wapbl_truncate(wl, flushsize, 0);          error = wapbl_truncate(wl, flushsize);
         if (error)          if (error)
                 goto out2;                  goto out;
   
         off = wl->wl_head;          off = wl->wl_head;
         KASSERT((off == 0) || ((off >= wl->wl_circ_off) &&          KASSERT((off == 0) || (off >= wl->wl_circ_off));
                               (off < wl->wl_circ_off + wl->wl_circ_size)));          KASSERT((off == 0) || (off < wl->wl_circ_off + wl->wl_circ_size));
         error = wapbl_write_blocks(wl, &off);          error = wapbl_write_blocks(wl, &off);
         if (error)          if (error)
                 goto out2;                  goto out;
         error = wapbl_write_revocations(wl, &off);          error = wapbl_write_revocations(wl, &off);
         if (error)          if (error)
                 goto out2;                  goto out;
         error = wapbl_write_inodes(wl, &off);          error = wapbl_write_inodes(wl, &off);
         if (error)          if (error)
                 goto out2;                  goto out;
   
         reserved = 0;          reserved = 0;
         if (wl->wl_inohashcnt)          if (wl->wl_inohashcnt)
Line 1531  wapbl_flush(struct wapbl *wl, int waitfo
Line 1623  wapbl_flush(struct wapbl *wl, int waitfo
   
         wapbl_advance_head(wl->wl_circ_size, wl->wl_circ_off, flushsize,          wapbl_advance_head(wl->wl_circ_size, wl->wl_circ_off, flushsize,
             &head, &tail);              &head, &tail);
 #ifdef WAPBL_DEBUG  
         if (head != off) {          KASSERTMSG(head == off,
                 panic("lost head! head=%"PRIdMAX" tail=%" PRIdMAX              "lost head! head=%"PRIdMAX" tail=%" PRIdMAX
                       " off=%"PRIdMAX" flush=%zu\n",              " off=%"PRIdMAX" flush=%zu",
                       (intmax_t)head, (intmax_t)tail, (intmax_t)off,              (intmax_t)head, (intmax_t)tail, (intmax_t)off,
                       flushsize);              flushsize);
         }  
 #else  
         KASSERT(head == off);  
 #endif  
   
         /* Opportunistically move the tail forward if we can */          /* Opportunistically move the tail forward if we can */
         if (!wapbl_lazy_truncate) {          mutex_enter(&wl->wl_mtx);
                 mutex_enter(&wl->wl_mtx);          delta = wl->wl_reclaimable_bytes;
                 delta = wl->wl_reclaimable_bytes;          mutex_exit(&wl->wl_mtx);
                 mutex_exit(&wl->wl_mtx);          wapbl_advance_tail(wl->wl_circ_size, wl->wl_circ_off, delta,
                 wapbl_advance_tail(wl->wl_circ_size, wl->wl_circ_off, delta,              &head, &tail);
                     &head, &tail);  
         }  
   
         error = wapbl_write_commit(wl, head, tail);          error = wapbl_write_commit(wl, head, tail);
         if (error)          if (error)
                 goto out2;                  goto out;
   
         we = pool_get(&wapbl_entry_pool, PR_WAITOK);          we = pool_get(&wapbl_entry_pool, PR_WAITOK);
   
Line 1631  wapbl_flush(struct wapbl *wl, int waitfo
Line 1717  wapbl_flush(struct wapbl *wl, int waitfo
                      curproc->p_pid, curlwp->l_lid));                       curproc->p_pid, curlwp->l_lid));
 #endif  #endif
   
  out:   wait_out:
   
         /*          /*
          * If the waitfor flag is set, don't return until everything is           * If the waitfor flag is set, don't return until everything is
Line 1639  wapbl_flush(struct wapbl *wl, int waitfo
Line 1725  wapbl_flush(struct wapbl *wl, int waitfo
          */           */
         if (waitfor) {          if (waitfor) {
                 error = wapbl_truncate(wl, wl->wl_circ_size -                  error = wapbl_truncate(wl, wl->wl_circ_size -
                         wl->wl_reserved_bytes, wapbl_lazy_truncate);                          wl->wl_reserved_bytes);
         }          }
   
  out2:   out:
         if (error) {          if (error) {
                 wl->wl_flush_abort(wl->wl_mount, wl->wl_deallocblks,                  wl->wl_flush_abort(wl->wl_mount, wl->wl_deallocblks,
                     wl->wl_dealloclens, wl->wl_dealloccnt);                      wl->wl_dealloclens, wl->wl_dealloccnt);
Line 1947  wapbl_unregister_inode(struct wapbl *wl,
Line 2033  wapbl_unregister_inode(struct wapbl *wl,
   
 /****************************************************************/  /****************************************************************/
   
   /*
    * wapbl_transaction_inodes_len(wl)
    *
    *      Calculate the number of bytes required for inode registration
    *      log records in wl.
    */
 static inline size_t  static inline size_t
 wapbl_transaction_inodes_len(struct wapbl *wl)  wapbl_transaction_inodes_len(struct wapbl *wl)
 {  {
Line 1963  wapbl_transaction_inodes_len(struct wapb
Line 2055  wapbl_transaction_inodes_len(struct wapb
 }  }
   
   
 /* Calculate amount of space a transaction will take on disk */  /*
    * wapbl_transaction_len(wl)
    *
    *      Calculate number of bytes required for all log records in wl.
    */
 static size_t  static size_t
 wapbl_transaction_len(struct wapbl *wl)  wapbl_transaction_len(struct wapbl *wl)
 {  {
Line 1986  wapbl_transaction_len(struct wapbl *wl)
Line 2082  wapbl_transaction_len(struct wapbl *wl)
 }  }
   
 /*  /*
  * wapbl_cache_sync: issue DIOCCACHESYNC   * wapbl_cache_sync(wl, msg)
    *
    *      Issue DIOCCACHESYNC to wl->wl_devvp.
    *
    *      If sysctl(vfs.wapbl.verbose_commit) >= 2, print a message
    *      including msg about the duration of the cache sync.
  */   */
 static int  static int
 wapbl_cache_sync(struct wapbl *wl, const char *msg)  wapbl_cache_sync(struct wapbl *wl, const char *msg)
Line 2006  wapbl_cache_sync(struct wapbl *wl, const
Line 2107  wapbl_cache_sync(struct wapbl *wl, const
             FWRITE, FSCRED);              FWRITE, FSCRED);
         if (error) {          if (error) {
                 WAPBL_PRINTF(WAPBL_PRINT_ERROR,                  WAPBL_PRINTF(WAPBL_PRINT_ERROR,
                     ("wapbl_cache_sync: DIOCCACHESYNC on dev 0x%x "                      ("wapbl_cache_sync: DIOCCACHESYNC on dev 0x%jx "
                     "returned %d\n", wl->wl_devvp->v_rdev, error));                      "returned %d\n", (uintmax_t)wl->wl_devvp->v_rdev, error));
         }          }
         if (verbose) {          if (verbose) {
                 struct bintime d;                  struct bintime d;
Line 2024  wapbl_cache_sync(struct wapbl *wl, const
Line 2125  wapbl_cache_sync(struct wapbl *wl, const
 }  }
   
 /*  /*
  * Perform commit operation   * wapbl_write_commit(wl, head, tail)
    *
    *      Issue a disk cache sync to wait for all pending writes to the
    *      log to complete, and then synchronously commit the current
    *      circular queue head and tail to the log, in the next of two
    *      locations for commit headers on disk.
  *   *
  * Note that generation number incrementation needs to   *      Increment the generation number.  If the generation number
  * be protected against racing with other invocations   *      rolls over to zero, then a subsequent commit would appear to
  * of wapbl_write_commit.  This is ok since this routine   *      have an older generation than this one -- in that case, issue a
  * is only invoked from wapbl_flush   *      duplicate commit to avoid this.
    *
    *      => Caller must have exclusive access to wl, either by holding
    *      wl->wl_rwlock for writer or by being wapbl_start before anyone
    *      else has seen wl.
  */   */
 static int  static int
 wapbl_write_commit(struct wapbl *wl, off_t head, off_t tail)  wapbl_write_commit(struct wapbl *wl, off_t head, off_t tail)
Line 2099  wapbl_write_commit(struct wapbl *wl, off
Line 2209  wapbl_write_commit(struct wapbl *wl, off
                  */                   */
                 if (error)                  if (error)
                         panic("wapbl_write_commit: error writing duplicate "                          panic("wapbl_write_commit: error writing duplicate "
                               "log header: %d\n", error);                                "log header: %d", error);
         }          }
         return 0;          return 0;
 }  }
   
 /* Returns new offset value */  /*
    * wapbl_write_blocks(wl, offp)
    *
    *      Write all pending physical blocks in the current transaction
    *      from wapbl_add_buf to the log on disk, adding to the circular
    *      queue head at byte offset *offp, and returning the new head's
    *      byte offset in *offp.
    */
 static int  static int
 wapbl_write_blocks(struct wapbl *wl, off_t *offp)  wapbl_write_blocks(struct wapbl *wl, off_t *offp)
 {  {
Line 2194  wapbl_write_blocks(struct wapbl *wl, off
Line 2311  wapbl_write_blocks(struct wapbl *wl, off
         return 0;          return 0;
 }  }
   
   /*
    * wapbl_write_revocations(wl, offp)
    *
    *      Write all pending deallocations in the current transaction from
    *      wapbl_register_deallocation to the log on disk, adding to the
    *      circular queue's head at byte offset *offp, and returning the
    *      new head's byte offset in *offp.
    */
 static int  static int
 wapbl_write_revocations(struct wapbl *wl, off_t *offp)  wapbl_write_revocations(struct wapbl *wl, off_t *offp)
 {  {
Line 2235  wapbl_write_revocations(struct wapbl *wl
Line 2360  wapbl_write_revocations(struct wapbl *wl
         return 0;          return 0;
 }  }
   
   /*
    * wapbl_write_inodes(wl, offp)
    *
    *      Write all pending inode allocations in the current transaction
    *      from wapbl_register_inode to the log on disk, adding to the
    *      circular queue's head at byte offset *offp and returning the
    *      new head's byte offset in *offp.
    */
 static int  static int
 wapbl_write_inodes(struct wapbl *wl, off_t *offp)  wapbl_write_inodes(struct wapbl *wl, off_t *offp)
 {  {
Line 2392  wapbl_blkhash_clear(struct wapbl_replay 
Line 2525  wapbl_blkhash_clear(struct wapbl_replay 
   
 /****************************************************************/  /****************************************************************/
   
   /*
    * wapbl_circ_read(wr, data, len, offp)
    *
    *      Read len bytes into data from the circular queue of wr,
    *      starting at the linear byte offset *offp, and returning the new
    *      linear byte offset in *offp.
    *
    *      If the starting linear byte offset precedes wr->wr_circ_off,
    *      the read instead begins at wr->wr_circ_off.  XXX WTF?  This
    *      should be a KASSERT, not a conditional.
    */
 static int  static int
 wapbl_circ_read(struct wapbl_replay *wr, void *data, size_t len, off_t *offp)  wapbl_circ_read(struct wapbl_replay *wr, void *data, size_t len, off_t *offp)
 {  {
Line 2432  wapbl_circ_read(struct wapbl_replay *wr,
Line 2576  wapbl_circ_read(struct wapbl_replay *wr,
         return 0;          return 0;
 }  }
   
   /*
    * wapbl_circ_advance(wr, len, offp)
    *
    *      Compute the linear byte offset of the circular queue of wr that
    *      is len bytes past *offp, and store it in *offp.
    *
    *      This is as if wapbl_circ_read, but without actually reading
    *      anything.
    *
    *      If the starting linear byte offset precedes wr->wr_circ_off, it
    *      is taken to be wr->wr_circ_off instead.  XXX WTF?  This should
    *      be a KASSERT, not a conditional.
    */
 static void  static void
 wapbl_circ_advance(struct wapbl_replay *wr, size_t len, off_t *offp)  wapbl_circ_advance(struct wapbl_replay *wr, size_t len, off_t *offp)
 {  {
Line 2961  wapbl_modcmd(modcmd_t cmd, void *arg)
Line 3118  wapbl_modcmd(modcmd_t cmd, void *arg)
                 wapbl_init();                  wapbl_init();
                 return 0;                  return 0;
         case MODULE_CMD_FINI:          case MODULE_CMD_FINI:
                 return wapbl_fini(true);                  return wapbl_fini();
         default:          default:
                 return ENOTTY;                  return ENOTTY;
         }          }

Legend:
Removed from v.1.61.2.2  
changed lines
  Added in v.1.61.2.3

CVSweb <webmaster@jp.NetBSD.org>