151188Sbostic /* 251188Sbostic * Copyright (c) 1991 Regents of the University of California. 351188Sbostic * All rights reserved. 451188Sbostic * 551188Sbostic * %sccs.include.redist.c% 651188Sbostic * 7*52328Sbostic * @(#)lfs_segment.c 7.10 (Berkeley) 02/04/92 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 79*52328Sbostic /* 80*52328Sbostic * Ifile and meta data blocks are not marked busy, so segment writes MUST be 81*52328Sbostic * single threaded. Currently, there are two paths into lfs_segwrite, sync() 82*52328Sbostic * and getnewbuf(). They both mark the file system busy. Lfs_vflush() 83*52328Sbostic * explicitly marks the file system busy. So lfs_segwrite is safe. I think. 84*52328Sbostic */ 85*52328Sbostic 8651188Sbostic int 87*52328Sbostic lfs_vflush(vp) 88*52328Sbostic struct vnode *vp; 89*52328Sbostic { 90*52328Sbostic struct inode *ip; 91*52328Sbostic struct lfs *fs; 92*52328Sbostic struct mount *mp; 93*52328Sbostic struct segment *sp; 94*52328Sbostic int error, s; 95*52328Sbostic 96*52328Sbostic #ifdef VERBOSE 97*52328Sbostic printf("lfs_vflush\n"); 98*52328Sbostic #endif 99*52328Sbostic mp = vp->v_mount; 100*52328Sbostic fs = VFSTOUFS(mp)->um_lfs; 101*52328Sbostic 102*52328Sbostic /* 103*52328Sbostic * XXX 104*52328Sbostic * check flags? 105*52328Sbostic * mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY) || 106*52328Sbostic */ 107*52328Sbostic if (vfs_busy(mp)) 108*52328Sbostic return (0); 109*52328Sbostic 110*52328Sbostic /* 111*52328Sbostic * Allocate a segment structure and enough space to hold pointers to 112*52328Sbostic * the maximum possible number of buffers which can be described in a 113*52328Sbostic * single summary block. 114*52328Sbostic */ 115*52328Sbostic sp = malloc(sizeof(struct segment), M_SEGMENT, M_WAITOK); 116*52328Sbostic sp->bpp = malloc(((LFS_SUMMARY_SIZE - sizeof(SEGSUM)) / 117*52328Sbostic sizeof(daddr_t) + 1) * sizeof(struct buf *), M_SEGMENT, M_WAITOK); 118*52328Sbostic sp->seg_flags = SEGM_CKP; 119*52328Sbostic lfs_initseg(fs, sp); 120*52328Sbostic 121*52328Sbostic /* 122*52328Sbostic * Keep a cumulative count of the outstanding I/O operations. If the 123*52328Sbostic * disk drive catches up with us it could go to zero before we finish, 124*52328Sbostic * so we artificially increment it by one until we've scheduled all of 125*52328Sbostic * the writes we intend to do. 126*52328Sbostic */ 127*52328Sbostic s = splbio(); 128*52328Sbostic fs->lfs_iocount = 1; 129*52328Sbostic splx(s); 130*52328Sbostic 131*52328Sbostic if (vp->v_dirtyblkhd != NULL) 132*52328Sbostic lfs_writefile(fs, sp, vp); 133*52328Sbostic ip = VTOI(vp); 134*52328Sbostic lfs_writeinode(fs, sp, ip); 135*52328Sbostic ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG); 136*52328Sbostic 137*52328Sbostic lfs_writeseg(fs, sp); 138*52328Sbostic 139*52328Sbostic /* 140*52328Sbostic * If the I/O count is non-zero, sleep until it reaches zero. At the 141*52328Sbostic * moment, the user's process hangs around so we can sleep. 142*52328Sbostic */ 143*52328Sbostic s = splbio(); 144*52328Sbostic if (--fs->lfs_iocount && (error = 145*52328Sbostic tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs vflush", 0))) 146*52328Sbostic return (error); 147*52328Sbostic splx(s); 148*52328Sbostic vfs_unbusy(mp); 149*52328Sbostic 150*52328Sbostic free(sp->bpp, M_SEGMENT); 151*52328Sbostic free(sp, M_SEGMENT); 152*52328Sbostic 153*52328Sbostic return (0); 154*52328Sbostic } 155*52328Sbostic 156*52328Sbostic int 15751215Sbostic lfs_segwrite(mp, do_ckp) 15852085Sbostic struct mount *mp; 15951860Sbostic int do_ckp; /* Do a checkpoint. */ 16051188Sbostic { 16152085Sbostic struct inode *ip; 16251499Sbostic struct lfs *fs; 16352085Sbostic struct segment *sp; 16452085Sbostic struct vnode *vp; 165*52328Sbostic int error, islocked, s; 16651188Sbostic 16751860Sbostic #ifdef VERBOSE 16851860Sbostic printf("lfs_segwrite\n"); 16951860Sbostic #endif 170*52328Sbostic fs = VFSTOUFS(mp)->um_lfs; 17152085Sbostic 17251860Sbostic /* 173*52328Sbostic * Allocate a segment structure and enough space to hold pointers to 174*52328Sbostic * the maximum possible number of buffers which can be described in a 175*52328Sbostic * single summary block. 176*52328Sbostic */ 177*52328Sbostic sp = malloc(sizeof(struct segment), M_SEGMENT, M_WAITOK); 178*52328Sbostic sp->bpp = malloc(((LFS_SUMMARY_SIZE - sizeof(SEGSUM)) / 179*52328Sbostic sizeof(daddr_t) + 1) * sizeof(struct buf *), M_SEGMENT, M_WAITOK); 180*52328Sbostic sp->seg_flags = do_ckp ? SEGM_CKP : 0; 181*52328Sbostic lfs_initseg(fs, sp); 182*52328Sbostic 183*52328Sbostic /* 18451860Sbostic * If doing a checkpoint, we keep a cumulative count of the outstanding 18551860Sbostic * I/O operations. If the disk drive catches up with us it could go to 18651860Sbostic * zero before we finish, so we artificially increment it by one until 18751860Sbostic * we've scheduled all of the writes we intend to do. 18851860Sbostic */ 18951860Sbostic if (do_ckp) { 19051860Sbostic s = splbio(); 19151860Sbostic fs->lfs_iocount = 1; 19251860Sbostic splx(s); 19351860Sbostic } 19451342Sbostic 195*52328Sbostic loop: for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 19651188Sbostic /* 19751188Sbostic * If the vnode that we are about to sync is no longer 19851188Sbostic * associated with this mount point, start over. 19951188Sbostic */ 20051188Sbostic if (vp->v_mount != mp) 20151188Sbostic goto loop; 20251860Sbostic 203*52328Sbostic islocked = VOP_ISLOCKED(vp); 20451860Sbostic 20552077Sbostic /* 20652077Sbostic * XXX 20752077Sbostic * This is wrong, I think -- we should just wait until we 20852077Sbostic * get the vnode and go on. Probably going to reschedule 20952077Sbostic * all of the writes we already scheduled... 21052077Sbostic */ 211*52328Sbostic if (islocked) 212*52328Sbostic VREF(vp); 213*52328Sbostic else if (vget(vp)) 21452085Sbostic { 21552085Sbostic printf("lfs_segment: failed to get vnode (tell Keith)!\n"); 21651188Sbostic goto loop; 21752085Sbostic } 218*52328Sbostic /* 219*52328Sbostic * Write the inode/file if dirty and it's not the 220*52328Sbostic * the IFILE. 221*52328Sbostic */ 222*52328Sbostic ip = VTOI(vp); 223*52328Sbostic if ((ip->i_flag & (IMOD | IACC | IUPD | ICHG) || 224*52328Sbostic vp->v_dirtyblkhd != NULL) && 225*52328Sbostic ip->i_number != LFS_IFILE_INUM) { 226*52328Sbostic if (vp->v_dirtyblkhd != NULL) 227*52328Sbostic lfs_writefile(fs, sp, vp); 228*52328Sbostic lfs_writeinode(fs, sp, ip); 229*52328Sbostic ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG); 230*52328Sbostic } 231*52328Sbostic if (islocked) 232*52328Sbostic vrele(vp); 233*52328Sbostic else 234*52328Sbostic vput(vp); 23551188Sbostic } 23651860Sbostic if (do_ckp) { 23752077Sbostic vp = fs->lfs_ivnode; 23852077Sbostic while (vget(vp)); 23952077Sbostic ip = VTOI(vp); 24052077Sbostic if (vp->v_dirtyblkhd != NULL) 24152077Sbostic lfs_writefile(fs, sp, vp); 24252077Sbostic lfs_writeinode(fs, sp, ip); 24352077Sbostic ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG); 24452077Sbostic vput(vp); 24551860Sbostic } 24651342Sbostic lfs_writeseg(fs, sp); 24751342Sbostic 24851215Sbostic /* 24951860Sbostic * If the I/O count is non-zero, sleep until it reaches zero. At the 25051860Sbostic * moment, the user's process hangs around so we can sleep. 25151215Sbostic */ 25251860Sbostic if (do_ckp) { 25351860Sbostic s = splbio(); 25452085Sbostic if (--fs->lfs_iocount && (error = 25552085Sbostic tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs sync", 0))) 25651915Sbostic return (error); 25751860Sbostic splx(s); 25851860Sbostic lfs_writesuper(fs, sp); 25951860Sbostic } 26051215Sbostic 26151927Sbostic free(sp->bpp, M_SEGMENT); 26251927Sbostic free(sp, M_SEGMENT); 26351215Sbostic 26451860Sbostic /* Wake up any cleaning processes waiting on this file system. */ 26551860Sbostic wakeup(&fs->lfs_nextseg); 26651860Sbostic wakeup(&lfs_allclean_wakeup); 26752085Sbostic 26851860Sbostic return (0); 26951188Sbostic } 27051188Sbostic 27151860Sbostic /* 27251860Sbostic * Write the dirty blocks associated with a vnode. 27351860Sbostic */ 27452077Sbostic void 27551860Sbostic lfs_writefile(fs, sp, vp) 27651499Sbostic struct lfs *fs; 27752085Sbostic struct segment *sp; 27852085Sbostic struct vnode *vp; 27951188Sbostic { 28051860Sbostic struct buf *bp; 28152085Sbostic struct finfo *fip; 28251860Sbostic IFILE *ifp; 28351188Sbostic 28451860Sbostic #ifdef VERBOSE 28551860Sbostic printf("lfs_writefile\n"); 28651860Sbostic #endif 28752085Sbostic if (sp->seg_bytes_left < fs->lfs_bsize || 28852085Sbostic sp->sum_bytes_left < sizeof(struct finfo)) { 28952085Sbostic lfs_writeseg(fs, sp); 29052085Sbostic lfs_initseg(fs, sp); 29152085Sbostic } 29252085Sbostic sp->sum_bytes_left -= sizeof(struct finfo) - sizeof(daddr_t); 29351215Sbostic 29452085Sbostic fip = sp->fip; 29552085Sbostic fip->fi_nblocks = 0; 29652085Sbostic fip->fi_ino = VTOI(vp)->i_number; 29752085Sbostic LFS_IENTRY(ifp, fs, fip->fi_ino, bp); 29852085Sbostic fip->fi_version = ifp->if_version; 29952085Sbostic brelse(bp); 30051188Sbostic 30152085Sbostic /* 30252085Sbostic * It may not be necessary to write the meta-data blocks at this point, 30352085Sbostic * as the roll-forward recovery code should be able to reconstruct the 30452085Sbostic * list. 30552085Sbostic */ 30652085Sbostic lfs_gather(fs, sp, vp, lfs_match_data); 30752085Sbostic lfs_gather(fs, sp, vp, lfs_match_indir); 30852085Sbostic lfs_gather(fs, sp, vp, lfs_match_dindir); 30951860Sbostic #ifdef TRIPLE 31052085Sbostic lfs_gather(fs, sp, vp, lfs_match_tindir); 31151860Sbostic #endif 31251342Sbostic 31352085Sbostic fip = sp->fip; 31451860Sbostic #ifdef META 31552085Sbostic printf("lfs_writefile: adding %d blocks\n", fip->fi_nblocks); 31651860Sbostic #endif 31752085Sbostic if (fip->fi_nblocks != 0) { 31852085Sbostic ++((SEGSUM *)(sp->segsum))->ss_nfinfo; 31952085Sbostic sp->fip = 32052085Sbostic (struct finfo *)((caddr_t)fip + sizeof(struct finfo) + 32152085Sbostic sizeof(daddr_t) * (fip->fi_nblocks - 1)); 32251860Sbostic } 32351215Sbostic } 32451215Sbostic 32552077Sbostic void 32651915Sbostic lfs_writeinode(fs, sp, ip) 32751915Sbostic struct lfs *fs; 32852085Sbostic struct segment *sp; 32952085Sbostic struct inode *ip; 33051915Sbostic { 33152085Sbostic struct buf *bp, *ibp; 33252077Sbostic IFILE *ifp; 33351915Sbostic daddr_t next_addr; 33452077Sbostic ino_t ino; 33551915Sbostic int ndx; 33651915Sbostic 33751915Sbostic #ifdef VERBOSE 33851915Sbostic printf("lfs_writeinode\n"); 33951915Sbostic #endif 34051915Sbostic /* Allocate a new inode block if necessary. */ 34151915Sbostic if (sp->ibp == NULL) { 34251915Sbostic /* Allocate a new segment if necessary. */ 34351915Sbostic if (sp->seg_bytes_left < fs->lfs_bsize || 34451915Sbostic sp->sum_bytes_left < sizeof(daddr_t)) { 34551915Sbostic lfs_writeseg(fs, sp); 34651915Sbostic lfs_initseg(fs, sp); 34751915Sbostic } 34851915Sbostic 34951915Sbostic /* Get next inode block. */ 35051915Sbostic next_addr = fs->lfs_offset; 35151915Sbostic fs->lfs_offset += fsbtodb(fs, 1); 35251915Sbostic sp->ibp = *sp->cbpp++ = 35351915Sbostic lfs_newbuf(fs, sp, next_addr, fs->lfs_bsize); 35451915Sbostic 35551915Sbostic /* Set remaining space counter. */ 35651915Sbostic sp->seg_bytes_left -= fs->lfs_bsize; 35751915Sbostic sp->sum_bytes_left -= sizeof(daddr_t); 35852077Sbostic ndx = LFS_SUMMARY_SIZE / sizeof(daddr_t) - 35951915Sbostic sp->ninodes / INOPB(fs) - 1; 36051915Sbostic ((daddr_t *)(sp->segsum))[ndx] = next_addr; 36151915Sbostic } 36251915Sbostic 36352085Sbostic /* Update the inode times and copy the inode onto the inode page. */ 36452077Sbostic ITIMES(ip, &time, &time); 36551915Sbostic bp = sp->ibp; 36652085Sbostic bp->b_un.b_dino[sp->ninodes % INOPB(fs)] = ip->i_din; 36751915Sbostic 36851915Sbostic /* Increment inode count in segment summary block. */ 36951915Sbostic ++((SEGSUM *)(sp->segsum))->ss_ninos; 37051915Sbostic 37151915Sbostic /* If this page is full, set flag to allocate a new page. */ 37251915Sbostic if (++sp->ninodes % INOPB(fs) == 0) 37351915Sbostic sp->ibp = NULL; 37451915Sbostic 37551915Sbostic /* 37652077Sbostic * If updating the ifile, update the super-block. Update the disk 37752077Sbostic * address and access times for this inode in the ifile. 37851915Sbostic */ 37952077Sbostic ino = ip->i_number; 38052077Sbostic if (ino == LFS_IFILE_INUM) 38151915Sbostic fs->lfs_idaddr = bp->b_blkno; 38252077Sbostic 38352077Sbostic LFS_IENTRY(ifp, fs, ino, ibp); 38452077Sbostic ifp->if_daddr = bp->b_blkno; 38552085Sbostic LFS_UBWRITE(ibp); 38651915Sbostic } 38751915Sbostic 38852077Sbostic void 38951215Sbostic lfs_gather(fs, sp, vp, match) 39051499Sbostic struct lfs *fs; 39152085Sbostic struct segment *sp; 39252085Sbostic struct vnode *vp; 39352085Sbostic int (*match) __P((struct lfs *, struct buf *)); 39451215Sbostic { 39552085Sbostic struct buf **bpp, *bp, *nbp; 39652085Sbostic struct finfo *fip; 39752085Sbostic struct inode *ip; 39851215Sbostic daddr_t *lbp, *start_lbp; 39951342Sbostic u_long version; 40051342Sbostic int s; 40151215Sbostic 40251860Sbostic #ifdef VERBOSE 40351860Sbostic printf("lfs_gather\n"); 40451860Sbostic #endif 40551215Sbostic ip = VTOI(vp); 40651215Sbostic bpp = sp->cbpp; 40751215Sbostic fip = sp->fip; 40851215Sbostic start_lbp = lbp = &fip->fi_blocks[fip->fi_nblocks]; 40951215Sbostic 41051215Sbostic s = splbio(); 41151215Sbostic for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { 41251215Sbostic nbp = bp->b_blockf; 41351915Sbostic /* 41451915Sbostic * XXX 41551915Sbostic * Should probably sleep on any BUSY buffer if 41651915Sbostic * doing an fsync? 41751915Sbostic */ 418*52328Sbostic if (bp->b_flags & B_BUSY || !match(fs, bp)) 41951215Sbostic continue; 420*52328Sbostic 42151342Sbostic #ifdef DIAGNOSTIC 42251860Sbostic if (!(bp->b_flags & B_DELWRI)) 42351915Sbostic panic("lfs_gather: bp not B_DELWRI"); 42451860Sbostic if (!(bp->b_flags & B_LOCKED)) 42551915Sbostic panic("lfs_gather: bp not B_LOCKED"); 42651342Sbostic #endif 42751342Sbostic /* Insert into the buffer list, update the FINFO block. */ 42851342Sbostic *sp->cbpp++ = bp; 42951342Sbostic ++fip->fi_nblocks; 43051215Sbostic *lbp++ = bp->b_lblkno; 43151342Sbostic 43251860Sbostic /* 43351860Sbostic * If full, finish this segment. We may be doing I/O, so 43451860Sbostic * release and reacquire the splbio(). 43551860Sbostic */ 43651215Sbostic sp->sum_bytes_left -= sizeof(daddr_t); 43751215Sbostic sp->seg_bytes_left -= bp->b_bufsize; 43851342Sbostic if (sp->sum_bytes_left < sizeof(daddr_t) || 43951215Sbostic sp->seg_bytes_left < fs->lfs_bsize) { 44051215Sbostic splx(s); 44151342Sbostic lfs_updatemeta(fs, 44251860Sbostic sp, vp, start_lbp, bpp, lbp - start_lbp); 44351215Sbostic 44451342Sbostic /* Add the current file to the segment summary. */ 44551342Sbostic ++((SEGSUM *)(sp->segsum))->ss_nfinfo; 44651215Sbostic 44751342Sbostic version = fip->fi_version; 44851860Sbostic lfs_writeseg(fs, sp); 44951915Sbostic lfs_initseg(fs, sp); 45051342Sbostic 45151215Sbostic fip = sp->fip; 45251342Sbostic fip->fi_version = version; 45351215Sbostic fip->fi_ino = ip->i_number; 45451342Sbostic start_lbp = lbp = fip->fi_blocks; 45551342Sbostic 45651215Sbostic bpp = sp->cbpp; 45751215Sbostic s = splbio(); 45851215Sbostic } 45951188Sbostic } 46051215Sbostic splx(s); 46151860Sbostic lfs_updatemeta(fs, sp, vp, start_lbp, bpp, lbp - start_lbp); 46251188Sbostic } 46351188Sbostic 46451342Sbostic /* 46551342Sbostic * Update the metadata that points to the blocks listed in the FINFO 46651188Sbostic * array. 46751188Sbostic */ 46852077Sbostic void 46951860Sbostic lfs_updatemeta(fs, sp, vp, lbp, bpp, nblocks) 47051499Sbostic struct lfs *fs; 47152085Sbostic struct segment *sp; 47252085Sbostic struct vnode *vp; 47351215Sbostic daddr_t *lbp; 47452085Sbostic struct buf **bpp; 47551215Sbostic int nblocks; 47651188Sbostic { 47751915Sbostic SEGUSE *sup; 47852085Sbostic struct buf *bp; 47951860Sbostic INDIR a[NIADDR], *ap; 48052085Sbostic struct inode *ip; 48151915Sbostic daddr_t daddr, lbn, off; 48251860Sbostic int db_per_fsb, error, i, num; 48351188Sbostic 48451860Sbostic #ifdef VERBOSE 48551860Sbostic printf("lfs_updatemeta\n"); 48651860Sbostic #endif 48751342Sbostic if (nblocks == 0) 48851215Sbostic return; 48951215Sbostic 49051915Sbostic /* Sort the blocks. */ 49152077Sbostic lfs_shellsort(bpp, lbp, nblocks); 49251215Sbostic 49351915Sbostic /* 49451915Sbostic * Assign disk addresses, and update references to the logical 49551915Sbostic * block and the segment usage information. 49651915Sbostic */ 49751860Sbostic db_per_fsb = fsbtodb(fs, 1); 49851915Sbostic for (i = nblocks; i--; ++bpp) { 49951915Sbostic lbn = *lbp++; 50051915Sbostic (*bpp)->b_blkno = off = fs->lfs_offset; 50151860Sbostic fs->lfs_offset += db_per_fsb; 50251215Sbostic 50351860Sbostic if (error = lfs_bmaparray(vp, lbn, &daddr, a, &num)) 50452085Sbostic panic("lfs_updatemeta: lfs_bmaparray %d", error); 50551860Sbostic ip = VTOI(vp); 50651860Sbostic switch (num) { 50751860Sbostic case 0: 50851915Sbostic ip->i_db[lbn] = off; 50951860Sbostic break; 51051860Sbostic case 1: 51151915Sbostic ip->i_ib[a[0].in_off] = off; 51251860Sbostic break; 51351860Sbostic default: 51451860Sbostic ap = &a[num - 1]; 51551860Sbostic if (bread(vp, ap->in_lbn, fs->lfs_bsize, NOCRED, &bp)) 51651860Sbostic panic("lfs_updatemeta: bread bno %d", 51751860Sbostic ap->in_lbn); 51851915Sbostic bp->b_un.b_daddr[ap->in_off] = off; 51951342Sbostic lfs_bwrite(bp); 52051188Sbostic } 52151915Sbostic 52251915Sbostic /* Update segment usage information. */ 52351915Sbostic if (daddr != UNASSIGNED) { 52451915Sbostic LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp); 52551915Sbostic sup->su_lastmod = time.tv_sec; 52651915Sbostic #ifdef DIAGNOSTIC 52751915Sbostic if (sup->su_nbytes < fs->lfs_bsize) 52851915Sbostic panic("lfs: negative bytes (segment %d)\n", 52951915Sbostic datosn(fs, daddr)); 53051915Sbostic #endif 53151915Sbostic sup->su_nbytes -= fs->lfs_bsize; 53252085Sbostic LFS_UBWRITE(bp); 53351915Sbostic } 53451188Sbostic } 53551188Sbostic } 53651188Sbostic 53751915Sbostic /* 53851915Sbostic * Start a new segment. 53951915Sbostic */ 54052077Sbostic void 54151915Sbostic lfs_initseg(fs, sp) 54251499Sbostic struct lfs *fs; 54352085Sbostic struct segment *sp; 54451188Sbostic { 54551915Sbostic SEGUSE *sup; 54651915Sbostic SEGSUM *ssp; 54751915Sbostic struct buf *bp; 54851915Sbostic daddr_t lbn, *lbnp; 54951215Sbostic 55051860Sbostic #ifdef VERBOSE 55151915Sbostic printf("lfs_initseg\n"); 55251860Sbostic #endif 55351915Sbostic /* Advance to the next segment. */ 55451927Sbostic if (!LFS_PARTIAL_FITS(fs)) { 55551927Sbostic lfs_newseg(fs); 55651927Sbostic fs->lfs_offset = fs->lfs_curseg; 55751915Sbostic sp->seg_number = datosn(fs, fs->lfs_curseg); 55851915Sbostic sp->seg_bytes_left = fs->lfs_dbpseg * DEV_BSIZE; 55951915Sbostic 56051915Sbostic /* 56151927Sbostic * If the segment contains a superblock, update the offset 56251927Sbostic * and summary address to skip over it. 56351915Sbostic */ 56452077Sbostic LFS_SEGENTRY(sup, fs, sp->seg_number, bp); 56551927Sbostic if (sup->su_flags & SEGUSE_SUPERBLOCK) { 56651915Sbostic fs->lfs_offset += LFS_SBPAD / DEV_BSIZE; 56751915Sbostic sp->seg_bytes_left -= LFS_SBPAD; 56851215Sbostic } 56952085Sbostic brelse(bp); 57051915Sbostic } else { 57151915Sbostic sp->seg_number = datosn(fs, fs->lfs_curseg); 57251915Sbostic sp->seg_bytes_left = (fs->lfs_dbpseg - 57351915Sbostic (fs->lfs_offset - fs->lfs_curseg)) * DEV_BSIZE; 57451915Sbostic } 57551342Sbostic 57651915Sbostic sp->ibp = NULL; 57751915Sbostic sp->ninodes = 0; 57851342Sbostic 57951915Sbostic /* Get a new buffer for SEGSUM and enter it into the buffer list. */ 58051915Sbostic sp->cbpp = sp->bpp; 58151915Sbostic *sp->cbpp = lfs_newbuf(fs, sp, fs->lfs_offset, LFS_SUMMARY_SIZE); 58251915Sbostic sp->segsum = (*sp->cbpp)->b_un.b_addr; 58351915Sbostic ++sp->cbpp; 58451915Sbostic fs->lfs_offset += LFS_SUMMARY_SIZE / DEV_BSIZE; 58551342Sbostic 58651915Sbostic /* Set point to SEGSUM, initialize it. */ 58751915Sbostic ssp = sp->segsum; 58851915Sbostic ssp->ss_next = fs->lfs_nextseg; 58951915Sbostic ssp->ss_nfinfo = ssp->ss_ninos = 0; 59051342Sbostic 59151915Sbostic /* Set pointer to first FINFO, initialize it. */ 59252085Sbostic sp->fip = (struct finfo *)(sp->segsum + sizeof(SEGSUM)); 59351915Sbostic sp->fip->fi_nblocks = 0; 59451342Sbostic 59551915Sbostic sp->seg_bytes_left -= LFS_SUMMARY_SIZE; 59651915Sbostic sp->sum_bytes_left = LFS_SUMMARY_SIZE - sizeof(SEGSUM); 59751915Sbostic } 59851342Sbostic 59951915Sbostic /* 60051915Sbostic * Return the next segment to write. 60151915Sbostic */ 60252077Sbostic void 60351915Sbostic lfs_newseg(fs) 60451915Sbostic struct lfs *fs; 60551915Sbostic { 60651927Sbostic CLEANERINFO *cip; 60751915Sbostic SEGUSE *sup; 60851915Sbostic struct buf *bp; 60951927Sbostic int curseg, isdirty, sn; 61051915Sbostic 61151915Sbostic #ifdef VERBOSE 61251915Sbostic printf("lfs_newseg\n"); 61351915Sbostic #endif 61451927Sbostic /* 61551927Sbostic * Turn off the active bit for the current segment, turn on the 61651927Sbostic * active and dirty bits for the next segment, update the cleaner 61751927Sbostic * info. Set the current segment to the next segment, get a new 61851927Sbostic * next segment. 61951927Sbostic */ 62051927Sbostic LFS_SEGENTRY(sup, fs, datosn(fs, fs->lfs_curseg), bp); 62151927Sbostic sup->su_flags &= ~SEGUSE_ACTIVE; 62252085Sbostic LFS_UBWRITE(bp); 62351927Sbostic 62451927Sbostic LFS_SEGENTRY(sup, fs, datosn(fs, fs->lfs_nextseg), bp); 62551927Sbostic sup->su_flags |= SEGUSE_ACTIVE | SEGUSE_DIRTY; 62652085Sbostic LFS_UBWRITE(bp); 62751927Sbostic 62851927Sbostic LFS_CLEANERINFO(cip, fs, bp); 62951927Sbostic --cip->clean; 63051927Sbostic ++cip->dirty; 63152085Sbostic LFS_UBWRITE(bp); 63251927Sbostic 63351927Sbostic fs->lfs_lastseg = fs->lfs_curseg; 63451927Sbostic fs->lfs_curseg = fs->lfs_nextseg; 63551927Sbostic for (sn = curseg = datosn(fs, fs->lfs_curseg);;) { 63651915Sbostic sn = (sn + 1) % fs->lfs_nseg; 63751927Sbostic if (sn == curseg) 63851915Sbostic panic("lfs_nextseg: no clean segments"); 63951915Sbostic LFS_SEGENTRY(sup, fs, sn, bp); 64051915Sbostic isdirty = sup->su_flags & SEGUSE_DIRTY; 64152085Sbostic brelse(bp); 64251915Sbostic if (!isdirty) 64351915Sbostic break; 64451915Sbostic } 64551927Sbostic fs->lfs_nextseg = sntoda(fs, sn); 64651188Sbostic } 64751188Sbostic 64852077Sbostic void 64951188Sbostic lfs_writeseg(fs, sp) 65051499Sbostic struct lfs *fs; 65152085Sbostic struct segment *sp; 65251188Sbostic { 65352085Sbostic struct buf **bpp, *bp; 65451188Sbostic SEGUSE *sup; 65552085Sbostic SEGSUM *ssp; 65651860Sbostic dev_t i_dev; 65751860Sbostic u_long *datap, *dp; 65851342Sbostic void *pmeta; 65952085Sbostic int flags, i, nblocks, s, (*strategy)__P((struct buf *)); 66051188Sbostic 66151860Sbostic #ifdef VERBOSE 66251860Sbostic printf("lfs_writeseg\n"); 66351860Sbostic #endif 66452085Sbostic if ((nblocks = sp->cbpp - sp->bpp) == 0) 66552085Sbostic return; 66652085Sbostic 66752085Sbostic /* Update the segment usage information. */ 66852085Sbostic LFS_SEGENTRY(sup, fs, sp->seg_number, bp); 66952085Sbostic sup->su_nbytes += nblocks - 1 << fs->lfs_bshift; 67052085Sbostic sup->su_lastmod = time.tv_sec; 67152085Sbostic LFS_UBWRITE(bp); 67252085Sbostic 67351188Sbostic /* 67452085Sbostic * Compute checksum across data and then across summary; the first 67552085Sbostic * block (the summary block) is skipped. Set the create time here 67652085Sbostic * so that it's guaranteed to be later than the inode mod times. 67751860Sbostic * 67851860Sbostic * XXX 67951860Sbostic * Fix this to do it inline, instead of malloc/copy. 68051188Sbostic */ 68151860Sbostic datap = dp = malloc(nblocks * sizeof(u_long), M_SEGMENT, M_WAITOK); 68251915Sbostic for (bpp = sp->bpp, i = nblocks - 1; i--;) 68351915Sbostic *dp++ = (*++bpp)->b_un.b_words[0]; 68452085Sbostic ssp = (SEGSUM *)sp->segsum; 68552103Sbostic ssp->ss_create = time.tv_sec; 68652085Sbostic ssp->ss_datasum = cksum(datap, nblocks * sizeof(u_long)); 68752085Sbostic ssp->ss_sumsum = 68852085Sbostic cksum(&ssp->ss_datasum, LFS_SUMMARY_SIZE - sizeof(ssp->ss_sumsum)); 68951927Sbostic free(datap, M_SEGMENT); 69051188Sbostic 69151188Sbostic /* 69251860Sbostic * When we gathered the blocks for I/O we did not mark them busy or 69351860Sbostic * remove them from the freelist. As we do this, turn off the B_LOCKED 69451860Sbostic * bit so the future brelse will put them on the LRU list, and add the 69551860Sbostic * B_CALL flags if we're doing a checkpoint so we can count I/O's. LFS 69651860Sbostic * requires that the super blocks (on checkpoint) be written after all 69751860Sbostic * the segment data. 69851188Sbostic */ 69951860Sbostic i_dev = VTOI(fs->lfs_ivnode)->i_dev; 70051860Sbostic strategy = VTOI(fs->lfs_ivnode)->i_devvp->v_op->vop_strategy; 70151301Sbostic 70251301Sbostic s = splbio(); 70351860Sbostic if (sp->seg_flags & SEGM_CKP) { 70451860Sbostic fs->lfs_iocount += nblocks; 70551915Sbostic flags = B_ASYNC | B_BUSY | B_CALL; 70651860Sbostic } else 70751915Sbostic flags = B_ASYNC | B_BUSY; 70851860Sbostic for (bpp = sp->bpp, i = nblocks; i--;) { 70951860Sbostic bp = *bpp++; 71051860Sbostic bp->b_flags |= flags; 71151915Sbostic bp->b_flags &= 71251915Sbostic ~(B_DONE | B_ERROR | B_READ | B_DELWRI | B_LOCKED); 71351860Sbostic bp->b_dev = i_dev; 71451860Sbostic bp->b_iodone = lfs_callback; 71551860Sbostic if (!(bp->b_flags & B_NOCACHE)) { 71651860Sbostic bremfree(bp); 71751860Sbostic reassignbuf(bp, bp->b_vp); 71851860Sbostic } 71951860Sbostic } 72051301Sbostic splx(s); 72152077Sbostic 72251860Sbostic for (bpp = sp->bpp, i = nblocks; i--;) 72351860Sbostic (strategy)(*bpp++); 72451188Sbostic } 72551188Sbostic 72652077Sbostic void 72751860Sbostic lfs_writesuper(fs, sp) 72851499Sbostic struct lfs *fs; 72952085Sbostic struct segment *sp; 73051301Sbostic { 73152085Sbostic struct buf *bp; 73251860Sbostic dev_t i_dev; 73352085Sbostic int (*strategy) __P((struct buf *)); 73451301Sbostic 73551860Sbostic #ifdef VERBOSE 73651860Sbostic printf("lfs_writesuper\n"); 73751860Sbostic #endif 73851860Sbostic i_dev = VTOI(fs->lfs_ivnode)->i_dev; 73951860Sbostic strategy = VTOI(fs->lfs_ivnode)->i_devvp->v_op->vop_strategy; 74051356Sbostic 74151342Sbostic /* Checksum the superblock and copy it into a buffer. */ 74251499Sbostic fs->lfs_cksum = cksum(fs, sizeof(struct lfs) - sizeof(fs->lfs_cksum)); 74351860Sbostic bp = lfs_newbuf(fs, sp, fs->lfs_sboffs[0], LFS_SBPAD); 74451860Sbostic *bp->b_un.b_lfs = *fs; 74551215Sbostic 74651356Sbostic /* Write the first superblock (wait). */ 74751860Sbostic bp->b_dev = i_dev; 74851915Sbostic bp->b_flags |= B_BUSY; 74951860Sbostic bp->b_flags &= ~(B_DONE | B_ERROR | B_READ | B_DELWRI); 75051342Sbostic (strategy)(bp); 75151215Sbostic biowait(bp); 75251342Sbostic 75351356Sbostic /* Write the second superblock (don't wait). */ 75451215Sbostic bp->b_blkno = bp->b_lblkno = fs->lfs_sboffs[1]; 75551915Sbostic bp->b_flags |= B_ASYNC | B_BUSY; 75651860Sbostic bp->b_flags &= ~(B_DONE | B_ERROR | B_READ | B_DELWRI); 75751342Sbostic (strategy)(bp); 75851215Sbostic } 75951215Sbostic 76051342Sbostic /* 76151342Sbostic * Logical block number match routines used when traversing the dirty block 76251342Sbostic * chain. 76351342Sbostic */ 76452077Sbostic int 76552077Sbostic lfs_match_data(fs, bp) 76651860Sbostic struct lfs *fs; 76752085Sbostic struct buf *bp; 76851215Sbostic { 76951342Sbostic return (bp->b_lblkno >= 0); 77051215Sbostic } 77151215Sbostic 77252077Sbostic int 77352077Sbostic lfs_match_indir(fs, bp) 77451860Sbostic struct lfs *fs; 77552085Sbostic struct buf *bp; 77651215Sbostic { 77751860Sbostic int lbn; 77851860Sbostic 77951860Sbostic lbn = bp->b_lblkno; 78051860Sbostic return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 0); 78151215Sbostic } 78251215Sbostic 78352077Sbostic int 78452077Sbostic lfs_match_dindir(fs, bp) 78551860Sbostic struct lfs *fs; 78652085Sbostic struct buf *bp; 78751215Sbostic { 78851860Sbostic int lbn; 78951860Sbostic 79051860Sbostic lbn = bp->b_lblkno; 79151860Sbostic return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 1); 79251215Sbostic } 79351215Sbostic 79452077Sbostic int 79552077Sbostic lfs_match_tindir(fs, bp) 79651499Sbostic struct lfs *fs; 79752085Sbostic struct buf *bp; 79851342Sbostic { 79951860Sbostic int lbn; 80051342Sbostic 80151860Sbostic lbn = bp->b_lblkno; 80251860Sbostic return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 2); 80351860Sbostic } 80451342Sbostic 80551860Sbostic /* 80651860Sbostic * Allocate a new buffer header. 80751860Sbostic */ 80852085Sbostic struct buf * 80951860Sbostic lfs_newbuf(fs, sp, daddr, size) 81051860Sbostic struct lfs *fs; 81152085Sbostic struct segment *sp; 81251860Sbostic daddr_t daddr; 81351860Sbostic size_t size; 81451860Sbostic { 81552085Sbostic struct buf *bp; 81651342Sbostic 81751860Sbostic #ifdef VERBOSE 81851860Sbostic printf("lfs_newbuf\n"); 81951860Sbostic #endif 82051860Sbostic bp = getnewbuf(); 82151860Sbostic bremhash(bp); 82251860Sbostic bgetvp(fs->lfs_ivnode, bp); 82351860Sbostic bp->b_bcount = 0; 82451860Sbostic bp->b_lblkno = daddr; 82551860Sbostic bp->b_blkno = daddr; 82651860Sbostic bp->b_error = 0; 82751860Sbostic bp->b_resid = 0; 82851860Sbostic allocbuf(bp, size); 82951860Sbostic bp->b_flags |= B_NOCACHE; 83051915Sbostic binshash(bp, &bfreelist[BQ_AGE]); 83151860Sbostic return (bp); 83251860Sbostic } 83351342Sbostic 83452077Sbostic int /* XXX should be void */ 83551860Sbostic lfs_callback(bp) 83652085Sbostic struct buf *bp; 83751860Sbostic { 83851860Sbostic struct lfs *fs; 83951342Sbostic 84051860Sbostic fs = VFSTOUFS(bp->b_vp->v_mount)->um_lfs; 84151860Sbostic #ifdef DIAGNOSTIC 84251860Sbostic if (fs->lfs_iocount == 0) 84351860Sbostic panic("lfs_callback: zero iocount\n"); 84451860Sbostic #endif 84551860Sbostic if (--fs->lfs_iocount == 0) 84651860Sbostic wakeup(&fs->lfs_iocount); 84751915Sbostic 84851860Sbostic brelse(bp); 84951860Sbostic } 85051342Sbostic 85151215Sbostic /* 85251188Sbostic * Shellsort (diminishing increment sort) from Data Structures and 85351188Sbostic * Algorithms, Aho, Hopcraft and Ullman, 1983 Edition, page 290; 85451188Sbostic * see also Knuth Vol. 3, page 84. The increments are selected from 85551188Sbostic * formula (8), page 95. Roughly O(N^3/2). 85651188Sbostic */ 85751188Sbostic /* 85851188Sbostic * This is our own private copy of shellsort because we want to sort 85951188Sbostic * two parallel arrays (the array of buffer pointers and the array of 86051188Sbostic * logical block numbers) simultaneously. Note that we cast the array 86151188Sbostic * of logical block numbers to a unsigned in this routine so that the 86251188Sbostic * negative block numbers (meta data blocks) sort AFTER the data blocks. 86351188Sbostic */ 86452077Sbostic void 86552077Sbostic lfs_shellsort(bp_array, lb_array, nmemb) 86652085Sbostic struct buf **bp_array; 86751215Sbostic daddr_t *lb_array; 86851188Sbostic register int nmemb; 86951188Sbostic { 87051188Sbostic static int __rsshell_increments[] = { 4, 1, 0 }; 87151188Sbostic register int incr, *incrp, t1, t2; 87252085Sbostic struct buf *bp_temp; 87351188Sbostic u_long lb_temp; 87451188Sbostic 87551188Sbostic for (incrp = __rsshell_increments; incr = *incrp++;) 87651188Sbostic for (t1 = incr; t1 < nmemb; ++t1) 87751188Sbostic for (t2 = t1 - incr; t2 >= 0;) 87851188Sbostic if (lb_array[t2] > lb_array[t2 + incr]) { 87951188Sbostic lb_temp = lb_array[t2]; 88051188Sbostic lb_array[t2] = lb_array[t2 + incr]; 88151188Sbostic lb_array[t2 + incr] = lb_temp; 88251188Sbostic bp_temp = bp_array[t2]; 88351188Sbostic bp_array[t2] = bp_array[t2 + incr]; 88451188Sbostic bp_array[t2 + incr] = bp_temp; 88551188Sbostic t2 -= incr; 88651188Sbostic } else 88751188Sbostic break; 88851188Sbostic } 889