Module Name: src
Committed By: riastradh
Date: Sun Feb 23 08:49:46 UTC 2020
Modified Files:
src/sys/ufs/lfs: lfs_alloc.c lfs_extern.h lfs_vfsops.c
Log Message:
Dust off the orphan detection code and try to make it work.
To generate a diff of this commit:
cvs rdiff -u -r1.140 -r1.141 src/sys/ufs/lfs/lfs_alloc.c
cvs rdiff -u -r1.117 -r1.118 src/sys/ufs/lfs/lfs_extern.h
cvs rdiff -u -r1.372 -r1.373 src/sys/ufs/lfs/lfs_vfsops.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/ufs/lfs/lfs_alloc.c
diff -u src/sys/ufs/lfs/lfs_alloc.c:1.140 src/sys/ufs/lfs/lfs_alloc.c:1.141
--- src/sys/ufs/lfs/lfs_alloc.c:1.140 Sun Feb 23 08:49:34 2020
+++ src/sys/ufs/lfs/lfs_alloc.c Sun Feb 23 08:49:46 2020
@@ -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 @@ lfs_vfree(struct vnode *vp, ino_t ino, i
* 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 @@ lfs_order_freelist(struct lfs *fs)
if (ino == LFS_UNUSED_INUM || ino == LFS_IFILE_INUM)
continue;
-#ifdef notyet
/*
* Address orphaned files.
*
@@ -757,40 +756,26 @@ lfs_order_freelist(struct lfs *fs)
* 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 @@ lfs_order_freelist(struct lfs *fs)
/* 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_orphan(struct lfs *fs, ino_t ino)
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);
+}
Index: src/sys/ufs/lfs/lfs_extern.h
diff -u src/sys/ufs/lfs/lfs_extern.h:1.117 src/sys/ufs/lfs/lfs_extern.h:1.118
--- src/sys/ufs/lfs/lfs_extern.h:1.117 Sun Feb 23 08:42:53 2020
+++ src/sys/ufs/lfs/lfs_extern.h Sun Feb 23 08:49:46 2020
@@ -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 @@ extern kcondvar_t locked_queue_cv;
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 **);
Index: src/sys/ufs/lfs/lfs_vfsops.c
diff -u src/sys/ufs/lfs/lfs_vfsops.c:1.372 src/sys/ufs/lfs/lfs_vfsops.c:1.373
--- src/sys/ufs/lfs/lfs_vfsops.c:1.372 Sun Feb 23 08:40:49 2020
+++ src/sys/ufs/lfs/lfs_vfsops.c Sun Feb 23 08:49:46 2020
@@ -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 @@ lfs_mountfs(struct vnode *devvp, struct
CLEANERINFO *cip;
SEGUSE *sup;
daddr_t sb_addr;
+ ino_t *orphan;
+ size_t norphan;
cred = l ? l->l_cred : NOCRED;
@@ -1162,8 +1164,8 @@ lfs_mountfs(struct vnode *devvp, struct
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 @@ lfs_mountfs(struct vnode *devvp, struct
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!