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