Skip to content

Commit 23081d4

Browse files
perseantperseant
authored andcommitted
* Use the LFS_IFDIRTY flag to keep track of whether the Ifile has
ungathered changes during checkpoint. Modify LFS_WRITESEGENTRY and make a new LFS_WRITEIENTRY macro to help track this. Prevents an infinite loop in lfs_writeinode, previously caught with a panic. * Fix a false-positive "negative bytes" panic when writing inodes into the same segment they were in before, and consolidate the accounting logic into new function lfs_subtract_inode. * Ensure that we do not clean any inodes that were unavailable during the first pass of cleaning, so that we never need to mix cleaning and non-cleaning blocks (except for the Ifile) when writing. * Straighten out the logic in lfs_writefile to make it more readable. * Include IMNT_WANTRDONLY in tests for closing out writes, not just IMNT_UNMOUNT. * Keep track of whether the kernel cleaner is active on a file system with a status flag; use a condvar to synchronously turn this on or off.
1 parent c21e870 commit 23081d4

12 files changed

Lines changed: 380 additions & 225 deletions

File tree

sys/ufs/lfs/lfs.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $NetBSD: lfs.h,v 1.213 2025/11/06 15:45:32 perseant Exp $ */
1+
/* $NetBSD: lfs.h,v 1.214 2025/12/02 01:23:09 perseant Exp $ */
22

33
/* from NetBSD: dinode.h,v 1.25 2016/01/22 23:06:10 dholland Exp */
44
/* from NetBSD: dir.h,v 1.25 2015/09/01 06:16:03 dholland Exp */
@@ -1140,6 +1140,10 @@ struct lfs {
11401140
struct lfs_autoclean_params lfs_autoclean;
11411141
long (*lfs_clean_selector)(struct lfs *, int, SEGUSE *);
11421142
uint64_t lfs_clean_accum;
1143+
# define LFS_AUTOCLEAN_STATUS_OFF 0
1144+
# define LFS_AUTOCLEAN_STATUS_ON 1
1145+
int lfs_autoclean_status;
1146+
kcondvar_t lfs_cleanquitcv; /* condvar for cleaner quit */
11431147

11441148
/* Last cleaned segment */
11451149
uint32_t lfs_lastcleaned;

sys/ufs/lfs/lfs_accessors.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $NetBSD: lfs_accessors.h,v 1.56 2025/11/19 22:31:52 andvar Exp $ */
1+
/* $NetBSD: lfs_accessors.h,v 1.57 2025/12/02 01:23:09 perseant Exp $ */
22

33
/* from NetBSD: lfs.h,v 1.165 2015/07/24 06:59:32 dholland Exp */
44
/* from NetBSD: dinode.h,v 1.25 2016/01/22 23:06:10 dholland Exp */
@@ -693,6 +693,8 @@ lfs_iblock_set(STRUCT_LFS *fs, void *block, unsigned ix, daddr_t val)
693693
} while (0)
694694

695695
#define LFS_WRITESEGENTRY(SP, F, IN, BP) do { \
696+
if (((BP)->b_flags & B_GATHERED) == 0) \
697+
(F)->lfs_flags |= LFS_IFDIRTY; \
696698
LFS_BWRITE_LOG(BP); \
697699
} while (0)
698700

@@ -865,6 +867,11 @@ lfs_ii_setblock(STRUCT_LFS *fs, IINFO *iip, uint64_t block)
865867
(IP) = (IFILE *)((IFILE_V1 *)(IP) + 1); \
866868
} \
867869
} while (0)
870+
#define LFS_WRITEIENTRY(IP, F, IN, BP) do { \
871+
if (((BP)->b_flags & B_GATHERED) == 0) \
872+
(F)->lfs_flags |= LFS_IFDIRTY; \
873+
LFS_BWRITE_LOG(BP); \
874+
} while (0)
868875

869876
#define LFS_DEF_IF_ACCESSOR(type, type32, field) \
870877
static __inline type \
@@ -1006,10 +1013,11 @@ lfs_ci_shiftdirtytoclean(STRUCT_LFS *fs, CLEANERINFO *cip, unsigned num)
10061013
lfs_ci_setfree_head(FS, CIP, VAL); \
10071014
if ((VAL) == LFS_UNUSED_INUM) \
10081015
lfs_ci_setfree_tail(FS, CIP, VAL); \
1009-
LFS_BWRITE_LOG(BP); \
10101016
mutex_enter(&lfs_lock); \
1011-
(FS)->lfs_flags |= LFS_IFDIRTY; \
1017+
if (((BP)->b_flags & B_GATHERED) == 0) \
1018+
(FS)->lfs_flags |= LFS_IFDIRTY; \
10121019
mutex_exit(&lfs_lock); \
1020+
LFS_BWRITE_LOG(BP); \
10131021
} \
10141022
} while (0)
10151023

