1 /* $NetBSD: ffs_vnops.c,v 1.137 2021/07/18 23:57:15 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.137 2021/07/18 23:57:15 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 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_strategy_desc, ffsext_strategy }, /* strategy */ 216 { &vop_print_desc, ufs_print }, /* print */ 217 { &vop_islocked_desc, genfs_islocked }, /* islocked */ 218 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 219 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ 220 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ 221 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ 222 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ 223 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ 224 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ 225 { &vop_getacl_desc, ufs_getacl }, /* getacl */ 226 { &vop_setacl_desc, ufs_setacl }, /* setacl */ 227 { &vop_aclcheck_desc, ufs_aclcheck }, /* aclcheck */ 228 { NULL, NULL } 229 }; 230 const struct vnodeopv_desc ffs_fifoop_opv_desc = 231 { &ffs_fifoop_p, ffs_fifoop_entries }; 232 233 #include <ufs/ufs/ufs_readwrite.c> 234 235 int 236 ffs_spec_fsync(void *v) 237 { 238 struct vop_fsync_args /* { 239 struct vnode *a_vp; 240 kauth_cred_t a_cred; 241 int a_flags; 242 off_t a_offlo; 243 off_t a_offhi; 244 struct lwp *a_l; 245 } */ *ap = v; 246 int error, flags, uflags; 247 struct vnode *vp; 248 249 flags = ap->a_flags; 250 uflags = UPDATE_CLOSE | ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0); 251 vp = ap->a_vp; 252 253 error = spec_fsync(v); 254 if (error) 255 goto out; 256 257 #ifdef WAPBL 258 struct mount *mp = vp->v_mount; 259 260 if (mp && mp->mnt_wapbl) { 261 /* 262 * Don't bother writing out metadata if the syncer is 263 * making the request. We will let the sync vnode 264 * write it out in a single burst through a call to 265 * VFS_SYNC(). 266 */ 267 if ((flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) 268 goto out; 269 if ((VTOI(vp)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE 270 | IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) != 0) { 271 error = UFS_WAPBL_BEGIN(mp); 272 if (error != 0) 273 goto out; 274 error = ffs_update(vp, NULL, NULL, uflags); 275 UFS_WAPBL_END(mp); 276 } 277 goto out; 278 } 279 #endif /* WAPBL */ 280 281 error = ffs_update(vp, NULL, NULL, uflags); 282 283 out: 284 return error; 285 } 286 287 int 288 ffs_fsync(void *v) 289 { 290 struct vop_fsync_args /* { 291 struct vnode *a_vp; 292 kauth_cred_t a_cred; 293 int a_flags; 294 off_t a_offlo; 295 off_t a_offhi; 296 struct lwp *a_l; 297 } */ *ap = v; 298 struct buf *bp; 299 int num, error, i; 300 struct indir ia[UFS_NIADDR + 1]; 301 int bsize; 302 daddr_t blk_high; 303 struct vnode *vp; 304 struct mount *mp; 305 306 vp = ap->a_vp; 307 mp = vp->v_mount; 308 309 if ((ap->a_offlo == 0 && ap->a_offhi == 0) || (vp->v_type != VREG)) { 310 error = ffs_full_fsync(vp, ap->a_flags); 311 goto out; 312 } 313 314 bsize = mp->mnt_stat.f_iosize; 315 blk_high = ap->a_offhi / bsize; 316 if (ap->a_offhi % bsize != 0) 317 blk_high++; 318 319 /* 320 * First, flush all pages in range. 321 */ 322 323 rw_enter(vp->v_uobj.vmobjlock, RW_WRITER); 324 error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo), 325 round_page(ap->a_offhi), PGO_CLEANIT | 326 ((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0)); 327 if (error) { 328 goto out; 329 } 330 331 #ifdef WAPBL 332 KASSERT(vp->v_type == VREG); 333 if (mp->mnt_wapbl) { 334 /* 335 * Don't bother writing out metadata if the syncer is 336 * making the request. We will let the sync vnode 337 * write it out in a single burst through a call to 338 * VFS_SYNC(). 339 */ 340 if ((ap->a_flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) { 341 return 0; 342 } 343 error = 0; 344 if (vp->v_tag == VT_UFS && VTOI(vp)->i_flag & 345 (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY | 346 IN_MODIFIED | IN_ACCESSED)) { 347 error = UFS_WAPBL_BEGIN(mp); 348 if (error) { 349 return error; 350 } 351 error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | 352 ((ap->a_flags & FSYNC_WAIT) ? UPDATE_WAIT : 0)); 353 UFS_WAPBL_END(mp); 354 } 355 if (error || (ap->a_flags & FSYNC_NOLOG) != 0) { 356 return error; 357 } 358 error = wapbl_flush(mp->mnt_wapbl, 0); 359 return error; 360 } 361 #endif /* WAPBL */ 362 363 /* 364 * Then, flush indirect blocks. 365 */ 366 367 if (blk_high >= UFS_NDADDR) { 368 error = ufs_getlbns(vp, blk_high, ia, &num); 369 if (error) 370 goto out; 371 372 mutex_enter(&bufcache_lock); 373 for (i = 0; i < num; i++) { 374 if ((bp = incore(vp, ia[i].in_lbn)) == NULL) 375 continue; 376 if ((bp->b_cflags & BC_BUSY) != 0 || 377 (bp->b_oflags & BO_DELWRI) == 0) 378 continue; 379 bp->b_cflags |= BC_BUSY | BC_VFLUSH; 380 mutex_exit(&bufcache_lock); 381 bawrite(bp); 382 mutex_enter(&bufcache_lock); 383 } 384 mutex_exit(&bufcache_lock); 385 } 386 387 if (ap->a_flags & FSYNC_WAIT) { 388 mutex_enter(vp->v_interlock); 389 while (vp->v_numoutput > 0) 390 cv_wait(&vp->v_cv, vp->v_interlock); 391 mutex_exit(vp->v_interlock); 392 } 393 394 error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | 395 (((ap->a_flags & (FSYNC_WAIT | FSYNC_DATAONLY)) == FSYNC_WAIT) 396 ? UPDATE_WAIT : 0)); 397 398 if (error == 0 && ap->a_flags & FSYNC_CACHE) { 399 int l = 0; 400 VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &l, FWRITE, 401 curlwp->l_cred); 402 } 403 404 out: 405 return error; 406 } 407 408 /* 409 * Synch an open file. Called for VOP_FSYNC(). 410 */ 411 /* ARGSUSED */ 412 int 413 ffs_full_fsync(struct vnode *vp, int flags) 414 { 415 int error, i, uflags; 416 417 KASSERT(vp->v_tag == VT_UFS); 418 KASSERT(VTOI(vp) != NULL); 419 KASSERT(vp->v_type != VCHR && vp->v_type != VBLK); 420 421 uflags = UPDATE_CLOSE | ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0); 422 423 #ifdef WAPBL 424 struct mount *mp = vp->v_mount; 425 426 if (mp && mp->mnt_wapbl) { 427 428 /* 429 * Flush all dirty data associated with the vnode. 430 */ 431 if (vp->v_type == VREG) { 432 int pflags = PGO_ALLPAGES | PGO_CLEANIT; 433 434 if ((flags & FSYNC_LAZY)) 435 pflags |= PGO_LAZY; 436 if ((flags & FSYNC_WAIT)) 437 pflags |= PGO_SYNCIO; 438 rw_enter(vp->v_uobj.vmobjlock, RW_WRITER); 439 error = VOP_PUTPAGES(vp, 0, 0, pflags); 440 if (error) 441 return error; 442 } 443 444 /* 445 * Don't bother writing out metadata if the syncer is 446 * making the request. We will let the sync vnode 447 * write it out in a single burst through a call to 448 * VFS_SYNC(). 449 */ 450 if ((flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) 451 return 0; 452 453 if ((VTOI(vp)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE 454 | IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) != 0) { 455 error = UFS_WAPBL_BEGIN(mp); 456 if (error) 457 return error; 458 error = ffs_update(vp, NULL, NULL, uflags); 459 UFS_WAPBL_END(mp); 460 } else { 461 error = 0; 462 } 463 if (error || (flags & FSYNC_NOLOG) != 0) 464 return error; 465 466 /* 467 * Don't flush the log if the vnode being flushed 468 * contains no dirty buffers that could be in the log. 469 */ 470 if (!LIST_EMPTY(&vp->v_dirtyblkhd)) { 471 error = wapbl_flush(mp->mnt_wapbl, 0); 472 if (error) 473 return error; 474 } 475 476 if ((flags & FSYNC_WAIT) != 0) { 477 mutex_enter(vp->v_interlock); 478 while (vp->v_numoutput != 0) 479 cv_wait(&vp->v_cv, vp->v_interlock); 480 mutex_exit(vp->v_interlock); 481 } 482 483 return error; 484 } 485 #endif /* WAPBL */ 486 487 error = vflushbuf(vp, flags); 488 if (error == 0) 489 error = ffs_update(vp, NULL, NULL, uflags); 490 if (error == 0 && (flags & FSYNC_CACHE) != 0) { 491 i = 1; 492 (void)VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &i, FWRITE, 493 kauth_cred_get()); 494 } 495 496 return error; 497 } 498 499 /* 500 * Reclaim an inode so that it can be used for other purposes. 501 */ 502 int 503 ffs_reclaim(void *v) 504 { 505 struct vop_reclaim_v2_args /* { 506 struct vnode *a_vp; 507 struct lwp *a_l; 508 } */ *ap = v; 509 struct vnode *vp = ap->a_vp; 510 struct inode *ip = VTOI(vp); 511 struct mount *mp = vp->v_mount; 512 struct ufsmount *ump = ip->i_ump; 513 void *data; 514 int error; 515 516 VOP_UNLOCK(vp); 517 518 /* 519 * The inode must be freed and updated before being removed 520 * from its hash chain. Other threads trying to gain a hold 521 * or lock on the inode will be stalled. 522 */ 523 error = UFS_WAPBL_BEGIN(mp); 524 if (error) { 525 return error; 526 } 527 if (ip->i_nlink <= 0 && ip->i_omode != 0 && 528 (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 529 ffs_vfree(vp, ip->i_number, ip->i_omode); 530 UFS_WAPBL_END(mp); 531 if ((error = ufs_reclaim(vp)) != 0) { 532 return (error); 533 } 534 if (ip->i_din.ffs1_din != NULL) { 535 if (ump->um_fstype == UFS1) 536 pool_cache_put(ffs_dinode1_cache, ip->i_din.ffs1_din); 537 else 538 pool_cache_put(ffs_dinode2_cache, ip->i_din.ffs2_din); 539 } 540 /* 541 * To interlock with ffs_sync(). 542 */ 543 genfs_node_destroy(vp); 544 mutex_enter(vp->v_interlock); 545 data = vp->v_data; 546 vp->v_data = NULL; 547 mutex_exit(vp->v_interlock); 548 549 /* 550 * XXX MFS ends up here, too, to free an inode. Should we create 551 * XXX a separate pool for MFS inodes? 552 */ 553 pool_cache_put(ffs_inode_cache, data); 554 return (0); 555 } 556 557 /* 558 * Return the last logical file offset that should be written for this file 559 * if we're doing a write that ends at "size". 560 */ 561 562 void 563 ffs_gop_size(struct vnode *vp, off_t size, off_t *eobp, int flags) 564 { 565 struct inode *ip = VTOI(vp); 566 struct fs *fs = ip->i_fs; 567 daddr_t olbn, nlbn; 568 569 olbn = ffs_lblkno(fs, ip->i_size); 570 nlbn = ffs_lblkno(fs, size); 571 if (nlbn < UFS_NDADDR && olbn <= nlbn) { 572 *eobp = ffs_fragroundup(fs, size); 573 } else { 574 *eobp = ffs_blkroundup(fs, size); 575 } 576 } 577