1 /* $NetBSD: ffs_vnops.c,v 1.113 2009/11/04 09:45:05 hannken Exp $ */ 2 3 /*- 4 * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Wasabi Systems, Inc, and by Andrew Doran. 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1982, 1986, 1989, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. Neither the name of the University nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 * 60 * @(#)ffs_vnops.c 8.15 (Berkeley) 5/14/95 61 */ 62 63 #include <sys/cdefs.h> 64 __KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.113 2009/11/04 09:45:05 hannken Exp $"); 65 66 #if defined(_KERNEL_OPT) 67 #include "opt_ffs.h" 68 #include "opt_wapbl.h" 69 #endif 70 71 #include <sys/param.h> 72 #include <sys/systm.h> 73 #include <sys/resourcevar.h> 74 #include <sys/kernel.h> 75 #include <sys/file.h> 76 #include <sys/stat.h> 77 #include <sys/buf.h> 78 #include <sys/event.h> 79 #include <sys/proc.h> 80 #include <sys/mount.h> 81 #include <sys/vnode.h> 82 #include <sys/pool.h> 83 #include <sys/signalvar.h> 84 #include <sys/kauth.h> 85 #include <sys/wapbl.h> 86 #include <sys/fstrans.h> 87 88 #include <miscfs/fifofs/fifo.h> 89 #include <miscfs/genfs/genfs.h> 90 #include <miscfs/specfs/specdev.h> 91 92 #include <ufs/ufs/inode.h> 93 #include <ufs/ufs/dir.h> 94 #include <ufs/ufs/ufs_extern.h> 95 #include <ufs/ufs/ufsmount.h> 96 #include <ufs/ufs/ufs_wapbl.h> 97 98 #include <ufs/ffs/fs.h> 99 #include <ufs/ffs/ffs_extern.h> 100 101 #include <uvm/uvm.h> 102 103 /* Global vfs data structures for ufs. */ 104 int (**ffs_vnodeop_p)(void *); 105 const struct vnodeopv_entry_desc ffs_vnodeop_entries[] = { 106 { &vop_default_desc, vn_default_error }, 107 { &vop_lookup_desc, ufs_lookup }, /* lookup */ 108 { &vop_create_desc, ufs_create }, /* create */ 109 { &vop_whiteout_desc, ufs_whiteout }, /* whiteout */ 110 { &vop_mknod_desc, ufs_mknod }, /* mknod */ 111 { &vop_open_desc, ufs_open }, /* open */ 112 { &vop_close_desc, ufs_close }, /* close */ 113 { &vop_access_desc, ufs_access }, /* access */ 114 { &vop_getattr_desc, ufs_getattr }, /* getattr */ 115 { &vop_setattr_desc, ufs_setattr }, /* setattr */ 116 { &vop_read_desc, ffs_read }, /* read */ 117 { &vop_write_desc, ffs_write }, /* write */ 118 { &vop_ioctl_desc, ufs_ioctl }, /* ioctl */ 119 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ 120 { &vop_poll_desc, ufs_poll }, /* poll */ 121 { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */ 122 { &vop_revoke_desc, ufs_revoke }, /* revoke */ 123 { &vop_mmap_desc, ufs_mmap }, /* mmap */ 124 { &vop_fsync_desc, ffs_fsync }, /* fsync */ 125 { &vop_seek_desc, ufs_seek }, /* seek */ 126 { &vop_remove_desc, ufs_remove }, /* remove */ 127 { &vop_link_desc, ufs_link }, /* link */ 128 { &vop_rename_desc, ufs_rename }, /* rename */ 129 { &vop_mkdir_desc, ufs_mkdir }, /* mkdir */ 130 { &vop_rmdir_desc, ufs_rmdir }, /* rmdir */ 131 { &vop_symlink_desc, ufs_symlink }, /* symlink */ 132 { &vop_readdir_desc, ufs_readdir }, /* readdir */ 133 { &vop_readlink_desc, ufs_readlink }, /* readlink */ 134 { &vop_abortop_desc, ufs_abortop }, /* abortop */ 135 { &vop_inactive_desc, ufs_inactive }, /* inactive */ 136 { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ 137 { &vop_lock_desc, ufs_lock }, /* lock */ 138 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 139 { &vop_bmap_desc, ufs_bmap }, /* bmap */ 140 { &vop_strategy_desc, ufs_strategy }, /* strategy */ 141 { &vop_print_desc, ufs_print }, /* print */ 142 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 143 { &vop_pathconf_desc, ufs_pathconf }, /* pathconf */ 144 { &vop_advlock_desc, ufs_advlock }, /* advlock */ 145 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 146 { &vop_getpages_desc, genfs_getpages }, /* getpages */ 147 { &vop_putpages_desc, genfs_putpages }, /* putpages */ 148 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ 149 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ 150 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ 151 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ 152 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ 153 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ 154 { NULL, NULL } 155 }; 156 const struct vnodeopv_desc ffs_vnodeop_opv_desc = 157 { &ffs_vnodeop_p, ffs_vnodeop_entries }; 158 159 int (**ffs_specop_p)(void *); 160 const struct vnodeopv_entry_desc ffs_specop_entries[] = { 161 { &vop_default_desc, vn_default_error }, 162 { &vop_lookup_desc, spec_lookup }, /* lookup */ 163 { &vop_create_desc, spec_create }, /* create */ 164 { &vop_mknod_desc, spec_mknod }, /* mknod */ 165 { &vop_open_desc, spec_open }, /* open */ 166 { &vop_close_desc, ufsspec_close }, /* close */ 167 { &vop_access_desc, ufs_access }, /* access */ 168 { &vop_getattr_desc, ufs_getattr }, /* getattr */ 169 { &vop_setattr_desc, ufs_setattr }, /* setattr */ 170 { &vop_read_desc, ufsspec_read }, /* read */ 171 { &vop_write_desc, ufsspec_write }, /* write */ 172 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 173 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ 174 { &vop_poll_desc, spec_poll }, /* poll */ 175 { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */ 176 { &vop_revoke_desc, spec_revoke }, /* revoke */ 177 { &vop_mmap_desc, spec_mmap }, /* mmap */ 178 { &vop_fsync_desc, ffs_fsync }, /* fsync */ 179 { &vop_seek_desc, spec_seek }, /* seek */ 180 { &vop_remove_desc, spec_remove }, /* remove */ 181 { &vop_link_desc, spec_link }, /* link */ 182 { &vop_rename_desc, spec_rename }, /* rename */ 183 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 184 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 185 { &vop_symlink_desc, spec_symlink }, /* symlink */ 186 { &vop_readdir_desc, spec_readdir }, /* readdir */ 187 { &vop_readlink_desc, spec_readlink }, /* readlink */ 188 { &vop_abortop_desc, spec_abortop }, /* abortop */ 189 { &vop_inactive_desc, ufs_inactive }, /* inactive */ 190 { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ 191 { &vop_lock_desc, ufs_lock }, /* lock */ 192 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 193 { &vop_bmap_desc, spec_bmap }, /* bmap */ 194 { &vop_strategy_desc, spec_strategy }, /* strategy */ 195 { &vop_print_desc, ufs_print }, /* print */ 196 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 197 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 198 { &vop_advlock_desc, spec_advlock }, /* advlock */ 199 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 200 { &vop_getpages_desc, spec_getpages }, /* getpages */ 201 { &vop_putpages_desc, spec_putpages }, /* putpages */ 202 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ 203 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ 204 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ 205 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ 206 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ 207 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ 208 { NULL, NULL } 209 }; 210 const struct vnodeopv_desc ffs_specop_opv_desc = 211 { &ffs_specop_p, ffs_specop_entries }; 212 213 int (**ffs_fifoop_p)(void *); 214 const struct vnodeopv_entry_desc ffs_fifoop_entries[] = { 215 { &vop_default_desc, vn_default_error }, 216 { &vop_lookup_desc, fifo_lookup }, /* lookup */ 217 { &vop_create_desc, fifo_create }, /* create */ 218 { &vop_mknod_desc, fifo_mknod }, /* mknod */ 219 { &vop_open_desc, fifo_open }, /* open */ 220 { &vop_close_desc, ufsfifo_close }, /* close */ 221 { &vop_access_desc, ufs_access }, /* access */ 222 { &vop_getattr_desc, ufs_getattr }, /* getattr */ 223 { &vop_setattr_desc, ufs_setattr }, /* setattr */ 224 { &vop_read_desc, ufsfifo_read }, /* read */ 225 { &vop_write_desc, ufsfifo_write }, /* write */ 226 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 227 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ 228 { &vop_poll_desc, fifo_poll }, /* poll */ 229 { &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */ 230 { &vop_revoke_desc, fifo_revoke }, /* revoke */ 231 { &vop_mmap_desc, fifo_mmap }, /* mmap */ 232 { &vop_fsync_desc, ffs_fsync }, /* fsync */ 233 { &vop_seek_desc, fifo_seek }, /* seek */ 234 { &vop_remove_desc, fifo_remove }, /* remove */ 235 { &vop_link_desc, fifo_link }, /* link */ 236 { &vop_rename_desc, fifo_rename }, /* rename */ 237 { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ 238 { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ 239 { &vop_symlink_desc, fifo_symlink }, /* symlink */ 240 { &vop_readdir_desc, fifo_readdir }, /* readdir */ 241 { &vop_readlink_desc, fifo_readlink }, /* readlink */ 242 { &vop_abortop_desc, fifo_abortop }, /* abortop */ 243 { &vop_inactive_desc, ufs_inactive }, /* inactive */ 244 { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ 245 { &vop_lock_desc, ufs_lock }, /* lock */ 246 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 247 { &vop_bmap_desc, fifo_bmap }, /* bmap */ 248 { &vop_strategy_desc, fifo_strategy }, /* strategy */ 249 { &vop_print_desc, ufs_print }, /* print */ 250 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 251 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */ 252 { &vop_advlock_desc, fifo_advlock }, /* advlock */ 253 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 254 { &vop_putpages_desc, fifo_putpages }, /* putpages */ 255 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ 256 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ 257 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ 258 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ 259 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ 260 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ 261 { NULL, NULL } 262 }; 263 const struct vnodeopv_desc ffs_fifoop_opv_desc = 264 { &ffs_fifoop_p, ffs_fifoop_entries }; 265 266 #include <ufs/ufs/ufs_readwrite.c> 267 268 int 269 ffs_fsync(void *v) 270 { 271 struct vop_fsync_args /* { 272 struct vnode *a_vp; 273 kauth_cred_t a_cred; 274 int a_flags; 275 off_t a_offlo; 276 off_t a_offhi; 277 struct lwp *a_l; 278 } */ *ap = v; 279 struct buf *bp; 280 int num, error, i; 281 struct indir ia[NIADDR + 1]; 282 int bsize; 283 daddr_t blk_high; 284 struct vnode *vp; 285 #ifdef WAPBL 286 struct mount *mp; 287 #endif 288 289 vp = ap->a_vp; 290 291 fstrans_start(vp->v_mount, FSTRANS_LAZY); 292 if ((ap->a_offlo == 0 && ap->a_offhi == 0) || (vp->v_type != VREG)) { 293 error = ffs_full_fsync(vp, ap->a_flags); 294 goto out; 295 } 296 297 bsize = vp->v_mount->mnt_stat.f_iosize; 298 blk_high = ap->a_offhi / bsize; 299 if (ap->a_offhi % bsize != 0) 300 blk_high++; 301 302 /* 303 * First, flush all pages in range. 304 */ 305 306 mutex_enter(&vp->v_interlock); 307 error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo), 308 round_page(ap->a_offhi), PGO_CLEANIT | 309 ((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0)); 310 if (error) { 311 goto out; 312 } 313 314 #ifdef WAPBL 315 mp = wapbl_vptomp(vp); 316 if (mp->mnt_wapbl) { 317 /* 318 * Don't bother writing out metadata if the syncer is 319 * making the request. We will let the sync vnode 320 * write it out in a single burst through a call to 321 * VFS_SYNC(). 322 */ 323 if ((ap->a_flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) { 324 fstrans_done(vp->v_mount); 325 return 0; 326 } 327 error = 0; 328 if (vp->v_tag == VT_UFS && VTOI(vp)->i_flag & 329 (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY | 330 IN_MODIFIED | IN_ACCESSED)) { 331 error = UFS_WAPBL_BEGIN(mp); 332 if (error) { 333 fstrans_done(vp->v_mount); 334 return error; 335 } 336 error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | 337 ((ap->a_flags & FSYNC_WAIT) ? UPDATE_WAIT : 0)); 338 UFS_WAPBL_END(mp); 339 } 340 if (error || (ap->a_flags & FSYNC_NOLOG) != 0) { 341 fstrans_done(vp->v_mount); 342 return error; 343 } 344 error = wapbl_flush(mp->mnt_wapbl, 0); 345 fstrans_done(vp->v_mount); 346 return error; 347 } 348 #endif /* WAPBL */ 349 350 /* 351 * Then, flush indirect blocks. 352 */ 353 354 if (blk_high >= NDADDR) { 355 error = ufs_getlbns(vp, blk_high, ia, &num); 356 if (error) 357 goto out; 358 359 mutex_enter(&bufcache_lock); 360 for (i = 0; i < num; i++) { 361 if ((bp = incore(vp, ia[i].in_lbn)) == NULL) 362 continue; 363 if ((bp->b_cflags & BC_BUSY) != 0 || 364 (bp->b_oflags & BO_DELWRI) == 0) 365 continue; 366 bp->b_cflags |= BC_BUSY | BC_VFLUSH; 367 mutex_exit(&bufcache_lock); 368 bawrite(bp); 369 mutex_enter(&bufcache_lock); 370 } 371 mutex_exit(&bufcache_lock); 372 } 373 374 if (ap->a_flags & FSYNC_WAIT) { 375 mutex_enter(&vp->v_interlock); 376 while (vp->v_numoutput > 0) 377 cv_wait(&vp->v_cv, &vp->v_interlock); 378 mutex_exit(&vp->v_interlock); 379 } 380 381 error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | 382 (((ap->a_flags & (FSYNC_WAIT | FSYNC_DATAONLY)) == FSYNC_WAIT) 383 ? UPDATE_WAIT : 0)); 384 385 if (error == 0 && ap->a_flags & FSYNC_CACHE) { 386 int l = 0; 387 VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &l, FWRITE, 388 curlwp->l_cred); 389 } 390 391 out: 392 fstrans_done(vp->v_mount); 393 return error; 394 } 395 396 /* 397 * Synch an open file. Called for VOP_FSYNC(). 398 */ 399 /* ARGSUSED */ 400 int 401 ffs_full_fsync(struct vnode *vp, int flags) 402 { 403 struct buf *bp, *nbp; 404 int error, passes, skipmeta, waitfor, i; 405 struct mount *mp; 406 407 KASSERT(VTOI(vp) != NULL); 408 KASSERT(vp->v_tag == VT_UFS); 409 410 error = 0; 411 412 mp = vp->v_mount; 413 if (vp->v_type == VBLK && vp->v_specmountpoint != NULL) { 414 mp = vp->v_specmountpoint; 415 } else { 416 mp = vp->v_mount; 417 } 418 419 /* 420 * Flush all dirty data associated with the vnode. 421 */ 422 if (vp->v_type == VREG || vp->v_type == VBLK) { 423 int pflags = PGO_ALLPAGES | PGO_CLEANIT; 424 425 if ((flags & FSYNC_WAIT)) 426 pflags |= PGO_SYNCIO; 427 if (vp->v_type == VREG && 428 fstrans_getstate(mp) == FSTRANS_SUSPENDING) 429 pflags |= PGO_FREE; 430 mutex_enter(&vp->v_interlock); 431 error = VOP_PUTPAGES(vp, 0, 0, pflags); 432 if (error) 433 return error; 434 } 435 436 #ifdef WAPBL 437 mp = wapbl_vptomp(vp); 438 if (mp && mp->mnt_wapbl) { 439 /* 440 * Don't bother writing out metadata if the syncer is 441 * making the request. We will let the sync vnode 442 * write it out in a single burst through a call to 443 * VFS_SYNC(). 444 */ 445 if ((flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) 446 return 0; 447 448 if ((VTOI(vp)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE 449 | IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) != 0) { 450 error = UFS_WAPBL_BEGIN(mp); 451 if (error) 452 return error; 453 error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | 454 ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0)); 455 UFS_WAPBL_END(mp); 456 } 457 if (error || (flags & FSYNC_NOLOG) != 0) 458 return error; 459 460 /* 461 * Don't flush the log if the vnode being flushed 462 * contains no dirty buffers that could be in the log. 463 */ 464 if (!LIST_EMPTY(&vp->v_dirtyblkhd)) { 465 error = wapbl_flush(mp->mnt_wapbl, 0); 466 if (error) 467 return error; 468 } 469 470 if ((flags & FSYNC_WAIT) != 0) { 471 mutex_enter(&vp->v_interlock); 472 while (vp->v_numoutput != 0) 473 cv_wait(&vp->v_cv, &vp->v_interlock); 474 mutex_exit(&vp->v_interlock); 475 } 476 477 return error; 478 } 479 #endif /* WAPBL */ 480 481 /* 482 * Write out metadata for non-logging file systems. XXX This block 483 * should be simplified now that softdep is gone. 484 */ 485 passes = NIADDR + 1; 486 skipmeta = 0; 487 if (flags & FSYNC_WAIT) 488 skipmeta = 1; 489 490 loop: 491 mutex_enter(&bufcache_lock); 492 LIST_FOREACH(bp, &vp->v_dirtyblkhd, b_vnbufs) { 493 bp->b_cflags &= ~BC_SCANNED; 494 } 495 for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { 496 nbp = LIST_NEXT(bp, b_vnbufs); 497 if (bp->b_cflags & (BC_BUSY | BC_SCANNED)) 498 continue; 499 if ((bp->b_oflags & BO_DELWRI) == 0) 500 panic("ffs_fsync: not dirty"); 501 if (skipmeta && bp->b_lblkno < 0) 502 continue; 503 bp->b_cflags |= BC_BUSY | BC_VFLUSH | BC_SCANNED; 504 mutex_exit(&bufcache_lock); 505 /* 506 * On our final pass through, do all I/O synchronously 507 * so that we can find out if our flush is failing 508 * because of write errors. 509 */ 510 if (passes > 0 || !(flags & FSYNC_WAIT)) 511 (void) bawrite(bp); 512 else if ((error = bwrite(bp)) != 0) 513 return (error); 514 /* 515 * Since we unlocked during the I/O, we need 516 * to start from a known point. 517 */ 518 mutex_enter(&bufcache_lock); 519 nbp = LIST_FIRST(&vp->v_dirtyblkhd); 520 } 521 mutex_exit(&bufcache_lock); 522 if (skipmeta) { 523 skipmeta = 0; 524 goto loop; 525 } 526 527 if ((flags & FSYNC_WAIT) != 0) { 528 mutex_enter(&vp->v_interlock); 529 while (vp->v_numoutput) { 530 cv_wait(&vp->v_cv, &vp->v_interlock); 531 } 532 mutex_exit(&vp->v_interlock); 533 534 /* 535 * Ensure that any filesystem metadata associated 536 * with the vnode has been written. 537 */ 538 if (!LIST_EMPTY(&vp->v_dirtyblkhd)) { 539 /* 540 * Block devices associated with filesystems may 541 * have new I/O requests posted for them even if 542 * the vnode is locked, so no amount of trying will 543 * get them clean. Thus we give block devices a 544 * good effort, then just give up. For all other file 545 * types, go around and try again until it is clean. 546 */ 547 if (passes > 0) { 548 passes--; 549 goto loop; 550 } 551 #ifdef DIAGNOSTIC 552 if (vp->v_type != VBLK) 553 vprint("ffs_fsync: dirty", vp); 554 #endif 555 } 556 } 557 558 waitfor = (flags & FSYNC_WAIT) ? UPDATE_WAIT : 0; 559 error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | waitfor); 560 561 if (error == 0 && (flags & FSYNC_CACHE) != 0) { 562 (void)VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &i, FWRITE, 563 kauth_cred_get()); 564 } 565 566 return error; 567 } 568 569 /* 570 * Reclaim an inode so that it can be used for other purposes. 571 */ 572 int 573 ffs_reclaim(void *v) 574 { 575 struct vop_reclaim_args /* { 576 struct vnode *a_vp; 577 struct lwp *a_l; 578 } */ *ap = v; 579 struct vnode *vp = ap->a_vp; 580 struct inode *ip = VTOI(vp); 581 struct mount *mp = vp->v_mount; 582 struct ufsmount *ump = ip->i_ump; 583 void *data; 584 int error; 585 586 fstrans_start(mp, FSTRANS_LAZY); 587 if ((error = ufs_reclaim(vp)) != 0) { 588 fstrans_done(mp); 589 return (error); 590 } 591 if (ip->i_din.ffs1_din != NULL) { 592 if (ump->um_fstype == UFS1) 593 pool_cache_put(ffs_dinode1_cache, ip->i_din.ffs1_din); 594 else 595 pool_cache_put(ffs_dinode2_cache, ip->i_din.ffs2_din); 596 } 597 /* 598 * To interlock with ffs_sync(). 599 */ 600 genfs_node_destroy(vp); 601 mutex_enter(&vp->v_interlock); 602 data = vp->v_data; 603 vp->v_data = NULL; 604 mutex_exit(&vp->v_interlock); 605 606 /* 607 * XXX MFS ends up here, too, to free an inode. Should we create 608 * XXX a separate pool for MFS inodes? 609 */ 610 pool_cache_put(ffs_inode_cache, data); 611 fstrans_done(mp); 612 return (0); 613 } 614 615 /* 616 * Return the last logical file offset that should be written for this file 617 * if we're doing a write that ends at "size". 618 */ 619 620 void 621 ffs_gop_size(struct vnode *vp, off_t size, off_t *eobp, int flags) 622 { 623 struct inode *ip = VTOI(vp); 624 struct fs *fs = ip->i_fs; 625 daddr_t olbn, nlbn; 626 627 olbn = lblkno(fs, ip->i_size); 628 nlbn = lblkno(fs, size); 629 if (nlbn < NDADDR && olbn <= nlbn) { 630 *eobp = fragroundup(fs, size); 631 } else { 632 *eobp = blkroundup(fs, size); 633 } 634 } 635 636 int 637 ffs_openextattr(void *v) 638 { 639 struct vop_openextattr_args /* { 640 struct vnode *a_vp; 641 kauth_cred_t a_cred; 642 struct proc *a_p; 643 } */ *ap = v; 644 struct inode *ip = VTOI(ap->a_vp); 645 struct fs *fs = ip->i_fs; 646 647 /* Not supported for UFS1 file systems. */ 648 if (fs->fs_magic == FS_UFS1_MAGIC) 649 return (EOPNOTSUPP); 650 651 /* XXX Not implemented for UFS2 file systems. */ 652 return (EOPNOTSUPP); 653 } 654 655 int 656 ffs_closeextattr(void *v) 657 { 658 struct vop_closeextattr_args /* { 659 struct vnode *a_vp; 660 int a_commit; 661 kauth_cred_t a_cred; 662 struct proc *a_p; 663 } */ *ap = v; 664 struct inode *ip = VTOI(ap->a_vp); 665 struct fs *fs = ip->i_fs; 666 667 /* Not supported for UFS1 file systems. */ 668 if (fs->fs_magic == FS_UFS1_MAGIC) 669 return (EOPNOTSUPP); 670 671 /* XXX Not implemented for UFS2 file systems. */ 672 return (EOPNOTSUPP); 673 } 674 675 int 676 ffs_getextattr(void *v) 677 { 678 struct vop_getextattr_args /* { 679 struct vnode *a_vp; 680 int a_attrnamespace; 681 const char *a_name; 682 struct uio *a_uio; 683 size_t *a_size; 684 kauth_cred_t a_cred; 685 struct proc *a_p; 686 } */ *ap = v; 687 struct vnode *vp = ap->a_vp; 688 struct inode *ip = VTOI(vp); 689 struct fs *fs = ip->i_fs; 690 691 if (fs->fs_magic == FS_UFS1_MAGIC) { 692 #ifdef UFS_EXTATTR 693 int error; 694 695 fstrans_start(vp->v_mount, FSTRANS_SHARED); 696 error = ufs_getextattr(ap); 697 fstrans_done(vp->v_mount); 698 return error; 699 #else 700 return (EOPNOTSUPP); 701 #endif 702 } 703 704 /* XXX Not implemented for UFS2 file systems. */ 705 return (EOPNOTSUPP); 706 } 707 708 int 709 ffs_setextattr(void *v) 710 { 711 struct vop_setextattr_args /* { 712 struct vnode *a_vp; 713 int a_attrnamespace; 714 const char *a_name; 715 struct uio *a_uio; 716 kauth_cred_t a_cred; 717 struct proc *a_p; 718 } */ *ap = v; 719 struct vnode *vp = ap->a_vp; 720 struct inode *ip = VTOI(vp); 721 struct fs *fs = ip->i_fs; 722 723 if (fs->fs_magic == FS_UFS1_MAGIC) { 724 #ifdef UFS_EXTATTR 725 int error; 726 727 fstrans_start(vp->v_mount, FSTRANS_SHARED); 728 error = ufs_setextattr(ap); 729 fstrans_done(vp->v_mount); 730 return error; 731 #else 732 return (EOPNOTSUPP); 733 #endif 734 } 735 736 /* XXX Not implemented for UFS2 file systems. */ 737 return (EOPNOTSUPP); 738 } 739 740 int 741 ffs_listextattr(void *v) 742 { 743 struct vop_listextattr_args /* { 744 struct vnode *a_vp; 745 int a_attrnamespace; 746 struct uio *a_uio; 747 size_t *a_size; 748 kauth_cred_t a_cred; 749 struct proc *a_p; 750 } */ *ap = v; 751 struct inode *ip = VTOI(ap->a_vp); 752 struct fs *fs = ip->i_fs; 753 754 /* Not supported for UFS1 file systems. */ 755 if (fs->fs_magic == FS_UFS1_MAGIC) 756 return (EOPNOTSUPP); 757 758 /* XXX Not implemented for UFS2 file systems. */ 759 return (EOPNOTSUPP); 760 } 761 762 int 763 ffs_deleteextattr(void *v) 764 { 765 struct vop_deleteextattr_args /* { 766 struct vnode *a_vp; 767 int a_attrnamespace; 768 kauth_cred_t a_cred; 769 struct proc *a_p; 770 } */ *ap = v; 771 struct vnode *vp = ap->a_vp; 772 struct inode *ip = VTOI(vp); 773 struct fs *fs = ip->i_fs; 774 775 if (fs->fs_magic == FS_UFS1_MAGIC) { 776 #ifdef UFS_EXTATTR 777 int error; 778 779 fstrans_start(vp->v_mount, FSTRANS_SHARED); 780 error = ufs_deleteextattr(ap); 781 fstrans_done(vp->v_mount); 782 return error; 783 #else 784 return (EOPNOTSUPP); 785 #endif 786 } 787 788 /* XXX Not implemented for UFS2 file systems. */ 789 return (EOPNOTSUPP); 790 } 791