Source-Changes-HG archive

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

[src/trunk]: src/sys/ufs/lfs Dust off the orphan detection code and try to ma...



details:   https://anonhg.NetBSD.org/src/rev/11bd89cf0a79
branches:  trunk
changeset: 745138:11bd89cf0a79
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Sun Feb 23 08:49:46 2020 +0000

description:
Dust off the orphan detection code and try to make it work.

diffstat:

 sys/ufs/lfs/lfs_alloc.c  |  162 +++++++++++++++++++++++++++++++++++-----------
 sys/ufs/lfs/lfs_extern.h |    5 +-
 sys/ufs/lfs/lfs_vfsops.c |   13 ++-
 3 files changed, 133 insertions(+), 47 deletions(-)

diffs (283 lines):

diff -r b039f26441c7 -r 11bd89cf0a79 sys/ufs/lfs/lfs_alloc.c
--- a/sys/ufs/lfs/lfs_alloc.c   Sun Feb 23 08:49:34 2020 +0000
+++ b/sys/ufs/lfs/lfs_alloc.c   Sun Feb 23 08:49:46 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs_alloc.c,v 1.140 2020/02/23 08:49:34 riastradh Exp $        */
+/*     $NetBSD: lfs_alloc.c,v 1.141 2020/02/23 08:49:46 riastradh Exp $        */
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2002, 2003, 2007 The NetBSD Foundation, Inc.
@@ -60,7 +60,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: lfs_alloc.c,v 1.140 2020/02/23 08:49:34 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: lfs_alloc.c,v 1.141 2020/02/23 08:49:46 riastradh Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_quota.h"
@@ -705,16 +705,16 @@
  * Takes the segmenet lock.
  */
 void
