1 /* $NetBSD: lfs_subr.c,v 1.18 2001/07/13 20:30:24 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/param.h> 74 #include <sys/systm.h> 75 #include <sys/namei.h> 76 #include <sys/vnode.h> 77 #include <sys/buf.h> 78 #include <sys/mount.h> 79 #include <sys/malloc.h> 80 #include <sys/proc.h> 81 82 #include <ufs/ufs/quota.h> 83 #include <ufs/ufs/inode.h> 84 #include <ufs/lfs/lfs.h> 85 #include <ufs/lfs/lfs_extern.h> 86 87 /* 88 * Return buffer with the contents of block "offset" from the beginning of 89 * directory "ip". If "res" is non-zero, fill it in with a pointer to the 90 * remaining space in the directory. 91 */ 92 int 93 lfs_blkatoff(void *v) 94 { 95 struct vop_blkatoff_args /* { 96 struct vnode *a_vp; 97 off_t a_offset; 98 char **a_res; 99 struct buf **a_bpp; 100 } */ *ap = v; 101 struct lfs *fs; 102 struct inode *ip; 103 struct buf *bp; 104 ufs_daddr_t lbn; 105 int bsize, error; 106 107 ip = VTOI(ap->a_vp); 108 fs = ip->i_lfs; 109 lbn = lblkno(fs, ap->a_offset); 110 bsize = blksize(fs, ip, lbn); 111 112 *ap->a_bpp = NULL; 113 if ((error = bread(ap->a_vp, lbn, bsize, NOCRED, &bp)) != 0) { 114 brelse(bp); 115 return (error); 116 } 117 if (ap->a_res) 118 *ap->a_res = (char *)bp->b_data + blkoff(fs, ap->a_offset); 119 *ap->a_bpp = bp; 120 return (0); 121 } 122 123 124 /* 125 * lfs_seglock -- 126 * Single thread the segment writer. 127 */ 128 void 129 lfs_seglock(struct lfs *fs, unsigned long flags) 130 { 131 struct segment *sp; 132 int s; 133 134 if (fs->lfs_seglock) { 135 if (fs->lfs_lockpid == curproc->p_pid) { 136 ++fs->lfs_seglock; 137 fs->lfs_sp->seg_flags |= flags; 138 return; 139 } else while (fs->lfs_seglock) 140 (void)tsleep(&fs->lfs_seglock, PRIBIO + 1, 141 "lfs seglock", 0); 142 } 143 144 fs->lfs_seglock = 1; 145 fs->lfs_lockpid = curproc->p_pid; 146 147 sp = fs->lfs_sp = malloc(sizeof(struct segment), M_SEGMENT, M_WAITOK); 148 sp->bpp = malloc(((fs->lfs_sumsize - SEGSUM_SIZE(fs)) / 149 sizeof(ufs_daddr_t) + 1) * sizeof(struct buf *), 150 M_SEGMENT, M_WAITOK); 151 sp->seg_flags = flags; 152 sp->vp = NULL; 153 (void) lfs_initseg(fs); 154 155 /* 156 * Keep a cumulative count of the outstanding I/O operations. If the 157 * disk drive catches up with us it could go to zero before we finish, 158 * so we artificially increment it by one until we've scheduled all of 159 * the writes we intend to do. 160 */ 161 s = splbio(); 162 ++fs->lfs_iocount; 163 splx(s); 164 } 165 166 /* 167 * lfs_segunlock -- 168 * Single thread the segment writer. 169 */ 170 void 171 lfs_segunlock(struct lfs *fs) 172 { 173 struct segment *sp; 174 unsigned long sync, ckp; 175 int s; 176 struct vnode *vp; 177 struct mount *mp; 178 extern int lfs_dirvcount; 179 180 sp = fs->lfs_sp; 181 182 if (fs->lfs_seglock == 1 && !(sp->seg_flags & SEGM_PROT)) { 183 184 mp = fs->lfs_ivnode->v_mount; 185 /* 186 * Go through and unmark all DIROP vnodes, possibly 187 * calling VOP_INACTIVE (through vrele). This is 188 * delayed until now in order not to accidentally 189 * write a DIROP node through lfs_flush. 190 */ 191 #ifndef LFS_NO_BACKVP_HACK 192 /* BEGIN HACK */ 193 #define VN_OFFSET (((caddr_t)&vp->v_mntvnodes.le_next) - (caddr_t)vp) 194 #define BACK_VP(VP) ((struct vnode *)(((caddr_t)VP->v_mntvnodes.le_prev) - VN_OFFSET)) 195 #define BEG_OF_VLIST ((struct vnode *)(((caddr_t)&mp->mnt_vnodelist.lh_first) - VN_OFFSET)) 196 197 /* Find last vnode. */ 198 loop: for (vp = mp->mnt_vnodelist.lh_first; 199 vp && vp->v_mntvnodes.le_next != NULL; 200 vp = vp->v_mntvnodes.le_next); 201 for (; vp && vp != BEG_OF_VLIST; vp = BACK_VP(vp)) { 202 #else 203 loop: 204 for (vp = mp->mnt_vnodelist.lh_first; 205 vp != NULL; 206 vp = vp->v_mntvnodes.le_next) { 207 #endif 208 if (vp->v_mount != mp) 209 goto loop; 210 if (vp->v_type == VNON) 211 continue; 212 if (lfs_vref(vp)) 213 continue; 214 if (VOP_ISLOCKED(vp) && 215 vp->v_lock.lk_lockholder != curproc->p_pid) { 216 lfs_vunref(vp); 217 continue; 218 } 219 if ((vp->v_flag & VDIROP) && 220 !(VTOI(vp)->i_flag & IN_ADIROP)) { 221 --lfs_dirvcount; 222 vp->v_flag &= ~VDIROP; 223 wakeup(&lfs_dirvcount); 224 fs->lfs_unlockvp = vp; 225 lfs_vunref(vp); 226 vrele(vp); 227 fs->lfs_unlockvp = NULL; 228 } else { 229 lfs_vunref(vp); 230 } 231 } 232 } 233 234 if (fs->lfs_seglock == 1) { 235 sync = sp->seg_flags & SEGM_SYNC; 236 ckp = sp->seg_flags & SEGM_CKP; 237 if (sp->bpp != sp->cbpp) { 238 /* Free allocated segment summary */ 239 fs->lfs_offset -= btofsb(fs, fs->lfs_sumsize); 240 lfs_freebuf(*sp->bpp); 241 } else 242 printf ("unlock to 0 with no summary"); 243 244 free(sp->bpp, M_SEGMENT); 245 sp->bpp = NULL; 246 free(sp, M_SEGMENT); 247 fs->lfs_sp = NULL; 248 249 /* 250 * If the I/O count is non-zero, sleep until it reaches zero. 251 * At the moment, the user's process hangs around so we can 252 * sleep. 253 */ 254 s = splbio(); 255 --fs->lfs_iocount; 256 /* 257 * We let checkpoints happen asynchronously. That means 258 * that during recovery, we have to roll forward between 259 * the two segments described by the first and second 260 * superblocks to make sure that the checkpoint described 261 * by a superblock completed. 262 */ 263 while (sync && fs->lfs_iocount) 264 (void)tsleep(&fs->lfs_iocount, PRIBIO + 1, 265 "lfs vflush", 0); 266 splx(s); 267 if (ckp) { 268 fs->lfs_nactive = 0; 269 /* If we *know* everything's on disk, write both sbs */ 270 if(sync) 271 lfs_writesuper(fs,fs->lfs_sboffs[fs->lfs_activesb]); 272 fs->lfs_activesb = 1 - fs->lfs_activesb; 273 lfs_writesuper(fs,fs->lfs_sboffs[fs->lfs_activesb]); 274 } 275 --fs->lfs_seglock; 276 fs->lfs_lockpid = 0; 277 wakeup(&fs->lfs_seglock); 278 } else if (fs->lfs_seglock == 0) { 279 panic ("Seglock not held"); 280 } else { 281 --fs->lfs_seglock; 282 } 283 } 284