Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys during truncate with wapbl, register deallocation for up...



details:   https://anonhg.NetBSD.org/src/rev/edfc5c316b7d
branches:  trunk
changeset: 818975:edfc5c316b7d
user:      jdolecek <jdolecek%NetBSD.org@localhost>
date:      Thu Nov 10 20:56:32 2016 +0000

description:
during truncate with wapbl, register deallocation for upper indirect block
before recursing into lower blocks, to make sure that it will be removed after
all its referenced blocks are removed

fixes 'ffs_blkfree_common: freeing free block' panic triggered by
ufs_truncate_retry() when just the upper indirect block registration failed,
code tried to free the lower blocks again after wapbl flush

problem found by hannken@, thank you

diffstat:

 sys/kern/vfs_wapbl.c    |  74 +++++++++++++++++++++++++++++++++---------------
 sys/sys/wapbl.h         |   8 +++-
 sys/ufs/ffs/ffs_inode.c |  66 +++++++++++++++++++++++++++++-------------
 sys/ufs/ffs/ffs_wapbl.c |   8 ++--
 sys/ufs/ufs/ufs_wapbl.h |  16 +++++++--
 5 files changed, 117 insertions(+), 55 deletions(-)

diffs (truncated from 445 to 300 lines):

diff -r 08ddd896efa4 -r edfc5c316b7d sys/kern/vfs_wapbl.c
--- a/sys/kern/vfs_wapbl.c      Thu Nov 10 19:10:05 2016 +0000
+++ b/sys/kern/vfs_wapbl.c      Thu Nov 10 20:56:32 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: vfs_wapbl.c,v 1.85 2016/10/28 20:38:12 jdolecek Exp $  */
+/*     $NetBSD: vfs_wapbl.c,v 1.86 2016/11/10 20:56:32 jdolecek Exp $  */
 
 /*-
  * Copyright (c) 2003, 2008, 2009 The NetBSD Foundation, Inc.
@@ -36,7 +36,7 @@
 #define WAPBL_INTERNAL
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_wapbl.c,v 1.85 2016/10/28 20:38:12 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_wapbl.c,v 1.86 2016/11/10 20:56:32 jdolecek Exp $");
 
 #include <sys/param.h>
 #include <sys/bitops.h>
@@ -206,7 +206,7 @@
        int wl_brperjblock;     /* r Block records per journal block */
 #endif
 
-       SIMPLEQ_HEAD(, wapbl_dealloc) wl_dealloclist;   /* lm:  list head */
+       TAILQ_HEAD(, wapbl_dealloc) wl_dealloclist;     /* lm:  list head */
        int wl_dealloccnt;                              /* lm:  total count */
        int wl_dealloclim;                              /* r:   max count */
 
@@ -267,6 +267,9 @@
 static size_t wapbl_transaction_len(struct wapbl *wl);
 static inline size_t wapbl_transaction_inodes_len(struct wapbl *wl);
 
+static void wapbl_deallocation_free(struct wapbl *, struct wapbl_dealloc *,
+       bool);
+
 #if 0
 int wapbl_replay_verify(struct wapbl_replay *, struct vnode *);
 #endif
@@ -512,7 +515,7 @@
 
        /* XXX tie this into resource estimation */
        wl->wl_dealloclim = wl->wl_bufbytes_max / mp->mnt_stat.f_bsize / 2;
-       SIMPLEQ_INIT(&wl->wl_dealloclist);
+       TAILQ_INIT(&wl->wl_dealloclist);
        
        wl->wl_buffer = wapbl_alloc(MAXPHYS);
        wl->wl_buffer_used = 0;
@@ -586,7 +589,7 @@
         * if we want to call flush from inside a transaction
         */
        rw_enter(&wl->wl_rwlock, RW_WRITER);
-       wl->wl_flush(wl->wl_mount, SIMPLEQ_FIRST(&wl->wl_dealloclist));
+       wl->wl_flush(wl->wl_mount, TAILQ_FIRST(&wl->wl_dealloclist));
 
 #ifdef WAPBL_DEBUG_PRINT
        {
@@ -688,11 +691,8 @@
        }
 
        /* Discard list of deallocs */
-       while ((wd = SIMPLEQ_FIRST(&wl->wl_dealloclist)) != NULL) {
-               SIMPLEQ_REMOVE_HEAD(&wl->wl_dealloclist, wd_entries);
-               pool_put(&wapbl_dealloc_pool, wd);
-               wl->wl_dealloccnt--;
-       }
+       while ((wd = TAILQ_FIRST(&wl->wl_dealloclist)) != NULL)
+               wapbl_deallocation_free(wl, wd, true);
 
        /* XXX should we clear wl_reserved_bytes? */
 
@@ -702,7 +702,7 @@
        KASSERT(LIST_EMPTY(&wl->wl_bufs));
        KASSERT(SIMPLEQ_EMPTY(&wl->wl_entries));
        KASSERT(wl->wl_inohashcnt == 0);
