1 /* $NetBSD: ffs_vnops.c,v 1.138 2021/12/14 11:06:12 chs 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.138 2021/12/14 11:06:12 chs 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_parsepath_desc, genfs_parsepath }, /* parsepath */ 106 { &vop_lookup_desc, ufs_lookup }, /* lookup */ 107 { &vop_create_desc, ufs_create }, /* create */ 108 { &vop_whiteout_desc, ufs_whiteout }, /* whiteout */ 109 { &vop_mknod_desc, ufs_mknod }, /* mknod */ 110 { &vop_open_desc, ufs_open }, /* open */ 111 { &vop_close_desc, ufs_close }, /* close */ 112 { &vop_access_desc, genfs_access }, /* access */ 113 { &vop_accessx_desc, ufs_accessx }, /* accessx */ 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, genfs_enoioctl }, /* ioctl */ 121 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 122 { &vop_poll_desc, genfs_poll }, /* poll */ 123 { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */ 124 { &vop_revoke_desc, genfs_revoke }, /* revoke */ 125 { &vop_mmap_desc, genfs_mmap }, /* mmap */ 126 { &vop_fsync_desc, ffs_fsync }, /* fsync */ 127 { &vop_seek_desc, genfs_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, genfs_abortop }, /* abortop */ 137 { &vop_inactive_desc, ufs_inactive }, /* inactive */ 138 { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ 139 { &vop_lock_desc, genfs_lock }, /* lock */ 140 { &vop_unlock_desc, genfs_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, genfs_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 { &vop_getacl_desc, ufs_getacl }, /* getacl */ 157 { &vop_setacl_desc, ufs_setacl }, /* setacl */ 158 { &vop_aclcheck_desc, ufs_aclcheck }, /* aclcheck */ 159 { NULL, NULL } 160 }; 161 const struct vnodeopv_desc ffs_vnodeop_opv_desc = 162 { &ffs_vnodeop_p, ffs_vnodeop_entries }; 163 164 int (**ffs_specop_p)(void *); 165 const struct vnodeopv_entry_desc ffs_specop_entries[] = { 166 { &vop_default_desc, vn_default_error }, 167 GENFS_SPECOP_ENTRIES, 168 { &vop_close_desc, ufsspec_close }, /* close */ 169 { &vop_access_desc, genfs_access }, /* access */ 170 { &vop_accessx_desc, ufs_accessx }, /* accessx */ 171 { &vop_getattr_desc, ufs_getattr }, /* getattr */ 172 { &vop_setattr_desc, ufs_setattr }, /* setattr */ 173 { &vop_read_desc, ufsspec_read }, /* read */ 174 { &vop_write_desc, ufsspec_write }, /* write */ 175 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 176 { &vop_fsync_desc, ffs_spec_fsync }, /* fsync */ 177 { &vop_inactive_desc, ufs_inactive }, /* inactive */ 178 { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ 179 { &vop_lock_desc, genfs_lock }, /* lock */ 180 { &vop_unlock_desc, genfs_unlock }, /* unlock */ 181 { &vop_print_desc, ufs_print }, /* print */ 182 { &vop_islocked_desc, genfs_islocked }, /* islocked */ 183 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 184 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ 185 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ 186 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ 187 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ 188 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ 189 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ 190 { &vop_getacl_desc, ufs_getacl }, /* getacl */ 191 { &vop_setacl_desc, ufs_setacl }, /* setacl */ 192 { &vop_aclcheck_desc, ufs_aclcheck }, /* aclcheck */ 193 { NULL, NULL } 194 }; 195 const struct vnodeopv_desc ffs_specop_opv_desc = 196 { &ffs_specop_p, ffs_specop_entries }; 197 198 int (**ffs_fifoop_p)(void *); 199 const struct vnodeopv_entry_desc ffs_fifoop_entries[] = { 200 { &vop_default_desc, vn_default_error }, 201 GENFS_FIFOOP_ENTRIES, 202 { &vop_close_desc, ufsfifo_close }, /* close */ 203 { &vop_access_desc, genfs_access }, /* access */ 204 { &vop_accessx_desc, ufs_accessx }, /* accessx */ 205 { &vop_getattr_desc, ufs_getattr }, /* getattr */ 206 { &vop_setattr_desc, ufs_setattr }, /* setattr */ 207 { &vop_read_desc, ufsfifo_read }, /* read */ 208 { &vop_write_desc, ufsfifo_write }, /* write */ 209 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 210 { &vop_fsync_desc, ffs_fsync }, /* fsync */ 211 { &vop_inactive_desc, ufs_inactive }, /* inactive */ 212 { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ 213 { &vop_lock_desc, genfs_lock }, /* lock */ 214 { &vop_unlock_desc, genfs_unlock }, /* unlock */ 215 { &vop_bmap_desc, ufs_bmap }, /* bmap */ 216 { &vop_strategy_desc, ffsext_strategy }, /* strategy */ 217 { &vop_print_desc, ufs_print }, /* print */ 218 { &vop_islocked_desc, genfs_islocked }, /* islocked */ 219 { &vop_pathconf_desc, ufs_pathconf }, /* pathconf */ 220 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 221 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ 222 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ 223 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ 224 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ 225 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ 226 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ 227 { &vop_getacl_desc, ufs_getacl }, /* getacl */ 228 { &vop_setacl_desc, ufs_setacl }, /* setacl */ 229 { &vop_aclcheck_desc, ufs_aclcheck }, /* aclcheck */ 230 { NULL, NULL } 231 }; 232 const struct vnodeopv_desc ffs_fifoop_opv_desc = 233 { &ffs_fifoop_p, ffs_fifoop_entries }; 234 235 #include <ufs/ufs/ufs_readwrite.c> 236 237 int 238 ffs_spec_fsync(void *v) 239 { 240 struct vop_fsync_args /* { 241 struct vnode *a_vp; 242 kauth_cred_t a_cred; 243 int a_flags; 244 off_t a_offlo; 245 off_t a_offhi; 246 struct lwp *a_l; 247 } */ *ap = v; 248 int error, flags, uflags; 249 struct vnode *vp; 250 251 flags = ap->a_flags; 252 uflags = UPDATE_CLOSE | ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0); 253 vp = ap->a_vp; 254 255 error = spec_fsync(v); 256 if (error) 257 goto out; 258 259 #ifdef WAPBL 260 struct mount *mp = vp->v_mount; 261 262 if (mp && mp->mnt_wapbl) { 263 /* 264 * Don't bother writing out metadata if the syncer is 265 * making the request. We will let the sync vnode 266 * write it out in a single burst through a call to 267 * VFS_SYNC(). 268 */ 269 if ((flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) 270 goto out; 271 if ((VTOI(vp)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE 272 | IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) != 0) { 273 error = UFS_WAPBL_BEGIN(mp); 274 if (error != 0) 275 goto out; 276 error = ffs_update(vp, NULL, NULL, uflags); 277 UFS_WAPBL_END(mp); 278 } 279 goto out; 280 } 281 #endif /* WAPBL */ 282 283 error = ffs_update(vp, NULL, NULL, uflags); 284 285 out: 286 return error; 287 } 288 289 int 290 ffs_fsync(void *v) 291 { 292 struct vop_fsync_args /* { 293 struct vnode *a_vp; 294 kauth_cred_t a_cred; 295 int a_flags; 296 off_t a_offlo; 297 off_t a_offhi; 298 struct lwp *a_l; 299 } */ *ap = v; 300 struct buf *bp; 301 int num, error, i; 302 struct indir ia[UFS_NIADDR + 1]; 303 int bsize; 304 daddr_t blk_high; 305 struct vnode *vp; 306 struct mount *mp; 307 308 vp = ap->a_vp; 309 mp = vp->v_mount; 310 311 if ((ap->a_offlo == 0 && ap->a_offhi == 0) || (vp->v_type != VREG)) { 312 error = ffs_full_fsync(vp, ap->a_flags); 313 goto out; 314 } 315 316 bsize = mp->mnt_stat.f_iosize; 317 blk_high = ap->a_offhi / bsize; 318 if (ap->a_offhi % bsize != 0) 319 blk_high++; 320 321 /* 322 * First, flush all pages in range. 323 */ 324 325 rw_enter(vp->v_uobj.vmobjlock, RW_WRITER); 326 error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo), 327 round_page(ap->a_offhi), PGO_CLEANIT | 328 ((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0)); 329 if (error) { 330 goto out; 331 } 332 333 #ifdef WAPBL 334 KASSERT(vp->v_type == VREG); 335 if (mp->mnt_wapbl) { 336 /* 337 * Don't bother writing out metadata if the syncer is 338 * making the request. We will let the sync vnode 339 * write it out in a single burst through a call to 340 * VFS_SYNC(). 341 */ 342 if ((ap->a_flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) { 343 return 0; 344 } 345 error = 0; 346 if (vp->v_tag == VT_UFS && VTOI(vp)->i_flag & 347 (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY | 348 IN_MODIFIED | IN_ACCESSED)) { 349 error = UFS_WAPBL_BEGIN(mp); 350 if (error) { 351 return error; 352 } 353 error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | 354 ((ap->a_flags & FSYNC_WAIT) ? UPDATE_WAIT : 0)); 355 UFS_WAPBL_END(mp); 356 } 357 if (error || (ap->a_flags & FSYNC_NOLOG) != 0) { 358 return error; 359 } 360 error = wapbl_flush(mp->mnt_wapbl, 0); 361 return error; 362 } 363 #endif /* WAPBL */ 364 365 /* 366 * Then, flush indirect blocks. 367 */ 368 369 if (blk_high >= UFS_NDADDR) { 370 error = ufs_getlbns(vp, blk_high, ia, &num); 371 if (error) 372 goto out; 373 374 mutex_enter(&bufcache_lock); 375 for (i = 0; i < num; i++) { 376 if ((bp = incore(vp, ia[i].in_lbn)) == NULL) 377 continue; 378 if ((bp->b_cflags & BC_BUSY) != 0 || 379 (bp->b_oflags & BO_DELWRI) == 0) 380 continue; 381 bp->b_cflags |= BC_BUSY | BC_VFLUSH; 382 mutex_exit(&bufcache_lock); 383 bawrite(bp); 384 mutex_enter(&bufcache_lock); 385 } 386 mutex_exit(&bufcache_lock); 387 } 388 389 if (ap->a_flags & FSYNC_WAIT) { 390 mutex_enter(vp->v_interlock); 391 while (vp->v_numoutput > 0) 392 cv_wait(&vp->v_cv, vp->v_interlock); 393 mutex_exit(vp->v_interlock); 394 } 395 396 error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | 397 (((ap->a_flags & (FSYNC_WAIT | FSYNC_DATAONLY)) == FSYNC_WAIT) 398 ? UPDATE_WAIT : 0)); 399 400 if (error == 0 && ap->a_flags & FSYNC_CACHE) { 401 int l = 0; 402 VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &l, FWRITE, 403 curlwp->l_cred); 404 } 405 406 out: 407 return error; 408 } 409 410 /* 411 * Synch an open file. Called for VOP_FSYNC(). 412 */ 413 /* ARGSUSED */ 414 int 415 ffs_full_fsync(struct vnode *vp, int flags) 416 { 417 int error, i, uflags; 418 419 KASSERT(vp->v_tag == VT_UFS); 420 KASSERT(VTOI(vp) != NULL); 421 KASSERT(vp->v_type != VCHR && vp->v_type != VBLK); 422 423 uflags = UPDATE_CLOSE | ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0); 424 425 #ifdef WAPBL 426 struct mount *mp = vp->v_mount; 427 428 if (mp && mp->mnt_wapbl) { 429 430 /* 431 * Flush all dirty data associated with the vnode. 432 */ 433 if (vp->v_type == VREG) { 434 int pflags = PGO_ALLPAGES | PGO_CLEANIT; 435 436 if ((flags & FSYNC_LAZY)) 437 pflags |= PGO_LAZY; 438 if ((flags & FSYNC_WAIT)) 439 pflags |= PGO_SYNCIO; 440 rw_enter(vp->v_uobj.vmobjlock, RW_WRITER); 441 error = VOP_PUTPAGES(vp, 0, 0, pflags); 442 if (error) 443 return error; 444 } 445 446 /* 447 * Don't bother writing out metadata if the syncer is 448 * making the request. We will let the sync vnode 449 * write it out in a single burst through a call to 450 * VFS_SYNC(). 451 */ 452 if ((flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) 453 return 0; 454 455 if ((VTOI(vp)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE 456 | IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) != 0) { 457 error = UFS_WAPBL_BEGIN(mp); 458 if (error) 459 return error; 460 error = ffs_update(vp, NULL, NULL, uflags); 461 UFS_WAPBL_END(mp); 462 } else { 463 error = 0; 464 } 465 if (error || (flags & FSYNC_NOLOG) != 0) 466 return error; 467 468 /* 469 * Don't flush the log if the vnode being flushed 470 * contains no dirty buffers that could be in the log. 471 */ 472 if (!LIST_EMPTY(&vp->v_dirtyblkhd)) { 473 error = wapbl_flush(mp->mnt_wapbl, 0); 474 if (error) 475 return error; 476 } 477 478 if ((flags & FSYNC_WAIT) != 0) { 479 mutex_enter(vp->v_interlock); 480 while (vp->v_numoutput != 0) 481 cv_wait(&vp->v_cv, vp->v_interlock); 482 mutex_exit(vp->v_interlock); 483 } 484 485 return error; 486 } 487 #endif /* WAPBL */ 488 489 error = vflushbuf(vp, flags); 490 if (error == 0) 491 error = ffs_update(vp, NULL, NULL, uflags); 492 if (error == 0 && (flags & FSYNC_CACHE) != 0) { 493 i = 1; 494 (void)VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &i, FWRITE, 495 kauth_cred_get()); 496 } 497 498 return error; 499 } 500 501 /* 502 * Reclaim an inode so that it can be used for other purposes. 503 */ 504 int 505 ffs_reclaim(void *v) 506 { 507 struct vop_reclaim_v2_args /* { 508 struct vnode *a_vp; 509 struct lwp *a_l; 510 } */ *ap = v; 511 struct vnode *vp = ap->a_vp; 512 struct inode *ip = VTOI(vp); 513 struct mount *mp = vp->v_mount; 514 struct ufsmount *ump = ip->i_ump; 515 void *data; 516 int error; 517 518 VOP_UNLOCK(vp); 519 520 /* 521 * The inode must be freed and updated before being removed 522 * from its hash chain. Other threads trying to gain a hold 523 * or lock on the inode will be stalled. 524 */ 525 error = UFS_WAPBL_BEGIN(mp); 526 if (error) { 527 return error; 528 } 529 if (ip->i_nlink <= 0 && ip->i_omode != 0 && 530 (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 531 ffs_vfree(vp, ip->i_number, ip->i_omode); 532 UFS_WAPBL_END(mp); 533 if ((error = ufs_reclaim(vp)) != 0) { 534 return (error); 535 } 536 if (ip->i_din.ffs1_din != NULL) { 537 if (ump->um_fstype == UFS1) 538 pool_cache_put(ffs_dinode1_cache, ip->i_din.ffs1_din); 539 else 540 pool_cache_put(ffs_dinode2_cache, ip->i_din.ffs2_din); 541 } 542 /* 543 * To interlock with ffs_sync(). 544 */ 545 genfs_node_destroy(vp); 546 mutex_enter(vp->v_interlock); 547 data = vp->v_data; 548 vp->v_data = NULL; 549 mutex_exit(vp->v_interlock); 550 551 /* 552 * XXX MFS ends up here, too, to free an inode. Should we create 553 * XXX a separate pool for MFS inodes? 554 */ 555 pool_cache_put(ffs_inode_cache, data); 556 return (0); 557 } 558 559 /* 560 * Return the last logical file offset that should be written for this file 561 * if we're doing a write that ends at "size". 562 */ 563 564 void 565 ffs_gop_size(struct vnode *vp, off_t size, off_t *eobp, int flags) 566 { 567 struct inode *ip = VTOI(vp); 568 struct fs *fs = ip->i_fs; 569 daddr_t olbn, nlbn; 570 571 olbn = ffs_lblkno(fs, ip->i_size); 572 nlbn = ffs_lblkno(fs, size); 573 if (nlbn < UFS_NDADDR && olbn <= nlbn) { 574 *eobp = ffs_fragroundup(fs, size); 575 } else { 576 *eobp = ffs_blkroundup(fs, size); 577 } 578 } 579