151500Sbostic /* 263375Sbostic * Copyright (c) 1991, 1993 363375Sbostic * The Regents of the University of California. All rights reserved. 451500Sbostic * 551500Sbostic * %sccs.include.redist.c% 651500Sbostic * 7*64520Sbostic * @(#)lfs_subr.c 8.2 (Berkeley) 09/21/93 851500Sbostic */ 951500Sbostic 1051500Sbostic #include <sys/param.h> 1151500Sbostic #include <sys/namei.h> 1251500Sbostic #include <sys/vnode.h> 1351500Sbostic #include <sys/buf.h> 1454264Sbostic #include <sys/mount.h> 1557064Smargo #include <sys/malloc.h> 1657064Smargo #include <sys/proc.h> 1751500Sbostic 1851500Sbostic #include <ufs/ufs/quota.h> 1951500Sbostic #include <ufs/ufs/inode.h> 2051500Sbostic #include <ufs/lfs/lfs.h> 2151500Sbostic #include <ufs/lfs/lfs_extern.h> 2251500Sbostic 2351500Sbostic /* 2451500Sbostic * Return buffer with the contents of block "offset" from the beginning of 2551500Sbostic * directory "ip". If "res" is non-zero, fill it in with a pointer to the 2651500Sbostic * remaining space in the directory. 2751500Sbostic */ 2851500Sbostic int 2954691Sbostic lfs_blkatoff(ap) 3054691Sbostic struct vop_blkatoff_args /* { 3154691Sbostic struct vnode *a_vp; 3254691Sbostic off_t a_offset; 3354691Sbostic char **a_res; 3454691Sbostic struct buf **a_bpp; 3554691Sbostic } */ *ap; 3651500Sbostic { 3751500Sbostic register struct lfs *fs; 3851557Smckusick struct inode *ip; 3951500Sbostic struct buf *bp; 4051500Sbostic daddr_t lbn; 4151500Sbostic int bsize, error; 4251500Sbostic 4353592Sheideman ip = VTOI(ap->a_vp); 4451500Sbostic fs = ip->i_lfs; 4553592Sheideman lbn = lblkno(fs, ap->a_offset); 4651500Sbostic bsize = blksize(fs); 4751500Sbostic 4853592Sheideman *ap->a_bpp = NULL; 4953592Sheideman if (error = bread(ap->a_vp, lbn, bsize, NOCRED, &bp)) { 5051500Sbostic brelse(bp); 5151500Sbostic return (error); 5251500Sbostic } 5353592Sheideman if (ap->a_res) 54*64520Sbostic *ap->a_res = (char *)bp->b_data + blkoff(fs, ap->a_offset); 5553592Sheideman *ap->a_bpp = bp; 5651500Sbostic return (0); 5751500Sbostic } 5854264Sbostic 5957064Smargo 6054691Sbostic /* 6154691Sbostic * lfs_seglock -- 6254691Sbostic * Single thread the segment writer. 6354691Sbostic */ 6454691Sbostic void 6557064Smargo lfs_seglock(fs, flags) 6654691Sbostic struct lfs *fs; 6757064Smargo unsigned long flags; 6854264Sbostic { 6957064Smargo struct segment *sp; 7057064Smargo int s; 7157064Smargo 7257064Smargo if (fs->lfs_seglock) 7357064Smargo if (fs->lfs_lockpid == curproc->p_pid) { 7457064Smargo ++fs->lfs_seglock; 7557064Smargo fs->lfs_sp->seg_flags |= flags; 7657064Smargo return; 7757064Smargo } else while (fs->lfs_seglock) 7857064Smargo (void)tsleep(&fs->lfs_seglock, PRIBIO + 1, 7957064Smargo "lfs seglock", 0); 8057064Smargo 8154691Sbostic fs->lfs_seglock = 1; 8257064Smargo fs->lfs_lockpid = curproc->p_pid; 8357064Smargo 8457064Smargo sp = fs->lfs_sp = malloc(sizeof(struct segment), M_SEGMENT, M_WAITOK); 8557064Smargo sp->bpp = malloc(((LFS_SUMMARY_SIZE - sizeof(SEGSUM)) / 8657064Smargo sizeof(daddr_t) + 1) * sizeof(struct buf *), M_SEGMENT, M_WAITOK); 8757064Smargo sp->seg_flags = flags; 8857064Smargo sp->vp = NULL; 8957064Smargo (void) lfs_initseg(fs); 9057064Smargo 9157064Smargo /* 9257064Smargo * Keep a cumulative count of the outstanding I/O operations. If the 9357064Smargo * disk drive catches up with us it could go to zero before we finish, 9457064Smargo * so we artificially increment it by one until we've scheduled all of 9557064Smargo * the writes we intend to do. 9657064Smargo */ 9757064Smargo s = splbio(); 9857064Smargo ++fs->lfs_iocount; 9957064Smargo splx(s); 10054264Sbostic } 10154264Sbostic /* 10254691Sbostic * lfs_segunlock -- 10354691Sbostic * Single thread the segment writer. 10454264Sbostic */ 10554691Sbostic void 10654691Sbostic lfs_segunlock(fs) 10754691Sbostic struct lfs *fs; 10854264Sbostic { 10957064Smargo struct segment *sp; 11057064Smargo unsigned long sync, ckp; 11157064Smargo int s; 11257064Smargo 11357064Smargo if (fs->lfs_seglock == 1) { 11457064Smargo 11557064Smargo sp = fs->lfs_sp; 11657064Smargo sync = sp->seg_flags & SEGM_SYNC; 11757064Smargo ckp = sp->seg_flags & SEGM_CKP; 11857064Smargo if (sp->bpp != sp->cbpp) { 11957064Smargo /* Free allocated segment summary */ 12057064Smargo fs->lfs_offset -= LFS_SUMMARY_SIZE / DEV_BSIZE; 12157064Smargo brelvp(*sp->bpp); 122*64520Sbostic free((*sp->bpp)->b_data, M_SEGMENT); 12357064Smargo free(*sp->bpp, M_SEGMENT); 12457064Smargo } else 12557064Smargo printf ("unlock to 0 with no summary"); 12657064Smargo free(sp->bpp, M_SEGMENT); 12757064Smargo free(sp, M_SEGMENT); 12857064Smargo 12957064Smargo /* 13057064Smargo * If the I/O count is non-zero, sleep until it reaches zero. 13157064Smargo * At the moment, the user's process hangs around so we can 13257064Smargo * sleep. 13357064Smargo */ 13457064Smargo s = splbio(); 13557064Smargo --fs->lfs_iocount; 13657064Smargo /* 13757064Smargo * We let checkpoints happen asynchronously. That means 13857064Smargo * that during recovery, we have to roll forward between 13957064Smargo * the two segments described by the first and second 14057064Smargo * superblocks to make sure that the checkpoint described 14157064Smargo * by a superblock completed. 14257064Smargo */ 14357064Smargo if (sync && fs->lfs_iocount) 14457064Smargo (void)tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs vflush", 0); 14557064Smargo splx(s); 14657064Smargo if (ckp) { 14757064Smargo fs->lfs_nactive = 0; 14857064Smargo lfs_writesuper(fs); 14957064Smargo } 15057064Smargo --fs->lfs_seglock; 15157064Smargo fs->lfs_lockpid = 0; 15257064Smargo wakeup(&fs->lfs_seglock); 15357064Smargo } else if (fs->lfs_seglock == 0) { 15457064Smargo panic ("Seglock not held"); 15557064Smargo } else { 15657064Smargo --fs->lfs_seglock; 15757064Smargo } 15854264Sbostic } 159