-       KASSERT(SIMPLEQ_EMPTY(&wl->wl_dealloclist));
+       KASSERT(TAILQ_EMPTY(&wl->wl_dealloclist));
        KASSERT(wl->wl_dealloccnt == 0);
 
        rw_exit(&wl->wl_rwlock);
@@ -738,7 +738,7 @@
        KASSERT(wl->wl_dealloccnt == 0);
        KASSERT(SIMPLEQ_EMPTY(&wl->wl_entries));
        KASSERT(wl->wl_inohashcnt == 0);
-       KASSERT(SIMPLEQ_EMPTY(&wl->wl_dealloclist));
+       KASSERT(TAILQ_EMPTY(&wl->wl_dealloclist));
        KASSERT(wl->wl_dealloccnt == 0);
 
        wapbl_free(wl->wl_wc_scratch, wl->wl_wc_header->wc_len);
@@ -1561,7 +1561,7 @@
         * if we want to call flush from inside a transaction
         */
        rw_enter(&wl->wl_rwlock, RW_WRITER);
-       wl->wl_flush(wl->wl_mount, SIMPLEQ_FIRST(&wl->wl_dealloclist));
+       wl->wl_flush(wl->wl_mount, TAILQ_FIRST(&wl->wl_dealloclist));
 
        /*
         * Now that we are exclusively locked and the file system has
@@ -1739,7 +1739,7 @@
  out:
        if (error) {
                wl->wl_flush_abort(wl->wl_mount,
-                   SIMPLEQ_FIRST(&wl->wl_dealloclist));
+                   TAILQ_FIRST(&wl->wl_dealloclist));
        }
 
 #ifdef WAPBL_DEBUG_PRINT
@@ -1878,7 +1878,7 @@
                {
                        struct wapbl_dealloc *wd;
                        cnt = 0;
-                       SIMPLEQ_FOREACH(wd, &wl->wl_dealloclist, wd_entries) {
+                       TAILQ_FOREACH(wd, &wl->wl_dealloclist, wd_entries) {
                                (*pr)(" %"PRId64":%d,",
                                      wd->wd_blkno,
                                      wd->wd_len);
@@ -1930,7 +1930,8 @@
 /****************************************************************/
 
 int
-wapbl_register_deallocation(struct wapbl *wl, daddr_t blk, int len, bool force)
+wapbl_register_deallocation(struct wapbl *wl, daddr_t blk, int len, bool force,
+    void **cookiep)
 {
        struct wapbl_dealloc *wd;
        int error = 0;
@@ -1967,7 +1968,10 @@
        wd->wd_len = len;
 
        mutex_enter(&wl->wl_mtx);
-       SIMPLEQ_INSERT_TAIL(&wl->wl_dealloclist, wd, wd_entries);
+       TAILQ_INSERT_TAIL(&wl->wl_dealloclist, wd, wd_entries);
+
+       if (cookiep)
+               *cookiep = wd;
 
  out:
        mutex_exit(&wl->wl_mtx);
@@ -1979,6 +1983,32 @@
        return error;
 }
 
+static void
+wapbl_deallocation_free(struct wapbl *wl, struct wapbl_dealloc *wd,
+       bool locked)
+{
+       KASSERT(!locked
+           || rw_lock_held(&wl->wl_rwlock) || mutex_owned(&wl->wl_mtx));
+
+       if (!locked)
+               mutex_enter(&wl->wl_mtx);
+
+       TAILQ_REMOVE(&wl->wl_dealloclist, wd, wd_entries);
+       wl->wl_dealloccnt--;
+
+       if (!locked)
+               mutex_exit(&wl->wl_mtx);
+
+       pool_put(&wapbl_dealloc_pool, wd);
+}
+
+void
+wapbl_unregister_deallocation(struct wapbl *wl, void *cookie)
+{
+       KASSERT(cookie != NULL);
+       wapbl_deallocation_free(wl, cookie, false);
+}
+
 /****************************************************************/
 
 static void
@@ -2356,7 +2386,7 @@
        if (wl->wl_dealloccnt == 0)
                return 0;
 