@@ -1024,10 +1032,11 @@ lfs_ci_shiftdirtytoclean(STRUCT_LFS *fs, CLEANERINFO *cip, unsigned num)
10241032
lfs_ci_setfree_tail(FS, CIP, VAL); \
10251033
if ((VAL) == LFS_UNUSED_INUM) \
10261034
lfs_ci_setfree_head(FS, CIP, VAL); \
1027-
LFS_BWRITE_LOG(BP); \
10281035
mutex_enter(&lfs_lock); \
1029-
(FS)->lfs_flags |= LFS_IFDIRTY; \
1036+
if (((BP)->b_flags & B_GATHERED) == 0) \
1037+
(FS)->lfs_flags |= LFS_IFDIRTY; \
10301038
mutex_exit(&lfs_lock); \
1039+
LFS_BWRITE_LOG(BP); \
10311040
} while (0)
10321041

10331042
/*

sys/ufs/lfs/lfs_alloc.c

Lines changed: 23 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $NetBSD: lfs_alloc.c,v 1.147 2025/11/03 22:21:12 perseant Exp $ */
1+
/* $NetBSD: lfs_alloc.c,v 1.148 2025/12/02 01:23:09 perseant Exp $ */
22

33
/*-
44
* Copyright (c) 1999, 2000, 2001, 2002, 2003, 2007 The NetBSD Foundation, Inc.
@@ -60,7 +60,7 @@
6060
*/
6161

6262
#include <sys/cdefs.h>
63-
__KERNEL_RCSID(0, "$NetBSD: lfs_alloc.c,v 1.147 2025/11/03 22:21:12 perseant Exp $");
63+
__KERNEL_RCSID(0, "$NetBSD: lfs_alloc.c,v 1.148 2025/12/02 01:23:09 perseant Exp $");
6464

