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!

Reply via email to