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*68550Smckusick * @(#)lfs_subr.c 8.3 (Berkeley) 03/21/95 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; 40*68550Smckusick ufs_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) 5464520Sbostic *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)) / 86*68550Smckusick sizeof(ufs_daddr_t) + 1) * sizeof(struct buf *), 87*68550Smckusick M_SEGMENT, M_WAITOK); 8857064Smargo sp->seg_flags = flags; 8957064Smargo sp->vp = NULL; 9057064Smargo (void) lfs_initseg(fs); 9157064Smargo 9257064Smargo /* 9357064Smargo * Keep a cumulative count of the outstanding I/O operations. If the 9457064Smargo * disk drive catches up with us it could go to zero before we finish, 9557064Smargo * so we artificially increment it by one until we've scheduled all of 9657064Smargo * the writes we intend to do. 9757064Smargo */ 9857064Smargo s = splbio(); 9957064Smargo ++fs->lfs_iocount; 10057064Smargo splx(s); 10154264Sbostic } 10254264Sbostic /* 10354691Sbostic * lfs_segunlock -- 10454691Sbostic * Single thread the segment writer. 10554264Sbostic */ 10654691Sbostic void 10754691Sbostic lfs_segunlock(fs) 10854691Sbostic struct lfs *fs; 10954264Sbostic { 11057064Smargo struct segment *sp; 11157064Smargo unsigned long sync, ckp; 11257064Smargo int s; 11357064Smargo 11457064Smargo if (fs->lfs_seglock == 1) { 11557064Smargo 11657064Smargo sp = fs->lfs_sp; 11757064Smargo sync = sp->seg_flags & SEGM_SYNC; 11857064Smargo ckp = sp->seg_flags & SEGM_CKP; 11957064Smargo if (sp->bpp != sp->cbpp) { 12057064Smargo /* Free allocated segment summary */ 12157064Smargo fs->lfs_offset -= LFS_SUMMARY_SIZE / DEV_BSIZE; 12257064Smargo brelvp(*sp->bpp); 12364520Sbostic free((*sp->bpp)->b_data, M_SEGMENT); 12457064Smargo free(*sp->bpp, M_SEGMENT); 12557064Smargo } else 12657064Smargo printf ("unlock to 0 with no summary"); 12757064Smargo free(sp->bpp, M_SEGMENT); 12857064Smargo free(sp, M_SEGMENT); 12957064Smargo 13057064Smargo /* 13157064Smargo * If the I/O count is non-zero, sleep until it reaches zero. 13257064Smargo * At the moment, the user's process hangs around so we can 13357064Smargo * sleep. 13457064Smargo */ 13557064Smargo s = splbio(); 13657064Smargo --fs->lfs_iocount; 13757064Smargo /* 13857064Smargo * We let checkpoints happen asynchronously. That means 13957064Smargo * that during recovery, we have to roll forward between 14057064Smargo * the two segments described by the first and second 14157064Smargo * superblocks to make sure that the checkpoint described 14257064Smargo * by a superblock completed. 14357064Smargo */ 14457064Smargo if (sync && fs->lfs_iocount) 14557064Smargo (void)tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs vflush", 0); 14657064Smargo splx(s); 14757064Smargo if (ckp) { 14857064Smargo fs->lfs_nactive = 0; 14957064Smargo lfs_writesuper(fs); 15057064Smargo } 15157064Smargo --fs->lfs_seglock; 15257064Smargo fs->lfs_lockpid = 0; 15357064Smargo wakeup(&fs->lfs_seglock); 15457064Smargo } else if (fs->lfs_seglock == 0) { 15557064Smargo panic ("Seglock not held"); 15657064Smargo } else { 15757064Smargo --fs->lfs_seglock; 15857064Smargo } 15954264Sbostic } 160