-       while ((wd = SIMPLEQ_FIRST(&wl->wl_dealloclist)) != NULL) {
+       while ((wd = TAILQ_FIRST(&wl->wl_dealloclist)) != NULL) {
                wc->wc_type = WAPBL_WC_REVOCATIONS;
                wc->wc_len = blocklen;
                wc->wc_blkcount = 0;
@@ -2367,7 +2397,7 @@
                            wd->wd_len;
                        wc->wc_blkcount++;
 
-                       wd = SIMPLEQ_NEXT(wd, wd_entries);
+                       wd = TAILQ_NEXT(wd, wd_entries);
                }
                WAPBL_PRINTF(WAPBL_PRINT_WRITE,
                    ("wapbl_write_revocations: len = %u off = %"PRIdMAX"\n",
@@ -2378,12 +2408,10 @@
 
                /* free all successfully written deallocs */
                lwd = wd;
-               while ((wd = SIMPLEQ_FIRST(&wl->wl_dealloclist)) != NULL) {
+               while ((wd = TAILQ_FIRST(&wl->wl_dealloclist)) != NULL) {
                        if (wd == lwd)
                                break;
-                       SIMPLEQ_REMOVE_HEAD(&wl->wl_dealloclist, wd_entries);
-                       pool_put(&wapbl_dealloc_pool, wd);
-                       wl->wl_dealloccnt--;
+                       wapbl_deallocation_free(wl, wd, true);
                }
        }
        *offp = off;
diff -r 08ddd896efa4 -r edfc5c316b7d sys/sys/wapbl.h
--- a/sys/sys/wapbl.h   Thu Nov 10 19:10:05 2016 +0000
+++ b/sys/sys/wapbl.h   Thu Nov 10 20:56:32 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: wapbl.h,v 1.19 2016/10/28 20:38:12 jdolecek Exp $      */
+/*     $NetBSD: wapbl.h,v 1.20 2016/11/10 20:56:32 jdolecek Exp $      */
 
 /*-
  * Copyright (c) 2003,2008 The NetBSD Foundation, Inc.
@@ -95,7 +95,7 @@
 struct wapbl;
 
 struct wapbl_dealloc {
-       SIMPLEQ_ENTRY(wapbl_dealloc) wd_entries;
+       TAILQ_ENTRY(wapbl_dealloc) wd_entries;
        daddr_t wd_blkno;       /* address of block */
        int wd_len;             /* size of block */
 };
@@ -173,7 +173,9 @@
  * the corresponding blocks from being reused as data
  * blocks until the log is on disk.
  */
-int    wapbl_register_deallocation(struct wapbl *, daddr_t, int, bool);
+int    wapbl_register_deallocation(struct wapbl *, daddr_t, int, bool,
+               void **);
+void   wapbl_unregister_deallocation(struct wapbl *, void *);
 
 void   wapbl_jlock_assert(struct wapbl *wl);
 void   wapbl_junlock_assert(struct wapbl *wl);
diff -r 08ddd896efa4 -r edfc5c316b7d sys/ufs/ffs/ffs_inode.c
--- a/sys/ufs/ffs/ffs_inode.c   Thu Nov 10 19:10:05 2016 +0000
+++ b/sys/ufs/ffs/ffs_inode.c   Thu Nov 10 20:56:32 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ffs_inode.c,v 1.121 2016/11/10 19:10:05 jdolecek Exp $ */
+/*     $NetBSD: ffs_inode.c,v 1.122 2016/11/10 20:56:32 jdolecek Exp $ */
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ffs_inode.c,v 1.121 2016/11/10 19:10:05 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ffs_inode.c,v 1.122 2016/11/10 20:56:32 jdolecek Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_ffs.h"
@@ -218,6 +218,7 @@
        off_t osize;
        int sync;
        struct ufsmount *ump = oip->i_ump;
+       void *dcookie;
 
        UFS_WAPBL_JLOCK_ASSERT(ip->i_ump->um_mountp);
 
@@ -419,20 +420,31 @@
                else
                        bn = ufs_rw64(oip->i_ffs2_ib[level],UFS_FSNEEDSWAP(fs));
                if (bn != 0) {
+                       if (lastiblock[level] < 0 &&
+                           oip->i_ump->um_mountp->mnt_wapbl) {
+                               error = UFS_WAPBL_REGISTER_DEALLOCATION(
+                                   oip->i_ump->um_mountp,
+                                   FFS_FSBTODB(fs, bn), fs->fs_bsize,
+                                   &dcookie);
+                               if (error)
+                                       goto out;
+                       } else {
+                               dcookie = NULL;
+                       }
+                           
                        error = ffs_indirtrunc(oip, indir_lbn[level],
                            FFS_FSBTODB(fs, bn), lastiblock[level], level,
                            &blocksreleased);
-                       if (error)
+                       if (error) {
+                               if (dcookie) {
+                                       UFS_WAPBL_UNREGISTER_DEALLOCATION(
+                                           oip->i_ump->um_mountp, dcookie);
+                               }
                                goto out;
+                       }
 
                        if (lastiblock[level] < 0) {
-                               if (oip->i_ump->um_mountp->mnt_wapbl) {
-                                       error = UFS_WAPBL_REGISTER_DEALLOCATION(
-                                           oip->i_ump->um_mountp,
-                                           FFS_FSBTODB(fs, bn), fs->fs_bsize);
-                                       if (error)
-                                               goto out;
-                               } else
+                               if (!dcookie)
                                        ffs_blkfree(fs, oip->i_devvp, bn,
                                            fs->fs_bsize, oip->i_number);
                                DIP_ASSIGN(oip, ib[level], 0);
@@ -461,7 +473,7 @@
                    (ovp->v_type != VREG)) {
                        error = UFS_WAPBL_REGISTER_DEALLOCATION(



Home | Main Index | Thread Index | Old Index