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