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!