151188Sbostic /* 251188Sbostic * Copyright (c) 1991 Regents of the University of California. 351188Sbostic * All rights reserved. 451188Sbostic * 551188Sbostic * %sccs.include.redist.c% 651188Sbostic * 7*52103Sbostic * @(#)lfs_segment.c 7.9 (Berkeley) 12/31/91 851188Sbostic */ 951188Sbostic 1051490Sbostic #include <sys/param.h> 1151490Sbostic #include <sys/systm.h> 1251490Sbostic #include <sys/namei.h> 1352085Sbostic #include <sys/kernel.h> 1451490Sbostic #include <sys/resourcevar.h> 1551490Sbostic #include <sys/file.h> 1651490Sbostic #include <sys/stat.h> 1751490Sbostic #include <sys/buf.h> 1851490Sbostic #include <sys/proc.h> 1951490Sbostic #include <sys/conf.h> 2051490Sbostic #include <sys/vnode.h> 2151490Sbostic #include <sys/specdev.h> 2251490Sbostic #include <sys/fifo.h> 2351490Sbostic #include <sys/malloc.h> 2451490Sbostic #include <sys/mount.h> 2551188Sbostic 2651499Sbostic #include <ufs/ufs/quota.h> 2751499Sbostic #include <ufs/ufs/inode.h> 2851499Sbostic #include <ufs/ufs/dir.h> 2951499Sbostic #include <ufs/ufs/ufsmount.h> 3051490Sbostic 3151499Sbostic #include <ufs/lfs/lfs.h> 3251499Sbostic #include <ufs/lfs/lfs_extern.h> 3351490Sbostic 3451860Sbostic /* In-memory description of a segment about to be written. */ 3551860Sbostic struct segment { 3652085Sbostic struct buf **bpp; /* pointer to buffer array */ 3752085Sbostic struct buf **cbpp; /* pointer to next available bp */ 3852085Sbostic struct buf *ibp; /* buffer pointer to inode page */ 3952085Sbostic struct finfo *fip; /* current fileinfo pointer */ 4051860Sbostic void *segsum; /* segment summary info */ 4151860Sbostic u_long ninodes; /* number of inodes in this segment */ 4251860Sbostic u_long seg_bytes_left; /* bytes left in segment */ 4351860Sbostic u_long sum_bytes_left; /* bytes left in summary block */ 4451860Sbostic u_long seg_number; /* number of this segment */ 4551860Sbostic #define SEGM_CKP 0x01 /* doing a checkpoint */ 4651860Sbostic u_long seg_flags; /* run-time flags for this segment */ 4751860Sbostic }; 4851860Sbostic 4951188Sbostic /* 5051860Sbostic * Determine if it's OK to start a partial in this segment, or if we need 5151860Sbostic * to go on to a new segment. 5251301Sbostic */ 5351860Sbostic #define LFS_PARTIAL_FITS(fs) \ 5451860Sbostic ((fs)->lfs_dbpseg - ((fs)->lfs_offset - (fs)->lfs_curseg) > \ 5551860Sbostic 1 << (fs)->lfs_fsbtodb) 5651188Sbostic 5752085Sbostic int lfs_callback __P((struct buf *)); 5852085Sbostic void lfs_gather __P((struct lfs *, struct segment *, 5952085Sbostic struct vnode *, int (*) __P((struct lfs *, struct buf *)))); 6052085Sbostic void lfs_initseg __P((struct lfs *, struct segment *)); 6152085Sbostic void lfs_iset __P((struct inode *, daddr_t, time_t)); 6252085Sbostic int lfs_match_data __P((struct lfs *, struct buf *)); 6352085Sbostic int lfs_match_dindir __P((struct lfs *, struct buf *)); 6452085Sbostic int lfs_match_indir __P((struct lfs *, struct buf *)); 6552085Sbostic int lfs_match_tindir __P((struct lfs *, struct buf *)); 6652085Sbostic struct buf * 6752085Sbostic lfs_newbuf __P((struct lfs *, struct segment *, daddr_t, size_t)); 6852077Sbostic void lfs_newseg __P((struct lfs *)); 6952085Sbostic void lfs_shellsort __P((struct buf **, daddr_t *, register int)); 7052077Sbostic void lfs_updatemeta __P((struct lfs *, 7152085Sbostic struct segment *, struct vnode *, daddr_t *, struct buf **, int)); 7252085Sbostic void lfs_writefile __P((struct lfs *, struct segment *, struct vnode *)); 7352085Sbostic void lfs_writeinode __P((struct lfs *, struct segment *, struct inode *)); 7452085Sbostic void lfs_writeseg __P((struct lfs *, struct segment *)); 7552085Sbostic void lfs_writesuper __P((struct lfs *, struct segment *)); 7651188Sbostic 7751860Sbostic int lfs_allclean_wakeup; /* Cleaner wakeup address. */ 7851860Sbostic 7951188Sbostic int 8051215Sbostic lfs_segwrite(mp, do_ckp) 8152085Sbostic struct mount *mp; 8251860Sbostic int do_ckp; /* Do a checkpoint. */ 8351188Sbostic { 8452085Sbostic struct inode *ip; 8551499Sbostic struct lfs *fs; 8652085Sbostic struct segment *sp; 8752085Sbostic struct vnode *vp; 8851915Sbostic int s, error; 8951188Sbostic 9052085Sbostic /* 9152085Sbostic * Ifile and meta data blocks are not marked busy, so segment writes 9252085Sbostic * must be single threaded. Currently, there are two paths into this 9352085Sbostic * code, sync() and getnewbuf(). They both mark the file system busy, 9452085Sbostic * so lfs_segwrite is safe. I think. 9552085Sbostic */ 9651860Sbostic #ifdef VERBOSE 9751860Sbostic printf("lfs_segwrite\n"); 9851860Sbostic #endif 9952085Sbostic 10051860Sbostic /* 10151860Sbostic * If doing a checkpoint, we keep a cumulative count of the outstanding 10251860Sbostic * I/O operations. If the disk drive catches up with us it could go to 10351860Sbostic * zero before we finish, so we artificially increment it by one until 10451860Sbostic * we've scheduled all of the writes we intend to do. 10551860Sbostic */ 10651915Sbostic fs = VFSTOUFS(mp)->um_lfs; 10751860Sbostic if (do_ckp) { 10851860Sbostic s = splbio(); 10951860Sbostic fs->lfs_iocount = 1; 11051860Sbostic splx(s); 11151860Sbostic } 11251342Sbostic 11351301Sbostic /* 11451860Sbostic * Allocate a segment structure and enough space to hold pointers to 11551860Sbostic * the maximum possible number of buffers which can be described in a 11651860Sbostic * single summary block. 11751301Sbostic */ 11852085Sbostic sp = malloc(sizeof(struct segment), M_SEGMENT, M_WAITOK); 11951860Sbostic sp->bpp = malloc(((LFS_SUMMARY_SIZE - sizeof(SEGSUM)) / 12052085Sbostic sizeof(daddr_t) + 1) * sizeof(struct buf *), M_SEGMENT, M_WAITOK); 12151860Sbostic sp->seg_flags = do_ckp ? SEGM_CKP : 0; 12251915Sbostic lfs_initseg(fs, sp); 12351188Sbostic loop: 12451188Sbostic for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 12551188Sbostic /* 12651188Sbostic * If the vnode that we are about to sync is no longer 12751188Sbostic * associated with this mount point, start over. 12851188Sbostic */ 12951188Sbostic if (vp->v_mount != mp) 13051188Sbostic goto loop; 13151188Sbostic if (VOP_ISLOCKED(vp)) 13251188Sbostic continue; 13351860Sbostic 13451915Sbostic /* 13551915Sbostic * Write the inode/file if dirty and it's not the 13651915Sbostic * the IFILE. 13751915Sbostic */ 13851188Sbostic ip = VTOI(vp); 13951860Sbostic if (ip->i_flag & (IMOD | IACC | IUPD | ICHG) == 0 && 14051860Sbostic vp->v_dirtyblkhd == NULL || 14151860Sbostic ip->i_number == LFS_IFILE_INUM) 14251188Sbostic continue; 14351860Sbostic 14452077Sbostic /* 14552077Sbostic * XXX 14652077Sbostic * This is wrong, I think -- we should just wait until we 14752077Sbostic * get the vnode and go on. Probably going to reschedule 14852077Sbostic * all of the writes we already scheduled... 14952077Sbostic */ 15051188Sbostic if (vget(vp)) 15152085Sbostic { 15252085Sbostic printf("lfs_segment: failed to get vnode (tell Keith)!\n"); 15351188Sbostic goto loop; 15452085Sbostic } 15552077Sbostic 15652077Sbostic if (vp->v_dirtyblkhd != NULL) 15752077Sbostic lfs_writefile(fs, sp, vp); 15851915Sbostic lfs_writeinode(fs, sp, ip); 15952077Sbostic ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG); 16051188Sbostic vput(vp); 16151188Sbostic } 16251860Sbostic if (do_ckp) { 16352077Sbostic vp = fs->lfs_ivnode; 16452077Sbostic while (vget(vp)); 16552077Sbostic ip = VTOI(vp); 16652077Sbostic if (vp->v_dirtyblkhd != NULL) 16752077Sbostic lfs_writefile(fs, sp, vp); 16852077Sbostic lfs_writeinode(fs, sp, ip); 16952077Sbostic ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG); 17052077Sbostic vput(vp); 17151860Sbostic } 17251342Sbostic lfs_writeseg(fs, sp); 17351342Sbostic 17451215Sbostic /* 17551860Sbostic * If the I/O count is non-zero, sleep until it reaches zero. At the 17651860Sbostic * moment, the user's process hangs around so we can sleep. 17751215Sbostic */ 17851860Sbostic if (do_ckp) { 17951860Sbostic s = splbio(); 18052085Sbostic if (--fs->lfs_iocount && (error = 18152085Sbostic tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs sync", 0))) 18251915Sbostic return (error); 18351860Sbostic splx(s); 18451860Sbostic lfs_writesuper(fs, sp); 18551860Sbostic } 18651215Sbostic 18751927Sbostic free(sp->bpp, M_SEGMENT); 18851927Sbostic free(sp, M_SEGMENT); 18951215Sbostic 19051860Sbostic /* Wake up any cleaning processes waiting on this file system. */ 19151860Sbostic wakeup(&fs->lfs_nextseg); 19251860Sbostic wakeup(&lfs_allclean_wakeup); 19352085Sbostic 19451860Sbostic return (0); 19551188Sbostic } 19651188Sbostic 19751860Sbostic /* 19851860Sbostic * Write the dirty blocks associated with a vnode. 19951860Sbostic */ 20052077Sbostic void 20151860Sbostic lfs_writefile(fs, sp, vp) 20251499Sbostic struct lfs *fs; 20352085Sbostic struct segment *sp; 20452085Sbostic struct vnode *vp; 20551188Sbostic { 20651860Sbostic struct buf *bp; 20752085Sbostic struct finfo *fip; 20851860Sbostic IFILE *ifp; 20951188Sbostic 21051860Sbostic #ifdef VERBOSE 21151860Sbostic printf("lfs_writefile\n"); 21251860Sbostic #endif 21352085Sbostic if (sp->seg_bytes_left < fs->lfs_bsize || 21452085Sbostic sp->sum_bytes_left < sizeof(struct finfo)) { 21552085Sbostic lfs_writeseg(fs, sp); 21652085Sbostic lfs_initseg(fs, sp); 21752085Sbostic } 21852085Sbostic sp->sum_bytes_left -= sizeof(struct finfo) - sizeof(daddr_t); 21951215Sbostic 22052085Sbostic fip = sp->fip; 22152085Sbostic fip->fi_nblocks = 0; 22252085Sbostic fip->fi_ino = VTOI(vp)->i_number; 22352085Sbostic LFS_IENTRY(ifp, fs, fip->fi_ino, bp); 22452085Sbostic fip->fi_version = ifp->if_version; 22552085Sbostic brelse(bp); 22651188Sbostic 22752085Sbostic /* 22852085Sbostic * It may not be necessary to write the meta-data blocks at this point, 22952085Sbostic * as the roll-forward recovery code should be able to reconstruct the 23052085Sbostic * list. 23152085Sbostic */ 23252085Sbostic lfs_gather(fs, sp, vp, lfs_match_data); 23352085Sbostic lfs_gather(fs, sp, vp, lfs_match_indir); 23452085Sbostic lfs_gather(fs, sp, vp, lfs_match_dindir); 23551860Sbostic #ifdef TRIPLE 23652085Sbostic lfs_gather(fs, sp, vp, lfs_match_tindir); 23751860Sbostic #endif 23851342Sbostic 23952085Sbostic fip = sp->fip; 24051860Sbostic #ifdef META 24152085Sbostic printf("lfs_writefile: adding %d blocks\n", fip->fi_nblocks); 24251860Sbostic #endif 24352085Sbostic if (fip->fi_nblocks != 0) { 24452085Sbostic ++((SEGSUM *)(sp->segsum))->ss_nfinfo; 24552085Sbostic sp->fip = 24652085Sbostic (struct finfo *)((caddr_t)fip + sizeof(struct finfo) + 24752085Sbostic sizeof(daddr_t) * (fip->fi_nblocks - 1)); 24851860Sbostic } 24951215Sbostic } 25051215Sbostic 25152077Sbostic void 25251915Sbostic lfs_writeinode(fs, sp, ip) 25351915Sbostic struct lfs *fs; 25452085Sbostic struct segment *sp; 25552085Sbostic struct inode *ip; 25651915Sbostic { 25752085Sbostic struct buf *bp, *ibp; 25852077Sbostic IFILE *ifp; 25951915Sbostic daddr_t next_addr; 26052077Sbostic ino_t ino; 26151915Sbostic int ndx; 26251915Sbostic 26351915Sbostic #ifdef VERBOSE 26451915Sbostic printf("lfs_writeinode\n"); 26551915Sbostic #endif 26651915Sbostic /* Allocate a new inode block if necessary. */ 26751915Sbostic if (sp->ibp == NULL) { 26851915Sbostic /* Allocate a new segment if necessary. */ 26951915Sbostic if (sp->seg_bytes_left < fs->lfs_bsize || 27051915Sbostic sp->sum_bytes_left < sizeof(daddr_t)) { 27151915Sbostic lfs_writeseg(fs, sp); 27251915Sbostic lfs_initseg(fs, sp); 27351915Sbostic } 27451915Sbostic 27551915Sbostic /* Get next inode block. */ 27651915Sbostic next_addr = fs->lfs_offset; 27751915Sbostic fs->lfs_offset += fsbtodb(fs, 1); 27851915Sbostic sp->ibp = *sp->cbpp++ = 27951915Sbostic lfs_newbuf(fs, sp, next_addr, fs->lfs_bsize); 28051915Sbostic 28151915Sbostic /* Set remaining space counter. */ 28251915Sbostic sp->seg_bytes_left -= fs->lfs_bsize; 28351915Sbostic sp->sum_bytes_left -= sizeof(daddr_t); 28452077Sbostic ndx = LFS_SUMMARY_SIZE / sizeof(daddr_t) - 28551915Sbostic sp->ninodes / INOPB(fs) - 1; 28651915Sbostic ((daddr_t *)(sp->segsum))[ndx] = next_addr; 28751915Sbostic } 28851915Sbostic 28952085Sbostic /* Update the inode times and copy the inode onto the inode page. */ 29052077Sbostic ITIMES(ip, &time, &time); 29151915Sbostic bp = sp->ibp; 29252085Sbostic bp->b_un.b_dino[sp->ninodes % INOPB(fs)] = ip->i_din; 29351915Sbostic 29451915Sbostic /* Increment inode count in segment summary block. */ 29551915Sbostic ++((SEGSUM *)(sp->segsum))->ss_ninos; 29651915Sbostic 29751915Sbostic /* If this page is full, set flag to allocate a new page. */ 29851915Sbostic if (++sp->ninodes % INOPB(fs) == 0) 29951915Sbostic sp->ibp = NULL; 30051915Sbostic 30151915Sbostic /* 30252077Sbostic * If updating the ifile, update the super-block. Update the disk 30352077Sbostic * address and access times for this inode in the ifile. 30451915Sbostic */ 30552077Sbostic ino = ip->i_number; 30652077Sbostic if (ino == LFS_IFILE_INUM) 30751915Sbostic fs->lfs_idaddr = bp->b_blkno; 30852077Sbostic 30952077Sbostic LFS_IENTRY(ifp, fs, ino, ibp); 31052077Sbostic ifp->if_daddr = bp->b_blkno; 31152085Sbostic LFS_UBWRITE(ibp); 31251915Sbostic } 31351915Sbostic 31452077Sbostic void 31551215Sbostic lfs_gather(fs, sp, vp, match) 31651499Sbostic struct lfs *fs; 31752085Sbostic struct segment *sp; 31852085Sbostic struct vnode *vp; 31952085Sbostic int (*match) __P((struct lfs *, struct buf *)); 32051215Sbostic { 32152085Sbostic struct buf **bpp, *bp, *nbp; 32252085Sbostic struct finfo *fip; 32352085Sbostic struct inode *ip; 32451215Sbostic daddr_t *lbp, *start_lbp; 32551342Sbostic u_long version; 32651342Sbostic int s; 32751215Sbostic 32851860Sbostic #ifdef VERBOSE 32951860Sbostic printf("lfs_gather\n"); 33051860Sbostic #endif 33151215Sbostic ip = VTOI(vp); 33251215Sbostic bpp = sp->cbpp; 33351215Sbostic fip = sp->fip; 33451215Sbostic start_lbp = lbp = &fip->fi_blocks[fip->fi_nblocks]; 33551215Sbostic 33651215Sbostic s = splbio(); 33751215Sbostic for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { 33851215Sbostic nbp = bp->b_blockf; 33951915Sbostic /* 34051915Sbostic * XXX 34151915Sbostic * Should probably sleep on any BUSY buffer if 34251915Sbostic * doing an fsync? 34351915Sbostic */ 34451342Sbostic if (bp->b_flags & B_BUSY) 34551215Sbostic continue; 34651342Sbostic #ifdef DIAGNOSTIC 34751860Sbostic if (!(bp->b_flags & B_DELWRI)) 34851915Sbostic panic("lfs_gather: bp not B_DELWRI"); 34951860Sbostic if (!(bp->b_flags & B_LOCKED)) 35051915Sbostic panic("lfs_gather: bp not B_LOCKED"); 35151342Sbostic #endif 35251860Sbostic if (!match(fs, bp)) 35351215Sbostic continue; 35451342Sbostic 35551342Sbostic /* Insert into the buffer list, update the FINFO block. */ 35651342Sbostic *sp->cbpp++ = bp; 35751342Sbostic ++fip->fi_nblocks; 35851215Sbostic *lbp++ = bp->b_lblkno; 35951342Sbostic 36051860Sbostic /* 36151860Sbostic * If full, finish this segment. We may be doing I/O, so 36251860Sbostic * release and reacquire the splbio(). 36351860Sbostic */ 36451215Sbostic sp->sum_bytes_left -= sizeof(daddr_t); 36551215Sbostic sp->seg_bytes_left -= bp->b_bufsize; 36651342Sbostic if (sp->sum_bytes_left < sizeof(daddr_t) || 36751215Sbostic sp->seg_bytes_left < fs->lfs_bsize) { 36851215Sbostic splx(s); 36951342Sbostic lfs_updatemeta(fs, 37051860Sbostic sp, vp, start_lbp, bpp, lbp - start_lbp); 37151215Sbostic 37251342Sbostic /* Add the current file to the segment summary. */ 37351342Sbostic ++((SEGSUM *)(sp->segsum))->ss_nfinfo; 37451215Sbostic 37551342Sbostic version = fip->fi_version; 37651860Sbostic lfs_writeseg(fs, sp); 37751915Sbostic lfs_initseg(fs, sp); 37851342Sbostic 37951215Sbostic fip = sp->fip; 38051342Sbostic fip->fi_version = version; 38151215Sbostic fip->fi_ino = ip->i_number; 38251342Sbostic start_lbp = lbp = fip->fi_blocks; 38351342Sbostic 38451215Sbostic bpp = sp->cbpp; 38551215Sbostic s = splbio(); 38651215Sbostic } 38751188Sbostic } 38851215Sbostic splx(s); 38951860Sbostic lfs_updatemeta(fs, sp, vp, start_lbp, bpp, lbp - start_lbp); 39051188Sbostic } 39151188Sbostic 39251342Sbostic /* 39351342Sbostic * Update the metadata that points to the blocks listed in the FINFO 39451188Sbostic * array. 39551188Sbostic */ 39652077Sbostic void 39751860Sbostic lfs_updatemeta(fs, sp, vp, lbp, bpp, nblocks) 39851499Sbostic struct lfs *fs; 39952085Sbostic struct segment *sp; 40052085Sbostic struct vnode *vp; 40151215Sbostic daddr_t *lbp; 40252085Sbostic struct buf **bpp; 40351215Sbostic int nblocks; 40451188Sbostic { 40551915Sbostic SEGUSE *sup; 40652085Sbostic struct buf *bp; 40751860Sbostic INDIR a[NIADDR], *ap; 40852085Sbostic struct inode *ip; 40951915Sbostic daddr_t daddr, lbn, off; 41051860Sbostic int db_per_fsb, error, i, num; 41151188Sbostic 41251860Sbostic #ifdef VERBOSE 41351860Sbostic printf("lfs_updatemeta\n"); 41451860Sbostic #endif 41551342Sbostic if (nblocks == 0) 41651215Sbostic return; 41751215Sbostic 41851915Sbostic /* Sort the blocks. */ 41952077Sbostic lfs_shellsort(bpp, lbp, nblocks); 42051215Sbostic 42151915Sbostic /* 42251915Sbostic * Assign disk addresses, and update references to the logical 42351915Sbostic * block and the segment usage information. 42451915Sbostic */ 42551860Sbostic db_per_fsb = fsbtodb(fs, 1); 42651915Sbostic for (i = nblocks; i--; ++bpp) { 42751915Sbostic lbn = *lbp++; 42851915Sbostic (*bpp)->b_blkno = off = fs->lfs_offset; 42951860Sbostic fs->lfs_offset += db_per_fsb; 43051215Sbostic 43151860Sbostic if (error = lfs_bmaparray(vp, lbn, &daddr, a, &num)) 43252085Sbostic panic("lfs_updatemeta: lfs_bmaparray %d", error); 43351860Sbostic ip = VTOI(vp); 43451860Sbostic switch (num) { 43551860Sbostic case 0: 43651915Sbostic ip->i_db[lbn] = off; 43751860Sbostic break; 43851860Sbostic case 1: 43951915Sbostic ip->i_ib[a[0].in_off] = off; 44051860Sbostic break; 44151860Sbostic default: 44251860Sbostic ap = &a[num - 1]; 44351860Sbostic if (bread(vp, ap->in_lbn, fs->lfs_bsize, NOCRED, &bp)) 44451860Sbostic panic("lfs_updatemeta: bread bno %d", 44551860Sbostic ap->in_lbn); 44651915Sbostic bp->b_un.b_daddr[ap->in_off] = off; 44751342Sbostic lfs_bwrite(bp); 44851188Sbostic } 44951915Sbostic 45051915Sbostic /* Update segment usage information. */ 45151915Sbostic if (daddr != UNASSIGNED) { 45251915Sbostic LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp); 45351915Sbostic sup->su_lastmod = time.tv_sec; 45451915Sbostic #ifdef DIAGNOSTIC 45551915Sbostic if (sup->su_nbytes < fs->lfs_bsize) 45651915Sbostic panic("lfs: negative bytes (segment %d)\n", 45751915Sbostic datosn(fs, daddr)); 45851915Sbostic #endif 45951915Sbostic sup->su_nbytes -= fs->lfs_bsize; 46052085Sbostic LFS_UBWRITE(bp); 46151915Sbostic } 46251188Sbostic } 46351188Sbostic } 46451188Sbostic 46551915Sbostic /* 46651915Sbostic * Start a new segment. 46751915Sbostic */ 46852077Sbostic void 46951915Sbostic lfs_initseg(fs, sp) 47051499Sbostic struct lfs *fs; 47152085Sbostic struct segment *sp; 47251188Sbostic { 47351915Sbostic SEGUSE *sup; 47451915Sbostic SEGSUM *ssp; 47551915Sbostic struct buf *bp; 47651915Sbostic daddr_t lbn, *lbnp; 47751215Sbostic 47851860Sbostic #ifdef VERBOSE 47951915Sbostic printf("lfs_initseg\n"); 48051860Sbostic #endif 48151915Sbostic /* Advance to the next segment. */ 48251927Sbostic if (!LFS_PARTIAL_FITS(fs)) { 48351927Sbostic lfs_newseg(fs); 48451927Sbostic fs->lfs_offset = fs->lfs_curseg; 48551915Sbostic sp->seg_number = datosn(fs, fs->lfs_curseg); 48651915Sbostic sp->seg_bytes_left = fs->lfs_dbpseg * DEV_BSIZE; 48751915Sbostic 48851915Sbostic /* 48951927Sbostic * If the segment contains a superblock, update the offset 49051927Sbostic * and summary address to skip over it. 49151915Sbostic */ 49252077Sbostic LFS_SEGENTRY(sup, fs, sp->seg_number, bp); 49351927Sbostic if (sup->su_flags & SEGUSE_SUPERBLOCK) { 49451915Sbostic fs->lfs_offset += LFS_SBPAD / DEV_BSIZE; 49551915Sbostic sp->seg_bytes_left -= LFS_SBPAD; 49651215Sbostic } 49752085Sbostic brelse(bp); 49851915Sbostic } else { 49951915Sbostic sp->seg_number = datosn(fs, fs->lfs_curseg); 50051915Sbostic sp->seg_bytes_left = (fs->lfs_dbpseg - 50151915Sbostic (fs->lfs_offset - fs->lfs_curseg)) * DEV_BSIZE; 50251915Sbostic } 50351342Sbostic 50451915Sbostic sp->ibp = NULL; 50551915Sbostic sp->ninodes = 0; 50651342Sbostic 50751915Sbostic /* Get a new buffer for SEGSUM and enter it into the buffer list. */ 50851915Sbostic sp->cbpp = sp->bpp; 50951915Sbostic *sp->cbpp = lfs_newbuf(fs, sp, fs->lfs_offset, LFS_SUMMARY_SIZE); 51051915Sbostic sp->segsum = (*sp->cbpp)->b_un.b_addr; 51151915Sbostic ++sp->cbpp; 51251915Sbostic fs->lfs_offset += LFS_SUMMARY_SIZE / DEV_BSIZE; 51351342Sbostic 51451915Sbostic /* Set point to SEGSUM, initialize it. */ 51551915Sbostic ssp = sp->segsum; 51651915Sbostic ssp->ss_next = fs->lfs_nextseg; 51751915Sbostic ssp->ss_nfinfo = ssp->ss_ninos = 0; 51851342Sbostic 51951915Sbostic /* Set pointer to first FINFO, initialize it. */ 52052085Sbostic sp->fip = (struct finfo *)(sp->segsum + sizeof(SEGSUM)); 52151915Sbostic sp->fip->fi_nblocks = 0; 52251342Sbostic 52351915Sbostic sp->seg_bytes_left -= LFS_SUMMARY_SIZE; 52451915Sbostic sp->sum_bytes_left = LFS_SUMMARY_SIZE - sizeof(SEGSUM); 52551915Sbostic } 52651342Sbostic 52751915Sbostic /* 52851915Sbostic * Return the next segment to write. 52951915Sbostic */ 53052077Sbostic void 53151915Sbostic lfs_newseg(fs) 53251915Sbostic struct lfs *fs; 53351915Sbostic { 53451927Sbostic CLEANERINFO *cip; 53551915Sbostic SEGUSE *sup; 53651915Sbostic struct buf *bp; 53751927Sbostic int curseg, isdirty, sn; 53851915Sbostic 53951915Sbostic #ifdef VERBOSE 54051915Sbostic printf("lfs_newseg\n"); 54151915Sbostic #endif 54251927Sbostic /* 54351927Sbostic * Turn off the active bit for the current segment, turn on the 54451927Sbostic * active and dirty bits for the next segment, update the cleaner 54551927Sbostic * info. Set the current segment to the next segment, get a new 54651927Sbostic * next segment. 54751927Sbostic */ 54851927Sbostic LFS_SEGENTRY(sup, fs, datosn(fs, fs->lfs_curseg), bp); 54951927Sbostic sup->su_flags &= ~SEGUSE_ACTIVE; 55052085Sbostic LFS_UBWRITE(bp); 55151927Sbostic 55251927Sbostic LFS_SEGENTRY(sup, fs, datosn(fs, fs->lfs_nextseg), bp); 55351927Sbostic sup->su_flags |= SEGUSE_ACTIVE | SEGUSE_DIRTY; 55452085Sbostic LFS_UBWRITE(bp); 55551927Sbostic 55651927Sbostic LFS_CLEANERINFO(cip, fs, bp); 55751927Sbostic --cip->clean; 55851927Sbostic ++cip->dirty; 55952085Sbostic LFS_UBWRITE(bp); 56051927Sbostic 56151927Sbostic fs->lfs_lastseg = fs->lfs_curseg; 56251927Sbostic fs->lfs_curseg = fs->lfs_nextseg; 56351927Sbostic for (sn = curseg = datosn(fs, fs->lfs_curseg);;) { 56451915Sbostic sn = (sn + 1) % fs->lfs_nseg; 56551927Sbostic if (sn == curseg) 56651915Sbostic panic("lfs_nextseg: no clean segments"); 56751915Sbostic LFS_SEGENTRY(sup, fs, sn, bp); 56851915Sbostic isdirty = sup->su_flags & SEGUSE_DIRTY; 56952085Sbostic brelse(bp); 57051915Sbostic if (!isdirty) 57151915Sbostic break; 57251915Sbostic } 57351927Sbostic fs->lfs_nextseg = sntoda(fs, sn); 57451188Sbostic } 57551188Sbostic 57652077Sbostic void 57751188Sbostic lfs_writeseg(fs, sp) 57851499Sbostic struct lfs *fs; 57952085Sbostic struct segment *sp; 58051188Sbostic { 58152085Sbostic struct buf **bpp, *bp; 58251188Sbostic SEGUSE *sup; 58352085Sbostic SEGSUM *ssp; 58451860Sbostic dev_t i_dev; 58551860Sbostic u_long *datap, *dp; 58651342Sbostic void *pmeta; 58752085Sbostic int flags, i, nblocks, s, (*strategy)__P((struct buf *)); 58851188Sbostic 58951860Sbostic #ifdef VERBOSE 59051860Sbostic printf("lfs_writeseg\n"); 59151860Sbostic #endif 59252085Sbostic if ((nblocks = sp->cbpp - sp->bpp) == 0) 59352085Sbostic return; 59452085Sbostic 59552085Sbostic /* Update the segment usage information. */ 59652085Sbostic LFS_SEGENTRY(sup, fs, sp->seg_number, bp); 59752085Sbostic sup->su_nbytes += nblocks - 1 << fs->lfs_bshift; 59852085Sbostic sup->su_lastmod = time.tv_sec; 59952085Sbostic LFS_UBWRITE(bp); 60052085Sbostic 60151188Sbostic /* 60252085Sbostic * Compute checksum across data and then across summary; the first 60352085Sbostic * block (the summary block) is skipped. Set the create time here 60452085Sbostic * so that it's guaranteed to be later than the inode mod times. 60551860Sbostic * 60651860Sbostic * XXX 60751860Sbostic * Fix this to do it inline, instead of malloc/copy. 60851188Sbostic */ 60951860Sbostic datap = dp = malloc(nblocks * sizeof(u_long), M_SEGMENT, M_WAITOK); 61051915Sbostic for (bpp = sp->bpp, i = nblocks - 1; i--;) 61151915Sbostic *dp++ = (*++bpp)->b_un.b_words[0]; 61252085Sbostic ssp = (SEGSUM *)sp->segsum; 613*52103Sbostic ssp->ss_create = time.tv_sec; 61452085Sbostic ssp->ss_datasum = cksum(datap, nblocks * sizeof(u_long)); 61552085Sbostic ssp->ss_sumsum = 61652085Sbostic cksum(&ssp->ss_datasum, LFS_SUMMARY_SIZE - sizeof(ssp->ss_sumsum)); 61751927Sbostic free(datap, M_SEGMENT); 61851188Sbostic 61951188Sbostic /* 62051860Sbostic * When we gathered the blocks for I/O we did not mark them busy or 62151860Sbostic * remove them from the freelist. As we do this, turn off the B_LOCKED 62251860Sbostic * bit so the future brelse will put them on the LRU list, and add the 62351860Sbostic * B_CALL flags if we're doing a checkpoint so we can count I/O's. LFS 62451860Sbostic * requires that the super blocks (on checkpoint) be written after all 62551860Sbostic * the segment data. 62651188Sbostic */ 62751860Sbostic i_dev = VTOI(fs->lfs_ivnode)->i_dev; 62851860Sbostic strategy = VTOI(fs->lfs_ivnode)->i_devvp->v_op->vop_strategy; 62951301Sbostic 63051301Sbostic s = splbio(); 63151860Sbostic if (sp->seg_flags & SEGM_CKP) { 63251860Sbostic fs->lfs_iocount += nblocks; 63351915Sbostic flags = B_ASYNC | B_BUSY | B_CALL; 63451860Sbostic } else 63551915Sbostic flags = B_ASYNC | B_BUSY; 63651860Sbostic for (bpp = sp->bpp, i = nblocks; i--;) { 63751860Sbostic bp = *bpp++; 63851860Sbostic bp->b_flags |= flags; 63951915Sbostic bp->b_flags &= 64051915Sbostic ~(B_DONE | B_ERROR | B_READ | B_DELWRI | B_LOCKED); 64151860Sbostic bp->b_dev = i_dev; 64251860Sbostic bp->b_iodone = lfs_callback; 64351860Sbostic if (!(bp->b_flags & B_NOCACHE)) { 64451860Sbostic bremfree(bp); 64551860Sbostic reassignbuf(bp, bp->b_vp); 64651860Sbostic } 64751860Sbostic } 64851301Sbostic splx(s); 64952077Sbostic 65051860Sbostic for (bpp = sp->bpp, i = nblocks; i--;) 65151860Sbostic (strategy)(*bpp++); 65251188Sbostic } 65351188Sbostic 65452077Sbostic void 65551860Sbostic lfs_writesuper(fs, sp) 65651499Sbostic struct lfs *fs; 65752085Sbostic struct segment *sp; 65851301Sbostic { 65952085Sbostic struct buf *bp; 66051860Sbostic dev_t i_dev; 66152085Sbostic int (*strategy) __P((struct buf *)); 66251301Sbostic 66351860Sbostic #ifdef VERBOSE 66451860Sbostic printf("lfs_writesuper\n"); 66551860Sbostic #endif 66651860Sbostic i_dev = VTOI(fs->lfs_ivnode)->i_dev; 66751860Sbostic strategy = VTOI(fs->lfs_ivnode)->i_devvp->v_op->vop_strategy; 66851356Sbostic 66951342Sbostic /* Checksum the superblock and copy it into a buffer. */ 67051499Sbostic fs->lfs_cksum = cksum(fs, sizeof(struct lfs) - sizeof(fs->lfs_cksum)); 67151860Sbostic bp = lfs_newbuf(fs, sp, fs->lfs_sboffs[0], LFS_SBPAD); 67251860Sbostic *bp->b_un.b_lfs = *fs; 67351215Sbostic 67451356Sbostic /* Write the first superblock (wait). */ 67551860Sbostic bp->b_dev = i_dev; 67651915Sbostic bp->b_flags |= B_BUSY; 67751860Sbostic bp->b_flags &= ~(B_DONE | B_ERROR | B_READ | B_DELWRI); 67851342Sbostic (strategy)(bp); 67951215Sbostic biowait(bp); 68051342Sbostic 68151356Sbostic /* Write the second superblock (don't wait). */ 68251215Sbostic bp->b_blkno = bp->b_lblkno = fs->lfs_sboffs[1]; 68351915Sbostic bp->b_flags |= B_ASYNC | B_BUSY; 68451860Sbostic bp->b_flags &= ~(B_DONE | B_ERROR | B_READ | B_DELWRI); 68551342Sbostic (strategy)(bp); 68651215Sbostic } 68751215Sbostic 68851342Sbostic /* 68951342Sbostic * Logical block number match routines used when traversing the dirty block 69051342Sbostic * chain. 69151342Sbostic */ 69252077Sbostic int 69352077Sbostic lfs_match_data(fs, bp) 69451860Sbostic struct lfs *fs; 69552085Sbostic struct buf *bp; 69651215Sbostic { 69751342Sbostic return (bp->b_lblkno >= 0); 69851215Sbostic } 69951215Sbostic 70052077Sbostic int 70152077Sbostic lfs_match_indir(fs, bp) 70251860Sbostic struct lfs *fs; 70352085Sbostic struct buf *bp; 70451215Sbostic { 70551860Sbostic int lbn; 70651860Sbostic 70751860Sbostic lbn = bp->b_lblkno; 70851860Sbostic return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 0); 70951215Sbostic } 71051215Sbostic 71152077Sbostic int 71252077Sbostic lfs_match_dindir(fs, bp) 71351860Sbostic struct lfs *fs; 71452085Sbostic struct buf *bp; 71551215Sbostic { 71651860Sbostic int lbn; 71751860Sbostic 71851860Sbostic lbn = bp->b_lblkno; 71951860Sbostic return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 1); 72051215Sbostic } 72151215Sbostic 72252077Sbostic int 72352077Sbostic lfs_match_tindir(fs, bp) 72451499Sbostic struct lfs *fs; 72552085Sbostic struct buf *bp; 72651342Sbostic { 72751860Sbostic int lbn; 72851342Sbostic 72951860Sbostic lbn = bp->b_lblkno; 73051860Sbostic return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 2); 73151860Sbostic } 73251342Sbostic 73351860Sbostic /* 73451860Sbostic * Allocate a new buffer header. 73551860Sbostic */ 73652085Sbostic struct buf * 73751860Sbostic lfs_newbuf(fs, sp, daddr, size) 73851860Sbostic struct lfs *fs; 73952085Sbostic struct segment *sp; 74051860Sbostic daddr_t daddr; 74151860Sbostic size_t size; 74251860Sbostic { 74352085Sbostic struct buf *bp; 74451342Sbostic 74551860Sbostic #ifdef VERBOSE 74651860Sbostic printf("lfs_newbuf\n"); 74751860Sbostic #endif 74851860Sbostic bp = getnewbuf(); 74951860Sbostic bremhash(bp); 75051860Sbostic bgetvp(fs->lfs_ivnode, bp); 75151860Sbostic bp->b_bcount = 0; 75251860Sbostic bp->b_lblkno = daddr; 75351860Sbostic bp->b_blkno = daddr; 75451860Sbostic bp->b_error = 0; 75551860Sbostic bp->b_resid = 0; 75651860Sbostic allocbuf(bp, size); 75751860Sbostic bp->b_flags |= B_NOCACHE; 75851915Sbostic binshash(bp, &bfreelist[BQ_AGE]); 75951860Sbostic return (bp); 76051860Sbostic } 76151342Sbostic 76252077Sbostic int /* XXX should be void */ 76351860Sbostic lfs_callback(bp) 76452085Sbostic struct buf *bp; 76551860Sbostic { 76651860Sbostic struct lfs *fs; 76751342Sbostic 76851860Sbostic fs = VFSTOUFS(bp->b_vp->v_mount)->um_lfs; 76951860Sbostic #ifdef DIAGNOSTIC 77051860Sbostic if (fs->lfs_iocount == 0) 77151860Sbostic panic("lfs_callback: zero iocount\n"); 77251860Sbostic #endif 77351860Sbostic if (--fs->lfs_iocount == 0) 77451860Sbostic wakeup(&fs->lfs_iocount); 77551915Sbostic 77651860Sbostic brelse(bp); 77751860Sbostic } 77851342Sbostic 77951215Sbostic /* 78051188Sbostic * Shellsort (diminishing increment sort) from Data Structures and 78151188Sbostic * Algorithms, Aho, Hopcraft and Ullman, 1983 Edition, page 290; 78251188Sbostic * see also Knuth Vol. 3, page 84. The increments are selected from 78351188Sbostic * formula (8), page 95. Roughly O(N^3/2). 78451188Sbostic */ 78551188Sbostic /* 78651188Sbostic * This is our own private copy of shellsort because we want to sort 78751188Sbostic * two parallel arrays (the array of buffer pointers and the array of 78851188Sbostic * logical block numbers) simultaneously. Note that we cast the array 78951188Sbostic * of logical block numbers to a unsigned in this routine so that the 79051188Sbostic * negative block numbers (meta data blocks) sort AFTER the data blocks. 79151188Sbostic */ 79252077Sbostic void 79352077Sbostic lfs_shellsort(bp_array, lb_array, nmemb) 79452085Sbostic struct buf **bp_array; 79551215Sbostic daddr_t *lb_array; 79651188Sbostic register int nmemb; 79751188Sbostic { 79851188Sbostic static int __rsshell_increments[] = { 4, 1, 0 }; 79951188Sbostic register int incr, *incrp, t1, t2; 80052085Sbostic struct buf *bp_temp; 80151188Sbostic u_long lb_temp; 80251188Sbostic 80351188Sbostic for (incrp = __rsshell_increments; incr = *incrp++;) 80451188Sbostic for (t1 = incr; t1 < nmemb; ++t1) 80551188Sbostic for (t2 = t1 - incr; t2 >= 0;) 80651188Sbostic if (lb_array[t2] > lb_array[t2 + incr]) { 80751188Sbostic lb_temp = lb_array[t2]; 80851188Sbostic lb_array[t2] = lb_array[t2 + incr]; 80951188Sbostic lb_array[t2 + incr] = lb_temp; 81051188Sbostic bp_temp = bp_array[t2]; 81151188Sbostic bp_array[t2] = bp_array[t2 + incr]; 81251188Sbostic bp_array[t2 + incr] = bp_temp; 81351188Sbostic t2 -= incr; 81451188Sbostic } else 81551188Sbostic break; 81651188Sbostic } 817