6565
#if defined(_KERNEL_OPT)
6666
#include "opt_quota.h"
@@ -305,7 +305,7 @@ lfs_valloc(struct vnode *pvp, int mode, kauth_cred_t cred,
305305
*/
306306
lfs_if_setdaddr(fs, ifp, LFS_ILLEGAL_DADDR);
307307
lfs_if_setnextfree(fs, ifp, LFS_UNUSED_INUM);
308-
LFS_BWRITE_LOG(bp);
308+
LFS_WRITEIENTRY(ifp, fs, *ino, bp);
309309

310310
if (lfs_sb_getfreehd(fs) == LFS_UNUSED_INUM) {
311311
/*
@@ -448,7 +448,7 @@ lfs_valloc_fixed(struct lfs *fs, ino_t ino, int vers)
448448
lfs_if_setnextfree(fs, ifp, LFS_UNUSED_INUM);
449449
/* See comment in lfs_valloc */
450450
lfs_if_setdaddr(fs, ifp, LFS_ILLEGAL_DADDR);
451-
LFS_BWRITE_LOG(bp);
451+
LFS_WRITEIENTRY(ifp, fs, ino, bp);
452452

453453
if (lfs_sb_getfreehd(fs) == LFS_UNUSED_INUM) {
454454
int error;
@@ -556,7 +556,6 @@ lfs_freelist_prev(struct lfs *fs, ino_t ino)
556556
int
557557
lfs_vfree(struct vnode *vp, ino_t ino, int mode)
558558
{
559-
SEGUSE *sup;
560559
CLEANERINFO *cip;
561560
struct buf *cbp, *bp;
562561
IFILE *ifp;
@@ -569,9 +568,10 @@ lfs_vfree(struct vnode *vp, ino_t ino, int mode)
569568
fs = ip->i_lfs;
570569
ino = ip->i_number;
571570

572-
/* XXX: assert not readonly */
573-
574571
ASSERT_NO_SEGLOCK(fs);
572+
KASSERTMSG((ino != LFS_UNUSED_INUM), "inode 0 freed");
573+
KASSERT(!fs->lfs_ronly);
574+
575575
DLOG((DLOG_ALLOC, "lfs_vfree: free ino %lld\n", (long long)ino));
576576

577577
/* Drain of pending writes */
@@ -668,7 +668,7 @@ lfs_vfree(struct vnode *vp, ino_t ino, int mode)
668668
LFS_PUT_HEADFREE(fs, cip, cbp, ino);
669669

670670
/* write the ifile block */
671-
(void) LFS_BWRITE_LOG(bp); /* Ifile */
671+
LFS_WRITEIENTRY(ifp, fs, ino, bp);
672672
#if 0
673673
} else {
674674
ino_t tino, onf, otail;
@@ -679,7 +679,7 @@ lfs_vfree(struct vnode *vp, ino_t ino, int mode)
679679
* it seems both silly and dangerous.
680680
*/
681681
lfs_if_setnextfree(fs, ifp, LFS_UNUSED_INUM);
682-
(void) LFS_BWRITE_LOG(bp); /* Ifile */
682+
LFS_WRITEIENTRY(ifp, fs, ino, bp);
683683

684684
/*
685685
* Insert on freelist in order.
@@ -704,7 +704,7 @@ lfs_vfree(struct vnode *vp, ino_t ino, int mode)
704704
DLOG((DLOG_ALLOC, "lfs_vfree: headfree %lld -> %lld\n",
705705
(long long)nextfree, (long long)ino));
706706
/* write the ifile block */
707-
LFS_BWRITE_LOG(bp); /* Ifile */
707+
LFS_WRITEIENTRY(ifp, fs, ino, bp);
708708

709709
/* If the list was empty, set tail too */
710710
LFS_GET_TAILFREE(fs, cip, cbp, &otail);
@@ -730,14 +730,14 @@ lfs_vfree(struct vnode *vp, ino_t ino, int mode)
730730
onf = lfs_if_getnextfree(fs, ifp);
731731
lfs_if_setnextfree(fs, ifp, ino);
732732
/* write the block */
733-
LFS_BWRITE_LOG(bp); /* Ifile */
733+
LFS_WRITEIENTRY(ifp, fs, tino, bp);
734734

735735
/* load this inode's ifile block */
736736
LFS_IENTRY(ifp, fs, ino, bp);
737737
/* update the list pointer */
738738
lfs_if_setnextfree(fs, ifp, onf);
739739
/* write the block */
740-
LFS_BWRITE_LOG(bp); /* Ifile */
740+
LFS_WRITEIENTRY(ifp, fs, tino, bp);
741741

742742
/* If we're last, put us on the tail */
743743
if (onf == LFS_UNUSED_INUM) {
@@ -750,27 +750,12 @@ lfs_vfree(struct vnode *vp, ino_t ino, int mode)
750750
}
751751
}
752752
#endif
753-
/* XXX: shouldn't this check be further up *before* we trash the fs? */
754-
KASSERTMSG((ino != LFS_UNUSED_INUM), "inode 0 freed");
755753

756754
/*
757755
* Update the segment summary for the segment where the on-disk
758756
* copy used to be.
759757
*/
760-
if (!DADDR_IS_BAD(old_iaddr)) {
761-
/* load it */
762-
LFS_SEGENTRY(sup, fs, lfs_dtosn(fs, old_iaddr), bp);
763-
/* the number of bytes in the segment should not become < 0 */
764-
KASSERTMSG((sup->su_nbytes >= DINOSIZE(fs)),
765-
"lfs_vfree: negative byte count"
766-
" (segment %" PRIu32 " short by %d)\n",
767-
lfs_dtosn(fs, old_iaddr),
768-
(int)DINOSIZE(fs) - sup->su_nbytes);
769-
/* update the number of bytes in the segment */
770-
sup->su_nbytes -= DINOSIZE(fs);
771-
/* write the segment entry */
772-
LFS_WRITESEGENTRY(sup, fs, lfs_dtosn(fs, old_iaddr), bp); /* Ifile */
773-
}
758+
lfs_subtract_inode(fs, ip->i_number, old_iaddr);
774759

775760
/* Set superblock modified bit. */
776761
mutex_enter(&lfs_lock);
@@ -889,7 +874,7 @@ lfs_order_freelist(struct lfs *fs, ino_t **orphanp, size_t *norphanp)
889874
/* set the list pointer */
890875
lfs_if_setnextfree(fs, ifp, ino);
891876
/* write the block */
892-
LFS_BWRITE_LOG(bp);
877+
LFS_WRITEIENTRY(ifp, fs, lastino, bp);
893878

894879
/* reload this inode's ifile entry */
895880
LFS_IENTRY(ifp, fs, ino, bp);
@@ -984,15 +969,18 @@ lfs_orphan(struct lfs *fs, struct vnode *vp)
984969
mutex_exit(vp->v_interlock);
985970

986971
/* If not already done, mark this inode orphaned. */
972+
rw_enter(&fs->lfs_fraglock, RW_READER);
987973
LFS_IENTRY(ifp, fs, ip->i_number, bp);
988974
nextfree = lfs_if_getnextfree(fs, ifp);
989975
if (nextfree == LFS_ORPHAN_NEXTFREE(fs)) {
990976
brelse(bp, 0);
977+
rw_exit(&fs->lfs_fraglock);
991978
return;
992979
}
993980
KASSERT(nextfree == LFS_UNUSED_INUM);
994981
lfs_if_setnextfree(fs, ifp, LFS_ORPHAN_NEXTFREE(fs));
995-
LFS_BWRITE_LOG(bp);
982+
LFS_WRITEIENTRY(ifp, fs, ip->i_number, bp);
983+
rw_exit(&fs->lfs_fraglock);
996984
}
997985

998986
/*
@@ -1057,6 +1045,8 @@ lfs_free_orphans(struct lfs *fs, ino_t *orphan, size_t norphan)
10571045
error);
10581046
vput(vp);
10591047

1048+
rw_enter(&fs->lfs_fraglock, RW_READER);
1049+
10601050
/* Update the number of bytes in the segment summary. */
10611051
LFS_SEGENTRY(sup, fs, segno, bp);
10621052
KASSERT(sup->su_nbytes >= DINOSIZE(fs));
@@ -1066,7 +1056,9 @@ lfs_free_orphans(struct lfs *fs, ino_t *orphan, size_t norphan)
10661056
/* Drop the on-disk address. */
10671057
LFS_IENTRY(ifp, fs, ino, bp);
10681058
lfs_if_setdaddr(fs, ifp, LFS_UNUSED_DADDR);
1069-
LFS_BWRITE_LOG(bp);
1059+
LFS_WRITEIENTRY(ifp, fs, ino, bp);
1060+
1061+
rw_exit(&fs->lfs_fraglock);
10701062
}
10711063

10721064
if (orphan)

sys/ufs/lfs/lfs_bio.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $NetBSD: lfs_bio.c,v 1.152 2025/11/03 22:21:12 perseant Exp $ */
1+
/* $NetBSD: lfs_bio.c,v 1.153 2025/12/02 01:23:09 perseant Exp $ */
22

33
/*-
44
* Copyright (c) 1999, 2000, 2001, 2002, 2003, 2008 The NetBSD Foundation, Inc.
@@ -60,7 +60,7 @@
6060
*/
6161

6262
#include <sys/cdefs.h>
63-
__KERNEL_RCSID(0, "$NetBSD: lfs_bio.c,v 1.152 2025/11/03 22:21:12 perseant Exp $");
63+
__KERNEL_RCSID(0, "$NetBSD: lfs_bio.c,v 1.153 2025/12/02 01:23:09 perseant Exp $");
6464

6565
#include <sys/param.h>
6666
#include <sys/systm.h>
@@ -777,10 +777,10 @@ lfs_newbuf(struct lfs *fs, struct vnode *vp, daddr_t daddr, size_t size, int typ
777777
bp->b_error = 0;
778778
bp->b_resid = 0;
779779
bp->b_iodone = lfs_free_aiodone;
780-
bp->b_cflags |= BC_BUSY | BC_NOCACHE;
781780
bp->b_private = fs;
782781

783782
mutex_enter(&bufcache_lock);
783+
bp->b_cflags |= BC_BUSY | BC_NOCACHE;
784784
mutex_enter(vp->v_interlock);
785785
bgetvp(vp, bp);
786786
mutex_exit(vp->v_interlock);
@@ -794,17 +794,17 @@ lfs_freebuf(struct lfs *fs, struct buf *bp)
794794
{
795795
struct vnode *vp;
796796

797-
if ((vp = bp->b_vp) != NULL) {
798-
mutex_enter(&bufcache_lock);
799-
mutex_enter(vp->v_interlock);
797+
mutex_enter(&bufcache_lock);
798+
vp = bp->b_vp;
799+
mutex_enter(vp->v_interlock);
800+
if (vp != NULL)
800801
brelvp(bp);
801-
mutex_exit(vp->v_interlock);
802-
mutex_exit(&bufcache_lock);
803-
}
802+
mutex_exit(vp->v_interlock);
804803
if (!(bp->b_cflags & BC_INVAL)) { /* BC_INVAL indicates a "fake" buffer */
805804
lfs_free(fs, bp->b_data, LFS_NB_UNKNOWN);
806805
bp->b_data = NULL;
807806
}
807+
mutex_exit(&bufcache_lock);
808808
putiobuf(bp);
809809
}
810810

sys/ufs/lfs/lfs_extern.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $NetBSD: lfs_extern.h,v 1.126 2025/11/06 15:45:32 perseant Exp $ */
1+
/* $NetBSD: lfs_extern.h,v 1.127 2025/12/02 01:23:09 perseant Exp $ */
22

33
/*-
44
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -226,6 +226,7 @@ int lfs_vflush(struct vnode *);
226226
int lfs_segwrite(struct mount *, int);
227227
int lfs_writefile(struct lfs *, struct segment *, struct vnode *);
228228
int lfs_writeinode(struct lfs *, struct segment *, struct inode *);
229+
int lfs_subtract_inode(struct lfs *, ino_t, daddr_t);
229230
int lfs_gatherblock(struct segment *, struct buf *, kmutex_t *);
230231
int lfs_gather(struct lfs *, struct segment *, struct vnode *, int (*match )(struct lfs *, struct buf *));
231232
int lfs_ungather(struct lfs *, struct segment *, struct vnode *, int (*match)(struct lfs *, struct buf *));

sys/ufs/lfs/lfs_itimes.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $NetBSD: lfs_itimes.c,v 1.20 2017/06/10 05:29:36 maya Exp $ */
1+
/* $NetBSD: lfs_itimes.c,v 1.21 2025/12/02 01:23:09 perseant Exp $ */
22

33
/*-
44
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -29,7 +29,7 @@
2929
* POSSIBILITY OF SUCH DAMAGE.
3030
*/
3131
#include <sys/cdefs.h>
32-
__KERNEL_RCSID(0, "$NetBSD: lfs_itimes.c,v 1.20 2017/06/10 05:29:36 maya Exp $");
32+
__KERNEL_RCSID(0, "$NetBSD: lfs_itimes.c,v 1.21 2025/12/02 01:23:09 perseant Exp $");
3333

3434
#include <sys/param.h>
3535
#include <sys/time.h>
@@ -46,6 +46,7 @@ __KERNEL_RCSID(0, "$NetBSD: lfs_itimes.c,v 1.20 2017/06/10 05:29:36 maya Exp $")
4646
#else
4747
#include <ufs/lfs/ulfs_inode.h>
4848
#include <ufs/lfs/lfs_extern.h>
49+
#include <ufs/lfs/lfs_kernel.h>
4950
#include <sys/kauth.h>
5051
#endif
5152

@@ -77,10 +78,20 @@ lfs_itimes(struct inode *ip, const struct timespec *acc,
7778
struct buf *ibp;
7879
IFILE *ifp;
7980

81+
#ifdef _KERNEL
82+
if (!LFS_SEGLOCK_HELD(fs))
83+
rw_enter(&fs->lfs_fraglock, RW_READER);
84+
#endif /* _KERNEL */
8085
LFS_IENTRY(ifp, fs, ip->i_number, ibp);
8186
lfs_if_setatime_sec(fs, ifp, acc->tv_sec);
8287
lfs_if_setatime_nsec(fs, ifp, acc->tv_nsec);
88+
#ifdef _KERNEL
89+
LFS_WRITEIENTRY(ifp, fs, ip->i_number, ibp);
90+
if (!LFS_SEGLOCK_HELD(fs))
91+
rw_exit(&fs->lfs_fraglock);
92+
#else /* ! _KERNEL */
8393
LFS_BWRITE_LOG(ibp);
94+
#endif /* ! _KERNEL */
8495
mutex_enter(&lfs_lock);
8596
fs->lfs_flags |= LFS_IFDIRTY;
8697
mutex_exit(&lfs_lock);

0 commit comments

Comments
 (0)