-lfs_order_freelist(struct lfs *fs)
+lfs_order_freelist(struct lfs *fs, ino_t **orphanp, size_t *norphanp)
 {
        CLEANERINFO *cip;
        IFILE *ifp = NULL;
        struct buf *bp;
        ino_t ino, firstino, lastino, maxino;
-#ifdef notyet
-       struct vnode *vp;
-#endif
-       
+       ino_t *orphan = NULL;
+       size_t norphan = 0;
+       size_t norphan_alloc = 0;
+
        ASSERT_NO_SEGLOCK(fs);
        lfs_seglock(fs, SEGM_PROT);
 
@@ -745,7 +745,6 @@
                if (ino == LFS_UNUSED_INUM || ino == LFS_IFILE_INUM)
                        continue;
 
-#ifdef notyet
                /*
                 * Address orphaned files.
                 *
@@ -757,40 +756,26 @@
                 * but presumably it doesn't work... not sure what
                 * happens to such files currently. -- dholland 20160806
                 */
-               if (lfs_if_getnextfree(fs, ifp) == LFS_ORPHAN_NEXTFREE(fs) &&
-                   VFS_VGET(fs->lfs_ivnode->v_mount, ino, LK_EXCLUSIVE, &vp)
-                    == 0) {
-                       unsigned segno;
-
-                       /* get the segment the inode in on disk  */
-                       segno = lfs_dtosn(fs, lfs_if_getdaddr(fs, ifp));
-
-                       /* truncate the inode */
-                       lfs_truncate(vp, 0, 0, NOCRED);
-                       vput(vp);
-
-                       /* load the segment summary */
-                       LFS_SEGENTRY(sup, fs, segno, bp);
-                       /* update the number of bytes in the segment */
-                       KASSERT(sup->su_nbytes >= DINOSIZE(fs));
-                       sup->su_nbytes -= DINOSIZE(fs);
-                       /* write the segment summary */
-                       LFS_WRITESEGENTRY(sup, fs, segno, bp);
-
-                       /* Drop the on-disk address */
-                       lfs_if_setdaddr(fs, ifp, LFS_UNUSED_DADDR);
-                       /* write the ifile entry */
-                       LFS_BWRITE_LOG(bp);
-
-                       /*
-                        * and reload it (XXX: why? I guess
-                        * LFS_BWRITE_LOG drops it...)
-                        */
-                       LFS_IENTRY(ifp, fs, ino, bp);
-
-                       /* Fall through to next if block */
+               if (lfs_if_getnextfree(fs, ifp) == LFS_ORPHAN_NEXTFREE(fs)) {
+                       if (orphan == NULL) {
+                               norphan_alloc = 32; /* XXX pulled from arse */
+                               orphan = kmem_zalloc(sizeof(orphan[0]) *
+                                   norphan_alloc, KM_SLEEP);
+                       } else if (norphan == norphan_alloc) {
+                               ino_t *orphan_new;
+                               if (norphan_alloc >= 4096)
+                                       norphan_alloc += 4096;
+                               else
+                                       norphan_alloc *= 2;
+                               orphan_new = kmem_zalloc(sizeof(orphan[0]) *
+                                   norphan_alloc, KM_SLEEP);
+                               memcpy(orphan_new, orphan, sizeof(orphan[0]) *
+                                   norphan);
+                               kmem_free(orphan, sizeof(orphan[0]) * norphan);
+                               orphan = orphan_new;
+                       }
+                       orphan[norphan++] = ino;
                }
-#endif
 
                if (lfs_if_getdaddr(fs, ifp) == LFS_UNUSED_DADDR) {
 
@@ -837,6 +822,22 @@
 
        /* done */
        lfs_segunlock(fs);
+
+       /*
+        * Shrink the array of orphans so we don't have to carry around
+        * the allocation size.
+        */
+       if (norphan < norphan_alloc) {
+               ino_t *orphan_new = kmem_alloc(sizeof(orphan[0]) * norphan,
+                   KM_SLEEP);
+               memcpy(orphan_new, orphan, sizeof(orphan[0]) * norphan);
+               kmem_free(orphan, sizeof(orphan[0]) * norphan_alloc);
+               orphan = orphan_new;
+               norphan_alloc = norphan;
+       }
+
+       *orphanp = orphan;
+       *norphanp = norphan;
 }
 
 /*
@@ -855,3 +856,82 @@
        lfs_if_setnextfree(fs, ifp, LFS_ORPHAN_NEXTFREE(fs));
        LFS_BWRITE_LOG(bp);
 }
+
+/*
+ * Free orphans discovered during mount.  This is a separate stage
+ * because it requires fs->lfs_suflags to be set up, which is not done
+ * by the time we run lfs_order_freelist.  It's possible that we could
+ * run lfs_order_freelist later (i.e., set up fs->lfs_suflags sooner)
+ * but that requires more thought than I can put into this at the
+ * moment.
+ */
+void
+lfs_free_orphans(struct lfs *fs, ino_t *orphan, size_t norphan)
+{
+       size_t i;
+
+       for (i = 0; i < norphan; i++) {
+               ino_t ino = orphan[i];
+               unsigned segno;
+               struct vnode *vp;
+               struct inode *ip;
+               struct buf *bp;
+               IFILE *ifp;
+               SEGUSE *sup;
+               int error;
+
+               /* Get the segment the inode is in on disk.  */
+               LFS_IENTRY(ifp, fs, ino, bp);
+               segno = lfs_dtosn(fs, lfs_if_getdaddr(fs, ifp));
+               brelse(bp, 0);
+
+               /*
+                * Try to get the vnode.  If we can't, tough -- hope
+                * you have backups!
+                */
+               error = VFS_VGET(fs->lfs_ivnode->v_mount, ino, LK_EXCLUSIVE,
+                   &vp);
+               if (error) {
+                       printf("orphan %jd vget error %d\n", (intmax_t)ino,
+                           error);
+                       continue;
+               }
+
+               /*
+                * Sanity-check the inode.
+                *
+                * XXX What to do if it is still referenced?
+                */
+               ip = VTOI(vp);
+               if (ip->i_nlink != 0)
+                       printf("orphan %jd nlink %d\n", (intmax_t)ino,
+                           ip->i_nlink);
+
+               /*
+                * Truncate the inode, to free any blocks allocated for
+                * it, and release it, to free the inode number.
+                *
+                * XXX Isn't it redundant to truncate?  Won't vput do
+                * that for us?
+                */
+               error = lfs_truncate(vp, 0, 0, NOCRED);
+               if (error)
+                       printf("orphan %jd truncate error %d", (intmax_t)ino,
+                           error);
+               vput(vp);
+
+               /* Update the number of bytes in the segment summary.  */
+               LFS_SEGENTRY(sup, fs, segno, bp);
+               KASSERT(sup->su_nbytes >= DINOSIZE(fs));
+               sup->su_nbytes -= DINOSIZE(fs);
+               LFS_WRITESEGENTRY(sup, fs, segno, bp);
+
+               /* Drop the on-disk address.  */
+               LFS_IENTRY(ifp, fs, ino, bp);
+               lfs_if_setdaddr(fs, ifp, LFS_UNUSED_DADDR);
+               LFS_BWRITE_LOG(bp);
+       }
+
+       if (orphan)
+               kmem_free(orphan, sizeof(orphan[0]) * norphan);
+}
diff -r b039f26441c7 -r 11bd89cf0a79 sys/ufs/lfs/lfs_extern.h
--- a/sys/ufs/lfs/lfs_extern.h  Sun Feb 23 08:49:34 2020 +0000
+++ b/sys/ufs/lfs/lfs_extern.h  Sun Feb 23 08:49:46 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs_extern.h,v 1.117 2020/02/23 08:42:53 riastradh Exp $       */
+/*     $NetBSD: lfs_extern.h,v 1.118 2020/02/23 08:49:46 riastradh Exp $       */
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -127,9 +127,10 @@
 int lfs_valloc(struct vnode *, int, kauth_cred_t, ino_t *, int *);
 int lfs_valloc_fixed(struct lfs *, ino_t, int);
 int lfs_vfree(struct vnode *, ino_t, int);
-void lfs_order_freelist(struct lfs *);
+void lfs_order_freelist(struct lfs *, ino_t **, size_t *);
 int lfs_extend_ifile(struct lfs *, kauth_cred_t);
 void lfs_orphan(struct lfs *, ino_t);
+void lfs_free_orphans(struct lfs *, ino_t *, size_t);
 
 /* lfs_balloc.c */
 int lfs_balloc(struct vnode *, off_t, int, kauth_cred_t, int, struct buf **);
diff -r b039f26441c7 -r 11bd89cf0a79 sys/ufs/lfs/lfs_vfsops.c
--- a/sys/ufs/lfs/lfs_vfsops.c  Sun Feb 23 08:49:34 2020 +0000
+++ b/sys/ufs/lfs/lfs_vfsops.c  Sun Feb 23 08:49:46 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs_vfsops.c,v 1.372 2020/02/23 08:40:49 riastradh Exp $       */
+/*     $NetBSD: lfs_vfsops.c,v 1.373 2020/02/23 08:49:46 riastradh Exp $       */
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2002, 2003, 2007, 2007
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: lfs_vfsops.c,v 1.372 2020/02/23 08:40:49 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: lfs_vfsops.c,v 1.373 2020/02/23 08:49:46 riastradh Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_lfs.h"
@@ -870,6 +870,8 @@
        CLEANERINFO *cip;
        SEGUSE *sup;
        daddr_t sb_addr;
+       ino_t *orphan;
+       size_t norphan;
 
        cred = l ? l->l_cred : NOCRED;
 
@@ -1162,8 +1164,8 @@
        fs->lfs_ivnode = vp;
        vref(vp);
 
-       /* Set up inode bitmap and order free list */
-       lfs_order_freelist(fs);
+       /* Set up inode bitmap, order free list, and gather orphans.  */
+       lfs_order_freelist(fs, &orphan, &norphan);
 
        /* Set up segment usage flags for the autocleaner. */
        fs->lfs_nactive = 0;
@@ -1202,6 +1204,9 @@
                        brelse(bp, 0);
        }
 
+       /* Free the orphans we discovered while ordering the freelist.  */
+       lfs_free_orphans(fs, orphan, norphan);
+
        /*
         * XXX: if the fs has quotas, quotas should be on even if
         * readonly. Otherwise you can't query the quota info!



Home | Main Index | Thread Index | Old Index