1 /* $NetBSD: lfs_subr.c,v 1.25 2002/05/24 22:13:57 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.25 2002/05/24 22:13:57 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 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 */ 172 void 173 lfs_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, *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 free(sp, M_SEGMENT); 269 fs->lfs_sp = NULL; 270 271 /* 272 * If the I/O count is non-zero, sleep until it reaches zero. 273 * At the moment, the user's process hangs around so we can 274 * sleep. 275 */ 276 s = splbio(); 277 if (--fs->lfs_iocount < LFS_THROTTLE) 278 wakeup(&fs->lfs_iocount); 279 if(fs->lfs_iocount == 0) { 280 lfs_countlocked(&locked_queue_count, 281 &locked_queue_bytes, "lfs_segunlock"); 282 wakeup(&locked_queue_count); 283 wakeup(&fs->lfs_iocount); 284 } 285 /* 286 * We let checkpoints happen asynchronously. That means 287 * that during recovery, we have to roll forward between 288 * the two segments described by the first and second 289 * superblocks to make sure that the checkpoint described 290 * by a superblock completed. 291 */ 292 while (sync && fs->lfs_iocount) 293 (void)tsleep(&fs->lfs_iocount, PRIBIO + 1, 294 "lfs vflush", 0); 295 splx(s); 296 if (ckp) { 297 fs->lfs_nactive = 0; 298 /* If we *know* everything's on disk, write both sbs */ 299 if (sync) 300 lfs_writesuper(fs,fs->lfs_sboffs[fs->lfs_activesb]); 301 fs->lfs_activesb = 1 - fs->lfs_activesb; 302 lfs_writesuper(fs,fs->lfs_sboffs[fs->lfs_activesb]); 303 } 304 --fs->lfs_seglock; 305 fs->lfs_lockpid = 0; 306 wakeup(&fs->lfs_seglock); 307 } else if (fs->lfs_seglock == 0) { 308 panic ("Seglock not held"); 309 } else { 310 --fs->lfs_seglock; 311 } 312 } 313