1 /* 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)lfs_subr.c 8.2 (Berkeley) 09/21/93 8 */ 9 10 #include <sys/param.h> 11 #include <sys/namei.h> 12 #include <sys/vnode.h> 13 #include <sys/buf.h> 14 #include <sys/mount.h> 15 #include <sys/malloc.h> 16 #include <sys/proc.h> 17 18 #include <ufs/ufs/quota.h> 19 #include <ufs/ufs/inode.h> 20 #include <ufs/lfs/lfs.h> 21 #include <ufs/lfs/lfs_extern.h> 22 23 /* 24 * Return buffer with the contents of block "offset" from the beginning of 25 * directory "ip". If "res" is non-zero, fill it in with a pointer to the 26 * remaining space in the directory. 27 */ 28 int 29 lfs_blkatoff(ap) 30 struct vop_blkatoff_args /* { 31 struct vnode *a_vp; 32 off_t a_offset; 33 char **a_res; 34 struct buf **a_bpp; 35 } */ *ap; 36 { 37 register struct lfs *fs; 38 struct inode *ip; 39 struct buf *bp; 40 daddr_t lbn; 41 int bsize, error; 42 43 ip = VTOI(ap->a_vp); 44 fs = ip->i_lfs; 45 lbn = lblkno(fs, ap->a_offset); 46 bsize = blksize(fs); 47 48 *ap->a_bpp = NULL; 49 if (error = bread(ap->a_vp, lbn, bsize, NOCRED, &bp)) { 50 brelse(bp); 51 return (error); 52 } 53 if (ap->a_res) 54 *ap->a_res = (char *)bp->b_data + blkoff(fs, ap->a_offset); 55 *ap->a_bpp = bp; 56 return (0); 57 } 58 59 60 /* 61 * lfs_seglock -- 62 * Single thread the segment writer. 63 */ 64 void 65 lfs_seglock(fs, flags) 66 struct lfs *fs; 67 unsigned long flags; 68 { 69 struct segment *sp; 70 int s; 71 72 if (fs->lfs_seglock) 73 if (fs->lfs_lockpid == curproc->p_pid) { 74 ++fs->lfs_seglock; 75 fs->lfs_sp->seg_flags |= flags; 76 return; 77 } else while (fs->lfs_seglock) 78 (void)tsleep(&fs->lfs_seglock, PRIBIO + 1, 79 "lfs seglock", 0); 80 81 fs->lfs_seglock = 1; 82 fs->lfs_lockpid = curproc->p_pid; 83 84 sp = fs->lfs_sp = malloc(sizeof(struct segment), M_SEGMENT, M_WAITOK); 85 sp->bpp = malloc(((LFS_SUMMARY_SIZE - sizeof(SEGSUM)) / 86 sizeof(daddr_t) + 1) * sizeof(struct buf *), M_SEGMENT, M_WAITOK); 87 sp->seg_flags = flags; 88 sp->vp = NULL; 89 (void) lfs_initseg(fs); 90 91 /* 92 * Keep a cumulative count of the outstanding I/O operations. If the 93 * disk drive catches up with us it could go to zero before we finish, 94 * so we artificially increment it by one until we've scheduled all of 95 * the writes we intend to do. 96 */ 97 s = splbio(); 98 ++fs->lfs_iocount; 99 splx(s); 100 } 101 /* 102 * lfs_segunlock -- 103 * Single thread the segment writer. 104 */ 105 void 106 lfs_segunlock(fs) 107 struct lfs *fs; 108 { 109 struct segment *sp; 110 unsigned long sync, ckp; 111 int s; 112 113 if (fs->lfs_seglock == 1) { 114 115 sp = fs->lfs_sp; 116 sync = sp->seg_flags & SEGM_SYNC; 117 ckp = sp->seg_flags & SEGM_CKP; 118 if (sp->bpp != sp->cbpp) { 119 /* Free allocated segment summary */ 120 fs->lfs_offset -= LFS_SUMMARY_SIZE / DEV_BSIZE; 121 brelvp(*sp->bpp); 122 free((*sp->bpp)->b_data, M_SEGMENT); 123 free(*sp->bpp, M_SEGMENT); 124 } else 125 printf ("unlock to 0 with no summary"); 126 free(sp->bpp, M_SEGMENT); 127 free(sp, M_SEGMENT); 128 129 /* 130 * If the I/O count is non-zero, sleep until it reaches zero. 131 * At the moment, the user's process hangs around so we can 132 * sleep. 133 */ 134 s = splbio(); 135 --fs->lfs_iocount; 136 /* 137 * We let checkpoints happen asynchronously. That means 138 * that during recovery, we have to roll forward between 139 * the two segments described by the first and second 140 * superblocks to make sure that the checkpoint described 141 * by a superblock completed. 142 */ 143 if (sync && fs->lfs_iocount) 144 (void)tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs vflush", 0); 145 splx(s); 146 if (ckp) { 147 fs->lfs_nactive = 0; 148 lfs_writesuper(fs); 149 } 150 --fs->lfs_seglock; 151 fs->lfs_lockpid = 0; 152 wakeup(&fs->lfs_seglock); 153 } else if (fs->lfs_seglock == 0) { 154 panic ("Seglock not held"); 155 } else { 156 --fs->lfs_seglock; 157 } 158 } 159