1 /* $NetBSD: ffs_vnops.c,v 1.77 2005/12/11 12:25:25 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)ffs_vnops.c 8.15 (Berkeley) 5/14/95 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.77 2005/12/11 12:25:25 christos Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/resourcevar.h> 40 #include <sys/kernel.h> 41 #include <sys/file.h> 42 #include <sys/stat.h> 43 #include <sys/buf.h> 44 #include <sys/event.h> 45 #include <sys/proc.h> 46 #include <sys/mount.h> 47 #include <sys/vnode.h> 48 #include <sys/pool.h> 49 #include <sys/signalvar.h> 50 51 #include <miscfs/fifofs/fifo.h> 52 #include <miscfs/genfs/genfs.h> 53 #include <miscfs/specfs/specdev.h> 54 55 #include <ufs/ufs/inode.h> 56 #include <ufs/ufs/dir.h> 57 #include <ufs/ufs/ufs_extern.h> 58 #include <ufs/ufs/ufsmount.h> 59 60 #include <ufs/ffs/fs.h> 61 #include <ufs/ffs/ffs_extern.h> 62 63 #include <uvm/uvm.h> 64 65 static int ffs_full_fsync(void *); 66 67 /* Global vfs data structures for ufs. */ 68 int (**ffs_vnodeop_p)(void *); 69 const struct vnodeopv_entry_desc ffs_vnodeop_entries[] = { 70 { &vop_default_desc, vn_default_error }, 71 { &vop_lookup_desc, ufs_lookup }, /* lookup */ 72 { &vop_create_desc, ufs_create }, /* create */ 73 { &vop_whiteout_desc, ufs_whiteout }, /* whiteout */ 74 { &vop_mknod_desc, ufs_mknod }, /* mknod */ 75 { &vop_open_desc, ufs_open }, /* open */ 76 { &vop_close_desc, ufs_close }, /* close */ 77 { &vop_access_desc, ufs_access }, /* access */ 78 { &vop_getattr_desc, ufs_getattr }, /* getattr */ 79 { &vop_setattr_desc, ufs_setattr }, /* setattr */ 80 { &vop_read_desc, ffs_read }, /* read */ 81 { &vop_write_desc, ffs_write }, /* write */ 82 { &vop_lease_desc, ufs_lease_check }, /* lease */ 83 { &vop_ioctl_desc, ufs_ioctl }, /* ioctl */ 84 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ 85 { &vop_poll_desc, ufs_poll }, /* poll */ 86 { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */ 87 { &vop_revoke_desc, ufs_revoke }, /* revoke */ 88 { &vop_mmap_desc, ufs_mmap }, /* mmap */ 89 { &vop_fsync_desc, ffs_fsync }, /* fsync */ 90 { &vop_seek_desc, ufs_seek }, /* seek */ 91 { &vop_remove_desc, ufs_remove }, /* remove */ 92 { &vop_link_desc, ufs_link }, /* link */ 93 { &vop_rename_desc, ufs_rename }, /* rename */ 94 { &vop_mkdir_desc, ufs_mkdir }, /* mkdir */ 95 { &vop_rmdir_desc, ufs_rmdir }, /* rmdir */ 96 { &vop_symlink_desc, ufs_symlink }, /* symlink */ 97 { &vop_readdir_desc, ufs_readdir }, /* readdir */ 98 { &vop_readlink_desc, ufs_readlink }, /* readlink */ 99 { &vop_abortop_desc, ufs_abortop }, /* abortop */ 100 { &vop_inactive_desc, ufs_inactive }, /* inactive */ 101 { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ 102 { &vop_lock_desc, ufs_lock }, /* lock */ 103 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 104 { &vop_bmap_desc, ufs_bmap }, /* bmap */ 105 { &vop_strategy_desc, ufs_strategy }, /* strategy */ 106 { &vop_print_desc, ufs_print }, /* print */ 107 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 108 { &vop_pathconf_desc, ufs_pathconf }, /* pathconf */ 109 { &vop_advlock_desc, ufs_advlock }, /* advlock */ 110 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 111 { &vop_getpages_desc, ffs_getpages }, /* getpages */ 112 { &vop_putpages_desc, genfs_putpages }, /* putpages */ 113 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ 114 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ 115 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ 116 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ 117 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ 118 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ 119 { NULL, NULL } 120 }; 121 const struct vnodeopv_desc ffs_vnodeop_opv_desc = 122 { &ffs_vnodeop_p, ffs_vnodeop_entries }; 123 124 int (**ffs_specop_p)(void *); 125 const struct vnodeopv_entry_desc ffs_specop_entries[] = { 126 { &vop_default_desc, vn_default_error }, 127 { &vop_lookup_desc, spec_lookup }, /* lookup */ 128 { &vop_create_desc, spec_create }, /* create */ 129 { &vop_mknod_desc, spec_mknod }, /* mknod */ 130 { &vop_open_desc, spec_open }, /* open */ 131 { &vop_close_desc, ufsspec_close }, /* close */ 132 { &vop_access_desc, ufs_access }, /* access */ 133 { &vop_getattr_desc, ufs_getattr }, /* getattr */ 134 { &vop_setattr_desc, ufs_setattr }, /* setattr */ 135 { &vop_read_desc, ufsspec_read }, /* read */ 136 { &vop_write_desc, ufsspec_write }, /* write */ 137 { &vop_lease_desc, spec_lease_check }, /* lease */ 138 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 139 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ 140 { &vop_poll_desc, spec_poll }, /* poll */ 141 { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */ 142 { &vop_revoke_desc, spec_revoke }, /* revoke */ 143 { &vop_mmap_desc, spec_mmap }, /* mmap */ 144 { &vop_fsync_desc, ffs_fsync }, /* fsync */ 145 { &vop_seek_desc, spec_seek }, /* seek */ 146 { &vop_remove_desc, spec_remove }, /* remove */ 147 { &vop_link_desc, spec_link }, /* link */ 148 { &vop_rename_desc, spec_rename }, /* rename */ 149 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 150 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 151 { &vop_symlink_desc, spec_symlink }, /* symlink */ 152 { &vop_readdir_desc, spec_readdir }, /* readdir */ 153 { &vop_readlink_desc, spec_readlink }, /* readlink */ 154 { &vop_abortop_desc, spec_abortop }, /* abortop */ 155 { &vop_inactive_desc, ufs_inactive }, /* inactive */ 156 { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ 157 { &vop_lock_desc, ufs_lock }, /* lock */ 158 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 159 { &vop_bmap_desc, spec_bmap }, /* bmap */ 160 { &vop_strategy_desc, spec_strategy }, /* strategy */ 161 { &vop_print_desc, ufs_print }, /* print */ 162 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 163 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 164 { &vop_advlock_desc, spec_advlock }, /* advlock */ 165 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 166 { &vop_getpages_desc, spec_getpages }, /* getpages */ 167 { &vop_putpages_desc, spec_putpages }, /* putpages */ 168 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ 169 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ 170 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ 171 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ 172 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ 173 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ 174 { NULL, NULL } 175 }; 176 const struct vnodeopv_desc ffs_specop_opv_desc = 177 { &ffs_specop_p, ffs_specop_entries }; 178 179 int (**ffs_fifoop_p)(void *); 180 const struct vnodeopv_entry_desc ffs_fifoop_entries[] = { 181 { &vop_default_desc, vn_default_error }, 182 { &vop_lookup_desc, fifo_lookup }, /* lookup */ 183 { &vop_create_desc, fifo_create }, /* create */ 184 { &vop_mknod_desc, fifo_mknod }, /* mknod */ 185 { &vop_open_desc, fifo_open }, /* open */ 186 { &vop_close_desc, ufsfifo_close }, /* close */ 187 { &vop_access_desc, ufs_access }, /* access */ 188 { &vop_getattr_desc, ufs_getattr }, /* getattr */ 189 { &vop_setattr_desc, ufs_setattr }, /* setattr */ 190 { &vop_read_desc, ufsfifo_read }, /* read */ 191 { &vop_write_desc, ufsfifo_write }, /* write */ 192 { &vop_lease_desc, fifo_lease_check }, /* lease */ 193 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 194 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ 195 { &vop_poll_desc, fifo_poll }, /* poll */ 196 { &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */ 197 { &vop_revoke_desc, fifo_revoke }, /* revoke */ 198 { &vop_mmap_desc, fifo_mmap }, /* mmap */ 199 { &vop_fsync_desc, ffs_fsync }, /* fsync */ 200 { &vop_seek_desc, fifo_seek }, /* seek */ 201 { &vop_remove_desc, fifo_remove }, /* remove */ 202 { &vop_link_desc, fifo_link }, /* link */ 203 { &vop_rename_desc, fifo_rename }, /* rename */ 204 { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ 205 { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ 206 { &vop_symlink_desc, fifo_symlink }, /* symlink */ 207 { &vop_readdir_desc, fifo_readdir }, /* readdir */ 208 { &vop_readlink_desc, fifo_readlink }, /* readlink */ 209 { &vop_abortop_desc, fifo_abortop }, /* abortop */ 210 { &vop_inactive_desc, ufs_inactive }, /* inactive */ 211 { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ 212 { &vop_lock_desc, ufs_lock }, /* lock */ 213 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 214 { &vop_bmap_desc, fifo_bmap }, /* bmap */ 215 { &vop_strategy_desc, fifo_strategy }, /* strategy */ 216 { &vop_print_desc, ufs_print }, /* print */ 217 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 218 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */ 219 { &vop_advlock_desc, fifo_advlock }, /* advlock */ 220 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 221 { &vop_putpages_desc, fifo_putpages }, /* putpages */ 222 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ 223 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ 224 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ 225 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ 226 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ 227 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ 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_fsync(void *v) 237 { 238 struct vop_fsync_args /* { 239 struct vnode *a_vp; 240 struct ucred *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 struct buf *bp; 247 int s, num, error, i; 248 struct indir ia[NIADDR + 1]; 249 int bsize; 250 daddr_t blk_high; 251 struct vnode *vp; 252 253 /* 254 * XXX no easy way to sync a range in a file with softdep. 255 */ 256 if ((ap->a_offlo == 0 && ap->a_offhi == 0) || DOINGSOFTDEP(ap->a_vp) || 257 (ap->a_vp->v_type != VREG)) 258 return ffs_full_fsync(v); 259 260 vp = ap->a_vp; 261 262 bsize = ap->a_vp->v_mount->mnt_stat.f_iosize; 263 blk_high = ap->a_offhi / bsize; 264 if (ap->a_offhi % bsize != 0) 265 blk_high++; 266 267 /* 268 * First, flush all pages in range. 269 */ 270 271 simple_lock(&vp->v_interlock); 272 error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo), 273 round_page(ap->a_offhi), PGO_CLEANIT | 274 ((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0)); 275 if (error) { 276 return error; 277 } 278 279 /* 280 * Then, flush indirect blocks. 281 */ 282 283 s = splbio(); 284 if (blk_high >= NDADDR) { 285 error = ufs_getlbns(vp, blk_high, ia, &num); 286 if (error) { 287 splx(s); 288 return error; 289 } 290 for (i = 0; i < num; i++) { 291 bp = incore(vp, ia[i].in_lbn); 292 if (bp != NULL) { 293 simple_lock(&bp->b_interlock); 294 if (!(bp->b_flags & B_BUSY) && (bp->b_flags & B_DELWRI)) { 295 bp->b_flags |= B_BUSY | B_VFLUSH; 296 simple_unlock(&bp->b_interlock); 297 splx(s); 298 bawrite(bp); 299 s = splbio(); 300 } else { 301 simple_unlock(&bp->b_interlock); 302 } 303 } 304 } 305 } 306 307 if (ap->a_flags & FSYNC_WAIT) { 308 simple_lock(&global_v_numoutput_slock); 309 while (vp->v_numoutput > 0) { 310 vp->v_flag |= VBWAIT; 311 ltsleep(&vp->v_numoutput, PRIBIO + 1, "fsync_range", 0, 312 &global_v_numoutput_slock); 313 } 314 simple_unlock(&global_v_numoutput_slock); 315 } 316 splx(s); 317 318 error = ffs_update(vp, NULL, NULL, 319 ((ap->a_flags & (FSYNC_WAIT | FSYNC_DATAONLY)) == FSYNC_WAIT) 320 ? UPDATE_WAIT : 0); 321 322 if (error == 0 && ap->a_flags & FSYNC_CACHE) { 323 int l = 0; 324 VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &l, FWRITE, 325 ap->a_l->l_proc->p_ucred, ap->a_l); 326 } 327 328 return error; 329 } 330 331 /* 332 * Synch an open file. 333 */ 334 /* ARGSUSED */ 335 static int 336 ffs_full_fsync(void *v) 337 { 338 struct vop_fsync_args /* { 339 struct vnode *a_vp; 340 struct ucred *a_cred; 341 int a_flags; 342 off_t a_offlo; 343 off_t a_offhi; 344 struct lwp *a_l; 345 } */ *ap = v; 346 struct vnode *vp = ap->a_vp; 347 struct buf *bp, *nbp; 348 int s, error, passes, skipmeta, inodedeps_only, waitfor; 349 350 if (vp->v_type == VBLK && 351 vp->v_specmountpoint != NULL && 352 (vp->v_specmountpoint->mnt_flag & MNT_SOFTDEP)) 353 softdep_fsync_mountdev(vp); 354 355 inodedeps_only = DOINGSOFTDEP(vp) && (ap->a_flags & FSYNC_RECLAIM) 356 && vp->v_uobj.uo_npages == 0 && LIST_EMPTY(&vp->v_dirtyblkhd); 357 358 /* 359 * Flush all dirty data associated with a vnode. 360 */ 361 362 if (vp->v_type == VREG || vp->v_type == VBLK) { 363 simple_lock(&vp->v_interlock); 364 error = VOP_PUTPAGES(vp, 0, 0, PGO_ALLPAGES | PGO_CLEANIT | 365 ((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0)); 366 if (error) { 367 return error; 368 } 369 } 370 371 passes = NIADDR + 1; 372 skipmeta = 0; 373 if (ap->a_flags & FSYNC_WAIT) 374 skipmeta = 1; 375 s = splbio(); 376 377 loop: 378 LIST_FOREACH(bp, &vp->v_dirtyblkhd, b_vnbufs) 379 bp->b_flags &= ~B_SCANNED; 380 for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { 381 nbp = LIST_NEXT(bp, b_vnbufs); 382 simple_lock(&bp->b_interlock); 383 if (bp->b_flags & (B_BUSY | B_SCANNED)) { 384 simple_unlock(&bp->b_interlock); 385 continue; 386 } 387 if ((bp->b_flags & B_DELWRI) == 0) 388 panic("ffs_fsync: not dirty"); 389 if (skipmeta && bp->b_lblkno < 0) { 390 simple_unlock(&bp->b_interlock); 391 continue; 392 } 393 simple_unlock(&bp->b_interlock); 394 bp->b_flags |= B_BUSY | B_VFLUSH | B_SCANNED; 395 splx(s); 396 /* 397 * On our final pass through, do all I/O synchronously 398 * so that we can find out if our flush is failing 399 * because of write errors. 400 */ 401 if (passes > 0 || !(ap->a_flags & FSYNC_WAIT)) 402 (void) bawrite(bp); 403 else if ((error = bwrite(bp)) != 0) 404 return (error); 405 s = splbio(); 406 /* 407 * Since we may have slept during the I/O, we need 408 * to start from a known point. 409 */ 410 nbp = LIST_FIRST(&vp->v_dirtyblkhd); 411 } 412 if (skipmeta) { 413 skipmeta = 0; 414 goto loop; 415 } 416 if (ap->a_flags & FSYNC_WAIT) { 417 simple_lock(&global_v_numoutput_slock); 418 while (vp->v_numoutput) { 419 vp->v_flag |= VBWAIT; 420 (void) ltsleep(&vp->v_numoutput, PRIBIO + 1, 421 "ffsfsync", 0, &global_v_numoutput_slock); 422 } 423 simple_unlock(&global_v_numoutput_slock); 424 splx(s); 425 426 /* 427 * Ensure that any filesystem metadata associated 428 * with the vnode has been written. 429 */ 430 if ((error = softdep_sync_metadata(ap)) != 0) 431 return (error); 432 433 s = splbio(); 434 if (!LIST_EMPTY(&vp->v_dirtyblkhd)) { 435 /* 436 * Block devices associated with filesystems may 437 * have new I/O requests posted for them even if 438 * the vnode is locked, so no amount of trying will 439 * get them clean. Thus we give block devices a 440 * good effort, then just give up. For all other file 441 * types, go around and try again until it is clean. 442 */ 443 if (passes > 0) { 444 passes--; 445 goto loop; 446 } 447 #ifdef DIAGNOSTIC 448 if (vp->v_type != VBLK) 449 vprint("ffs_fsync: dirty", vp); 450 #endif 451 } 452 } 453 splx(s); 454 455 if (inodedeps_only) 456 waitfor = 0; 457 else 458 waitfor = (ap->a_flags & FSYNC_WAIT) ? UPDATE_WAIT : 0; 459 error = ffs_update(vp, NULL, NULL, waitfor); 460 461 if (error == 0 && ap->a_flags & FSYNC_CACHE) { 462 int i = 0; 463 VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &i, FWRITE, 464 ap->a_l->l_proc->p_ucred, ap->a_l); 465 } 466 467 return error; 468 } 469 470 /* 471 * Reclaim an inode so that it can be used for other purposes. 472 */ 473 int 474 ffs_reclaim(void *v) 475 { 476 struct vop_reclaim_args /* { 477 struct vnode *a_vp; 478 struct lwp *a_l; 479 } */ *ap = v; 480 struct vnode *vp = ap->a_vp; 481 struct inode *ip = VTOI(vp); 482 struct ufsmount *ump = ip->i_ump; 483 int error; 484 485 if ((error = ufs_reclaim(vp, ap->a_l)) != 0) 486 return (error); 487 if (ip->i_din.ffs1_din != NULL) { 488 if (ump->um_fstype == UFS1) 489 pool_put(&ffs_dinode1_pool, ip->i_din.ffs1_din); 490 else 491 pool_put(&ffs_dinode2_pool, ip->i_din.ffs2_din); 492 } 493 /* 494 * XXX MFS ends up here, too, to free an inode. Should we create 495 * XXX a separate pool for MFS inodes? 496 */ 497 pool_put(&ffs_inode_pool, vp->v_data); 498 vp->v_data = NULL; 499 return (0); 500 } 501 502 int 503 ffs_getpages(void *v) 504 { 505 struct vop_getpages_args /* { 506 struct vnode *a_vp; 507 voff_t a_offset; 508 struct vm_page **a_m; 509 int *a_count; 510 int a_centeridx; 511 vm_prot_t a_access_type; 512 int a_advice; 513 int a_flags; 514 } */ *ap = v; 515 struct vnode *vp = ap->a_vp; 516 struct inode *ip = VTOI(vp); 517 struct fs *fs = ip->i_fs; 518 519 /* 520 * don't allow a softdep write to create pages for only part of a block. 521 * the dependency tracking requires that all pages be in memory for 522 * a block involved in a dependency. 523 */ 524 525 if (ap->a_flags & PGO_OVERWRITE && 526 (blkoff(fs, ap->a_offset) != 0 || 527 blkoff(fs, *ap->a_count << PAGE_SHIFT) != 0) && 528 DOINGSOFTDEP(ap->a_vp)) { 529 if ((ap->a_flags & PGO_LOCKED) == 0) { 530 simple_unlock(&vp->v_interlock); 531 } 532 return EINVAL; 533 } 534 return genfs_getpages(v); 535 } 536 537 /* 538 * Return the last logical file offset that should be written for this file 539 * if we're doing a write that ends at "size". 540 */ 541 542 void 543 ffs_gop_size(struct vnode *vp, off_t size, off_t *eobp, int flags) 544 { 545 struct inode *ip = VTOI(vp); 546 struct fs *fs = ip->i_fs; 547 daddr_t olbn, nlbn; 548 549 KASSERT(flags & (GOP_SIZE_READ | GOP_SIZE_WRITE)); 550 KASSERT((flags & (GOP_SIZE_READ | GOP_SIZE_WRITE)) 551 != (GOP_SIZE_READ | GOP_SIZE_WRITE)); 552 553 olbn = lblkno(fs, ip->i_size); 554 nlbn = lblkno(fs, size); 555 if (nlbn < NDADDR && olbn <= nlbn) { 556 *eobp = fragroundup(fs, size); 557 } else { 558 *eobp = blkroundup(fs, size); 559 } 560 } 561 562 int 563 ffs_openextattr(void *v) 564 { 565 struct vop_openextattr_args /* { 566 struct vnode *a_vp; 567 struct ucred *a_cred; 568 struct proc *a_p; 569 } */ *ap = v; 570 struct inode *ip = VTOI(ap->a_vp); 571 struct fs *fs = ip->i_fs; 572 573 /* Not supported for UFS1 file systems. */ 574 if (fs->fs_magic == FS_UFS1_MAGIC) 575 return (EOPNOTSUPP); 576 577 /* XXX Not implemented for UFS2 file systems. */ 578 return (EOPNOTSUPP); 579 } 580 581 int 582 ffs_closeextattr(void *v) 583 { 584 struct vop_closeextattr_args /* { 585 struct vnode *a_vp; 586 int a_commit; 587 struct ucred *a_cred; 588 struct proc *a_p; 589 } */ *ap = v; 590 struct inode *ip = VTOI(ap->a_vp); 591 struct fs *fs = ip->i_fs; 592 593 /* Not supported for UFS1 file systems. */ 594 if (fs->fs_magic == FS_UFS1_MAGIC) 595 return (EOPNOTSUPP); 596 597 /* XXX Not implemented for UFS2 file systems. */ 598 return (EOPNOTSUPP); 599 } 600 601 int 602 ffs_getextattr(void *v) 603 { 604 struct vop_getextattr_args /* { 605 struct vnode *a_vp; 606 int a_attrnamespace; 607 const char *a_name; 608 struct uio *a_uio; 609 size_t *a_size; 610 struct ucred *a_cred; 611 struct proc *a_p; 612 } */ *ap = v; 613 struct inode *ip = VTOI(ap->a_vp); 614 struct fs *fs = ip->i_fs; 615 616 if (fs->fs_magic == FS_UFS1_MAGIC) { 617 #ifdef UFS_EXTATTR 618 return (ufs_getextattr(ap)); 619 #else 620 return (EOPNOTSUPP); 621 #endif 622 } 623 624 /* XXX Not implemented for UFS2 file systems. */ 625 return (EOPNOTSUPP); 626 } 627 628 int 629 ffs_setextattr(void *v) 630 { 631 struct vop_setextattr_args /* { 632 struct vnode *a_vp; 633 int a_attrnamespace; 634 const char *a_name; 635 struct uio *a_uio; 636 struct ucred *a_cred; 637 struct proc *a_p; 638 } */ *ap = v; 639 struct inode *ip = VTOI(ap->a_vp); 640 struct fs *fs = ip->i_fs; 641 642 if (fs->fs_magic == FS_UFS1_MAGIC) { 643 #ifdef UFS_EXTATTR 644 return (ufs_setextattr(ap)); 645 #else 646 return (EOPNOTSUPP); 647 #endif 648 } 649 650 /* XXX Not implemented for UFS2 file systems. */ 651 return (EOPNOTSUPP); 652 } 653 654 int 655 ffs_listextattr(void *v) 656 { 657 struct vop_listextattr_args /* { 658 struct vnode *a_vp; 659 int a_attrnamespace; 660 struct uio *a_uio; 661 size_t *a_size; 662 struct ucred *a_cred; 663 struct proc *a_p; 664 } */ *ap = v; 665 struct inode *ip = VTOI(ap->a_vp); 666 struct fs *fs = ip->i_fs; 667 668 /* Not supported for UFS1 file systems. */ 669 if (fs->fs_magic == FS_UFS1_MAGIC) 670 return (EOPNOTSUPP); 671 672 /* XXX Not implemented for UFS2 file systems. */ 673 return (EOPNOTSUPP); 674 } 675 676 int 677 ffs_deleteextattr(void *v) 678 { 679 struct vop_deleteextattr_args /* { 680 struct vnode *a_vp; 681 int a_attrnamespace; 682 struct ucred *a_cred; 683 struct proc *a_p; 684 } */ *ap = v; 685 struct inode *ip = VTOI(ap->a_vp); 686 struct fs *fs = ip->i_fs; 687 688 if (fs->fs_magic == FS_UFS1_MAGIC) { 689 #ifdef UFS_EXTATTR 690 return (ufs_deleteextattr(ap)); 691 #else 692 return (EOPNOTSUPP); 693 #endif 694 } 695 696 /* XXX Not implemented for UFS2 file systems. */ 697 return (EOPNOTSUPP); 698 } 699