1 /* $NetBSD: ffs_vnops.c,v 1.125 2014/07/25 08:20:53 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.125 2014/07/25 08:20:53 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_fallocate_desc, genfs_eopnotsupp }, /* fallocate */ 119 { &vop_fdiscard_desc, genfs_eopnotsupp }, /* fdiscard */ 120 { &vop_ioctl_desc, ufs_ioctl }, /* ioctl */ 121 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ 122 { &vop_poll_desc, ufs_poll }, /* poll */ 123 { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */ 124 { &vop_revoke_desc, ufs_revoke }, /* revoke */ 125 { &vop_mmap_desc, ufs_mmap }, /* mmap */ 126 { &vop_fsync_desc, ffs_fsync }, /* fsync */ 127 { &vop_seek_desc, ufs_seek }, /* seek */ 128 { &vop_remove_desc, ufs_remove }, /* remove */ 129 { &vop_link_desc, ufs_link }, /* link */ 130 { &vop_rename_desc, ufs_rename }, /* rename */ 131 { &vop_mkdir_desc, ufs_mkdir }, /* mkdir */ 132 { &vop_rmdir_desc, ufs_rmdir }, /* rmdir */ 133 { &vop_symlink_desc, ufs_symlink }, /* symlink */ 134 { &vop_readdir_desc, ufs_readdir }, /* readdir */ 135 { &vop_readlink_desc, ufs_readlink }, /* readlink */ 136 { &vop_abortop_desc, ufs_abortop }, /* abortop */ 137 { &vop_inactive_desc, ufs_inactive }, /* inactive */ 138 { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ 139 { &vop_lock_desc, ufs_lock }, /* lock */ 140 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 141 { &vop_bmap_desc, ufs_bmap }, /* bmap */ 142 { &vop_strategy_desc, ufs_strategy }, /* strategy */ 143 { &vop_print_desc, ufs_print }, /* print */ 144 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 145 { &vop_pathconf_desc, ufs_pathconf }, /* pathconf */ 146 { &vop_advlock_desc, ufs_advlock }, /* advlock */ 147 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 148 { &vop_getpages_desc, genfs_getpages }, /* getpages */ 149 { &vop_putpages_desc, genfs_putpages }, /* putpages */ 150 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ 151 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ 152 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ 153 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ 154 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ 155 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ 156 { NULL, NULL } 157 }; 158 const struct vnodeopv_desc ffs_vnodeop_opv_desc = 159 { &ffs_vnodeop_p, ffs_vnodeop_entries }; 160 161 int (**ffs_specop_p)(void *); 162 const struct vnodeopv_entry_desc ffs_specop_entries[] = { 163 { &vop_default_desc, vn_default_error }, 164 { &vop_lookup_desc, spec_lookup }, /* lookup */ 165 { &vop_create_desc, spec_create }, /* create */ 166 { &vop_mknod_desc, spec_mknod }, /* mknod */ 167 { &vop_open_desc, spec_open }, /* open */ 168 { &vop_close_desc, ufsspec_close }, /* close */ 169 { &vop_access_desc, ufs_access }, /* access */ 170 { &vop_getattr_desc, ufs_getattr }, /* getattr */ 171 { &vop_setattr_desc, ufs_setattr }, /* setattr */ 172 { &vop_read_desc, ufsspec_read }, /* read */ 173 { &vop_write_desc, ufsspec_write }, /* write */ 174 { &vop_fallocate_desc, spec_fallocate }, /* fallocate */ 175 { &vop_fdiscard_desc, spec_fdiscard }, /* fdiscard */ 176 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 177 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ 178 { &vop_poll_desc, spec_poll }, /* poll */ 179 { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */ 180 { &vop_revoke_desc, spec_revoke }, /* revoke */ 181 { &vop_mmap_desc, spec_mmap }, /* mmap */ 182 { &vop_fsync_desc, ffs_spec_fsync }, /* fsync */ 183 { &vop_seek_desc, spec_seek }, /* seek */ 184 { &vop_remove_desc, spec_remove }, /* remove */ 185 { &vop_link_desc, spec_link }, /* link */ 186 { &vop_rename_desc, spec_rename }, /* rename */ 187 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 188 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 189 { &vop_symlink_desc, spec_symlink }, /* symlink */ 190 { &vop_readdir_desc, spec_readdir }, /* readdir */ 191 { &vop_readlink_desc, spec_readlink }, /* readlink */ 192 { &vop_abortop_desc, spec_abortop }, /* abortop */ 193 { &vop_inactive_desc, ufs_inactive }, /* inactive */ 194 { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ 195 { &vop_lock_desc, ufs_lock }, /* lock */ 196 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 197 { &vop_bmap_desc, spec_bmap }, /* bmap */ 198 { &vop_strategy_desc, spec_strategy }, /* strategy */ 199 { &vop_print_desc, ufs_print }, /* print */ 200 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 201 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 202 { &vop_advlock_desc, spec_advlock }, /* advlock */ 203 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 204 { &vop_getpages_desc, spec_getpages }, /* getpages */ 205 { &vop_putpages_desc, spec_putpages }, /* putpages */ 206 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ 207 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ 208 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ 209 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ 210 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ 211 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ 212 { NULL, NULL } 213 }; 214 const struct vnodeopv_desc ffs_specop_opv_desc = 215 { &ffs_specop_p, ffs_specop_entries }; 216 217 int (**ffs_fifoop_p)(void *); 218 const struct vnodeopv_entry_desc ffs_fifoop_entries[] = { 219 { &vop_default_desc, vn_default_error }, 220 { &vop_lookup_desc, vn_fifo_bypass }, /* lookup */ 221 { &vop_create_desc, vn_fifo_bypass }, /* create */ 222 { &vop_mknod_desc, vn_fifo_bypass }, /* mknod */ 223 { &vop_open_desc, vn_fifo_bypass }, /* open */ 224 { &vop_close_desc, ufsfifo_close }, /* close */ 225 { &vop_access_desc, ufs_access }, /* access */ 226 { &vop_getattr_desc, ufs_getattr }, /* getattr */ 227 { &vop_setattr_desc, ufs_setattr }, /* setattr */ 228 { &vop_read_desc, ufsfifo_read }, /* read */ 229 { &vop_write_desc, ufsfifo_write }, /* write */ 230 { &vop_fallocate_desc, vn_fifo_bypass }, /* fallocate */ 231 { &vop_fdiscard_desc, vn_fifo_bypass }, /* fdiscard */ 232 { &vop_ioctl_desc, vn_fifo_bypass }, /* ioctl */ 233 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ 234 { &vop_poll_desc, vn_fifo_bypass }, /* poll */ 235 { &vop_kqfilter_desc, vn_fifo_bypass }, /* kqfilter */ 236 { &vop_revoke_desc, vn_fifo_bypass }, /* revoke */ 237 { &vop_mmap_desc, vn_fifo_bypass }, /* mmap */ 238 { &vop_fsync_desc, ffs_fsync }, /* fsync */ 239 { &vop_seek_desc, vn_fifo_bypass }, /* seek */ 240 { &vop_remove_desc, vn_fifo_bypass }, /* remove */ 241 { &vop_link_desc, vn_fifo_bypass }, /* link */ 242 { &vop_rename_desc, vn_fifo_bypass }, /* rename */ 243 { &vop_mkdir_desc, vn_fifo_bypass }, /* mkdir */ 244 { &vop_rmdir_desc, vn_fifo_bypass }, /* rmdir */ 245 { &vop_symlink_desc, vn_fifo_bypass }, /* symlink */ 246 { &vop_readdir_desc, vn_fifo_bypass }, /* readdir */ 247 { &vop_readlink_desc, vn_fifo_bypass }, /* readlink */ 248 { &vop_abortop_desc, vn_fifo_bypass }, /* abortop */ 249 { &vop_inactive_desc, ufs_inactive }, /* inactive */ 250 { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ 251 { &vop_lock_desc, ufs_lock }, /* lock */ 252 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 253 { &vop_bmap_desc, vn_fifo_bypass }, /* bmap */ 254 { &vop_strategy_desc, vn_fifo_bypass }, /* strategy */ 255 { &vop_print_desc, ufs_print }, /* print */ 256 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 257 { &vop_pathconf_desc, vn_fifo_bypass }, /* pathconf */ 258 { &vop_advlock_desc, vn_fifo_bypass }, /* advlock */ 259 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 260 { &vop_putpages_desc, vn_fifo_bypass }, /* putpages */ 261 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ 262 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ 263 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ 264 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ 265 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ 266 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ 267 { NULL, NULL } 268 }; 269 const struct vnodeopv_desc ffs_fifoop_opv_desc = 270 { &ffs_fifoop_p, ffs_fifoop_entries }; 271 272 #include <ufs/ufs/ufs_readwrite.c> 273 274 int 275 ffs_spec_fsync(void *v) 276 { 277 struct vop_fsync_args /* { 278 struct vnode *a_vp; 279 kauth_cred_t a_cred; 280 int a_flags; 281 off_t a_offlo; 282 off_t a_offhi; 283 struct lwp *a_l; 284 } */ *ap = v; 285 int error, flags, uflags; 286 struct vnode *vp; 287 struct mount *mp; 288 289 flags = ap->a_flags; 290 uflags = UPDATE_CLOSE | ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0); 291 vp = ap->a_vp; 292 mp = vp->v_mount; 293 294 fstrans_start(mp, FSTRANS_LAZY); 295 296 error = spec_fsync(v); 297 if (error) 298 goto out; 299 300 #ifdef WAPBL 301 if (mp && mp->mnt_wapbl) { 302 /* 303 * Don't bother writing out metadata if the syncer is 304 * making the request. We will let the sync vnode 305 * write it out in a single burst through a call to 306 * VFS_SYNC(). 307 */ 308 if ((flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) 309 goto out; 310 if ((VTOI(vp)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE 311 | IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) != 0) { 312 error = UFS_WAPBL_BEGIN(mp); 313 if (error != 0) 314 goto out; 315 error = ffs_update(vp, NULL, NULL, uflags); 316 UFS_WAPBL_END(mp); 317 } 318 goto out; 319 } 320 #endif /* WAPBL */ 321 322 error = ffs_update(vp, NULL, NULL, uflags); 323 324 out: 325 fstrans_done(mp); 326 return error; 327 } 328 329 int 330 ffs_fsync(void *v) 331 { 332 struct vop_fsync_args /* { 333 struct vnode *a_vp; 334 kauth_cred_t a_cred; 335 int a_flags; 336 off_t a_offlo; 337 off_t a_offhi; 338 struct lwp *a_l; 339 } */ *ap = v; 340 struct buf *bp; 341 int num, error, i; 342 struct indir ia[UFS_NIADDR + 1]; 343 int bsize; 344 daddr_t blk_high; 345 struct vnode *vp; 346 struct mount *mp; 347 348 vp = ap->a_vp; 349 mp = vp->v_mount; 350 351 fstrans_start(mp, FSTRANS_LAZY); 352 if ((ap->a_offlo == 0 && ap->a_offhi == 0) || (vp->v_type != VREG)) { 353 error = ffs_full_fsync(vp, ap->a_flags); 354 goto out; 355 } 356 357 bsize = mp->mnt_stat.f_iosize; 358 blk_high = ap->a_offhi / bsize; 359 if (ap->a_offhi % bsize != 0) 360 blk_high++; 361 362 /* 363 * First, flush all pages in range. 364 */ 365 366 mutex_enter(vp->v_interlock); 367 error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo), 368 round_page(ap->a_offhi), PGO_CLEANIT | 369 ((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0)); 370 if (error) { 371 goto out; 372 } 373 374 #ifdef WAPBL 375 KASSERT(vp->v_type == VREG); 376 if (mp->mnt_wapbl) { 377 /* 378 * Don't bother writing out metadata if the syncer is 379 * making the request. We will let the sync vnode 380 * write it out in a single burst through a call to 381 * VFS_SYNC(). 382 */ 383 if ((ap->a_flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) { 384 fstrans_done(mp); 385 return 0; 386 } 387 error = 0; 388 if (vp->v_tag == VT_UFS && VTOI(vp)->i_flag & 389 (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY | 390 IN_MODIFIED | IN_ACCESSED)) { 391 error = UFS_WAPBL_BEGIN(mp); 392 if (error) { 393 fstrans_done(mp); 394 return error; 395 } 396 error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | 397 ((ap->a_flags & FSYNC_WAIT) ? UPDATE_WAIT : 0)); 398 UFS_WAPBL_END(mp); 399 } 400 if (error || (ap->a_flags & FSYNC_NOLOG) != 0) { 401 fstrans_done(mp); 402 return error; 403 } 404 error = wapbl_flush(mp->mnt_wapbl, 0); 405 fstrans_done(mp); 406 return error; 407 } 408 #endif /* WAPBL */ 409 410 /* 411 * Then, flush indirect blocks. 412 */ 413 414 if (blk_high >= UFS_NDADDR) { 415 error = ufs_getlbns(vp, blk_high, ia, &num); 416 if (error) 417 goto out; 418 419 mutex_enter(&bufcache_lock); 420 for (i = 0; i < num; i++) { 421 if ((bp = incore(vp, ia[i].in_lbn)) == NULL) 422 continue; 423 if ((bp->b_cflags & BC_BUSY) != 0 || 424 (bp->b_oflags & BO_DELWRI) == 0) 425 continue; 426 bp->b_cflags |= BC_BUSY | BC_VFLUSH; 427 mutex_exit(&bufcache_lock); 428 bawrite(bp); 429 mutex_enter(&bufcache_lock); 430 } 431 mutex_exit(&bufcache_lock); 432 } 433 434 if (ap->a_flags & FSYNC_WAIT) { 435 mutex_enter(vp->v_interlock); 436 while (vp->v_numoutput > 0) 437 cv_wait(&vp->v_cv, vp->v_interlock); 438 mutex_exit(vp->v_interlock); 439 } 440 441 error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | 442 (((ap->a_flags & (FSYNC_WAIT | FSYNC_DATAONLY)) == FSYNC_WAIT) 443 ? UPDATE_WAIT : 0)); 444 445 if (error == 0 && ap->a_flags & FSYNC_CACHE) { 446 int l = 0; 447 VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &l, FWRITE, 448 curlwp->l_cred); 449 } 450 451 out: 452 fstrans_done(mp); 453 return error; 454 } 455 456 /* 457 * Synch an open file. Called for VOP_FSYNC(). 458 */ 459 /* ARGSUSED */ 460 int 461 ffs_full_fsync(struct vnode *vp, int flags) 462 { 463 int error, i, uflags; 464 465 KASSERT(vp->v_tag == VT_UFS); 466 KASSERT(VTOI(vp) != NULL); 467 KASSERT(vp->v_type != VCHR && vp->v_type != VBLK); 468 469 uflags = UPDATE_CLOSE | ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0); 470 471 #ifdef WAPBL 472 struct mount *mp = vp->v_mount; 473 if (mp && mp->mnt_wapbl) { 474 475 /* 476 * Flush all dirty data associated with the vnode. 477 */ 478 if (vp->v_type == VREG) { 479 int pflags = PGO_ALLPAGES | PGO_CLEANIT; 480 481 if ((flags & FSYNC_LAZY)) 482 pflags |= PGO_LAZY; 483 if ((flags & FSYNC_WAIT)) 484 pflags |= PGO_SYNCIO; 485 if (fstrans_getstate(mp) == FSTRANS_SUSPENDING) 486 pflags |= PGO_FREE; 487 mutex_enter(vp->v_interlock); 488 error = VOP_PUTPAGES(vp, 0, 0, pflags); 489 if (error) 490 return error; 491 } 492 493 /* 494 * Don't bother writing out metadata if the syncer is 495 * making the request. We will let the sync vnode 496 * write it out in a single burst through a call to 497 * VFS_SYNC(). 498 */ 499 if ((flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) 500 return 0; 501 502 if ((VTOI(vp)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE 503 | IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) != 0) { 504 error = UFS_WAPBL_BEGIN(mp); 505 if (error) 506 return error; 507 error = ffs_update(vp, NULL, NULL, uflags); 508 UFS_WAPBL_END(mp); 509 } else { 510 error = 0; 511 } 512 if (error || (flags & FSYNC_NOLOG) != 0) 513 return error; 514 515 /* 516 * Don't flush the log if the vnode being flushed 517 * contains no dirty buffers that could be in the log. 518 */ 519 if (!LIST_EMPTY(&vp->v_dirtyblkhd)) { 520 error = wapbl_flush(mp->mnt_wapbl, 0); 521 if (error) 522 return error; 523 } 524 525 if ((flags & FSYNC_WAIT) != 0) { 526 mutex_enter(vp->v_interlock); 527 while (vp->v_numoutput != 0) 528 cv_wait(&vp->v_cv, vp->v_interlock); 529 mutex_exit(vp->v_interlock); 530 } 531 532 return error; 533 } 534 #endif /* WAPBL */ 535 536 error = vflushbuf(vp, flags); 537 if (error == 0) 538 error = ffs_update(vp, NULL, NULL, uflags); 539 if (error == 0 && (flags & FSYNC_CACHE) != 0) { 540 i = 1; 541 (void)VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &i, FWRITE, 542 kauth_cred_get()); 543 } 544 545 return error; 546 } 547 548 /* 549 * Reclaim an inode so that it can be used for other purposes. 550 */ 551 int 552 ffs_reclaim(void *v) 553 { 554 struct vop_reclaim_args /* { 555 struct vnode *a_vp; 556 struct lwp *a_l; 557 } */ *ap = v; 558 struct vnode *vp = ap->a_vp; 559 struct inode *ip = VTOI(vp); 560 struct mount *mp = vp->v_mount; 561 struct ufsmount *ump = ip->i_ump; 562 void *data; 563 int error; 564 565 fstrans_start(mp, FSTRANS_LAZY); 566 /* 567 * The inode must be freed and updated before being removed 568 * from its hash chain. Other threads trying to gain a hold 569 * or lock on the inode will be stalled. 570 */ 571 error = UFS_WAPBL_BEGIN(mp); 572 if (error) { 573 fstrans_done(mp); 574 return error; 575 } 576 if (ip->i_nlink <= 0 && ip->i_omode != 0 && 577 (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 578 ffs_vfree(vp, ip->i_number, ip->i_omode); 579 UFS_WAPBL_END(mp); 580 if ((error = ufs_reclaim(vp)) != 0) { 581 fstrans_done(mp); 582 return (error); 583 } 584 if (ip->i_din.ffs1_din != NULL) { 585 if (ump->um_fstype == UFS1) 586 pool_cache_put(ffs_dinode1_cache, ip->i_din.ffs1_din); 587 else 588 pool_cache_put(ffs_dinode2_cache, ip->i_din.ffs2_din); 589 } 590 /* 591 * To interlock with ffs_sync(). 592 */ 593 genfs_node_destroy(vp); 594 mutex_enter(vp->v_interlock); 595 data = vp->v_data; 596 vp->v_data = NULL; 597 mutex_exit(vp->v_interlock); 598 599 /* 600 * XXX MFS ends up here, too, to free an inode. Should we create 601 * XXX a separate pool for MFS inodes? 602 */ 603 pool_cache_put(ffs_inode_cache, data); 604 fstrans_done(mp); 605 return (0); 606 } 607 608 /* 609 * Return the last logical file offset that should be written for this file 610 * if we're doing a write that ends at "size". 611 */ 612 613 void 614 ffs_gop_size(struct vnode *vp, off_t size, off_t *eobp, int flags) 615 { 616 struct inode *ip = VTOI(vp); 617 struct fs *fs = ip->i_fs; 618 daddr_t olbn, nlbn; 619 620 olbn = ffs_lblkno(fs, ip->i_size); 621 nlbn = ffs_lblkno(fs, size); 622 if (nlbn < UFS_NDADDR && olbn <= nlbn) { 623 *eobp = ffs_fragroundup(fs, size); 624 } else { 625 *eobp = ffs_blkroundup(fs, size); 626 } 627 } 628 629 int 630 ffs_openextattr(void *v) 631 { 632 struct vop_openextattr_args /* { 633 struct vnode *a_vp; 634 kauth_cred_t a_cred; 635 struct proc *a_p; 636 } */ *ap = v; 637 struct inode *ip = VTOI(ap->a_vp); 638 struct fs *fs = ip->i_fs; 639 640 /* Not supported for UFS1 file systems. */ 641 if (fs->fs_magic == FS_UFS1_MAGIC) 642 return (EOPNOTSUPP); 643 644 /* XXX Not implemented for UFS2 file systems. */ 645 return (EOPNOTSUPP); 646 } 647 648 int 649 ffs_closeextattr(void *v) 650 { 651 struct vop_closeextattr_args /* { 652 struct vnode *a_vp; 653 int a_commit; 654 kauth_cred_t a_cred; 655 struct proc *a_p; 656 } */ *ap = v; 657 struct inode *ip = VTOI(ap->a_vp); 658 struct fs *fs = ip->i_fs; 659 660 /* Not supported for UFS1 file systems. */ 661 if (fs->fs_magic == FS_UFS1_MAGIC) 662 return (EOPNOTSUPP); 663 664 /* XXX Not implemented for UFS2 file systems. */ 665 return (EOPNOTSUPP); 666 } 667 668 int 669 ffs_getextattr(void *v) 670 { 671 struct vop_getextattr_args /* { 672 struct vnode *a_vp; 673 int a_attrnamespace; 674 const char *a_name; 675 struct uio *a_uio; 676 size_t *a_size; 677 kauth_cred_t a_cred; 678 struct proc *a_p; 679 } */ *ap = v; 680 struct vnode *vp = ap->a_vp; 681 struct inode *ip = VTOI(vp); 682 struct fs *fs = ip->i_fs; 683 684 if (fs->fs_magic == FS_UFS1_MAGIC) { 685 #ifdef UFS_EXTATTR 686 int error; 687 688 fstrans_start(vp->v_mount, FSTRANS_SHARED); 689 error = ufs_getextattr(ap); 690 fstrans_done(vp->v_mount); 691 return error; 692 #else 693 return (EOPNOTSUPP); 694 #endif 695 } 696 697 /* XXX Not implemented for UFS2 file systems. */ 698 return (EOPNOTSUPP); 699 } 700 701 int 702 ffs_setextattr(void *v) 703 { 704 struct vop_setextattr_args /* { 705 struct vnode *a_vp; 706 int a_attrnamespace; 707 const char *a_name; 708 struct uio *a_uio; 709 kauth_cred_t a_cred; 710 struct proc *a_p; 711 } */ *ap = v; 712 struct vnode *vp = ap->a_vp; 713 struct inode *ip = VTOI(vp); 714 struct fs *fs = ip->i_fs; 715 716 if (fs->fs_magic == FS_UFS1_MAGIC) { 717 #ifdef UFS_EXTATTR 718 int error; 719 720 fstrans_start(vp->v_mount, FSTRANS_SHARED); 721 error = ufs_setextattr(ap); 722 fstrans_done(vp->v_mount); 723 return error; 724 #else 725 return (EOPNOTSUPP); 726 #endif 727 } 728 729 /* XXX Not implemented for UFS2 file systems. */ 730 return (EOPNOTSUPP); 731 } 732 733 int 734 ffs_listextattr(void *v) 735 { 736 struct vop_listextattr_args /* { 737 struct vnode *a_vp; 738 int a_attrnamespace; 739 struct uio *a_uio; 740 size_t *a_size; 741 kauth_cred_t a_cred; 742 struct proc *a_p; 743 } */ *ap = v; 744 struct inode *ip = VTOI(ap->a_vp); 745 struct fs *fs = ip->i_fs; 746 747 if (fs->fs_magic == FS_UFS1_MAGIC) { 748 #ifdef UFS_EXTATTR 749 struct vnode *vp = ap->a_vp; 750 int error; 751 752 fstrans_start(vp->v_mount, FSTRANS_SHARED); 753 error = ufs_listextattr(ap); 754 fstrans_done(vp->v_mount); 755 return error; 756 #else 757 return (EOPNOTSUPP); 758 #endif 759 } 760 761 /* XXX Not implemented for UFS2 file systems. */ 762 return (EOPNOTSUPP); 763 } 764 765 int 766 ffs_deleteextattr(void *v) 767 { 768 struct vop_deleteextattr_args /* { 769 struct vnode *a_vp; 770 int a_attrnamespace; 771 kauth_cred_t a_cred; 772 struct proc *a_p; 773 } */ *ap = v; 774 struct vnode *vp = ap->a_vp; 775 struct inode *ip = VTOI(vp); 776 struct fs *fs = ip->i_fs; 777 778 if (fs->fs_magic == FS_UFS1_MAGIC) { 779 #ifdef UFS_EXTATTR 780 int error; 781 782 fstrans_start(vp->v_mount, FSTRANS_SHARED); 783 error = ufs_deleteextattr(ap); 784 fstrans_done(vp->v_mount); 785 return error; 786 #else 787 return (EOPNOTSUPP); 788 #endif 789 } 790 791 /* XXX Not implemented for UFS2 file systems. */ 792 return (EOPNOTSUPP); 793 } 794