lfs_subr.c revision 1.22
1/* $NetBSD: lfs_subr.c,v 1.22 2002/05/14 20:03:54 perseant Exp $ */ 2 3/*- 4 * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Konrad E. Schroder <perseant@hhhh.org>. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38/* 39 * Copyright (c) 1991, 1993 40 * The Regents of the University of California. All rights reserved. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. All advertising materials mentioning features or use of this software 51 * must display the following acknowledgement: 52 * This product includes software developed by the University of 53 * California, Berkeley and its contributors. 54 * 4. Neither the name of the University nor the names of its contributors 55 * may be used to endorse or promote products derived from this software 56 * without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * SUCH DAMAGE. 69 * 70 * @(#)lfs_subr.c 8.4 (Berkeley) 5/8/95 71 */ 72 73#include <sys/cdefs.h> 74__KERNEL_RCSID(0, "$NetBSD: lfs_subr.c,v 1.22 2002/05/14 20:03:54 perseant Exp $"); 75 76#include <sys/param.h> 77#include <sys/systm.h> 78#include <sys/namei.h> 79#include <sys/vnode.h> 80#include <sys/buf.h> 81#include <sys/mount.h> 82#include <sys/malloc.h> 83#include <sys/proc.h> 84 85#include <ufs/ufs/inode.h> 86#include <ufs/lfs/lfs.h> 87#include <ufs/lfs/lfs_extern.h> 88 89/* 90 * Return buffer with the contents of block "offset" from the beginning of 91 * directory "ip". If "res" is non-zero, fill it in with a pointer to the 92 * remaining space in the directory. 93 */ 94int 95lfs_blkatoff(void *v) 96{ 97 struct vop_blkatoff_args /* { 98 struct vnode *a_vp; 99 off_t a_offset; 100 char **a_res; 101 struct buf **a_bpp; 102 } */ *ap = v; 103 struct lfs *fs; 104 struct inode *ip; 105 struct buf *bp; 106 ufs_daddr_t lbn; 107 int bsize, error; 108 109 ip = VTOI(ap->a_vp); 110 fs = ip->i_lfs; 111 lbn = lblkno(fs, ap->a_offset); 112 bsize = blksize(fs, ip, lbn); 113 114 *ap->a_bpp = NULL; 115 if ((error = bread(ap->a_vp, lbn, bsize, NOCRED, &bp)) != 0) { 116 brelse(bp); 117 return (error); 118 } 119 if (ap->a_res) 120 *ap->a_res = (char *)bp->b_data + blkoff(fs, ap->a_offset); 121 *ap->a_bpp = bp; 122 return (0); 123} 124 125 126/* 127 * lfs_seglock -- 128 * Single thread the segment writer. 129 */ 130void 131lfs_seglock(struct lfs *fs, unsigned long flags) 132{ 133 struct segment *sp; 134 int s; 135 136 if (fs->lfs_seglock) { 137 if (fs->lfs_lockpid == curproc->p_pid) { 138 ++fs->lfs_seglock; 139 fs->lfs_sp->seg_flags |= flags; 140 return; 141 } else while (fs->lfs_seglock) 142 (void)tsleep(&fs->lfs_seglock, PRIBIO + 1, 143 "lfs seglock", 0); 144 } 145 146 fs->lfs_seglock = 1; 147 fs->lfs_lockpid = curproc->p_pid; 148 149 sp = fs->lfs_sp = malloc(sizeof(struct segment), M_SEGMENT, M_WAITOK); 150 sp->bpp = malloc(((fs->lfs_sumsize - SEGSUM_SIZE(fs)) / 151 sizeof(ufs_daddr_t) + 1) * sizeof(struct buf *), 152 M_SEGMENT, M_WAITOK); 153 sp->seg_flags = flags; 154 sp->vp = NULL; 155 (void) lfs_initseg(fs); 156 157 /* 158 * Keep a cumulative count of the outstanding I/O operations. If the 159 * disk drive catches up with us it could go to zero before we finish, 160 * so we artificially increment it by one until we've scheduled all of 161 * the writes we intend to do. 162 */ 163 s = splbio(); 164 ++fs->lfs_iocount; 165 splx(s); 166} 167 168/* 169 * lfs_segunlock -- 170 * Single thread the segment writer. 171 */ 172void 173lfs_segunlock(struct lfs *fs) 174{ 175 struct segment *sp; 176 unsigned long sync, ckp; 177 int s; 178 struct buf *bp; 179 struct vnode *vp; 180 struct mount *mp; 181 extern int lfs_dirvcount; 182#ifdef LFS_MALLOC_SUMMARY 183 extern int locked_queue_count; 184 extern long locked_queue_bytes; 185#endif 186 187 sp = fs->lfs_sp; 188 189 if (fs->lfs_seglock == 1 && !(sp->seg_flags & SEGM_PROT)) { 190 191 mp = fs->lfs_ivnode->v_mount; 192 /* 193 * Go through and unmark all DIROP vnodes, possibly 194 * calling VOP_INACTIVE (through vrele). This is 195 * delayed until now in order not to accidentally 196 * write a DIROP node through lfs_flush. 197 */ 198#ifndef LFS_NO_BACKVP_HACK 199 /* BEGIN HACK */ 200#define VN_OFFSET (((caddr_t)&vp->v_mntvnodes.le_next) - (caddr_t)vp) 201#define BACK_VP(VP) ((struct vnode *)(((caddr_t)VP->v_mntvnodes.le_prev) - VN_OFFSET)) 202#define BEG_OF_VLIST ((struct vnode *)(((caddr_t)&mp->mnt_vnodelist.lh_first) - VN_OFFSET)) 203 204 /* Find last vnode. */ 205 loop: for (vp = mp->mnt_vnodelist.lh_first; 206 vp && vp->v_mntvnodes.le_next != NULL; 207 vp = vp->v_mntvnodes.le_next); 208 for (; vp && vp != BEG_OF_VLIST; vp = BACK_VP(vp)) { 209#else 210 loop: 211 for (vp = mp->mnt_vnodelist.lh_first; 212 vp != NULL; 213 vp = vp->v_mntvnodes.le_next) { 214#endif 215 if (vp->v_mount != mp) { 216 printf("lfs_segunlock: starting over\n"); 217 goto loop; 218 } 219 if (vp->v_type == VNON) 220 continue; 221 if (lfs_vref(vp)) 222 continue; 223 if (VOP_ISLOCKED(vp) && 224 vp->v_lock.lk_lockholder != curproc->p_pid) { 225 lfs_vunref(vp); 226 continue; 227 } 228 if ((vp->v_flag & VDIROP) && 229 !(VTOI(vp)->i_flag & IN_ADIROP)) { 230 --lfs_dirvcount; 231 vp->v_flag &= ~VDIROP; 232 wakeup(&lfs_dirvcount); 233 fs->lfs_unlockvp = vp; 234 lfs_vunref(vp); 235 vrele(vp); 236 fs->lfs_unlockvp = NULL; 237 } else { 238 lfs_vunref(vp); 239 } 240 } 241 } 242 243 if (fs->lfs_seglock == 1) { 244 sync = sp->seg_flags & SEGM_SYNC; 245 ckp = sp->seg_flags & SEGM_CKP; 246 if (sp->bpp != sp->cbpp) { 247 /* Free allocated segment summary */ 248 fs->lfs_offset -= btofsb(fs, fs->lfs_sumsize); 249 bp = *sp->bpp; 250#ifdef LFS_MALLOC_SUMMARY 251 lfs_freebuf(bp); 252#else 253 s = splbio(); 254 bremfree(bp); 255 splx(s); 256 bp->b_flags |= B_DONE|B_INVAL; 257 bp->b_flags &= ~B_DELWRI; 258 reassignbuf(bp,bp->b_vp); 259 brelse(bp); 260#endif 261 } else 262 printf ("unlock to 0 with no summary"); 263 264 free(sp->bpp, M_SEGMENT); 265 sp->bpp = NULL; 266 free(sp, M_SEGMENT); 267 fs->lfs_sp = NULL; 268 269 /* 270 * If the I/O count is non-zero, sleep until it reaches zero. 271 * At the moment, the user's process hangs around so we can 272 * sleep. 273 */ 274 s = splbio(); 275 if (--fs->lfs_iocount < LFS_THROTTLE) 276 wakeup(&fs->lfs_iocount); 277 if(fs->lfs_iocount == 0) { 278 lfs_countlocked(&locked_queue_count, 279 &locked_queue_bytes, "lfs_segunlock"); 280 wakeup(&locked_queue_count); 281 wakeup(&fs->lfs_iocount); 282 } 283 /* 284 * We let checkpoints happen asynchronously. That means 285 * that during recovery, we have to roll forward between 286 * the two segments described by the first and second 287 * superblocks to make sure that the checkpoint described 288 * by a superblock completed. 289 */ 290 while (sync && fs->lfs_iocount) 291 (void)tsleep(&fs->lfs_iocount, PRIBIO + 1, 292 "lfs vflush", 0); 293 splx(s); 294 if (ckp) { 295 fs->lfs_nactive = 0; 296 /* If we *know* everything's on disk, write both sbs */ 297 if (sync) 298 lfs_writesuper(fs,fs->lfs_sboffs[fs->lfs_activesb]); 299 fs->lfs_activesb = 1 - fs->lfs_activesb; 300 lfs_writesuper(fs,fs->lfs_sboffs[fs->lfs_activesb]); 301 } 302 --fs->lfs_seglock; 303 fs->lfs_lockpid = 0; 304 wakeup(&fs->lfs_seglock); 305 } else if (fs->lfs_seglock == 0) { 306 panic ("Seglock not held"); 307 } else { 308 --fs->lfs_seglock; 309 } 310} 311