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.4 (Berkeley) 05/08/95 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 ufs_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, ip, lbn); 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(ufs_daddr_t) + 1) * sizeof(struct buf *), 87 M_SEGMENT, M_WAITOK); 88 sp->seg_flags = flags; 89 sp->vp = NULL; 90 (void) lfs_initseg(fs); 91 92 /* 93 * Keep a cumulative count of the outstanding I/O operations. If the 94 * disk drive catches up with us it could go to zero before we finish, 95 * so we artificially increment it by one until we've scheduled all of 96 * the writes we intend to do. 97 */ 98 s = splbio(); 99 ++fs->lfs_iocount; 100 splx(s); 101 } 102 /* 103 * lfs_segunlock -- 104 * Single thread the segment writer. 105 */ 106 void 107 lfs_segunlock(fs) 108 struct lfs *fs; 109 { 110 struct segment *sp; 111 unsigned long sync, ckp; 112 int s; 113 114 if (fs->lfs_seglock == 1) { 115 116 sp = fs->lfs_sp; 117 sync = sp->seg_flags & SEGM_SYNC; 118 ckp = sp->seg_flags & SEGM_CKP; 119 if (sp->bpp != sp->cbpp) { 120 /* Free allocated segment summary */ 121 fs->lfs_offset -= LFS_SUMMARY_SIZE / DEV_BSIZE; 122 brelvp(*sp->bpp); 123 free((*sp->bpp)->b_data, M_SEGMENT); 124 free(*sp->bpp, M_SEGMENT); 125 } else 126 printf ("unlock to 0 with no summary"); 127 free(sp->bpp, M_SEGMENT); 128 free(sp, M_SEGMENT); 129 130 /* 131 * If the I/O count is non-zero, sleep until it reaches zero. 132 * At the moment, the user's process hangs around so we can 133 * sleep. 134 */ 135 s = splbio(); 136 --fs->lfs_iocount; 137 /* 138 * We let checkpoints happen asynchronously. That means 139 * that during recovery, we have to roll forward between 140 * the two segments described by the first and second 141 * superblocks to make sure that the checkpoint described 142 * by a superblock completed. 143 */ 144 if (sync && fs->lfs_iocount) 145 (void)tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs vflush", 0); 146 splx(s); 147 if (ckp) { 148 fs->lfs_nactive = 0; 149 lfs_writesuper(fs); 150 } 151 --fs->lfs_seglock; 152 fs->lfs_lockpid = 0; 153 wakeup(&fs->lfs_seglock); 154 } else if (fs->lfs_seglock == 0) { 155 panic ("Seglock not held"); 156 } else { 157 --fs->lfs_seglock; 158 } 159 } 160