151188Sbostic /* 251188Sbostic * Copyright (c) 1991 Regents of the University of California. 351188Sbostic * All rights reserved. 451188Sbostic * 551188Sbostic * %sccs.include.redist.c% 651188Sbostic * 7*52077Sbostic * @(#)lfs_segment.c 7.7 (Berkeley) 12/30/91 851188Sbostic */ 951188Sbostic 1051490Sbostic #include <sys/param.h> 1151490Sbostic #include <sys/systm.h> 1251490Sbostic #include <sys/namei.h> 1351490Sbostic #include <sys/resourcevar.h> 1451490Sbostic #include <sys/kernel.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> 2551915Sbostic #include <sys/kernel.h> /* XXX delete when time goes away */ 2651188Sbostic 2751499Sbostic #include <ufs/ufs/quota.h> 2851499Sbostic #include <ufs/ufs/inode.h> 2951499Sbostic #include <ufs/ufs/dir.h> 3051499Sbostic #include <ufs/ufs/ufsmount.h> 3151490Sbostic 3251499Sbostic #include <ufs/lfs/lfs.h> 3351499Sbostic #include <ufs/lfs/lfs_extern.h> 3451490Sbostic 3551860Sbostic /* In-memory description of a segment about to be written. */ 3651860Sbostic typedef struct segment SEGMENT; 3751860Sbostic struct segment { 3851860Sbostic BUF **bpp; /* pointer to buffer array */ 3951860Sbostic BUF **cbpp; /* pointer to next available bp */ 4051860Sbostic BUF *ibp; /* buffer pointer to inode page */ 4151860Sbostic void *segsum; /* segment summary info */ 4251860Sbostic u_long ninodes; /* number of inodes in this segment */ 4351860Sbostic u_long seg_bytes_left; /* bytes left in segment */ 4451860Sbostic u_long sum_bytes_left; /* bytes left in summary block */ 4551860Sbostic u_long seg_number; /* number of this segment */ 4651860Sbostic #define SEGM_CKP 0x01 /* doing a checkpoint */ 4751860Sbostic u_long seg_flags; /* run-time flags for this segment */ 4851860Sbostic FINFO *fip; /* current fileinfo pointer */ 4951860Sbostic }; 5051860Sbostic 5151188Sbostic /* 5251860Sbostic * Determine if it's OK to start a partial in this segment, or if we need 5351860Sbostic * to go on to a new segment. 5451301Sbostic */ 5551860Sbostic #define LFS_PARTIAL_FITS(fs) \ 5651860Sbostic ((fs)->lfs_dbpseg - ((fs)->lfs_offset - (fs)->lfs_curseg) > \ 5751860Sbostic 1 << (fs)->lfs_fsbtodb) 5851188Sbostic 5951860Sbostic #define datosn(fs, daddr) /* disk address to segment number */ \ 6051860Sbostic (((daddr) - (fs)->lfs_sboffs[0]) / fsbtodb((fs), (fs)->lfs_ssize)) 6151860Sbostic 6251860Sbostic #define sntoda(fs, sn) /* segment number to disk address */ \ 6351860Sbostic ((daddr_t)((sn) * ((fs)->lfs_ssize << (fs)->lfs_fsbtodb) + \ 6451860Sbostic (fs)->lfs_sboffs[0])) 6551860Sbostic 66*52077Sbostic int lfs_callback __P((BUF *)); 67*52077Sbostic void lfs_gather __P((struct lfs *, 68*52077Sbostic SEGMENT *, VNODE *, int (*) __P((struct lfs *, BUF *)))); 69*52077Sbostic void lfs_initseg __P((struct lfs *, SEGMENT *)); 70*52077Sbostic void lfs_iset __P((INODE *, daddr_t, time_t)); 71*52077Sbostic int lfs_match_data __P((struct lfs *, BUF *)); 72*52077Sbostic int lfs_match_dindir __P((struct lfs *, BUF *)); 73*52077Sbostic int lfs_match_indir __P((struct lfs *, BUF *)); 74*52077Sbostic int lfs_match_tindir __P((struct lfs *, BUF *)); 75*52077Sbostic BUF *lfs_newbuf __P((struct lfs *, SEGMENT *, daddr_t, size_t)); 76*52077Sbostic void lfs_newseg __P((struct lfs *)); 77*52077Sbostic void lfs_shellsort __P((BUF **, daddr_t *, register int)); 78*52077Sbostic void lfs_updatemeta __P((struct lfs *, 79*52077Sbostic SEGMENT *, VNODE *, daddr_t *, BUF **, int)); 80*52077Sbostic void lfs_writefile __P((struct lfs *, SEGMENT *, VNODE *)); 81*52077Sbostic void lfs_writeinode __P((struct lfs *, SEGMENT *, INODE *)); 82*52077Sbostic void lfs_writeseg __P((struct lfs *, SEGMENT *)); 83*52077Sbostic void lfs_writesuper __P((struct lfs *, SEGMENT *)); 8451188Sbostic 8551860Sbostic int lfs_allclean_wakeup; /* Cleaner wakeup address. */ 8651860Sbostic 8751188Sbostic int 8851215Sbostic lfs_segwrite(mp, do_ckp) 8951188Sbostic MOUNT *mp; 9051860Sbostic int do_ckp; /* Do a checkpoint. */ 9151188Sbostic { 9251188Sbostic INODE *ip; 9351499Sbostic struct lfs *fs; 9451188Sbostic VNODE *vp; 9551188Sbostic SEGMENT *sp; 9651915Sbostic int s, error; 9751188Sbostic 9851860Sbostic #ifdef VERBOSE 9951860Sbostic printf("lfs_segwrite\n"); 10051860Sbostic #endif 10151860Sbostic /* 10251860Sbostic * If doing a checkpoint, we keep a cumulative count of the outstanding 10351860Sbostic * I/O operations. If the disk drive catches up with us it could go to 10451860Sbostic * zero before we finish, so we artificially increment it by one until 10551860Sbostic * we've scheduled all of the writes we intend to do. 10651860Sbostic */ 10751915Sbostic fs = VFSTOUFS(mp)->um_lfs; 10851860Sbostic if (do_ckp) { 10951860Sbostic s = splbio(); 11051860Sbostic fs->lfs_iocount = 1; 11151860Sbostic splx(s); 11251860Sbostic } 11351342Sbostic 11451301Sbostic /* 11551860Sbostic * Allocate a segment structure and enough space to hold pointers to 11651860Sbostic * the maximum possible number of buffers which can be described in a 11751860Sbostic * single summary block. 11851301Sbostic */ 11951860Sbostic sp = malloc(sizeof(SEGMENT), M_SEGMENT, M_WAITOK); 12051860Sbostic sp->bpp = malloc(((LFS_SUMMARY_SIZE - sizeof(SEGSUM)) / 12151860Sbostic sizeof(daddr_t) + 1) * sizeof(BUF *), M_SEGMENT, M_WAITOK); 12251860Sbostic sp->seg_flags = do_ckp ? SEGM_CKP : 0; 12351915Sbostic lfs_initseg(fs, sp); 12451188Sbostic loop: 12551188Sbostic for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 12651188Sbostic /* 12751188Sbostic * If the vnode that we are about to sync is no longer 12851188Sbostic * associated with this mount point, start over. 12951188Sbostic */ 13051188Sbostic if (vp->v_mount != mp) 13151188Sbostic goto loop; 13251188Sbostic if (VOP_ISLOCKED(vp)) 13351188Sbostic continue; 13451860Sbostic 13551915Sbostic /* 13651915Sbostic * Write the inode/file if dirty and it's not the 13751915Sbostic * the IFILE. 13851915Sbostic */ 13951188Sbostic ip = VTOI(vp); 14051860Sbostic if (ip->i_flag & (IMOD | IACC | IUPD | ICHG) == 0 && 14151860Sbostic vp->v_dirtyblkhd == NULL || 14251860Sbostic ip->i_number == LFS_IFILE_INUM) 14351188Sbostic continue; 14451860Sbostic 145*52077Sbostic /* 146*52077Sbostic * XXX 147*52077Sbostic * This is wrong, I think -- we should just wait until we 148*52077Sbostic * get the vnode and go on. Probably going to reschedule 149*52077Sbostic * all of the writes we already scheduled... 150*52077Sbostic */ 15151188Sbostic if (vget(vp)) 15251188Sbostic goto loop; 153*52077Sbostic 154*52077Sbostic if (vp->v_dirtyblkhd != NULL) 155*52077Sbostic lfs_writefile(fs, sp, vp); 15651915Sbostic lfs_writeinode(fs, sp, ip); 157*52077Sbostic ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG); 15851188Sbostic vput(vp); 15951188Sbostic } 160*52077Sbostic /* 161*52077Sbostic * XXX 162*52077Sbostic * Should we always do the dirty blocks of the ifile? Why just 163*52077Sbostic * for a checkpoint. No seeks are involved. 164*52077Sbostic */ 16551860Sbostic if (do_ckp) { 166*52077Sbostic vp = fs->lfs_ivnode; 167*52077Sbostic while (vget(vp)); 168*52077Sbostic ip = VTOI(vp); 169*52077Sbostic if (vp->v_dirtyblkhd != NULL) 170*52077Sbostic lfs_writefile(fs, sp, vp); 171*52077Sbostic lfs_writeinode(fs, sp, ip); 172*52077Sbostic ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG); 173*52077Sbostic vput(vp); 17451860Sbostic } 17551342Sbostic lfs_writeseg(fs, sp); 17651342Sbostic 17751215Sbostic /* 17851860Sbostic * If the I/O count is non-zero, sleep until it reaches zero. At the 17951860Sbostic * moment, the user's process hangs around so we can sleep. 18051215Sbostic */ 18151860Sbostic if (do_ckp) { 18251860Sbostic s = splbio(); 18351915Sbostic if (--fs->lfs_iocount && 18451915Sbostic (error = tsleep(&fs->lfs_iocount, PRIBIO + 1, "sync", 0))) 18551915Sbostic return (error); 18651860Sbostic splx(s); 18751860Sbostic lfs_writesuper(fs, sp); 18851860Sbostic } 18951215Sbostic 19051927Sbostic free(sp->bpp, M_SEGMENT); 19151927Sbostic free(sp, M_SEGMENT); 19251215Sbostic 19351860Sbostic /* Wake up any cleaning processes waiting on this file system. */ 19451860Sbostic wakeup(&fs->lfs_nextseg); 19551860Sbostic wakeup(&lfs_allclean_wakeup); 19651915Sbostic printf("sync returned\n"); 19751860Sbostic return (0); 19851188Sbostic } 19951188Sbostic 20051860Sbostic /* 20151860Sbostic * Write the dirty blocks associated with a vnode. 20251860Sbostic */ 203*52077Sbostic void 20451860Sbostic lfs_writefile(fs, sp, vp) 20551499Sbostic struct lfs *fs; 20651188Sbostic SEGMENT *sp; 20751860Sbostic VNODE *vp; 20851188Sbostic { 20951860Sbostic struct buf *bp; 21051860Sbostic FINFO *fip; 21151860Sbostic IFILE *ifp; 21251860Sbostic ino_t inum; 21351188Sbostic 21451860Sbostic #ifdef VERBOSE 21551860Sbostic printf("lfs_writefile\n"); 21651860Sbostic #endif 21751860Sbostic inum = VTOI(vp)->i_number; 21851860Sbostic if (vp->v_dirtyblkhd != NULL) { 21951860Sbostic if (sp->seg_bytes_left < fs->lfs_bsize || 22051860Sbostic sp->sum_bytes_left < sizeof(FINFO)) { 22151860Sbostic lfs_writeseg(fs, sp); 22251915Sbostic lfs_initseg(fs, sp); 22351860Sbostic } 22451860Sbostic sp->sum_bytes_left -= sizeof(FINFO) - sizeof(daddr_t); 22551215Sbostic 22651860Sbostic fip = sp->fip; 22751860Sbostic fip->fi_nblocks = 0; 22851860Sbostic if (inum == LFS_IFILE_INUM) 22951860Sbostic fip->fi_version = 1; 23051860Sbostic else { 23151860Sbostic LFS_IENTRY(ifp, fs, inum, bp); 23251860Sbostic fip->fi_version = ifp->if_version; 233*52077Sbostic LFS_IRELEASE(fs, bp); 23451860Sbostic } 23551860Sbostic fip->fi_ino = inum; 23651188Sbostic 23751860Sbostic /* 23851860Sbostic * It may not be necessary to write the meta-data blocks 23951860Sbostic * at this point, as the roll-forward recovery code should 24051860Sbostic * be able to reconstruct the list. 24151860Sbostic */ 242*52077Sbostic lfs_gather(fs, sp, vp, lfs_match_data); 243*52077Sbostic lfs_gather(fs, sp, vp, lfs_match_indir); 244*52077Sbostic lfs_gather(fs, sp, vp, lfs_match_dindir); 24551860Sbostic #ifdef TRIPLE 246*52077Sbostic lfs_gather(fs, sp, vp, lfs_match_tindir); 24751860Sbostic #endif 24851342Sbostic 24951860Sbostic fip = sp->fip; 25051860Sbostic #ifdef META 25151860Sbostic printf("lfs_writefile: adding %d blocks\n", fip->fi_nblocks); 25251860Sbostic #endif 25351860Sbostic if (fip->fi_nblocks != 0) { 25451860Sbostic ++((SEGSUM *)(sp->segsum))->ss_nfinfo; 25551860Sbostic sp->fip = (FINFO *)((caddr_t)fip + sizeof(FINFO) + 25651860Sbostic sizeof(daddr_t) * (fip->fi_nblocks - 1)); 25751860Sbostic } 25851860Sbostic } 25951215Sbostic } 26051215Sbostic 261*52077Sbostic void 26251915Sbostic lfs_writeinode(fs, sp, ip) 26351915Sbostic struct lfs *fs; 26451915Sbostic SEGMENT *sp; 26551915Sbostic INODE *ip; 26651915Sbostic { 267*52077Sbostic BUF *bp, *ibp; 268*52077Sbostic IFILE *ifp; 26951915Sbostic daddr_t next_addr; 270*52077Sbostic ino_t ino; 27151915Sbostic int ndx; 27251915Sbostic 27351915Sbostic #ifdef VERBOSE 27451915Sbostic printf("lfs_writeinode\n"); 27551915Sbostic #endif 27651915Sbostic /* Allocate a new inode block if necessary. */ 27751915Sbostic if (sp->ibp == NULL) { 27851915Sbostic /* Allocate a new segment if necessary. */ 27951915Sbostic if (sp->seg_bytes_left < fs->lfs_bsize || 28051915Sbostic sp->sum_bytes_left < sizeof(daddr_t)) { 28151915Sbostic lfs_writeseg(fs, sp); 28251915Sbostic lfs_initseg(fs, sp); 28351915Sbostic } 28451915Sbostic 28551915Sbostic /* Get next inode block. */ 28651915Sbostic next_addr = fs->lfs_offset; 28751915Sbostic fs->lfs_offset += fsbtodb(fs, 1); 28851915Sbostic sp->ibp = *sp->cbpp++ = 28951915Sbostic lfs_newbuf(fs, sp, next_addr, fs->lfs_bsize); 29051915Sbostic 29151915Sbostic /* Set remaining space counter. */ 29251915Sbostic sp->seg_bytes_left -= fs->lfs_bsize; 29351915Sbostic sp->sum_bytes_left -= sizeof(daddr_t); 294*52077Sbostic ndx = LFS_SUMMARY_SIZE / sizeof(daddr_t) - 29551915Sbostic sp->ninodes / INOPB(fs) - 1; 29651915Sbostic ((daddr_t *)(sp->segsum))[ndx] = next_addr; 29751915Sbostic } 29851915Sbostic 299*52077Sbostic /* 300*52077Sbostic * Update the inode times and copy the inode onto the inode page. 301*52077Sbostic * 30251915Sbostic * XXX 30351915Sbostic * Do struct assignment. 30451915Sbostic */ 305*52077Sbostic ITIMES(ip, &time, &time); 30651915Sbostic bp = sp->ibp; 30751915Sbostic bcopy(&ip->i_din, 30851915Sbostic bp->b_un.b_dino + (sp->ninodes % INOPB(fs)), sizeof(DINODE)); 30951915Sbostic 31051915Sbostic /* Increment inode count in segment summary block. */ 31151915Sbostic ++((SEGSUM *)(sp->segsum))->ss_ninos; 31251915Sbostic 31351915Sbostic /* If this page is full, set flag to allocate a new page. */ 31451915Sbostic if (++sp->ninodes % INOPB(fs) == 0) 31551915Sbostic sp->ibp = NULL; 31651915Sbostic 31751915Sbostic /* 318*52077Sbostic * If updating the ifile, update the super-block. Update the disk 319*52077Sbostic * address and access times for this inode in the ifile. 320*52077Sbostic * 321*52077Sbostic * XXX 322*52077Sbostic * The access time in the ifile is currently unused. 32351915Sbostic */ 324*52077Sbostic ino = ip->i_number; 325*52077Sbostic if (ino == LFS_IFILE_INUM) 32651915Sbostic fs->lfs_idaddr = bp->b_blkno; 327*52077Sbostic 328*52077Sbostic LFS_IENTRY(ifp, fs, ino, ibp); 329*52077Sbostic ifp->if_daddr = bp->b_blkno; 330*52077Sbostic ifp->if_st_atime = ip->i_atime; 331*52077Sbostic LFS_IWRITE(fs, ibp); 33251915Sbostic } 33351915Sbostic 334*52077Sbostic void 33551215Sbostic lfs_gather(fs, sp, vp, match) 33651499Sbostic struct lfs *fs; 33751215Sbostic SEGMENT *sp; 33851215Sbostic VNODE *vp; 33951860Sbostic int (*match) __P((struct lfs *, BUF *)); 34051215Sbostic { 34151215Sbostic BUF **bpp, *bp, *nbp; 34251215Sbostic FINFO *fip; 34351215Sbostic INODE *ip; 34451215Sbostic daddr_t *lbp, *start_lbp; 34551342Sbostic u_long version; 34651342Sbostic int s; 34751215Sbostic 34851860Sbostic #ifdef VERBOSE 34951860Sbostic printf("lfs_gather\n"); 35051860Sbostic #endif 35151215Sbostic ip = VTOI(vp); 35251215Sbostic bpp = sp->cbpp; 35351215Sbostic fip = sp->fip; 35451215Sbostic start_lbp = lbp = &fip->fi_blocks[fip->fi_nblocks]; 35551215Sbostic 35651215Sbostic s = splbio(); 35751215Sbostic for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { 35851215Sbostic nbp = bp->b_blockf; 35951915Sbostic /* 36051915Sbostic * XXX 36151915Sbostic * Should probably sleep on any BUSY buffer if 36251915Sbostic * doing an fsync? 36351915Sbostic */ 36451342Sbostic if (bp->b_flags & B_BUSY) 36551215Sbostic continue; 36651342Sbostic #ifdef DIAGNOSTIC 36751860Sbostic if (!(bp->b_flags & B_DELWRI)) 36851915Sbostic panic("lfs_gather: bp not B_DELWRI"); 36951860Sbostic if (!(bp->b_flags & B_LOCKED)) 37051915Sbostic panic("lfs_gather: bp not B_LOCKED"); 37151342Sbostic #endif 37251860Sbostic if (!match(fs, bp)) 37351215Sbostic continue; 37451342Sbostic 37551342Sbostic /* Insert into the buffer list, update the FINFO block. */ 37651342Sbostic *sp->cbpp++ = bp; 37751342Sbostic ++fip->fi_nblocks; 37851215Sbostic *lbp++ = bp->b_lblkno; 37951342Sbostic 38051860Sbostic /* 38151860Sbostic * If full, finish this segment. We may be doing I/O, so 38251860Sbostic * release and reacquire the splbio(). 38351860Sbostic */ 38451215Sbostic sp->sum_bytes_left -= sizeof(daddr_t); 38551215Sbostic sp->seg_bytes_left -= bp->b_bufsize; 38651342Sbostic if (sp->sum_bytes_left < sizeof(daddr_t) || 38751215Sbostic sp->seg_bytes_left < fs->lfs_bsize) { 38851215Sbostic splx(s); 38951342Sbostic lfs_updatemeta(fs, 39051860Sbostic sp, vp, start_lbp, bpp, lbp - start_lbp); 39151215Sbostic 39251342Sbostic /* Add the current file to the segment summary. */ 39351342Sbostic ++((SEGSUM *)(sp->segsum))->ss_nfinfo; 39451215Sbostic 39551342Sbostic version = fip->fi_version; 39651860Sbostic lfs_writeseg(fs, sp); 39751915Sbostic lfs_initseg(fs, sp); 39851342Sbostic 39951215Sbostic fip = sp->fip; 40051342Sbostic fip->fi_version = version; 40151215Sbostic fip->fi_ino = ip->i_number; 40251342Sbostic start_lbp = lbp = fip->fi_blocks; 40351342Sbostic 40451215Sbostic bpp = sp->cbpp; 40551215Sbostic s = splbio(); 40651215Sbostic } 40751188Sbostic } 40851215Sbostic splx(s); 40951860Sbostic lfs_updatemeta(fs, sp, vp, start_lbp, bpp, lbp - start_lbp); 41051188Sbostic } 41151188Sbostic 41251342Sbostic /* 41351342Sbostic * Update the metadata that points to the blocks listed in the FINFO 41451188Sbostic * array. 41551188Sbostic */ 416*52077Sbostic void 41751860Sbostic lfs_updatemeta(fs, sp, vp, lbp, bpp, nblocks) 41851499Sbostic struct lfs *fs; 41951215Sbostic SEGMENT *sp; 42051860Sbostic VNODE *vp; 42151215Sbostic daddr_t *lbp; 42251188Sbostic BUF **bpp; 42351215Sbostic int nblocks; 42451188Sbostic { 42551915Sbostic SEGUSE *sup; 42651915Sbostic BUF *bp; 42751860Sbostic INDIR a[NIADDR], *ap; 42851860Sbostic INODE *ip; 42951915Sbostic daddr_t daddr, lbn, off; 43051860Sbostic int db_per_fsb, error, i, num; 43151188Sbostic 43251860Sbostic #ifdef VERBOSE 43351860Sbostic printf("lfs_updatemeta\n"); 43451860Sbostic #endif 43551342Sbostic if (nblocks == 0) 43651215Sbostic return; 43751215Sbostic 43851915Sbostic /* Sort the blocks. */ 439*52077Sbostic lfs_shellsort(bpp, lbp, nblocks); 44051215Sbostic 44151915Sbostic /* 44251915Sbostic * Assign disk addresses, and update references to the logical 44351915Sbostic * block and the segment usage information. 44451915Sbostic */ 44551860Sbostic db_per_fsb = fsbtodb(fs, 1); 44651915Sbostic for (i = nblocks; i--; ++bpp) { 44751915Sbostic lbn = *lbp++; 44851915Sbostic (*bpp)->b_blkno = off = fs->lfs_offset; 44951860Sbostic fs->lfs_offset += db_per_fsb; 45051215Sbostic 45151860Sbostic if (error = lfs_bmaparray(vp, lbn, &daddr, a, &num)) 45251915Sbostic panic("lfs_updatemeta: lfs_bmaparray returned %d", 45351915Sbostic error); 45451860Sbostic #ifdef META 45551860Sbostic printf("daddr: %d num: %d\n", daddr, num); 45651860Sbostic if (num != 0) { 45751860Sbostic int x; 45851915Sbostic printf("array from bmaparray:\n"); 45951860Sbostic for (x = 0; x < num; x++) 46051860Sbostic printf("\tlbn %d off %d\n", a[x].in_lbn, a[x].in_off); 46151860Sbostic } 46251860Sbostic #endif 46351860Sbostic ip = VTOI(vp); 46451860Sbostic switch (num) { 46551860Sbostic case 0: 46651356Sbostic #ifdef META 46751860Sbostic printf("update inode for direct block %d\n", lbn); 46851356Sbostic #endif 46951915Sbostic ip->i_db[lbn] = off; 47051860Sbostic break; 47151860Sbostic case 1: 47251915Sbostic ip->i_ib[a[0].in_off] = off; 47351860Sbostic break; 47451860Sbostic default: 47551860Sbostic ap = &a[num - 1]; 47651356Sbostic #ifdef META 47751860Sbostic printf("update indirect block %d offset %d\n", 478*52077Sbostic ap->in_lbn, ap->in_off); 47951356Sbostic #endif 48051860Sbostic if (bread(vp, ap->in_lbn, fs->lfs_bsize, NOCRED, &bp)) 48151860Sbostic panic("lfs_updatemeta: bread bno %d", 48251860Sbostic ap->in_lbn); 48351915Sbostic bp->b_un.b_daddr[ap->in_off] = off; 48451342Sbostic lfs_bwrite(bp); 48551188Sbostic } 48651915Sbostic 48751915Sbostic /* Update segment usage information. */ 48851915Sbostic if (daddr != UNASSIGNED) { 48951915Sbostic LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp); 49051915Sbostic sup->su_lastmod = time.tv_sec; 49151915Sbostic #ifdef DIAGNOSTIC 49251915Sbostic if (sup->su_nbytes < fs->lfs_bsize) 49351915Sbostic panic("lfs: negative bytes (segment %d)\n", 49451915Sbostic datosn(fs, daddr)); 49551915Sbostic #endif 49651915Sbostic sup->su_nbytes -= fs->lfs_bsize; 497*52077Sbostic LFS_IWRITE(fs, bp); 49851915Sbostic } 49951188Sbostic } 50051188Sbostic } 50151188Sbostic 50251915Sbostic /* 50351915Sbostic * Start a new segment. 50451915Sbostic */ 505*52077Sbostic void 50651915Sbostic lfs_initseg(fs, sp) 50751499Sbostic struct lfs *fs; 50851215Sbostic SEGMENT *sp; 50951188Sbostic { 51051915Sbostic SEGUSE *sup; 51151915Sbostic SEGSUM *ssp; 51251915Sbostic struct buf *bp; 51351915Sbostic daddr_t lbn, *lbnp; 51451215Sbostic 51551860Sbostic #ifdef VERBOSE 51651915Sbostic printf("lfs_initseg\n"); 51751860Sbostic #endif 51851915Sbostic /* Advance to the next segment. */ 51951927Sbostic if (!LFS_PARTIAL_FITS(fs)) { 52051927Sbostic lfs_newseg(fs); 52151927Sbostic fs->lfs_offset = fs->lfs_curseg; 52251915Sbostic sp->seg_number = datosn(fs, fs->lfs_curseg); 52351915Sbostic sp->seg_bytes_left = fs->lfs_dbpseg * DEV_BSIZE; 52451915Sbostic 52551915Sbostic /* 52651927Sbostic * If the segment contains a superblock, update the offset 52751927Sbostic * and summary address to skip over it. 52851915Sbostic */ 529*52077Sbostic LFS_SEGENTRY(sup, fs, sp->seg_number, bp); 53051927Sbostic if (sup->su_flags & SEGUSE_SUPERBLOCK) { 53151915Sbostic fs->lfs_offset += LFS_SBPAD / DEV_BSIZE; 53251915Sbostic sp->seg_bytes_left -= LFS_SBPAD; 53351215Sbostic } 534*52077Sbostic LFS_IRELEASE(fs, bp); 53551915Sbostic } else { 53651915Sbostic sp->seg_number = datosn(fs, fs->lfs_curseg); 53751915Sbostic sp->seg_bytes_left = (fs->lfs_dbpseg - 53851915Sbostic (fs->lfs_offset - fs->lfs_curseg)) * DEV_BSIZE; 53951915Sbostic } 54051342Sbostic 54151915Sbostic sp->ibp = NULL; 54251915Sbostic sp->ninodes = 0; 54351342Sbostic 54451915Sbostic /* Get a new buffer for SEGSUM and enter it into the buffer list. */ 54551915Sbostic sp->cbpp = sp->bpp; 54651915Sbostic *sp->cbpp = lfs_newbuf(fs, sp, fs->lfs_offset, LFS_SUMMARY_SIZE); 54751915Sbostic sp->segsum = (*sp->cbpp)->b_un.b_addr; 54851915Sbostic ++sp->cbpp; 54951915Sbostic fs->lfs_offset += LFS_SUMMARY_SIZE / DEV_BSIZE; 55051342Sbostic 55151915Sbostic /* Set point to SEGSUM, initialize it. */ 55251915Sbostic ssp = sp->segsum; 55351915Sbostic ssp->ss_next = fs->lfs_nextseg; 55451915Sbostic ssp->ss_create = time.tv_sec; 55551915Sbostic ssp->ss_nfinfo = ssp->ss_ninos = 0; 55651342Sbostic 55751915Sbostic /* Set pointer to first FINFO, initialize it. */ 55851915Sbostic sp->fip = (FINFO *)(sp->segsum + sizeof(SEGSUM)); 55951915Sbostic sp->fip->fi_nblocks = 0; 56051342Sbostic 56151915Sbostic sp->seg_bytes_left -= LFS_SUMMARY_SIZE; 56251915Sbostic sp->sum_bytes_left = LFS_SUMMARY_SIZE - sizeof(SEGSUM); 56351915Sbostic } 56451342Sbostic 56551915Sbostic /* 56651915Sbostic * Return the next segment to write. 56751915Sbostic */ 568*52077Sbostic void 56951915Sbostic lfs_newseg(fs) 57051915Sbostic struct lfs *fs; 57151915Sbostic { 57251927Sbostic CLEANERINFO *cip; 57351915Sbostic SEGUSE *sup; 57451915Sbostic struct buf *bp; 57551927Sbostic int curseg, isdirty, sn; 57651915Sbostic 57751915Sbostic #ifdef VERBOSE 57851915Sbostic printf("lfs_newseg\n"); 57951915Sbostic #endif 58051927Sbostic /* 58151927Sbostic * Turn off the active bit for the current segment, turn on the 58251927Sbostic * active and dirty bits for the next segment, update the cleaner 58351927Sbostic * info. Set the current segment to the next segment, get a new 58451927Sbostic * next segment. 58551927Sbostic */ 58651927Sbostic LFS_SEGENTRY(sup, fs, datosn(fs, fs->lfs_curseg), bp); 58751927Sbostic sup->su_flags &= ~SEGUSE_ACTIVE; 588*52077Sbostic LFS_IWRITE(fs, bp); 58951927Sbostic 59051927Sbostic LFS_SEGENTRY(sup, fs, datosn(fs, fs->lfs_nextseg), bp); 59151927Sbostic sup->su_flags |= SEGUSE_ACTIVE | SEGUSE_DIRTY; 592*52077Sbostic LFS_IWRITE(fs, bp); 59351927Sbostic 59451927Sbostic LFS_CLEANERINFO(cip, fs, bp); 59551927Sbostic --cip->clean; 59651927Sbostic ++cip->dirty; 597*52077Sbostic LFS_IWRITE(fs, bp); 59851927Sbostic 59951927Sbostic fs->lfs_lastseg = fs->lfs_curseg; 60051927Sbostic fs->lfs_curseg = fs->lfs_nextseg; 60151927Sbostic for (sn = curseg = datosn(fs, fs->lfs_curseg);;) { 60251915Sbostic sn = (sn + 1) % fs->lfs_nseg; 60351927Sbostic if (sn == curseg) 60451915Sbostic panic("lfs_nextseg: no clean segments"); 60551915Sbostic LFS_SEGENTRY(sup, fs, sn, bp); 60651915Sbostic isdirty = sup->su_flags & SEGUSE_DIRTY; 607*52077Sbostic LFS_IRELEASE(fs, bp); 60851915Sbostic if (!isdirty) 60951915Sbostic break; 61051915Sbostic } 61151927Sbostic fs->lfs_nextseg = sntoda(fs, sn); 61251188Sbostic } 61351188Sbostic 614*52077Sbostic void 61551188Sbostic lfs_writeseg(fs, sp) 61651499Sbostic struct lfs *fs; 61751188Sbostic SEGMENT *sp; 61851188Sbostic { 61951915Sbostic BUF **bpp, *bp; 62051188Sbostic SEGUSE *sup; 62151860Sbostic SEGSUM *segp; 62251860Sbostic dev_t i_dev; 62351860Sbostic u_long *datap, *dp; 62451342Sbostic void *pmeta; 62551927Sbostic int flags, i, nblocks, s, (*strategy)__P((BUF *)); 62651188Sbostic 62751860Sbostic #ifdef VERBOSE 62851860Sbostic printf("lfs_writeseg\n"); 62951860Sbostic #endif 63051188Sbostic /* 63151915Sbostic * Compute checksum across data and then across summary; 63251915Sbostic * the first block (the summary block) is skipped. 63351860Sbostic * 63451860Sbostic * XXX 63551860Sbostic * Fix this to do it inline, instead of malloc/copy. 63651188Sbostic */ 63751927Sbostic nblocks = sp->cbpp - sp->bpp; 63851860Sbostic datap = dp = malloc(nblocks * sizeof(u_long), M_SEGMENT, M_WAITOK); 63951915Sbostic for (bpp = sp->bpp, i = nblocks - 1; i--;) 64051915Sbostic *dp++ = (*++bpp)->b_un.b_words[0]; 641*52077Sbostic 64251860Sbostic segp = (SEGSUM *)sp->segsum; 64351860Sbostic segp->ss_datasum = cksum(datap, nblocks * sizeof(u_long)); 644*52077Sbostic segp->ss_sumsum = cksum(&segp->ss_datasum, 64551860Sbostic LFS_SUMMARY_SIZE - sizeof(segp->ss_sumsum)); 64651927Sbostic free(datap, M_SEGMENT); 64751188Sbostic 64851188Sbostic /* 64951860Sbostic * When we gathered the blocks for I/O we did not mark them busy or 65051860Sbostic * remove them from the freelist. As we do this, turn off the B_LOCKED 65151860Sbostic * bit so the future brelse will put them on the LRU list, and add the 65251860Sbostic * B_CALL flags if we're doing a checkpoint so we can count I/O's. LFS 65351860Sbostic * requires that the super blocks (on checkpoint) be written after all 65451860Sbostic * the segment data. 65551188Sbostic */ 65651860Sbostic i_dev = VTOI(fs->lfs_ivnode)->i_dev; 65751860Sbostic strategy = VTOI(fs->lfs_ivnode)->i_devvp->v_op->vop_strategy; 65851301Sbostic 65951301Sbostic s = splbio(); 66051860Sbostic if (sp->seg_flags & SEGM_CKP) { 66151860Sbostic fs->lfs_iocount += nblocks; 66251915Sbostic flags = B_ASYNC | B_BUSY | B_CALL; 66351860Sbostic } else 66451915Sbostic flags = B_ASYNC | B_BUSY; 66551860Sbostic for (bpp = sp->bpp, i = nblocks; i--;) { 66651860Sbostic bp = *bpp++; 66751860Sbostic bp->b_flags |= flags; 66851915Sbostic bp->b_flags &= 66951915Sbostic ~(B_DONE | B_ERROR | B_READ | B_DELWRI | B_LOCKED); 67051860Sbostic bp->b_dev = i_dev; 67151860Sbostic bp->b_iodone = lfs_callback; 67251860Sbostic if (!(bp->b_flags & B_NOCACHE)) { 67351860Sbostic bremfree(bp); 67451860Sbostic reassignbuf(bp, bp->b_vp); 67551860Sbostic } 67651860Sbostic } 67751301Sbostic splx(s); 678*52077Sbostic 67951860Sbostic for (bpp = sp->bpp, i = nblocks; i--;) 68051860Sbostic (strategy)(*bpp++); 68151927Sbostic 68251927Sbostic /* Update the segment usage information. */ 68351927Sbostic LFS_SEGENTRY(sup, fs, sp->seg_number, bp); 68451927Sbostic sup->su_nbytes += LFS_SUMMARY_SIZE + (nblocks - 1 << fs->lfs_bshift); 68551927Sbostic sup->su_lastmod = time.tv_sec; 686*52077Sbostic LFS_IWRITE(fs, bp); 68751188Sbostic } 68851188Sbostic 689*52077Sbostic void 69051860Sbostic lfs_writesuper(fs, sp) 69151499Sbostic struct lfs *fs; 69251860Sbostic SEGMENT *sp; 69351301Sbostic { 69451301Sbostic BUF *bp; 69551860Sbostic dev_t i_dev; 69651342Sbostic int (*strategy) __P((BUF *)); 69751301Sbostic 69851860Sbostic #ifdef VERBOSE 69951860Sbostic printf("lfs_writesuper\n"); 70051860Sbostic #endif 70151860Sbostic i_dev = VTOI(fs->lfs_ivnode)->i_dev; 70251860Sbostic strategy = VTOI(fs->lfs_ivnode)->i_devvp->v_op->vop_strategy; 70351356Sbostic 70451342Sbostic /* Checksum the superblock and copy it into a buffer. */ 70551499Sbostic fs->lfs_cksum = cksum(fs, sizeof(struct lfs) - sizeof(fs->lfs_cksum)); 70651860Sbostic bp = lfs_newbuf(fs, sp, fs->lfs_sboffs[0], LFS_SBPAD); 70751860Sbostic *bp->b_un.b_lfs = *fs; 70851215Sbostic 70951356Sbostic /* Write the first superblock (wait). */ 71051860Sbostic bp->b_dev = i_dev; 71151915Sbostic bp->b_flags |= B_BUSY; 71251860Sbostic bp->b_flags &= ~(B_DONE | B_ERROR | B_READ | B_DELWRI); 71351342Sbostic (strategy)(bp); 71451215Sbostic biowait(bp); 71551342Sbostic 71651356Sbostic /* Write the second superblock (don't wait). */ 71751215Sbostic bp->b_blkno = bp->b_lblkno = fs->lfs_sboffs[1]; 71851915Sbostic bp->b_flags |= B_ASYNC | B_BUSY; 71951860Sbostic bp->b_flags &= ~(B_DONE | B_ERROR | B_READ | B_DELWRI); 72051342Sbostic (strategy)(bp); 72151215Sbostic } 72251215Sbostic 72351342Sbostic /* 72451342Sbostic * Logical block number match routines used when traversing the dirty block 72551342Sbostic * chain. 72651342Sbostic */ 727*52077Sbostic int 728*52077Sbostic lfs_match_data(fs, bp) 72951860Sbostic struct lfs *fs; 73051215Sbostic BUF *bp; 73151215Sbostic { 73251342Sbostic return (bp->b_lblkno >= 0); 73351215Sbostic } 73451215Sbostic 735*52077Sbostic int 736*52077Sbostic lfs_match_indir(fs, bp) 73751860Sbostic struct lfs *fs; 73851215Sbostic BUF *bp; 73951215Sbostic { 74051860Sbostic int lbn; 74151860Sbostic 74251860Sbostic lbn = bp->b_lblkno; 74351860Sbostic return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 0); 74451215Sbostic } 74551215Sbostic 746*52077Sbostic int 747*52077Sbostic lfs_match_dindir(fs, bp) 74851860Sbostic struct lfs *fs; 74951215Sbostic BUF *bp; 75051215Sbostic { 75151860Sbostic int lbn; 75251860Sbostic 75351860Sbostic lbn = bp->b_lblkno; 75451860Sbostic return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 1); 75551215Sbostic } 75651215Sbostic 757*52077Sbostic int 758*52077Sbostic lfs_match_tindir(fs, bp) 75951499Sbostic struct lfs *fs; 76051860Sbostic BUF *bp; 76151342Sbostic { 76251860Sbostic int lbn; 76351342Sbostic 76451860Sbostic lbn = bp->b_lblkno; 76551860Sbostic return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 2); 76651860Sbostic } 76751342Sbostic 76851860Sbostic /* 76951860Sbostic * Allocate a new buffer header. 77051860Sbostic */ 771*52077Sbostic BUF * 77251860Sbostic lfs_newbuf(fs, sp, daddr, size) 77351860Sbostic struct lfs *fs; 77451860Sbostic SEGMENT *sp; 77551860Sbostic daddr_t daddr; 77651860Sbostic size_t size; 77751860Sbostic { 77851860Sbostic BUF *bp; 77951342Sbostic 78051860Sbostic #ifdef VERBOSE 78151860Sbostic printf("lfs_newbuf\n"); 78251860Sbostic #endif 78351860Sbostic bp = getnewbuf(); 78451860Sbostic bremhash(bp); 78551860Sbostic bgetvp(fs->lfs_ivnode, bp); 78651860Sbostic bp->b_bcount = 0; 78751860Sbostic bp->b_lblkno = daddr; 78851860Sbostic bp->b_blkno = daddr; 78951860Sbostic bp->b_error = 0; 79051860Sbostic bp->b_resid = 0; 79151860Sbostic allocbuf(bp, size); 79251860Sbostic bp->b_flags |= B_NOCACHE; 79351915Sbostic binshash(bp, &bfreelist[BQ_AGE]); 79451860Sbostic return (bp); 79551860Sbostic } 79651342Sbostic 797*52077Sbostic int /* XXX should be void */ 79851860Sbostic lfs_callback(bp) 79951860Sbostic BUF *bp; 80051860Sbostic { 80151860Sbostic struct lfs *fs; 80251342Sbostic 80351860Sbostic fs = VFSTOUFS(bp->b_vp->v_mount)->um_lfs; 80451860Sbostic #ifdef DIAGNOSTIC 80551860Sbostic if (fs->lfs_iocount == 0) 80651860Sbostic panic("lfs_callback: zero iocount\n"); 80751860Sbostic #endif 80851860Sbostic if (--fs->lfs_iocount == 0) 80951860Sbostic wakeup(&fs->lfs_iocount); 81051915Sbostic 81151860Sbostic brelse(bp); 81251860Sbostic } 81351342Sbostic 81451215Sbostic /* 81551188Sbostic * Shellsort (diminishing increment sort) from Data Structures and 81651188Sbostic * Algorithms, Aho, Hopcraft and Ullman, 1983 Edition, page 290; 81751188Sbostic * see also Knuth Vol. 3, page 84. The increments are selected from 81851188Sbostic * formula (8), page 95. Roughly O(N^3/2). 81951188Sbostic */ 82051188Sbostic /* 82151188Sbostic * This is our own private copy of shellsort because we want to sort 82251188Sbostic * two parallel arrays (the array of buffer pointers and the array of 82351188Sbostic * logical block numbers) simultaneously. Note that we cast the array 82451188Sbostic * of logical block numbers to a unsigned in this routine so that the 82551188Sbostic * negative block numbers (meta data blocks) sort AFTER the data blocks. 82651188Sbostic */ 827*52077Sbostic void 828*52077Sbostic lfs_shellsort(bp_array, lb_array, nmemb) 82951188Sbostic BUF **bp_array; 83051215Sbostic daddr_t *lb_array; 83151188Sbostic register int nmemb; 83251188Sbostic { 83351188Sbostic static int __rsshell_increments[] = { 4, 1, 0 }; 83451188Sbostic register int incr, *incrp, t1, t2; 83551188Sbostic BUF *bp_temp; 83651188Sbostic u_long lb_temp; 83751188Sbostic 83851188Sbostic for (incrp = __rsshell_increments; incr = *incrp++;) 83951188Sbostic for (t1 = incr; t1 < nmemb; ++t1) 84051188Sbostic for (t2 = t1 - incr; t2 >= 0;) 84151188Sbostic if (lb_array[t2] > lb_array[t2 + incr]) { 84251188Sbostic lb_temp = lb_array[t2]; 84351188Sbostic lb_array[t2] = lb_array[t2 + incr]; 84451188Sbostic lb_array[t2 + incr] = lb_temp; 84551188Sbostic bp_temp = bp_array[t2]; 84651188Sbostic bp_array[t2] = bp_array[t2 + incr]; 84751188Sbostic bp_array[t2 + incr] = bp_temp; 84851188Sbostic t2 -= incr; 84951188Sbostic } else 85051188Sbostic break; 85151188Sbostic } 852