1 /* $NetBSD: ffs_vnops.c,v 1.133 2020/09/05 16:30:13 riastradh 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.133 2020/09/05 16:30:13 riastradh 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 87 #include <miscfs/fifofs/fifo.h> 88 #include <miscfs/genfs/genfs.h> 89 #include <miscfs/specfs/specdev.h> 90 91 #include <ufs/ufs/acl.h> 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 /* Global vfs data structures for ufs. */ 102 int (**ffs_vnodeop_p)(void *); 103 const struct vnodeopv_entry_desc ffs_vnodeop_entries[] = { 104 { &vop_default_desc, vn_default_error }, 105 { &vop_lookup_desc, ufs_lookup }, /* lookup */ 106 { &vop_create_desc, ufs_create }, /* create */ 107 { &vop_whiteout_desc, ufs_whiteout }, /* whiteout */ 108 { &vop_mknod_desc, ufs_mknod }, /* mknod */ 109 { &vop_open_desc, ufs_open }, /* open */ 110 { &vop_close_desc, ufs_close }, /* close */ 111 { &vop_access_desc, genfs_access }, /* access */ 112 { &vop_accessx_desc, ufs_accessx }, /* accessx */ 113 { &vop_getattr_desc, ufs_getattr }, /* getattr */ 114 { &vop_setattr_desc, ufs_setattr }, /* setattr */ 115 { &vop_read_desc, ffs_read }, /* read */ 116 { &vop_write_desc, ffs_write }, /* write */ 117 { &vop_fallocate_desc, genfs_eopnotsupp }, /* fallocate */ 118 { &vop_fdiscard_desc, genfs_eopnotsupp }, /* fdiscard */ 119 { &vop_ioctl_desc, ufs_ioctl }, /* ioctl */ 120 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ 121 { &vop_poll_desc, ufs_poll }, /* poll */ 122 { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */ 123 { &vop_revoke_desc, ufs_revoke }, /* revoke */ 124 { &vop_mmap_desc, ufs_mmap }, /* mmap */ 125 { &vop_fsync_desc, ffs_fsync }, /* fsync */ 126 { &vop_seek_desc, ufs_seek }, /* seek */ 127 { &vop_remove_desc, ufs_remove }, /* remove */ 128 { &vop_link_desc, ufs_link }, /* link */ 129 { &vop_rename_desc, ufs_rename }, /* rename */ 130 { &vop_mkdir_desc, ufs_mkdir }, /* mkdir */ 131 { &vop_rmdir_desc, ufs_rmdir }, /* rmdir */ 132 { &vop_symlink_desc, ufs_symlink }, /* symlink */ 133 { &vop_readdir_desc, ufs_readdir }, /* readdir */ 134 { &vop_readlink_desc, ufs_readlink }, /* readlink */ 135 { &vop_abortop_desc, ufs_abortop }, /* abortop */ 136 { &vop_inactive_desc, ufs_inactive }, /* inactive */ 137 { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ 138 { &vop_lock_desc, ufs_lock }, /* lock */ 139 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 140 { &vop_bmap_desc, ufs_bmap }, /* bmap */ 141 { &vop_strategy_desc, ufs_strategy }, /* strategy */ 142 { &vop_print_desc, ufs_print }, /* print */ 143 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 144 { &vop_pathconf_desc, ufs_pathconf }, /* pathconf */ 145 { &vop_advlock_desc, ufs_advlock }, /* advlock */ 146 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 147 { &vop_getpages_desc, genfs_getpages }, /* getpages */ 148 { &vop_putpages_desc, genfs_putpages }, /* putpages */ 149 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ 150 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ 151 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ 152 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ 153 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ 154 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ 155 { &vop_getacl_desc, ufs_getacl }, /* getacl */ 156 { &vop_setacl_desc, ufs_setacl }, /* setacl */ 157 { &vop_aclcheck_desc, ufs_aclcheck }, /* aclcheck */ 158 { NULL, NULL } 159 }; 160 const struct vnodeopv_desc ffs_vnodeop_opv_desc = 161 { &ffs_vnodeop_p, ffs_vnodeop_entries }; 162 163 int (**ffs_specop_p)(void *); 164 const struct vnodeopv_entry_desc ffs_specop_entries[] = { 165 { &vop_default_desc, vn_default_error }, 166 { &vop_lookup_desc, spec_lookup }, /* lookup */ 167 { &vop_create_desc, spec_create }, /* create */ 168 { &vop_mknod_desc, spec_mknod }, /* mknod */ 169 { &vop_open_desc, spec_open }, /* open */ 170 { &vop_close_desc, ufsspec_close }, /* close */ 171 { &vop_access_desc, genfs_access }, /* access */ 172 { &vop_accessx_desc, ufs_accessx }, /* accessx */ 173 { &vop_getattr_desc, ufs_getattr }, /* getattr */ 174 { &vop_setattr_desc, ufs_setattr }, /* setattr */ 175 { &vop_read_desc, ufsspec_read }, /* read */ 176 { &vop_write_desc, ufsspec_write }, /* write */ 177 { &vop_fallocate_desc, spec_fallocate }, /* fallocate */ 178 { &vop_fdiscard_desc, spec_fdiscard }, /* fdiscard */ 179 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 180 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ 181 { &vop_poll_desc, spec_poll }, /* poll */ 182 { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */ 183 { &vop_revoke_desc, spec_revoke }, /* revoke */ 184 { &vop_mmap_desc, spec_mmap }, /* mmap */ 185 { &vop_fsync_desc, ffs_spec_fsync }, /* fsync */ 186 { &vop_seek_desc, spec_seek }, /* seek */ 187 { &vop_remove_desc, spec_remove }, /* remove */ 188 { &vop_link_desc, spec_link }, /* link */ 189 { &vop_rename_desc, spec_rename }, /* rename */ 190 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 191 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 192 { &vop_symlink_desc, spec_symlink }, /* symlink */ 193 { &vop_readdir_desc, spec_readdir }, /* readdir */ 194 { &vop_readlink_desc, spec_readlink }, /* readlink */ 195 { &vop_abortop_desc, spec_abortop }, /* abortop */ 196 { &vop_inactive_desc, ufs_inactive }, /* inactive */ 197 { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ 198 { &vop_lock_desc, ufs_lock }, /* lock */ 199 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 200 { &vop_bmap_desc, spec_bmap }, /* bmap */ 201 { &vop_strategy_desc, spec_strategy }, /* strategy */ 202 { &vop_print_desc, ufs_print }, /* print */ 203 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 204 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 205 { &vop_advlock_desc, spec_advlock }, /* advlock */ 206 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 207 { &vop_getpages_desc, spec_getpages }, /* getpages */ 208 { &vop_putpages_desc, spec_putpages }, /* putpages */ 209 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ 210 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ 211 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ 212 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ 213 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ 214 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ 215 { &vop_getacl_desc, ufs_getacl }, /* getacl */ 216 { &vop_setacl_desc, ufs_setacl }, /* setacl */ 217 { &vop_aclcheck_desc, ufs_aclcheck }, /* aclcheck */ 218 { NULL, NULL } 219 }; 220 const struct vnodeopv_desc ffs_specop_opv_desc = 221 { &ffs_specop_p, ffs_specop_entries }; 222 223 int (**ffs_fifoop_p)(void *); 224 const struct vnodeopv_entry_desc ffs_fifoop_entries[] = { 225 { &vop_default_desc, vn_default_error }, 226 { &vop_lookup_desc, vn_fifo_bypass }, /* lookup */ 227 { &vop_create_desc, vn_fifo_bypass }, /* create */ 228 { &vop_mknod_desc, vn_fifo_bypass }, /* mknod */ 229 { &vop_open_desc, vn_fifo_bypass }, /* open */ 230 { &vop_close_desc, ufsfifo_close }, /* close */ 231 { &vop_access_desc, genfs_access }, /* access */ 232 { &vop_accessx_desc, ufs_accessx }, /* accessx */ 233 { &vop_getattr_desc, ufs_getattr }, /* getattr */ 234 { &vop_setattr_desc, ufs_setattr }, /* setattr */ 235 { &vop_read_desc, ufsfifo_read }, /* read */ 236 { &vop_write_desc, ufsfifo_write }, /* write */ 237 { &vop_fallocate_desc, vn_fifo_bypass }, /* fallocate */ 238 { &vop_fdiscard_desc, vn_fifo_bypass }, /* fdiscard */ 239 { &vop_ioctl_desc, vn_fifo_bypass }, /* ioctl */ 240 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ 241 { &vop_poll_desc, vn_fifo_bypass }, /* poll */ 242 { &vop_kqfilter_desc, vn_fifo_bypass }, /* kqfilter */ 243 { &vop_revoke_desc, vn_fifo_bypass }, /* revoke */ 244 { &vop_mmap_desc, vn_fifo_bypass }, /* mmap */ 245 { &vop_fsync_desc, ffs_fsync }, /* fsync */ 246 { &vop_seek_desc, vn_fifo_bypass }, /* seek */ 247 { &vop_remove_desc, vn_fifo_bypass }, /* remove */ 248 { &vop_link_desc, vn_fifo_bypass }, /* link */ 249 { &vop_rename_desc, vn_fifo_bypass }, /* rename */ 250 { &vop_mkdir_desc, vn_fifo_bypass }, /* mkdir */ 251 { &vop_rmdir_desc, vn_fifo_bypass }, /* rmdir */ 252 { &vop_symlink_desc, vn_fifo_bypass }, /* symlink */ 253 { &vop_readdir_desc, vn_fifo_bypass }, /* readdir */ 254 { &vop_readlink_desc, vn_fifo_bypass }, /* readlink */ 255 { &vop_abortop_desc, vn_fifo_bypass }, /* abortop */ 256 { &vop_inactive_desc, ufs_inactive }, /* inactive */ 257 { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ 258 { &vop_lock_desc, ufs_lock }, /* lock */ 259 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 260 { &vop_bmap_desc, vn_fifo_bypass }, /* bmap */ 261 { &vop_strategy_desc, vn_fifo_bypass }, /* strategy */ 262 { &vop_print_desc, ufs_print }, /* print */ 263 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 264 { &vop_pathconf_desc, vn_fifo_bypass }, /* pathconf */ 265 { &vop_advlock_desc, vn_fifo_bypass }, /* advlock */ 266 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 267 { &vop_putpages_desc, vn_fifo_bypass }, /* putpages */ 268 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ 269 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ 270 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ 271 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ 272 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ 273 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ 274 { &vop_getacl_desc, ufs_getacl }, /* getacl */ 275 { &vop_setacl_desc, ufs_setacl }, /* setacl */ 276 { &vop_aclcheck_desc, ufs_aclcheck }, /* aclcheck */ 277 { NULL, NULL } 278 }; 279 const struct vnodeopv_desc ffs_fifoop_opv_desc = 280 { &ffs_fifoop_p, ffs_fifoop_entries }; 281 282 #include <ufs/ufs/ufs_readwrite.c> 283 284 int 285 ffs_spec_fsync(void *v) 286 { 287 struct vop_fsync_args /* { 288 struct vnode *a_vp; 289 kauth_cred_t a_cred; 290 int a_flags; 291 off_t a_offlo; 292 off_t a_offhi; 293 struct lwp *a_l; 294 } */ *ap = v; 295 int error, flags, uflags; 296 struct vnode *vp; 297 298 flags = ap->a_flags; 299 uflags = UPDATE_CLOSE | ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0); 300 vp = ap->a_vp; 301 302 error = spec_fsync(v); 303 if (error) 304 goto out; 305 306 #ifdef WAPBL 307 struct mount *mp = vp->v_mount; 308 309 if (mp && mp->mnt_wapbl) { 310 /* 311 * Don't bother writing out metadata if the syncer is 312 * making the request. We will let the sync vnode 313 * write it out in a single burst through a call to 314 * VFS_SYNC(). 315 */ 316 if ((flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) 317 goto out; 318 if ((VTOI(vp)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE 319 | IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) != 0) { 320 error = UFS_WAPBL_BEGIN(mp); 321 if (error != 0) 322 goto out; 323 error = ffs_update(vp, NULL, NULL, uflags); 324 UFS_WAPBL_END(mp); 325 } 326 goto out; 327 } 328 #endif /* WAPBL */ 329 330 error = ffs_update(vp, NULL, NULL, uflags); 331 332 out: 333 return error; 334 } 335 336 int 337 ffs_fsync(void *v) 338 { 339 struct vop_fsync_args /* { 340 struct vnode *a_vp; 341 kauth_cred_t a_cred; 342 int a_flags; 343 off_t a_offlo; 344 off_t a_offhi; 345 struct lwp *a_l; 346 } */ *ap = v; 347 struct buf *bp; 348 int num, error, i; 349 struct indir ia[UFS_NIADDR + 1]; 350 int bsize; 351 daddr_t blk_high; 352 struct vnode *vp; 353 struct mount *mp; 354 355 vp = ap->a_vp; 356 mp = vp->v_mount; 357 358 if ((ap->a_offlo == 0 && ap->a_offhi == 0) || (vp->v_type != VREG)) { 359 error = ffs_full_fsync(vp, ap->a_flags); 360 goto out; 361 } 362 363 bsize = mp->mnt_stat.f_iosize; 364 blk_high = ap->a_offhi / bsize; 365 if (ap->a_offhi % bsize != 0) 366 blk_high++; 367 368 /* 369 * First, flush all pages in range. 370 */ 371 372 rw_enter(vp->v_uobj.vmobjlock, RW_WRITER); 373 error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo), 374 round_page(ap->a_offhi), PGO_CLEANIT | 375 ((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0)); 376 if (error) { 377 goto out; 378 } 379 380 #ifdef WAPBL 381 KASSERT(vp->v_type == VREG); 382 if (mp->mnt_wapbl) { 383 /* 384 * Don't bother writing out metadata if the syncer is 385 * making the request. We will let the sync vnode 386 * write it out in a single burst through a call to 387 * VFS_SYNC(). 388 */ 389 if ((ap->a_flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) { 390 return 0; 391 } 392 error = 0; 393 if (vp->v_tag == VT_UFS && VTOI(vp)->i_flag & 394 (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY | 395 IN_MODIFIED | IN_ACCESSED)) { 396 error = UFS_WAPBL_BEGIN(mp); 397 if (error) { 398 return error; 399 } 400 error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | 401 ((ap->a_flags & FSYNC_WAIT) ? UPDATE_WAIT : 0)); 402 UFS_WAPBL_END(mp); 403 } 404 if (error || (ap->a_flags & FSYNC_NOLOG) != 0) { 405 return error; 406 } 407 error = wapbl_flush(mp->mnt_wapbl, 0); 408 return error; 409 } 410 #endif /* WAPBL */ 411 412 /* 413 * Then, flush indirect blocks. 414 */ 415 416 if (blk_high >= UFS_NDADDR) { 417 error = ufs_getlbns(vp, blk_high, ia, &num); 418 if (error) 419 goto out; 420 421 mutex_enter(&bufcache_lock); 422 for (i = 0; i < num; i++) { 423 if ((bp = incore(vp, ia[i].in_lbn)) == NULL) 424 continue; 425 if ((bp->b_cflags & BC_BUSY) != 0 || 426 (bp->b_oflags & BO_DELWRI) == 0) 427 continue; 428 bp->b_cflags |= BC_BUSY | BC_VFLUSH; 429 mutex_exit(&bufcache_lock); 430 bawrite(bp); 431 mutex_enter(&bufcache_lock); 432 } 433 mutex_exit(&bufcache_lock); 434 } 435 436 if (ap->a_flags & FSYNC_WAIT) { 437 mutex_enter(vp->v_interlock); 438 while (vp->v_numoutput > 0) 439 cv_wait(&vp->v_cv, vp->v_interlock); 440 mutex_exit(vp->v_interlock); 441 } 442 443 error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | 444 (((ap->a_flags & (FSYNC_WAIT | FSYNC_DATAONLY)) == FSYNC_WAIT) 445 ? UPDATE_WAIT : 0)); 446 447 if (error == 0 && ap->a_flags & FSYNC_CACHE) { 448 int l = 0; 449 VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &l, FWRITE, 450 curlwp->l_cred); 451 } 452 453 out: 454 return error; 455 } 456 457 /* 458 * Synch an open file. Called for VOP_FSYNC(). 459 */ 460 /* ARGSUSED */ 461 int 462 ffs_full_fsync(struct vnode *vp, int flags) 463 { 464 int error, i, uflags; 465 466 KASSERT(vp->v_tag == VT_UFS); 467 KASSERT(VTOI(vp) != NULL); 468 KASSERT(vp->v_type != VCHR && vp->v_type != VBLK); 469 470 uflags = UPDATE_CLOSE | ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0); 471 472 #ifdef WAPBL 473 struct mount *mp = vp->v_mount; 474 475 if (mp && mp->mnt_wapbl) { 476 477 /* 478 * Flush all dirty data associated with the vnode. 479 */ 480 if (vp->v_type == VREG) { 481 int pflags = PGO_ALLPAGES | PGO_CLEANIT; 482 483 if ((flags & FSYNC_LAZY)) 484 pflags |= PGO_LAZY; 485 if ((flags & FSYNC_WAIT)) 486 pflags |= PGO_SYNCIO; 487 rw_enter(vp->v_uobj.vmobjlock, RW_WRITER); 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_v2_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 VOP_UNLOCK(vp); 566 567 /* 568 * The inode must be freed and updated before being removed 569 * from its hash chain. Other threads trying to gain a hold 570 * or lock on the inode will be stalled. 571 */ 572 error = UFS_WAPBL_BEGIN(mp); 573 if (error) { 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 return (error); 582 } 583 if (ip->i_din.ffs1_din != NULL) { 584 if (ump->um_fstype == UFS1) 585 pool_cache_put(ffs_dinode1_cache, ip->i_din.ffs1_din); 586 else 587 pool_cache_put(ffs_dinode2_cache, ip->i_din.ffs2_din); 588 } 589 /* 590 * To interlock with ffs_sync(). 591 */ 592 genfs_node_destroy(vp); 593 mutex_enter(vp->v_interlock); 594 data = vp->v_data; 595 vp->v_data = NULL; 596 mutex_exit(vp->v_interlock); 597 598 /* 599 * XXX MFS ends up here, too, to free an inode. Should we create 600 * XXX a separate pool for MFS inodes? 601 */ 602 pool_cache_put(ffs_inode_cache, data); 603 return (0); 604 } 605 606 /* 607 * Return the last logical file offset that should be written for this file 608 * if we're doing a write that ends at "size". 609 */ 610 611 void 612 ffs_gop_size(struct vnode *vp, off_t size, off_t *eobp, int flags) 613 { 614 struct inode *ip = VTOI(vp); 615 struct fs *fs = ip->i_fs; 616 daddr_t olbn, nlbn; 617 618 olbn = ffs_lblkno(fs, ip->i_size); 619 nlbn = ffs_lblkno(fs, size); 620 if (nlbn < UFS_NDADDR && olbn <= nlbn) { 621 *eobp = ffs_fragroundup(fs, size); 622 } else { 623 *eobp = ffs_blkroundup(fs, size); 624 } 625 } 626