lfs_subr.c revision 1.27
1/* $NetBSD: lfs_subr.c,v 1.27 2002/07/06 01:30:13 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.27 2002/07/06 01:30:13 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 135 /* 136 * SEGM_PROT specifies a shared lock, which can be held by multiple 137 * processes simultaneously. It is not possible to upgrade from a 138 * SEGM_PROT lock to a normal seglock. 139 */ 140 if (fs->lfs_seglock) { 141 if (fs->lfs_lockpid == curproc->p_pid) { 142 ++fs->lfs_seglock; 143 fs->lfs_sp->seg_flags |= flags; 144 return; 145 } else while (fs->lfs_seglock) 146 (void)tsleep(&fs->lfs_seglock, PRIBIO + 1, 147 "lfs seglock", 0); 148 } 149 150 fs->lfs_seglock = 1; 151 fs->lfs_lockpid = curproc->p_pid; 152 153 /* Drain fragment size changes out */ 154 lockmgr(&fs->lfs_fraglock, LK_EXCLUSIVE, 0); 155 156 sp = fs->lfs_sp = malloc(sizeof(struct segment), M_SEGMENT, M_WAITOK); 157 sp->bpp = malloc(((fs->lfs_sumsize - SEGSUM_SIZE(fs)) / 158 sizeof(ufs_daddr_t) + 1) * sizeof(struct buf *), 159 M_SEGMENT, M_WAITOK); 160 sp->seg_flags = flags; 161 sp->vp = NULL; 162 sp->seg_iocount = 0; 163 (void) lfs_initseg(fs); 164 165 /* 166 * Keep a cumulative count of the outstanding I/O operations. If the 167 * disk drive catches up with us it could go to zero before we finish, 168 * so we artificially increment it by one until we've scheduled all of 169 * the writes we intend to do. 170 */ 171 ++fs->lfs_iocount; 172} 173 174/* 175 * lfs_segunlock -- 176 * Single thread the segment writer. 177 */ 178void 179lfs_segunlock(struct lfs *fs) 180{ 181 struct segment *sp; 182 unsigned long sync, ckp; 183 struct buf *bp; 184 struct vnode *vp, *nvp; 185 struct mount *mp; 186 extern int lfs_dirvcount; 187#ifdef LFS_MALLOC_SUMMARY 188 extern int locked_queue_count; 189 extern long locked_queue_bytes; 190#endif 191 192 sp = fs->lfs_sp; 193 194 if (fs->lfs_seglock == 1 && !(sp->seg_flags & SEGM_PROT)) { 195 196 mp = fs->lfs_ivnode->v_mount; 197 /* 198 * Go through and unmark all DIROP vnodes, possibly 199 * calling VOP_INACTIVE (through vrele). This is 200 * delayed until now in order not to accidentally 201 * write a DIROP node through lfs_flush. 202 */ 203#ifndef LFS_NO_BACKVP_HACK 204 /* BEGIN HACK */ 205#define VN_OFFSET (((caddr_t)&LIST_NEXT(vp, v_mntvnodes)) - (caddr_t)vp) 206#define BACK_VP(VP) ((struct vnode *)(((caddr_t)(VP)->v_mntvnodes.le_prev) - VN_OFFSET)) 207#define BEG_OF_VLIST ((struct vnode *)(((caddr_t)&LIST_FIRST(&mp->mnt_vnodelist)) - VN_OFFSET)) 208 209 /* Find last vnode. */ 210 loop: for (vp = LIST_FIRST(&mp->mnt_vnodelist); 211 vp && LIST_NEXT(vp, v_mntvnodes) != NULL; 212 vp = LIST_NEXT(vp, v_mntvnodes)); 213 for (; vp && vp != BEG_OF_VLIST; vp = nvp) { 214 nvp = BACK_VP(vp); 215#else 216 loop: 217 for (vp = LIST_FIRST(&mp->mnt_vnodelist); 218 vp != NULL; 219 vp = nvp) { 220 nvp = LIST_NEXT(vp, v_mntvnodes); 221#endif 222 if (vp->v_mount != mp) { 223 printf("lfs_segunlock: starting over\n"); 224 goto loop; 225 } 226 if (vp->v_type == VNON) 227 continue; 228 if (lfs_vref(vp)) 229 continue; 230 if (VOP_ISLOCKED(vp) && 231 vp->v_lock.lk_lockholder != curproc->p_pid) { 232 lfs_vunref(vp); 233 continue; 234 } 235 if ((vp->v_flag & VDIROP) && 236 !(VTOI(vp)->i_flag & IN_ADIROP)) { 237 --lfs_dirvcount; 238 vp->v_flag &= ~VDIROP; 239 wakeup(&lfs_dirvcount); 240 fs->lfs_unlockvp = vp; 241 lfs_vunref(vp); 242 vrele(vp); 243 fs->lfs_unlockvp = NULL; 244 } else { 245 lfs_vunref(vp); 246 } 247 } 248 } 249 250 if (fs->lfs_seglock == 1) { 251 sync = sp->seg_flags & SEGM_SYNC; 252 ckp = sp->seg_flags & SEGM_CKP; 253 if (sp->bpp != sp->cbpp) { 254 /* Free allocated segment summary */ 255 fs->lfs_offset -= btofsb(fs, fs->lfs_sumsize); 256 bp = *sp->bpp; 257#ifdef LFS_MALLOC_SUMMARY 258 lfs_freebuf(bp); 259#else 260 s = splbio(); 261 bremfree(bp); 262 bp->b_flags |= B_DONE|B_INVAL; 263 bp->b_flags &= ~B_DELWRI; 264 reassignbuf(bp,bp->b_vp); 265 splx(s); 266 brelse(bp); 267#endif 268 } else 269 printf ("unlock to 0 with no summary"); 270 271 free(sp->bpp, M_SEGMENT); 272 sp->bpp = NULL; 273 /* The sync case holds a reference in `sp' to be freed below */ 274 if (!sync) 275 free(sp, M_SEGMENT); 276 fs->lfs_sp = NULL; 277 278 /* 279 * If the I/O count is non-zero, sleep until it reaches zero. 280 * At the moment, the user's process hangs around so we can 281 * sleep. 282 */ 283 if (--fs->lfs_iocount < LFS_THROTTLE) 284 wakeup(&fs->lfs_iocount); 285 if(fs->lfs_iocount == 0) { 286 lfs_countlocked(&locked_queue_count, 287 &locked_queue_bytes, "lfs_segunlock"); 288 wakeup(&locked_queue_count); 289 wakeup(&fs->lfs_iocount); 290 } 291 /* 292 * If we're not checkpointing, we don't have to block 293 * other processes to wait for a synchronous write 294 * to complete. 295 */ 296 if (!ckp) { 297 --fs->lfs_seglock; 298 fs->lfs_lockpid = 0; 299 wakeup(&fs->lfs_seglock); 300 } 301 /* 302 * We let checkpoints happen asynchronously. That means 303 * that during recovery, we have to roll forward between 304 * the two segments described by the first and second 305 * superblocks to make sure that the checkpoint described 306 * by a superblock completed. 307 */ 308 while (ckp && sync && fs->lfs_iocount) 309 (void)tsleep(&fs->lfs_iocount, PRIBIO + 1, 310 "lfs_iocount", 0); 311 while (sync && sp->seg_iocount) { 312 (void)tsleep(&sp->seg_iocount, PRIBIO + 1, 313 "seg_iocount", 0); 314 /* printf("sleeping on iocount %x == %d\n", sp, sp->seg_iocount); */ 315 } 316 if (sync) 317 free(sp, M_SEGMENT); 318 if (ckp) { 319 fs->lfs_nactive = 0; 320 /* If we *know* everything's on disk, write both sbs */ 321 if (sync) 322 lfs_writesuper(fs,fs->lfs_sboffs[fs->lfs_activesb]); 323 fs->lfs_activesb = 1 - fs->lfs_activesb; 324 lfs_writesuper(fs,fs->lfs_sboffs[fs->lfs_activesb]); 325 326 --fs->lfs_seglock; 327 fs->lfs_lockpid = 0; 328 wakeup(&fs->lfs_seglock); 329 } 330 /* Reenable fragment size changes */ 331 lockmgr(&fs->lfs_fraglock, LK_RELEASE, 0); 332 } else if (fs->lfs_seglock == 0) { 333 panic ("Seglock not held"); 334 } else { 335 --fs->lfs_seglock; 336 } 337} 338