1 /* $NetBSD: ffs_vnops.c,v 1.123 2013/06/23 07:28:37 dholland 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.123 2013/06/23 07:28:37 dholland 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_spec_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, vn_fifo_bypass }, /* lookup */ 217 { &vop_create_desc, vn_fifo_bypass }, /* create */ 218 { &vop_mknod_desc, vn_fifo_bypass }, /* mknod */ 219 { &vop_open_desc, vn_fifo_bypass }, /* 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, vn_fifo_bypass }, /* ioctl */ 227 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ 228 { &vop_poll_desc, vn_fifo_bypass }, /* poll */ 229 { &vop_kqfilter_desc, vn_fifo_bypass }, /* kqfilter */ 230 { &vop_revoke_desc, vn_fifo_bypass }, /* revoke */ 231 { &vop_mmap_desc, vn_fifo_bypass }, /* mmap */ 232 { &vop_fsync_desc, ffs_fsync }, /* fsync */ 233 { &vop_seek_desc, vn_fifo_bypass }, /* seek */ 234 { &vop_remove_desc, vn_fifo_bypass }, /* remove */ 235 { &vop_link_desc, vn_fifo_bypass }, /* link */ 236 { &vop_rename_desc, vn_fifo_bypass }, /* rename */ 237 { &vop_mkdir_desc, vn_fifo_bypass }, /* mkdir */ 238 { &vop_rmdir_desc, vn_fifo_bypass }, /* rmdir */ 239 { &vop_symlink_desc, vn_fifo_bypass }, /* symlink */ 240 { &vop_readdir_desc, vn_fifo_bypass }, /* readdir */ 241 { &vop_readlink_desc, vn_fifo_bypass }, /* readlink */ 242 { &vop_abortop_desc, vn_fifo_bypass }, /* 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, vn_fifo_bypass }, /* bmap */ 248 { &vop_strategy_desc, vn_fifo_bypass }, /* strategy */ 249 { &vop_print_desc, ufs_print }, /* print */ 250 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 251 { &vop_pathconf_desc, vn_fifo_bypass }, /* pathconf */ 252 { &vop_advlock_desc, vn_fifo_bypass }, /* advlock */ 253 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 254 { &vop_putpages_desc, vn_fifo_bypass }, /* 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_spec_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 int error, flags, uflags; 280 struct vnode *vp; 281 struct mount *mp; 282 283 flags = ap->a_flags; 284 uflags = UPDATE_CLOSE | ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0); 285 vp = ap->a_vp; 286 mp = vp->v_mount; 287 288 fstrans_start(mp, FSTRANS_LAZY); 289 290 error = spec_fsync(v); 291 if (error) 292 goto out; 293 294 #ifdef WAPBL 295 if (mp && mp->mnt_wapbl) { 296 /* 297 * Don't bother writing out metadata if the syncer is 298 * making the request. We will let the sync vnode 299 * write it out in a single burst through a call to 300 * VFS_SYNC(). 301 */ 302 if ((flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) 303 goto out; 304 if ((VTOI(vp)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE 305 | IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) != 0) { 306 error = UFS_WAPBL_BEGIN(mp); 307 if (error != 0) 308 goto out; 309 error = ffs_update(vp, NULL, NULL, uflags); 310 UFS_WAPBL_END(mp); 311 } 312 goto out; 313 } 314 #endif /* WAPBL */ 315 316 error = ffs_update(vp, NULL, NULL, uflags); 317 318 out: 319 fstrans_done(mp); 320 return error; 321 } 322 323 int 324 ffs_fsync(void *v) 325 { 326 struct vop_fsync_args /* { 327 struct vnode *a_vp; 328 kauth_cred_t a_cred; 329 int a_flags; 330 off_t a_offlo; 331 off_t a_offhi; 332 struct lwp *a_l; 333 } */ *ap = v; 334 struct buf *bp; 335 int num, error, i; 336 struct indir ia[UFS_NIADDR + 1]; 337 int bsize; 338 daddr_t blk_high; 339 struct vnode *vp; 340 struct mount *mp; 341 342 vp = ap->a_vp; 343 mp = vp->v_mount; 344 345 fstrans_start(mp, FSTRANS_LAZY); 346 if ((ap->a_offlo == 0 && ap->a_offhi == 0) || (vp->v_type != VREG)) { 347 error = ffs_full_fsync(vp, ap->a_flags); 348 goto out; 349 } 350 351 bsize = mp->mnt_stat.f_iosize; 352 blk_high = ap->a_offhi / bsize; 353 if (ap->a_offhi % bsize != 0) 354 blk_high++; 355 356 /* 357 * First, flush all pages in range. 358 */ 359 360 mutex_enter(vp->v_interlock); 361 error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo), 362 round_page(ap->a_offhi), PGO_CLEANIT | 363 ((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0)); 364 if (error) { 365 goto out; 366 } 367 368 #ifdef WAPBL 369 KASSERT(vp->v_type == VREG); 370 if (mp->mnt_wapbl) { 371 /* 372 * Don't bother writing out metadata if the syncer is 373 * making the request. We will let the sync vnode 374 * write it out in a single burst through a call to 375 * VFS_SYNC(). 376 */ 377 if ((ap->a_flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) { 378 fstrans_done(mp); 379 return 0; 380 } 381 error = 0; 382 if (vp->v_tag == VT_UFS && VTOI(vp)->i_flag & 383 (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY | 384 IN_MODIFIED | IN_ACCESSED)) { 385 error = UFS_WAPBL_BEGIN(mp); 386 if (error) { 387 fstrans_done(mp); 388 return error; 389 } 390 error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | 391 ((ap->a_flags & FSYNC_WAIT) ? UPDATE_WAIT : 0)); 392 UFS_WAPBL_END(mp); 393 } 394 if (error || (ap->a_flags & FSYNC_NOLOG) != 0) { 395 fstrans_done(mp); 396 return error; 397 } 398 error = wapbl_flush(mp->mnt_wapbl, 0); 399 fstrans_done(mp); 400 return error; 401 } 402 #endif /* WAPBL */ 403 404 /* 405 * Then, flush indirect blocks. 406 */ 407 408 if (blk_high >= UFS_NDADDR) { 409 error = ufs_getlbns(vp, blk_high, ia, &num); 410 if (error) 411 goto out; 412 413 mutex_enter(&bufcache_lock); 414 for (i = 0; i < num; i++) { 415 if ((bp = incore(vp, ia[i].in_lbn)) == NULL) 416 continue; 417 if ((bp->b_cflags & BC_BUSY) != 0 || 418 (bp->b_oflags & BO_DELWRI) == 0) 419 continue; 420 bp->b_cflags |= BC_BUSY | BC_VFLUSH; 421 mutex_exit(&bufcache_lock); 422 bawrite(bp); 423 mutex_enter(&bufcache_lock); 424 } 425 mutex_exit(&bufcache_lock); 426 } 427 428 if (ap->a_flags & FSYNC_WAIT) { 429 mutex_enter(vp->v_interlock); 430 while (vp->v_numoutput > 0) 431 cv_wait(&vp->v_cv, vp->v_interlock); 432 mutex_exit(vp->v_interlock); 433 } 434 435 error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | 436 (((ap->a_flags & (FSYNC_WAIT | FSYNC_DATAONLY)) == FSYNC_WAIT) 437 ? UPDATE_WAIT : 0)); 438 439 if (error == 0 && ap->a_flags & FSYNC_CACHE) { 440 int l = 0; 441 VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &l, FWRITE, 442 curlwp->l_cred); 443 } 444 445 out: 446 fstrans_done(mp); 447 return error; 448 } 449 450 /* 451 * Synch an open file. Called for VOP_FSYNC(). 452 */ 453 /* ARGSUSED */ 454 int 455 ffs_full_fsync(struct vnode *vp, int flags) 456 { 457 int error, i, uflags; 458 459 KASSERT(vp->v_tag == VT_UFS); 460 KASSERT(VTOI(vp) != NULL); 461 KASSERT(vp->v_type != VCHR && vp->v_type != VBLK); 462 463 uflags = UPDATE_CLOSE | ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0); 464 465 #ifdef WAPBL 466 struct mount *mp = vp->v_mount; 467 if (mp && mp->mnt_wapbl) { 468 469 /* 470 * Flush all dirty data associated with the vnode. 471 */ 472 if (vp->v_type == VREG) { 473 int pflags = PGO_ALLPAGES | PGO_CLEANIT; 474 475 if ((flags & FSYNC_LAZY)) 476 pflags |= PGO_LAZY; 477 if ((flags & FSYNC_WAIT)) 478 pflags |= PGO_SYNCIO; 479 if (fstrans_getstate(mp) == FSTRANS_SUSPENDING) 480 pflags |= PGO_FREE; 481 mutex_enter(vp->v_interlock); 482 error = VOP_PUTPAGES(vp, 0, 0, pflags); 483 if (error) 484 return error; 485 } 486 487 /* 488 * Don't bother writing out metadata if the syncer is 489 * making the request. We will let the sync vnode 490 * write it out in a single burst through a call to 491 * VFS_SYNC(). 492 */ 493 if ((flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) 494 return 0; 495 496 if ((VTOI(vp)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE 497 | IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) != 0) { 498 error = UFS_WAPBL_BEGIN(mp); 499 if (error) 500 return error; 501 error = ffs_update(vp, NULL, NULL, uflags); 502 UFS_WAPBL_END(mp); 503 } else { 504 error = 0; 505 } 506 if (error || (flags & FSYNC_NOLOG) != 0) 507 return error; 508 509 /* 510 * Don't flush the log if the vnode being flushed 511 * contains no dirty buffers that could be in the log. 512 */ 513 if (!LIST_EMPTY(&vp->v_dirtyblkhd)) { 514 error = wapbl_flush(mp->mnt_wapbl, 0); 515 if (error) 516 return error; 517 } 518 519 if ((flags & FSYNC_WAIT) != 0) { 520 mutex_enter(vp->v_interlock); 521 while (vp->v_numoutput != 0) 522 cv_wait(&vp->v_cv, vp->v_interlock); 523 mutex_exit(vp->v_interlock); 524 } 525 526 return error; 527 } 528 #endif /* WAPBL */ 529 530 error = vflushbuf(vp, flags); 531 if (error == 0) 532 error = ffs_update(vp, NULL, NULL, uflags); 533 if (error == 0 && (flags & FSYNC_CACHE) != 0) { 534 i = 1; 535 (void)VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &i, FWRITE, 536 kauth_cred_get()); 537 } 538 539 return error; 540 } 541 542 /* 543 * Reclaim an inode so that it can be used for other purposes. 544 */ 545 int 546 ffs_reclaim(void *v) 547 { 548 struct vop_reclaim_args /* { 549 struct vnode *a_vp; 550 struct lwp *a_l; 551 } */ *ap = v; 552 struct vnode *vp = ap->a_vp; 553 struct inode *ip = VTOI(vp); 554 struct mount *mp = vp->v_mount; 555 struct ufsmount *ump = ip->i_ump; 556 void *data; 557 int error; 558 559 fstrans_start(mp, FSTRANS_LAZY); 560 /* 561 * The inode must be freed and updated before being removed 562 * from its hash chain. Other threads trying to gain a hold 563 * on the inode will be stalled because it is locked (VI_XLOCK). 564 */ 565 error = UFS_WAPBL_BEGIN(mp); 566 if (error) { 567 fstrans_done(mp); 568 return error; 569 } 570 if (ip->i_nlink <= 0 && ip->i_omode != 0 && 571 (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 572 ffs_vfree(vp, ip->i_number, ip->i_omode); 573 UFS_WAPBL_END(mp); 574 if ((error = ufs_reclaim(vp)) != 0) { 575 fstrans_done(mp); 576 return (error); 577 } 578 if (ip->i_din.ffs1_din != NULL) { 579 if (ump->um_fstype == UFS1) 580 pool_cache_put(ffs_dinode1_cache, ip->i_din.ffs1_din); 581 else 582 pool_cache_put(ffs_dinode2_cache, ip->i_din.ffs2_din); 583 } 584 /* 585 * To interlock with ffs_sync(). 586 */ 587 genfs_node_destroy(vp); 588 mutex_enter(vp->v_interlock); 589 data = vp->v_data; 590 vp->v_data = NULL; 591 mutex_exit(vp->v_interlock); 592 593 /* 594 * XXX MFS ends up here, too, to free an inode. Should we create 595 * XXX a separate pool for MFS inodes? 596 */ 597 pool_cache_put(ffs_inode_cache, data); 598 fstrans_done(mp); 599 return (0); 600 } 601 602 /* 603 * Return the last logical file offset that should be written for this file 604 * if we're doing a write that ends at "size". 605 */ 606 607 void 608 ffs_gop_size(struct vnode *vp, off_t size, off_t *eobp, int flags) 609 { 610 struct inode *ip = VTOI(vp); 611 struct fs *fs = ip->i_fs; 612 daddr_t olbn, nlbn; 613 614 olbn = ffs_lblkno(fs, ip->i_size); 615 nlbn = ffs_lblkno(fs, size); 616 if (nlbn < UFS_NDADDR && olbn <= nlbn) { 617 *eobp = ffs_fragroundup(fs, size); 618 } else { 619 *eobp = ffs_blkroundup(fs, size); 620 } 621 } 622 623 int 624 ffs_openextattr(void *v) 625 { 626 struct vop_openextattr_args /* { 627 struct vnode *a_vp; 628 kauth_cred_t a_cred; 629 struct proc *a_p; 630 } */ *ap = v; 631 struct inode *ip = VTOI(ap->a_vp); 632 struct fs *fs = ip->i_fs; 633 634 /* Not supported for UFS1 file systems. */ 635 if (fs->fs_magic == FS_UFS1_MAGIC) 636 return (EOPNOTSUPP); 637 638 /* XXX Not implemented for UFS2 file systems. */ 639 return (EOPNOTSUPP); 640 } 641 642 int 643 ffs_closeextattr(void *v) 644 { 645 struct vop_closeextattr_args /* { 646 struct vnode *a_vp; 647 int a_commit; 648 kauth_cred_t a_cred; 649 struct proc *a_p; 650 } */ *ap = v; 651 struct inode *ip = VTOI(ap->a_vp); 652 struct fs *fs = ip->i_fs; 653 654 /* Not supported for UFS1 file systems. */ 655 if (fs->fs_magic == FS_UFS1_MAGIC) 656 return (EOPNOTSUPP); 657 658 /* XXX Not implemented for UFS2 file systems. */ 659 return (EOPNOTSUPP); 660 } 661 662 int 663 ffs_getextattr(void *v) 664 { 665 struct vop_getextattr_args /* { 666 struct vnode *a_vp; 667 int a_attrnamespace; 668 const char *a_name; 669 struct uio *a_uio; 670 size_t *a_size; 671 kauth_cred_t a_cred; 672 struct proc *a_p; 673 } */ *ap = v; 674 struct vnode *vp = ap->a_vp; 675 struct inode *ip = VTOI(vp); 676 struct fs *fs = ip->i_fs; 677 678 if (fs->fs_magic == FS_UFS1_MAGIC) { 679 #ifdef UFS_EXTATTR 680 int error; 681 682 fstrans_start(vp->v_mount, FSTRANS_SHARED); 683 error = ufs_getextattr(ap); 684 fstrans_done(vp->v_mount); 685 return error; 686 #else 687 return (EOPNOTSUPP); 688 #endif 689 } 690 691 /* XXX Not implemented for UFS2 file systems. */ 692 return (EOPNOTSUPP); 693 } 694 695 int 696 ffs_setextattr(void *v) 697 { 698 struct vop_setextattr_args /* { 699 struct vnode *a_vp; 700 int a_attrnamespace; 701 const char *a_name; 702 struct uio *a_uio; 703 kauth_cred_t a_cred; 704 struct proc *a_p; 705 } */ *ap = v; 706 struct vnode *vp = ap->a_vp; 707 struct inode *ip = VTOI(vp); 708 struct fs *fs = ip->i_fs; 709 710 if (fs->fs_magic == FS_UFS1_MAGIC) { 711 #ifdef UFS_EXTATTR 712 int error; 713 714 fstrans_start(vp->v_mount, FSTRANS_SHARED); 715 error = ufs_setextattr(ap); 716 fstrans_done(vp->v_mount); 717 return error; 718 #else 719 return (EOPNOTSUPP); 720 #endif 721 } 722 723 /* XXX Not implemented for UFS2 file systems. */ 724 return (EOPNOTSUPP); 725 } 726 727 int 728 ffs_listextattr(void *v) 729 { 730 struct vop_listextattr_args /* { 731 struct vnode *a_vp; 732 int a_attrnamespace; 733 struct uio *a_uio; 734 size_t *a_size; 735 kauth_cred_t a_cred; 736 struct proc *a_p; 737 } */ *ap = v; 738 struct inode *ip = VTOI(ap->a_vp); 739 struct fs *fs = ip->i_fs; 740 741 if (fs->fs_magic == FS_UFS1_MAGIC) { 742 #ifdef UFS_EXTATTR 743 struct vnode *vp = ap->a_vp; 744 int error; 745 746 fstrans_start(vp->v_mount, FSTRANS_SHARED); 747 error = ufs_listextattr(ap); 748 fstrans_done(vp->v_mount); 749 return error; 750 #else 751 return (EOPNOTSUPP); 752 #endif 753 } 754 755 /* XXX Not implemented for UFS2 file systems. */ 756 return (EOPNOTSUPP); 757 } 758 759 int 760 ffs_deleteextattr(void *v) 761 { 762 struct vop_deleteextattr_args /* { 763 struct vnode *a_vp; 764 int a_attrnamespace; 765 kauth_cred_t a_cred; 766 struct proc *a_p; 767 } */ *ap = v; 768 struct vnode *vp = ap->a_vp; 769 struct inode *ip = VTOI(vp); 770 struct fs *fs = ip->i_fs; 771 772 if (fs->fs_magic == FS_UFS1_MAGIC) { 773 #ifdef UFS_EXTATTR 774 int error; 775 776 fstrans_start(vp->v_mount, FSTRANS_SHARED); 777 error = ufs_deleteextattr(ap); 778 fstrans_done(vp->v_mount); 779 return error; 780 #else 781 return (EOPNOTSUPP); 782 #endif 783 } 784 785 /* XXX Not implemented for UFS2 file systems. */ 786 return (EOPNOTSUPP); 787 } 788