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*69291Smckusick * @(#)lfs_subr.c 8.4 (Berkeley) 05/08/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
lfs_blkatoff(ap)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;
4068550Smckusick 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);
46*69291Smckusick bsize = blksize(fs, ip, lbn);
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
lfs_seglock(fs,flags)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)) /
8668550Smckusick sizeof(ufs_daddr_t) + 1) * sizeof(struct buf *),
8768550Smckusick 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
lfs_segunlock(fs)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