1 /* 2 * Copyright (c) 1982, 1986, 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)ffs_vnops.c 8.15 (Berkeley) 5/14/95 34 * $FreeBSD: src/sys/ufs/ffs/ffs_vnops.c,v 1.64 2000/01/10 12:04:25 phk Exp $ 35 * $DragonFly: src/sys/vfs/ufs/ffs_vnops.c,v 1.6 2003/08/20 09:56:34 rob Exp $ 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/resourcevar.h> 41 #include <sys/signalvar.h> 42 #include <sys/kernel.h> 43 #include <sys/stat.h> 44 #include <sys/buf.h> 45 #include <sys/proc.h> 46 #include <sys/mount.h> 47 #include <sys/vnode.h> 48 #include <sys/conf.h> 49 50 #include <machine/limits.h> 51 52 #include <vm/vm.h> 53 #include <vm/vm_page.h> 54 #include <vm/vm_object.h> 55 #include <vm/vm_extern.h> 56 57 #include <sys/buf2.h> 58 59 #include "quota.h" 60 #include "inode.h" 61 #include "ufsmount.h" 62 #include "ufs_extern.h" 63 64 #include "fs.h" 65 #include "ffs_extern.h" 66 67 static int ffs_fsync (struct vop_fsync_args *); 68 static int ffs_getpages (struct vop_getpages_args *); 69 static int ffs_putpages (struct vop_putpages_args *); 70 static int ffs_read (struct vop_read_args *); 71 static int ffs_write (struct vop_write_args *); 72 73 /* Global vfs data structures for ufs. */ 74 vop_t **ffs_vnodeop_p; 75 static struct vnodeopv_entry_desc ffs_vnodeop_entries[] = { 76 { &vop_default_desc, (vop_t *) ufs_vnoperate }, 77 { &vop_fsync_desc, (vop_t *) ffs_fsync }, 78 { &vop_getpages_desc, (vop_t *) ffs_getpages }, 79 { &vop_putpages_desc, (vop_t *) ffs_putpages }, 80 { &vop_read_desc, (vop_t *) ffs_read }, 81 { &vop_balloc_desc, (vop_t *) ffs_balloc }, 82 { &vop_reallocblks_desc, (vop_t *) ffs_reallocblks }, 83 { &vop_write_desc, (vop_t *) ffs_write }, 84 { NULL, NULL } 85 }; 86 static struct vnodeopv_desc ffs_vnodeop_opv_desc = 87 { &ffs_vnodeop_p, ffs_vnodeop_entries }; 88 89 vop_t **ffs_specop_p; 90 static struct vnodeopv_entry_desc ffs_specop_entries[] = { 91 { &vop_default_desc, (vop_t *) ufs_vnoperatespec }, 92 { &vop_fsync_desc, (vop_t *) ffs_fsync }, 93 { NULL, NULL } 94 }; 95 static struct vnodeopv_desc ffs_specop_opv_desc = 96 { &ffs_specop_p, ffs_specop_entries }; 97 98 vop_t **ffs_fifoop_p; 99 static struct vnodeopv_entry_desc ffs_fifoop_entries[] = { 100 { &vop_default_desc, (vop_t *) ufs_vnoperatefifo }, 101 { &vop_fsync_desc, (vop_t *) ffs_fsync }, 102 { NULL, NULL } 103 }; 104 static struct vnodeopv_desc ffs_fifoop_opv_desc = 105 { &ffs_fifoop_p, ffs_fifoop_entries }; 106 107 VNODEOP_SET(ffs_vnodeop_opv_desc); 108 VNODEOP_SET(ffs_specop_opv_desc); 109 VNODEOP_SET(ffs_fifoop_opv_desc); 110 111 #include "ufs_readwrite.c" 112 113 /* 114 * Synch an open file. 115 */ 116 /* ARGSUSED */ 117 static int 118 ffs_fsync(ap) 119 struct vop_fsync_args /* { 120 struct vnode *a_vp; 121 struct ucred *a_cred; 122 int a_waitfor; 123 struct proc *a_p; 124 } */ *ap; 125 { 126 struct vnode *vp = ap->a_vp; 127 struct buf *bp; 128 struct buf *nbp; 129 int s, error, wait, passes, skipmeta; 130 daddr_t lbn; 131 132 wait = (ap->a_waitfor == MNT_WAIT); 133 if (vn_isdisk(vp, NULL)) { 134 lbn = INT_MAX; 135 if (vp->v_specmountpoint != NULL && 136 (vp->v_specmountpoint->mnt_flag & MNT_SOFTDEP)) 137 softdep_fsync_mountdev(vp); 138 } else { 139 struct inode *ip; 140 ip = VTOI(vp); 141 lbn = lblkno(ip->i_fs, (ip->i_size + ip->i_fs->fs_bsize - 1)); 142 } 143 144 /* 145 * Flush all dirty buffers associated with a vnode. 146 */ 147 passes = NIADDR + 1; 148 skipmeta = 0; 149 if (wait) 150 skipmeta = 1; 151 s = splbio(); 152 loop: 153 for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; 154 bp = TAILQ_NEXT(bp, b_vnbufs)) 155 bp->b_flags &= ~B_SCANNED; 156 for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { 157 nbp = TAILQ_NEXT(bp, b_vnbufs); 158 /* 159 * Reasons to skip this buffer: it has already been considered 160 * on this pass, this pass is the first time through on a 161 * synchronous flush request and the buffer being considered 162 * is metadata, the buffer has dependencies that will cause 163 * it to be redirtied and it has not already been deferred, 164 * or it is already being written. 165 */ 166 if ((bp->b_flags & B_SCANNED) != 0) 167 continue; 168 bp->b_flags |= B_SCANNED; 169 if ((skipmeta == 1 && bp->b_lblkno < 0)) 170 continue; 171 if (!wait && LIST_FIRST(&bp->b_dep) != NULL && 172 (bp->b_flags & B_DEFERRED) == 0 && 173 bioops.io_countdeps && (*bioops.io_countdeps)(bp, 0)) { 174 bp->b_flags |= B_DEFERRED; 175 continue; 176 } 177 if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) 178 continue; 179 if ((bp->b_flags & B_DELWRI) == 0) 180 panic("ffs_fsync: not dirty"); 181 if (vp != bp->b_vp) 182 panic("ffs_fsync: vp != vp->b_vp"); 183 /* 184 * If this is a synchronous flush request, or it is not a 185 * file or device, start the write on this buffer immediatly. 186 */ 187 if (wait || (vp->v_type != VREG && vp->v_type != VBLK)) { 188 189 /* 190 * On our final pass through, do all I/O synchronously 191 * so that we can find out if our flush is failing 192 * because of write errors. 193 */ 194 if (passes > 0 || !wait) { 195 if ((bp->b_flags & B_CLUSTEROK) && !wait) { 196 BUF_UNLOCK(bp); 197 (void) vfs_bio_awrite(bp); 198 } else { 199 bremfree(bp); 200 splx(s); 201 (void) bawrite(bp); 202 s = splbio(); 203 } 204 } else { 205 bremfree(bp); 206 splx(s); 207 if ((error = bwrite(bp)) != 0) 208 return (error); 209 s = splbio(); 210 } 211 } else if ((vp->v_type == VREG) && (bp->b_lblkno >= lbn)) { 212 /* 213 * If the buffer is for data that has been truncated 214 * off the file, then throw it away. 215 */ 216 bremfree(bp); 217 bp->b_flags |= B_INVAL | B_NOCACHE; 218 splx(s); 219 brelse(bp); 220 s = splbio(); 221 } else { 222 BUF_UNLOCK(bp); 223 vfs_bio_awrite(bp); 224 } 225 /* 226 * Since we may have slept during the I/O, we need 227 * to start from a known point. 228 */ 229 nbp = TAILQ_FIRST(&vp->v_dirtyblkhd); 230 } 231 /* 232 * If we were asked to do this synchronously, then go back for 233 * another pass, this time doing the metadata. 234 */ 235 if (skipmeta) { 236 skipmeta = 0; 237 goto loop; 238 } 239 240 if (wait) { 241 while (vp->v_numoutput) { 242 vp->v_flag |= VBWAIT; 243 (void) tsleep((caddr_t)&vp->v_numoutput, 0, "ffsfsn", 0); 244 } 245 246 /* 247 * Ensure that any filesystem metatdata associated 248 * with the vnode has been written. 249 */ 250 splx(s); 251 if ((error = softdep_sync_metadata(ap)) != 0) 252 return (error); 253 s = splbio(); 254 255 if (!TAILQ_EMPTY(&vp->v_dirtyblkhd)) { 256 /* 257 * Block devices associated with filesystems may 258 * have new I/O requests posted for them even if 259 * the vnode is locked, so no amount of trying will 260 * get them clean. Thus we give block devices a 261 * good effort, then just give up. For all other file 262 * types, go around and try again until it is clean. 263 */ 264 if (passes > 0) { 265 passes -= 1; 266 goto loop; 267 } 268 #ifdef DIAGNOSTIC 269 if (!vn_isdisk(vp, NULL)) 270 vprint("ffs_fsync: dirty", vp); 271 #endif 272 } 273 } 274 splx(s); 275 return (UFS_UPDATE(vp, wait)); 276 } 277