1 /* $NetBSD: lfs_vnops.c,v 1.64 2002/05/17 21:42:38 perseant Exp $ */ 2 3 /*- 4 * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Konrad E. Schroder <perseant@hhhh.org>. 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 /* 39 * Copyright (c) 1986, 1989, 1991, 1993, 1995 40 * The Regents of the University of California. All rights reserved. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. All advertising materials mentioning features or use of this software 51 * must display the following acknowledgement: 52 * This product includes software developed by the University of 53 * California, Berkeley and its contributors. 54 * 4. Neither the name of the University nor the names of its contributors 55 * may be used to endorse or promote products derived from this software 56 * without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * SUCH DAMAGE. 69 * 70 * @(#)lfs_vnops.c 8.13 (Berkeley) 6/10/95 71 */ 72 73 #include <sys/cdefs.h> 74 __KERNEL_RCSID(0, "$NetBSD: lfs_vnops.c,v 1.64 2002/05/17 21:42:38 perseant Exp $"); 75 76 #include <sys/param.h> 77 #include <sys/systm.h> 78 #include <sys/namei.h> 79 #include <sys/resourcevar.h> 80 #include <sys/kernel.h> 81 #include <sys/file.h> 82 #include <sys/stat.h> 83 #include <sys/buf.h> 84 #include <sys/proc.h> 85 #include <sys/conf.h> 86 #include <sys/mount.h> 87 #include <sys/vnode.h> 88 #include <sys/malloc.h> 89 #include <sys/pool.h> 90 #include <sys/signalvar.h> 91 92 #include <miscfs/fifofs/fifo.h> 93 #include <miscfs/genfs/genfs.h> 94 #include <miscfs/specfs/specdev.h> 95 96 #include <ufs/ufs/inode.h> 97 #include <ufs/ufs/dir.h> 98 #include <ufs/ufs/ufsmount.h> 99 #include <ufs/ufs/ufs_extern.h> 100 101 #include <ufs/lfs/lfs.h> 102 #include <ufs/lfs/lfs_extern.h> 103 104 /* Global vfs data structures for lfs. */ 105 int (**lfs_vnodeop_p)(void *); 106 const struct vnodeopv_entry_desc lfs_vnodeop_entries[] = { 107 { &vop_default_desc, vn_default_error }, 108 { &vop_lookup_desc, ufs_lookup }, /* lookup */ 109 { &vop_create_desc, lfs_create }, /* create */ 110 { &vop_whiteout_desc, lfs_whiteout }, /* whiteout */ 111 { &vop_mknod_desc, lfs_mknod }, /* mknod */ 112 { &vop_open_desc, ufs_open }, /* open */ 113 { &vop_close_desc, lfs_close }, /* close */ 114 { &vop_access_desc, ufs_access }, /* access */ 115 { &vop_getattr_desc, lfs_getattr }, /* getattr */ 116 { &vop_setattr_desc, lfs_setattr }, /* setattr */ 117 { &vop_read_desc, lfs_read }, /* read */ 118 { &vop_write_desc, lfs_write }, /* write */ 119 { &vop_lease_desc, ufs_lease_check }, /* lease */ 120 { &vop_ioctl_desc, ufs_ioctl }, /* ioctl */ 121 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ 122 { &vop_poll_desc, ufs_poll }, /* poll */ 123 { &vop_revoke_desc, ufs_revoke }, /* revoke */ 124 { &vop_mmap_desc, ufs_mmap }, /* mmap */ 125 { &vop_fsync_desc, lfs_fsync }, /* fsync */ 126 { &vop_seek_desc, ufs_seek }, /* seek */ 127 { &vop_remove_desc, lfs_remove }, /* remove */ 128 { &vop_link_desc, lfs_link }, /* link */ 129 { &vop_rename_desc, lfs_rename }, /* rename */ 130 { &vop_mkdir_desc, lfs_mkdir }, /* mkdir */ 131 { &vop_rmdir_desc, lfs_rmdir }, /* rmdir */ 132 { &vop_symlink_desc, lfs_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, lfs_inactive }, /* inactive */ 137 { &vop_reclaim_desc, lfs_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_blkatoff_desc, lfs_blkatoff }, /* blkatoff */ 147 { &vop_valloc_desc, lfs_valloc }, /* valloc */ 148 { &vop_balloc_desc, lfs_balloc }, /* balloc */ 149 { &vop_vfree_desc, lfs_vfree }, /* vfree */ 150 { &vop_truncate_desc, lfs_truncate }, /* truncate */ 151 { &vop_update_desc, lfs_update }, /* update */ 152 { &vop_bwrite_desc, lfs_bwrite }, /* bwrite */ 153 { &vop_getpages_desc, lfs_getpages }, /* getpages */ 154 { &vop_putpages_desc, lfs_putpages }, /* putpages */ 155 { NULL, NULL } 156 }; 157 const struct vnodeopv_desc lfs_vnodeop_opv_desc = 158 { &lfs_vnodeop_p, lfs_vnodeop_entries }; 159 160 int (**lfs_specop_p)(void *); 161 const struct vnodeopv_entry_desc lfs_specop_entries[] = { 162 { &vop_default_desc, vn_default_error }, 163 { &vop_lookup_desc, spec_lookup }, /* lookup */ 164 { &vop_create_desc, spec_create }, /* create */ 165 { &vop_mknod_desc, spec_mknod }, /* mknod */ 166 { &vop_open_desc, spec_open }, /* open */ 167 { &vop_close_desc, ufsspec_close }, /* close */ 168 { &vop_access_desc, ufs_access }, /* access */ 169 { &vop_getattr_desc, lfs_getattr }, /* getattr */ 170 { &vop_setattr_desc, lfs_setattr }, /* setattr */ 171 { &vop_read_desc, ufsspec_read }, /* read */ 172 { &vop_write_desc, ufsspec_write }, /* write */ 173 { &vop_lease_desc, spec_lease_check }, /* lease */ 174 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 175 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ 176 { &vop_poll_desc, spec_poll }, /* poll */ 177 { &vop_revoke_desc, spec_revoke }, /* revoke */ 178 { &vop_mmap_desc, spec_mmap }, /* mmap */ 179 { &vop_fsync_desc, spec_fsync }, /* fsync */ 180 { &vop_seek_desc, spec_seek }, /* seek */ 181 { &vop_remove_desc, spec_remove }, /* remove */ 182 { &vop_link_desc, spec_link }, /* link */ 183 { &vop_rename_desc, spec_rename }, /* rename */ 184 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 185 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 186 { &vop_symlink_desc, spec_symlink }, /* symlink */ 187 { &vop_readdir_desc, spec_readdir }, /* readdir */ 188 { &vop_readlink_desc, spec_readlink }, /* readlink */ 189 { &vop_abortop_desc, spec_abortop }, /* abortop */ 190 { &vop_inactive_desc, lfs_inactive }, /* inactive */ 191 { &vop_reclaim_desc, lfs_reclaim }, /* reclaim */ 192 { &vop_lock_desc, ufs_lock }, /* lock */ 193 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 194 { &vop_bmap_desc, spec_bmap }, /* bmap */ 195 { &vop_strategy_desc, spec_strategy }, /* strategy */ 196 { &vop_print_desc, ufs_print }, /* print */ 197 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 198 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 199 { &vop_advlock_desc, spec_advlock }, /* advlock */ 200 { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ 201 { &vop_valloc_desc, spec_valloc }, /* valloc */ 202 { &vop_vfree_desc, lfs_vfree }, /* vfree */ 203 { &vop_truncate_desc, spec_truncate }, /* truncate */ 204 { &vop_update_desc, lfs_update }, /* update */ 205 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 206 { &vop_getpages_desc, spec_getpages }, /* getpages */ 207 { &vop_putpages_desc, spec_putpages }, /* putpages */ 208 { NULL, NULL } 209 }; 210 const struct vnodeopv_desc lfs_specop_opv_desc = 211 { &lfs_specop_p, lfs_specop_entries }; 212 213 int (**lfs_fifoop_p)(void *); 214 const struct vnodeopv_entry_desc lfs_fifoop_entries[] = { 215 { &vop_default_desc, vn_default_error }, 216 { &vop_lookup_desc, fifo_lookup }, /* lookup */ 217 { &vop_create_desc, fifo_create }, /* create */ 218 { &vop_mknod_desc, fifo_mknod }, /* mknod */ 219 { &vop_open_desc, fifo_open }, /* open */ 220 { &vop_close_desc, ufsfifo_close }, /* close */ 221 { &vop_access_desc, ufs_access }, /* access */ 222 { &vop_getattr_desc, lfs_getattr }, /* getattr */ 223 { &vop_setattr_desc, lfs_setattr }, /* setattr */ 224 { &vop_read_desc, ufsfifo_read }, /* read */ 225 { &vop_write_desc, ufsfifo_write }, /* write */ 226 { &vop_lease_desc, fifo_lease_check }, /* lease */ 227 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 228 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ 229 { &vop_poll_desc, fifo_poll }, /* poll */ 230 { &vop_revoke_desc, fifo_revoke }, /* revoke */ 231 { &vop_mmap_desc, fifo_mmap }, /* mmap */ 232 { &vop_fsync_desc, fifo_fsync }, /* fsync */ 233 { &vop_seek_desc, fifo_seek }, /* seek */ 234 { &vop_remove_desc, fifo_remove }, /* remove */ 235 { &vop_link_desc, fifo_link }, /* link */ 236 { &vop_rename_desc, fifo_rename }, /* rename */ 237 { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ 238 { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ 239 { &vop_symlink_desc, fifo_symlink }, /* symlink */ 240 { &vop_readdir_desc, fifo_readdir }, /* readdir */ 241 { &vop_readlink_desc, fifo_readlink }, /* readlink */ 242 { &vop_abortop_desc, fifo_abortop }, /* abortop */ 243 { &vop_inactive_desc, lfs_inactive }, /* inactive */ 244 { &vop_reclaim_desc, lfs_reclaim }, /* reclaim */ 245 { &vop_lock_desc, ufs_lock }, /* lock */ 246 { &vop_unlock_desc, ufs_unlock }, /* unlock */ 247 { &vop_bmap_desc, fifo_bmap }, /* bmap */ 248 { &vop_strategy_desc, fifo_strategy }, /* strategy */ 249 { &vop_print_desc, ufs_print }, /* print */ 250 { &vop_islocked_desc, ufs_islocked }, /* islocked */ 251 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */ 252 { &vop_advlock_desc, fifo_advlock }, /* advlock */ 253 { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */ 254 { &vop_valloc_desc, fifo_valloc }, /* valloc */ 255 { &vop_vfree_desc, lfs_vfree }, /* vfree */ 256 { &vop_truncate_desc, fifo_truncate }, /* truncate */ 257 { &vop_update_desc, lfs_update }, /* update */ 258 { &vop_bwrite_desc, lfs_bwrite }, /* bwrite */ 259 { &vop_putpages_desc, fifo_putpages }, /* putpages */ 260 { NULL, NULL } 261 }; 262 const struct vnodeopv_desc lfs_fifoop_opv_desc = 263 { &lfs_fifoop_p, lfs_fifoop_entries }; 264 265 /* 266 * A function version of LFS_ITIMES, for the UFS functions which call ITIMES 267 */ 268 void 269 lfs_itimes(struct inode *ip, struct timespec *acc, struct timespec *mod, struct timespec *cre) 270 { 271 LFS_ITIMES(ip, acc, mod, cre); 272 } 273 274 #define LFS_READWRITE 275 #include <ufs/ufs/ufs_readwrite.c> 276 #undef LFS_READWRITE 277 278 /* 279 * Synch an open file. 280 */ 281 /* ARGSUSED */ 282 int 283 lfs_fsync(void *v) 284 { 285 struct vop_fsync_args /* { 286 struct vnode *a_vp; 287 struct ucred *a_cred; 288 int a_flags; 289 off_t offlo; 290 off_t offhi; 291 struct proc *a_p; 292 } */ *ap = v; 293 struct vnode *vp = ap->a_vp; 294 int error; 295 296 /* Ignore the trickle syncer */ 297 if (ap->a_flags & FSYNC_LAZY) 298 return 0; 299 300 simple_lock(&vp->v_interlock); 301 error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo), 302 round_page(ap->a_offhi), PGO_CLEANIT | PGO_SYNCIO); 303 if (error) 304 return error; 305 error = VOP_UPDATE(vp, NULL, NULL, 306 (ap->a_flags & FSYNC_WAIT) != 0 ? UPDATE_WAIT : 0); 307 #ifdef DEBUG 308 /* 309 * If we were called from vinvalbuf and lfs_update 310 * didn't flush all our buffers, we're in trouble. 311 */ 312 if ((ap->a_flags & FSYNC_WAIT) && LIST_FIRST(&vp->v_dirtyblkhd) != NULL) { 313 struct buf *bp; 314 315 bp = LIST_FIRST(&vp->v_dirtyblkhd); 316 printf("lfs_fsync: ino %d failed to sync", VTOI(vp)->i_number); 317 printf("lfs_fsync: iocount = %d\n", VTOI(vp)->i_lfs->lfs_iocount); 318 printf("lfs_fsync: flags are 0x%x, numoutput=%d\n", 319 VTOI(vp)->i_flag, vp->v_numoutput); 320 printf("lfs_fsync: writecount=%ld\n", vp->v_writecount); 321 printf("lfs_fsync: first bp: %p, flags=0x%lx, lbn=%d\n", 322 bp, bp->b_flags, bp->b_lblkno); 323 } 324 #endif 325 return error; 326 } 327 328 /* 329 * Take IN_ADIROP off, then call ufs_inactive. 330 */ 331 int 332 lfs_inactive(void *v) 333 { 334 struct vop_inactive_args /* { 335 struct vnode *a_vp; 336 struct proc *a_p; 337 } */ *ap = v; 338 struct inode *ip = VTOI(ap->a_vp); 339 340 if (ip->i_flag & IN_ADIROP) 341 --ip->i_lfs->lfs_nadirop; 342 ip->i_flag &= ~IN_ADIROP; 343 return ufs_inactive(v); 344 } 345 346 /* 347 * These macros are used to bracket UFS directory ops, so that we can 348 * identify all the pages touched during directory ops which need to 349 * be ordered and flushed atomically, so that they may be recovered. 350 */ 351 /* 352 * XXX KS - Because we have to mark nodes VDIROP in order to prevent 353 * the cache from reclaiming them while a dirop is in progress, we must 354 * also manage the number of nodes so marked (otherwise we can run out). 355 * We do this by setting lfs_dirvcount to the number of marked vnodes; it 356 * is decremented during segment write, when VDIROP is taken off. 357 */ 358 #define SET_DIROP(vp) lfs_set_dirop(vp) 359 static int lfs_set_dirop(struct vnode *); 360 extern int lfs_dirvcount; 361 362 static int 363 lfs_set_dirop(struct vnode *vp) 364 { 365 struct lfs *fs; 366 int error; 367 368 fs = VTOI(vp)->i_lfs; 369 /* 370 * We might need one directory block plus supporting indirect blocks, 371 * plus an inode block and ifile page for the new vnode. 372 */ 373 if ((error = lfs_reserve(fs, vp, btofsb(fs, (NIADDR + 3) << fs->lfs_bshift))) != 0) 374 return (error); 375 if (fs->lfs_dirops == 0) 376 lfs_check(vp, LFS_UNUSED_LBN, 0); 377 while (fs->lfs_writer || lfs_dirvcount > LFS_MAXDIROP) { 378 if (fs->lfs_writer) 379 tsleep(&fs->lfs_dirops, PRIBIO + 1, "lfs_sdirop", 0); 380 if (lfs_dirvcount > LFS_MAXDIROP && fs->lfs_dirops == 0) { 381 ++fs->lfs_writer; 382 lfs_flush(fs, 0); 383 if (--fs->lfs_writer == 0) 384 wakeup(&fs->lfs_dirops); 385 } 386 387 if (lfs_dirvcount > LFS_MAXDIROP) { 388 #ifdef DEBUG_LFS 389 printf("lfs_set_dirop: sleeping with dirops=%d, " 390 "dirvcount=%d\n", fs->lfs_dirops, 391 lfs_dirvcount); 392 #endif 393 if ((error = tsleep(&lfs_dirvcount, PCATCH|PUSER, 394 "lfs_maxdirop", 0)) != 0) { 395 lfs_reserve(fs, vp, -btofsb(fs, (NIADDR + 3) << fs->lfs_bshift)); 396 return error; 397 } 398 } 399 } 400 ++fs->lfs_dirops; 401 fs->lfs_doifile = 1; 402 403 /* Hold a reference so SET_ENDOP will be happy */ 404 lfs_vref(vp); 405 406 return 0; 407 } 408 409 #define SET_ENDOP(fs,vp,str) { \ 410 --(fs)->lfs_dirops; \ 411 if (!(fs)->lfs_dirops) { \ 412 if ((fs)->lfs_nadirop) { \ 413 panic("SET_ENDOP: %s: no dirops but nadirop=%d\n", \ 414 (str), (fs)->lfs_nadirop); \ 415 } \ 416 wakeup(&(fs)->lfs_writer); \ 417 lfs_check((vp),LFS_UNUSED_LBN,0); \ 418 } \ 419 lfs_reserve((fs), vp, -btofsb((fs), (NIADDR + 3) << (fs)->lfs_bshift)); /* XXX */ \ 420 lfs_vunref(vp); \ 421 } 422 423 #define MARK_VNODE(dvp) do { \ 424 if (!((dvp)->v_flag & VDIROP)) { \ 425 (void)lfs_vref(dvp); \ 426 ++lfs_dirvcount; \ 427 } \ 428 (dvp)->v_flag |= VDIROP; \ 429 if (!(VTOI(dvp)->i_flag & IN_ADIROP)) { \ 430 ++VTOI(dvp)->i_lfs->lfs_nadirop; \ 431 } \ 432 VTOI(dvp)->i_flag |= IN_ADIROP; \ 433 } while (0) 434 435 #define UNMARK_VNODE(vp) lfs_unmark_vnode(vp) 436 437 void lfs_unmark_vnode(struct vnode *vp) 438 { 439 struct inode *ip; 440 441 ip = VTOI(vp); 442 443 if (ip->i_flag & IN_ADIROP) 444 --ip->i_lfs->lfs_nadirop; 445 ip->i_flag &= ~IN_ADIROP; 446 } 447 448 int 449 lfs_symlink(void *v) 450 { 451 struct vop_symlink_args /* { 452 struct vnode *a_dvp; 453 struct vnode **a_vpp; 454 struct componentname *a_cnp; 455 struct vattr *a_vap; 456 char *a_target; 457 } */ *ap = v; 458 int error; 459 460 if ((error = SET_DIROP(ap->a_dvp)) != 0) { 461 vput(ap->a_dvp); 462 return error; 463 } 464 MARK_VNODE(ap->a_dvp); 465 error = ufs_symlink(ap); 466 UNMARK_VNODE(ap->a_dvp); 467 if (*(ap->a_vpp)) 468 UNMARK_VNODE(*(ap->a_vpp)); 469 SET_ENDOP(VTOI(ap->a_dvp)->i_lfs,ap->a_dvp,"symlink"); 470 return (error); 471 } 472 473 int 474 lfs_mknod(void *v) 475 { 476 struct vop_mknod_args /* { 477 struct vnode *a_dvp; 478 struct vnode **a_vpp; 479 struct componentname *a_cnp; 480 struct vattr *a_vap; 481 } */ *ap = v; 482 struct vattr *vap = ap->a_vap; 483 struct vnode **vpp = ap->a_vpp; 484 struct inode *ip; 485 int error; 486 struct mount *mp; 487 ino_t ino; 488 489 if ((error = SET_DIROP(ap->a_dvp)) != 0) { 490 vput(ap->a_dvp); 491 return error; 492 } 493 MARK_VNODE(ap->a_dvp); 494 error = ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode), 495 ap->a_dvp, vpp, ap->a_cnp); 496 UNMARK_VNODE(ap->a_dvp); 497 if (*(ap->a_vpp)) 498 UNMARK_VNODE(*(ap->a_vpp)); 499 500 /* Either way we're done with the dirop at this point */ 501 SET_ENDOP(VTOI(ap->a_dvp)->i_lfs,ap->a_dvp,"mknod"); 502 503 if (error) 504 return (error); 505 506 ip = VTOI(*vpp); 507 mp = (*vpp)->v_mount; 508 ino = ip->i_number; 509 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 510 if (vap->va_rdev != VNOVAL) { 511 /* 512 * Want to be able to use this to make badblock 513 * inodes, so don't truncate the dev number. 514 */ 515 #if 0 516 ip->i_ffs_rdev = ufs_rw32(vap->va_rdev, 517 UFS_MPNEEDSWAP((*vpp)->v_mount)); 518 #else 519 ip->i_ffs_rdev = vap->va_rdev; 520 #endif 521 } 522 /* 523 * Call fsync to write the vnode so that we don't have to deal with 524 * flushing it when it's marked VDIROP|VXLOCK. 525 * 526 * XXX KS - If we can't flush we also can't call vgone(), so must 527 * return. But, that leaves this vnode in limbo, also not good. 528 * Can this ever happen (barring hardware failure)? 529 */ 530 if ((error = VOP_FSYNC(*vpp, NOCRED, FSYNC_WAIT, 0, 0, curproc)) != 0) { 531 printf("Couldn't fsync in mknod (ino %d)---what do I do?\n", 532 VTOI(*vpp)->i_number); 533 return (error); 534 } 535 /* 536 * Remove vnode so that it will be reloaded by VFS_VGET and 537 * checked to see if it is an alias of an existing entry in 538 * the inode cache. 539 */ 540 /* Used to be vput, but that causes us to call VOP_INACTIVE twice. */ 541 VOP_UNLOCK(*vpp, 0); 542 lfs_vunref(*vpp); 543 (*vpp)->v_type = VNON; 544 vgone(*vpp); 545 error = VFS_VGET(mp, ino, vpp); 546 if (error != 0) { 547 *vpp = NULL; 548 return (error); 549 } 550 return (0); 551 } 552 553 int 554 lfs_create(void *v) 555 { 556 struct vop_create_args /* { 557 struct vnode *a_dvp; 558 struct vnode **a_vpp; 559 struct componentname *a_cnp; 560 struct vattr *a_vap; 561 } */ *ap = v; 562 int error; 563 564 if ((error = SET_DIROP(ap->a_dvp)) != 0) { 565 vput(ap->a_dvp); 566 return error; 567 } 568 MARK_VNODE(ap->a_dvp); 569 error = ufs_create(ap); 570 UNMARK_VNODE(ap->a_dvp); 571 if (*(ap->a_vpp)) 572 UNMARK_VNODE(*(ap->a_vpp)); 573 SET_ENDOP(VTOI(ap->a_dvp)->i_lfs,ap->a_dvp,"create"); 574 return (error); 575 } 576 577 int 578 lfs_whiteout(void *v) 579 { 580 struct vop_whiteout_args /* { 581 struct vnode *a_dvp; 582 struct componentname *a_cnp; 583 int a_flags; 584 } */ *ap = v; 585 int error; 586 587 if ((error = SET_DIROP(ap->a_dvp)) != 0) 588 /* XXX no unlock here? */ 589 return error; 590 MARK_VNODE(ap->a_dvp); 591 error = ufs_whiteout(ap); 592 UNMARK_VNODE(ap->a_dvp); 593 SET_ENDOP(VTOI(ap->a_dvp)->i_lfs,ap->a_dvp,"whiteout"); 594 return (error); 595 } 596 597 int 598 lfs_mkdir(void *v) 599 { 600 struct vop_mkdir_args /* { 601 struct vnode *a_dvp; 602 struct vnode **a_vpp; 603 struct componentname *a_cnp; 604 struct vattr *a_vap; 605 } */ *ap = v; 606 int error; 607 608 if ((error = SET_DIROP(ap->a_dvp)) != 0) { 609 vput(ap->a_dvp); 610 return error; 611 } 612 MARK_VNODE(ap->a_dvp); 613 error = ufs_mkdir(ap); 614 UNMARK_VNODE(ap->a_dvp); 615 if (*(ap->a_vpp)) 616 UNMARK_VNODE(*(ap->a_vpp)); 617 SET_ENDOP(VTOI(ap->a_dvp)->i_lfs,ap->a_dvp,"mkdir"); 618 return (error); 619 } 620 621 int 622 lfs_remove(void *v) 623 { 624 struct vop_remove_args /* { 625 struct vnode *a_dvp; 626 struct vnode *a_vp; 627 struct componentname *a_cnp; 628 } */ *ap = v; 629 struct vnode *dvp, *vp; 630 int error; 631 632 dvp = ap->a_dvp; 633 vp = ap->a_vp; 634 if ((error = SET_DIROP(dvp)) != 0) { 635 if (dvp == vp) 636 vrele(vp); 637 else 638 vput(vp); 639 vput(dvp); 640 return error; 641 } 642 MARK_VNODE(dvp); 643 MARK_VNODE(vp); 644 error = ufs_remove(ap); 645 UNMARK_VNODE(dvp); 646 UNMARK_VNODE(vp); 647 648 /* 649 * If ufs_remove failed, vp doesn't need to be VDIROP any more. 650 * If it succeeded, we can go ahead and wipe out vp, since 651 * its loss won't appear on disk until checkpoint, and by then 652 * dvp will have been written, completing the dirop. 653 */ 654 --lfs_dirvcount; 655 vp->v_flag &= ~VDIROP; 656 wakeup(&lfs_dirvcount); 657 vrele(vp); 658 659 SET_ENDOP(VTOI(dvp)->i_lfs,dvp,"remove"); 660 return (error); 661 } 662 663 int 664 lfs_rmdir(void *v) 665 { 666 struct vop_rmdir_args /* { 667 struct vnodeop_desc *a_desc; 668 struct vnode *a_dvp; 669 struct vnode *a_vp; 670 struct componentname *a_cnp; 671 } */ *ap = v; 672 int error; 673 674 if ((error = SET_DIROP(ap->a_dvp)) != 0) { 675 vrele(ap->a_dvp); 676 if (ap->a_vp->v_mountedhere != NULL) 677 VOP_UNLOCK(ap->a_dvp, 0); 678 vput(ap->a_vp); 679 return error; 680 } 681 MARK_VNODE(ap->a_dvp); 682 MARK_VNODE(ap->a_vp); 683 error = ufs_rmdir(ap); 684 UNMARK_VNODE(ap->a_dvp); 685 UNMARK_VNODE(ap->a_vp); 686 687 /* 688 * If ufs_rmdir failed, vp doesn't need to be VDIROP any more. 689 * If it succeeded, we can go ahead and wipe out vp, since 690 * its loss won't appear on disk until checkpoint, and by then 691 * dvp will have been written, completing the dirop. 692 */ 693 --lfs_dirvcount; 694 ap->a_vp->v_flag &= ~VDIROP; 695 wakeup(&lfs_dirvcount); 696 vrele(ap->a_vp); 697 698 SET_ENDOP(VTOI(ap->a_dvp)->i_lfs,ap->a_dvp,"rmdir"); 699 return (error); 700 } 701 702 int 703 lfs_link(void *v) 704 { 705 struct vop_link_args /* { 706 struct vnode *a_dvp; 707 struct vnode *a_vp; 708 struct componentname *a_cnp; 709 } */ *ap = v; 710 int error; 711 712 if ((error = SET_DIROP(ap->a_dvp)) != 0) { 713 vput(ap->a_dvp); 714 return error; 715 } 716 MARK_VNODE(ap->a_dvp); 717 error = ufs_link(ap); 718 UNMARK_VNODE(ap->a_dvp); 719 SET_ENDOP(VTOI(ap->a_dvp)->i_lfs,ap->a_dvp,"link"); 720 return (error); 721 } 722 723 int 724 lfs_rename(void *v) 725 { 726 struct vop_rename_args /* { 727 struct vnode *a_fdvp; 728 struct vnode *a_fvp; 729 struct componentname *a_fcnp; 730 struct vnode *a_tdvp; 731 struct vnode *a_tvp; 732 struct componentname *a_tcnp; 733 } */ *ap = v; 734 struct vnode *tvp, *fvp, *tdvp, *fdvp; 735 int error; 736 struct lfs *fs; 737 738 fs = VTOI(ap->a_fdvp)->i_lfs; 739 tvp = ap->a_tvp; 740 tdvp = ap->a_tdvp; 741 fvp = ap->a_fvp; 742 fdvp = ap->a_fdvp; 743 744 /* 745 * Check for cross-device rename. 746 * If it is, we don't want to set dirops, just error out. 747 * (In particular note that MARK_VNODE(tdvp) will DTWT on 748 * a cross-device rename.) 749 * 750 * Copied from ufs_rename. 751 */ 752 if ((fvp->v_mount != tdvp->v_mount) || 753 (tvp && (fvp->v_mount != tvp->v_mount))) { 754 error = EXDEV; 755 goto errout; 756 } 757 if ((error = SET_DIROP(fdvp)) != 0) 758 goto errout; 759 MARK_VNODE(fdvp); 760 MARK_VNODE(tdvp); 761 error = ufs_rename(ap); 762 UNMARK_VNODE(fdvp); 763 UNMARK_VNODE(tdvp); 764 SET_ENDOP(fs,fdvp,"rename"); 765 return (error); 766 767 errout: 768 VOP_ABORTOP(tdvp, ap->a_tcnp); /* XXX, why not in NFS? */ 769 if (tdvp == tvp) 770 vrele(tdvp); 771 else 772 vput(tdvp); 773 if (tvp) 774 vput(tvp); 775 VOP_ABORTOP(fdvp, ap->a_fcnp); /* XXX, why not in NFS? */ 776 vrele(fdvp); 777 vrele(fvp); 778 return (error); 779 } 780 781 /* XXX hack to avoid calling ITIMES in getattr */ 782 int 783 lfs_getattr(void *v) 784 { 785 struct vop_getattr_args /* { 786 struct vnode *a_vp; 787 struct vattr *a_vap; 788 struct ucred *a_cred; 789 struct proc *a_p; 790 } */ *ap = v; 791 struct vnode *vp = ap->a_vp; 792 struct inode *ip = VTOI(vp); 793 struct vattr *vap = ap->a_vap; 794 struct lfs *fs = ip->i_lfs; 795 /* 796 * Copy from inode table 797 */ 798 vap->va_fsid = ip->i_dev; 799 vap->va_fileid = ip->i_number; 800 vap->va_mode = ip->i_ffs_mode & ~IFMT; 801 vap->va_nlink = ip->i_ffs_nlink; 802 vap->va_uid = ip->i_ffs_uid; 803 vap->va_gid = ip->i_ffs_gid; 804 vap->va_rdev = (dev_t)ip->i_ffs_rdev; 805 vap->va_size = vp->v_size; 806 vap->va_atime.tv_sec = ip->i_ffs_atime; 807 vap->va_atime.tv_nsec = ip->i_ffs_atimensec; 808 vap->va_mtime.tv_sec = ip->i_ffs_mtime; 809 vap->va_mtime.tv_nsec = ip->i_ffs_mtimensec; 810 vap->va_ctime.tv_sec = ip->i_ffs_ctime; 811 vap->va_ctime.tv_nsec = ip->i_ffs_ctimensec; 812 vap->va_flags = ip->i_ffs_flags; 813 vap->va_gen = ip->i_ffs_gen; 814 /* this doesn't belong here */ 815 if (vp->v_type == VBLK) 816 vap->va_blocksize = BLKDEV_IOSIZE; 817 else if (vp->v_type == VCHR) 818 vap->va_blocksize = MAXBSIZE; 819 else 820 vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize; 821 vap->va_bytes = fsbtob(fs, (u_quad_t)ip->i_ffs_blocks); 822 vap->va_type = vp->v_type; 823 vap->va_filerev = ip->i_modrev; 824 return (0); 825 } 826 827 /* 828 * Check to make sure the inode blocks won't choke the buffer 829 * cache, then call ufs_setattr as usual. 830 */ 831 int 832 lfs_setattr(void *v) 833 { 834 struct vop_getattr_args /* { 835 struct vnode *a_vp; 836 struct vattr *a_vap; 837 struct ucred *a_cred; 838 struct proc *a_p; 839 } */ *ap = v; 840 struct vnode *vp = ap->a_vp; 841 842 lfs_check(vp, LFS_UNUSED_LBN, 0); 843 return ufs_setattr(v); 844 } 845 846 /* 847 * Close called 848 * 849 * XXX -- we were using ufs_close, but since it updates the 850 * times on the inode, we might need to bump the uinodes 851 * count. 852 */ 853 /* ARGSUSED */ 854 int 855 lfs_close(void *v) 856 { 857 struct vop_close_args /* { 858 struct vnode *a_vp; 859 int a_fflag; 860 struct ucred *a_cred; 861 struct proc *a_p; 862 } */ *ap = v; 863 struct vnode *vp = ap->a_vp; 864 struct inode *ip = VTOI(vp); 865 struct timespec ts; 866 867 simple_lock(&vp->v_interlock); 868 if (vp->v_usecount > 1) { 869 TIMEVAL_TO_TIMESPEC(&time, &ts); 870 LFS_ITIMES(ip, &ts, &ts, &ts); 871 } 872 simple_unlock(&vp->v_interlock); 873 return (0); 874 } 875 876 /* 877 * Reclaim an inode so that it can be used for other purposes. 878 */ 879 int lfs_no_inactive = 0; 880 881 int 882 lfs_reclaim(void *v) 883 { 884 struct vop_reclaim_args /* { 885 struct vnode *a_vp; 886 struct proc *a_p; 887 } */ *ap = v; 888 struct vnode *vp = ap->a_vp; 889 int error; 890 891 LFS_CLR_UINO(VTOI(vp), IN_ALLMOD); 892 if ((error = ufs_reclaim(vp, ap->a_p))) 893 return (error); 894 pool_put(&lfs_inode_pool, vp->v_data); 895 vp->v_data = NULL; 896 return (0); 897 } 898 899 int 900 lfs_getpages(void *v) 901 { 902 struct vop_getpages_args /* { 903 struct vnode *a_vp; 904 voff_t a_offset; 905 struct vm_page **a_m; 906 int *a_count; 907 int a_centeridx; 908 vm_prot_t a_access_type; 909 int a_advice; 910 int a_flags; 911 } */ *ap = v; 912 913 if ((ap->a_access_type & VM_PROT_WRITE) != 0) { 914 LFS_SET_UINO(VTOI(ap->a_vp), IN_MODIFIED); 915 } 916 return genfs_compat_getpages(v); 917 } 918 919 int 920 lfs_putpages(void *v) 921 { 922 int error; 923 924 error = genfs_putpages(v); 925 return error; 926 } 927