1 /* $NetBSD: ulfs_vnops.c,v 1.35 2015/11/14 22:03:54 pgoyette Exp $ */ 2 /* from NetBSD: ufs_vnops.c,v 1.213 2013/06/08 05:47:02 kardel Exp */ 3 4 /*- 5 * Copyright (c) 2008 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Wasabi Systems, Inc. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1982, 1986, 1989, 1993, 1995 35 * The Regents of the University of California. All rights reserved. 36 * (c) UNIX System Laboratories, Inc. 37 * All or some portions of this file are derived from material licensed 38 * to the University of California by American Telephone and Telegraph 39 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 40 * the permission of UNIX System Laboratories, Inc. 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. Neither the name of the University nor the names of its contributors 51 * may be used to endorse or promote products derived from this software 52 * without specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 64 * SUCH DAMAGE. 65 * 66 * @(#)ufs_vnops.c 8.28 (Berkeley) 7/31/95 67 */ 68 69 #include <sys/cdefs.h> 70 __KERNEL_RCSID(0, "$NetBSD: ulfs_vnops.c,v 1.35 2015/11/14 22:03:54 pgoyette Exp $"); 71 72 #if defined(_KERNEL_OPT) 73 #include "opt_lfs.h" 74 #include "opt_quota.h" 75 #endif 76 77 #include <sys/param.h> 78 #include <sys/systm.h> 79 #include <sys/namei.h> 80 #include <sys/resourcevar.h> 81 #include <sys/kernel.h> 82 #include <sys/file.h> 83 #include <sys/stat.h> 84 #include <sys/buf.h> 85 #include <sys/proc.h> 86 #include <sys/mount.h> 87 #include <sys/vnode.h> 88 #include <sys/kmem.h> 89 #include <sys/malloc.h> 90 #include <sys/dirent.h> 91 #include <sys/lockf.h> 92 #include <sys/kauth.h> 93 #include <sys/fstrans.h> 94 95 #include <miscfs/specfs/specdev.h> 96 #include <miscfs/fifofs/fifo.h> 97 #include <miscfs/genfs/genfs.h> 98 99 #include <ufs/lfs/lfs_extern.h> 100 #include <ufs/lfs/lfs.h> 101 #include <ufs/lfs/lfs_accessors.h> 102 103 #include <ufs/lfs/ulfs_inode.h> 104 #include <ufs/lfs/ulfsmount.h> 105 #include <ufs/lfs/ulfs_bswap.h> 106 #include <ufs/lfs/ulfs_extern.h> 107 #ifdef LFS_DIRHASH 108 #include <ufs/lfs/ulfs_dirhash.h> 109 #endif 110 111 #include <uvm/uvm.h> 112 113 static int ulfs_chmod(struct vnode *, int, kauth_cred_t, struct lwp *); 114 static int ulfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t, 115 struct lwp *); 116 117 /* 118 * Open called. 119 * 120 * Nothing to do. 121 */ 122 /* ARGSUSED */ 123 int 124 ulfs_open(void *v) 125 { 126 struct vop_open_args /* { 127 struct vnode *a_vp; 128 int a_mode; 129 kauth_cred_t a_cred; 130 } */ *ap = v; 131 132 /* 133 * Files marked append-only must be opened for appending. 134 */ 135 if ((VTOI(ap->a_vp)->i_flags & APPEND) && 136 (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) 137 return (EPERM); 138 return (0); 139 } 140 141 static int 142 ulfs_check_possible(struct vnode *vp, struct inode *ip, mode_t mode, 143 kauth_cred_t cred) 144 { 145 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2) 146 int error; 147 #endif 148 149 /* 150 * Disallow write attempts on read-only file systems; 151 * unless the file is a socket, fifo, or a block or 152 * character device resident on the file system. 153 */ 154 if (mode & VWRITE) { 155 switch (vp->v_type) { 156 case VDIR: 157 case VLNK: 158 case VREG: 159 if (vp->v_mount->mnt_flag & MNT_RDONLY) 160 return (EROFS); 161 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2) 162 fstrans_start(vp->v_mount, FSTRANS_SHARED); 163 error = lfs_chkdq(ip, 0, cred, 0); 164 fstrans_done(vp->v_mount); 165 if (error != 0) 166 return error; 167 #endif 168 break; 169 case VBAD: 170 case VBLK: 171 case VCHR: 172 case VSOCK: 173 case VFIFO: 174 case VNON: 175 default: 176 break; 177 } 178 } 179 180 /* If it is a snapshot, nobody gets access to it. */ 181 if ((ip->i_flags & SF_SNAPSHOT)) 182 return (EPERM); 183 /* If immutable bit set, nobody gets to write it. */ 184 if ((mode & VWRITE) && (ip->i_flags & IMMUTABLE)) 185 return (EPERM); 186 187 return 0; 188 } 189 190 static int 191 ulfs_check_permitted(struct vnode *vp, struct inode *ip, mode_t mode, 192 kauth_cred_t cred) 193 { 194 195 return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, vp->v_type, 196 ip->i_mode & ALLPERMS), vp, NULL, genfs_can_access(vp->v_type, 197 ip->i_mode & ALLPERMS, ip->i_uid, ip->i_gid, mode, cred)); 198 } 199 200 int 201 ulfs_access(void *v) 202 { 203 struct vop_access_args /* { 204 struct vnode *a_vp; 205 int a_mode; 206 kauth_cred_t a_cred; 207 } */ *ap = v; 208 struct vnode *vp; 209 struct inode *ip; 210 mode_t mode; 211 int error; 212 213 vp = ap->a_vp; 214 ip = VTOI(vp); 215 mode = ap->a_mode; 216 217 error = ulfs_check_possible(vp, ip, mode, ap->a_cred); 218 if (error) 219 return error; 220 221 error = ulfs_check_permitted(vp, ip, mode, ap->a_cred); 222 223 return error; 224 } 225 226 /* 227 * Set attribute vnode op. called from several syscalls 228 */ 229 int 230 ulfs_setattr(void *v) 231 { 232 struct vop_setattr_args /* { 233 struct vnode *a_vp; 234 struct vattr *a_vap; 235 kauth_cred_t a_cred; 236 } */ *ap = v; 237 struct vattr *vap; 238 struct vnode *vp; 239 struct inode *ip; 240 struct lfs *fs; 241 kauth_cred_t cred; 242 struct lwp *l; 243 int error; 244 kauth_action_t action; 245 bool changing_sysflags; 246 247 vap = ap->a_vap; 248 vp = ap->a_vp; 249 ip = VTOI(vp); 250 fs = ip->i_lfs; 251 cred = ap->a_cred; 252 l = curlwp; 253 action = KAUTH_VNODE_WRITE_FLAGS; 254 changing_sysflags = false; 255 256 /* 257 * Check for unsettable attributes. 258 */ 259 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 260 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 261 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 262 ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 263 return (EINVAL); 264 } 265 266 fstrans_start(vp->v_mount, FSTRANS_SHARED); 267 268 if (vap->va_flags != VNOVAL) { 269 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 270 error = EROFS; 271 goto out; 272 } 273 274 /* Snapshot flag cannot be set or cleared */ 275 if ((vap->va_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) != 276 (ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL))) { 277 error = EPERM; 278 goto out; 279 } 280 281 if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) { 282 action |= KAUTH_VNODE_HAS_SYSFLAGS; 283 } 284 285 if ((vap->va_flags & SF_SETTABLE) != (ip->i_flags & SF_SETTABLE)) { 286 action |= KAUTH_VNODE_WRITE_SYSFLAGS; 287 changing_sysflags = true; 288 } 289 290 error = kauth_authorize_vnode(cred, action, vp, NULL, 291 genfs_can_chflags(cred, vp->v_type, ip->i_uid, 292 changing_sysflags)); 293 if (error) 294 goto out; 295 296 if (changing_sysflags) { 297 ip->i_flags = vap->va_flags; 298 DIP_ASSIGN(ip, flags, ip->i_flags); 299 } else { 300 ip->i_flags &= SF_SETTABLE; 301 ip->i_flags |= (vap->va_flags & UF_SETTABLE); 302 DIP_ASSIGN(ip, flags, ip->i_flags); 303 } 304 ip->i_flag |= IN_CHANGE; 305 if (vap->va_flags & (IMMUTABLE | APPEND)) { 306 error = 0; 307 goto out; 308 } 309 } 310 if (ip->i_flags & (IMMUTABLE | APPEND)) { 311 error = EPERM; 312 goto out; 313 } 314 /* 315 * Go through the fields and update iff not VNOVAL. 316 */ 317 if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { 318 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 319 error = EROFS; 320 goto out; 321 } 322 error = ulfs_chown(vp, vap->va_uid, vap->va_gid, cred, l); 323 if (error) 324 goto out; 325 } 326 if (vap->va_size != VNOVAL) { 327 /* 328 * Disallow write attempts on read-only file systems; 329 * unless the file is a socket, fifo, or a block or 330 * character device resident on the file system. 331 */ 332 switch (vp->v_type) { 333 case VDIR: 334 error = EISDIR; 335 goto out; 336 case VCHR: 337 case VBLK: 338 case VFIFO: 339 break; 340 case VREG: 341 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 342 error = EROFS; 343 goto out; 344 } 345 if ((ip->i_flags & SF_SNAPSHOT) != 0) { 346 error = EPERM; 347 goto out; 348 } 349 error = lfs_truncate(vp, vap->va_size, 0, cred); 350 if (error) 351 goto out; 352 break; 353 default: 354 error = EOPNOTSUPP; 355 goto out; 356 } 357 } 358 ip = VTOI(vp); 359 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || 360 vap->va_birthtime.tv_sec != VNOVAL) { 361 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 362 error = EROFS; 363 goto out; 364 } 365 if ((ip->i_flags & SF_SNAPSHOT) != 0) { 366 error = EPERM; 367 goto out; 368 } 369 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp, 370 NULL, genfs_can_chtimes(vp, vap->va_vaflags, ip->i_uid, cred)); 371 if (error) 372 goto out; 373 if (vap->va_atime.tv_sec != VNOVAL) 374 if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) 375 ip->i_flag |= IN_ACCESS; 376 if (vap->va_mtime.tv_sec != VNOVAL) { 377 ip->i_flag |= IN_CHANGE | IN_UPDATE; 378 if (vp->v_mount->mnt_flag & MNT_RELATIME) 379 ip->i_flag |= IN_ACCESS; 380 } 381 if (vap->va_birthtime.tv_sec != VNOVAL) { 382 lfs_dino_setbirthtime(fs, ip->i_din, 383 &vap->va_birthtime); 384 } 385 error = lfs_update(vp, &vap->va_atime, &vap->va_mtime, 0); 386 if (error) 387 goto out; 388 } 389 error = 0; 390 if (vap->va_mode != (mode_t)VNOVAL) { 391 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 392 error = EROFS; 393 goto out; 394 } 395 if ((ip->i_flags & SF_SNAPSHOT) != 0 && 396 (vap->va_mode & (S_IXUSR | S_IWUSR | S_IXGRP | S_IWGRP | 397 S_IXOTH | S_IWOTH))) { 398 error = EPERM; 399 goto out; 400 } 401 error = ulfs_chmod(vp, (int)vap->va_mode, cred, l); 402 } 403 VN_KNOTE(vp, NOTE_ATTRIB); 404 out: 405 fstrans_done(vp->v_mount); 406 return (error); 407 } 408 409 /* 410 * Change the mode on a file. 411 * Inode must be locked before calling. 412 */ 413 static int 414 ulfs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct lwp *l) 415 { 416 struct inode *ip; 417 int error; 418 419 ip = VTOI(vp); 420 421 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp, 422 NULL, genfs_can_chmod(vp->v_type, cred, ip->i_uid, ip->i_gid, mode)); 423 if (error) 424 return (error); 425 426 fstrans_start(vp->v_mount, FSTRANS_SHARED); 427 ip->i_mode &= ~ALLPERMS; 428 ip->i_mode |= (mode & ALLPERMS); 429 ip->i_flag |= IN_CHANGE; 430 DIP_ASSIGN(ip, mode, ip->i_mode); 431 fstrans_done(vp->v_mount); 432 return (0); 433 } 434 435 /* 436 * Perform chown operation on inode ip; 437 * inode must be locked prior to call. 438 */ 439 static int 440 ulfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred, 441 struct lwp *l) 442 { 443 struct inode *ip; 444 int error = 0; 445 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2) 446 uid_t ouid; 447 gid_t ogid; 448 int64_t change; 449 #endif 450 ip = VTOI(vp); 451 error = 0; 452 453 if (uid == (uid_t)VNOVAL) 454 uid = ip->i_uid; 455 if (gid == (gid_t)VNOVAL) 456 gid = ip->i_gid; 457 458 error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp, 459 NULL, genfs_can_chown(cred, ip->i_uid, ip->i_gid, uid, gid)); 460 if (error) 461 return (error); 462 463 fstrans_start(vp->v_mount, FSTRANS_SHARED); 464 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2) 465 ogid = ip->i_gid; 466 ouid = ip->i_uid; 467 change = DIP(ip, blocks); 468 (void) lfs_chkdq(ip, -change, cred, 0); 469 (void) lfs_chkiq(ip, -1, cred, 0); 470 #endif 471 ip->i_gid = gid; 472 DIP_ASSIGN(ip, gid, gid); 473 ip->i_uid = uid; 474 DIP_ASSIGN(ip, uid, uid); 475 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2) 476 if ((error = lfs_chkdq(ip, change, cred, 0)) == 0) { 477 if ((error = lfs_chkiq(ip, 1, cred, 0)) == 0) 478 goto good; 479 else 480 (void) lfs_chkdq(ip, -change, cred, FORCE); 481 } 482 ip->i_gid = ogid; 483 DIP_ASSIGN(ip, gid, ogid); 484 ip->i_uid = ouid; 485 DIP_ASSIGN(ip, uid, ouid); 486 (void) lfs_chkdq(ip, change, cred, FORCE); 487 (void) lfs_chkiq(ip, 1, cred, FORCE); 488 fstrans_done(vp->v_mount); 489 return (error); 490 good: 491 #endif /* LFS_QUOTA || LFS_QUOTA2 */ 492 ip->i_flag |= IN_CHANGE; 493 fstrans_done(vp->v_mount); 494 return (0); 495 } 496 497 int 498 ulfs_remove(void *v) 499 { 500 struct vop_remove_args /* { 501 struct vnode *a_dvp; 502 struct vnode *a_vp; 503 struct componentname *a_cnp; 504 } */ *ap = v; 505 struct vnode *vp, *dvp; 506 struct inode *ip; 507 struct mount *mp; 508 int error; 509 struct ulfs_lookup_results *ulr; 510 511 vp = ap->a_vp; 512 dvp = ap->a_dvp; 513 ip = VTOI(vp); 514 mp = dvp->v_mount; 515 KASSERT(mp == vp->v_mount); /* XXX Not stable without lock. */ 516 517 /* XXX should handle this material another way */ 518 ulr = &VTOI(dvp)->i_crap; 519 ULFS_CHECK_CRAPCOUNTER(VTOI(dvp)); 520 521 fstrans_start(mp, FSTRANS_SHARED); 522 if (vp->v_type == VDIR || (ip->i_flags & (IMMUTABLE | APPEND)) || 523 (VTOI(dvp)->i_flags & APPEND)) 524 error = EPERM; 525 else { 526 error = ulfs_dirremove(dvp, ulr, 527 ip, ap->a_cnp->cn_flags, 0); 528 } 529 VN_KNOTE(vp, NOTE_DELETE); 530 VN_KNOTE(dvp, NOTE_WRITE); 531 if (dvp == vp) 532 vrele(vp); 533 else 534 vput(vp); 535 vput(dvp); 536 fstrans_done(mp); 537 return (error); 538 } 539 540 /* 541 * ulfs_link: create hard link. 542 */ 543 int 544 ulfs_link(void *v) 545 { 546 struct vop_link_v2_args /* { 547 struct vnode *a_dvp; 548 struct vnode *a_vp; 549 struct componentname *a_cnp; 550 } */ *ap = v; 551 struct vnode *dvp = ap->a_dvp; 552 struct vnode *vp = ap->a_vp; 553 struct componentname *cnp = ap->a_cnp; 554 struct mount *mp = dvp->v_mount; 555 struct inode *ip; 556 int error; 557 struct ulfs_lookup_results *ulr; 558 559 KASSERT(dvp != vp); 560 KASSERT(vp->v_type != VDIR); 561 KASSERT(mp == vp->v_mount); /* XXX Not stable without lock. */ 562 563 /* XXX should handle this material another way */ 564 ulr = &VTOI(dvp)->i_crap; 565 ULFS_CHECK_CRAPCOUNTER(VTOI(dvp)); 566 567 fstrans_start(mp, FSTRANS_SHARED); 568 error = vn_lock(vp, LK_EXCLUSIVE); 569 if (error) { 570 VOP_ABORTOP(dvp, cnp); 571 goto out2; 572 } 573 ip = VTOI(vp); 574 if ((nlink_t)ip->i_nlink >= LINK_MAX) { 575 VOP_ABORTOP(dvp, cnp); 576 error = EMLINK; 577 goto out1; 578 } 579 if (ip->i_flags & (IMMUTABLE | APPEND)) { 580 VOP_ABORTOP(dvp, cnp); 581 error = EPERM; 582 goto out1; 583 } 584 ip->i_nlink++; 585 DIP_ASSIGN(ip, nlink, ip->i_nlink); 586 ip->i_flag |= IN_CHANGE; 587 error = lfs_update(vp, NULL, NULL, UPDATE_DIROP); 588 if (!error) { 589 error = ulfs_direnter(dvp, ulr, vp, 590 cnp, ip->i_number, LFS_IFTODT(ip->i_mode), NULL); 591 } 592 if (error) { 593 ip->i_nlink--; 594 DIP_ASSIGN(ip, nlink, ip->i_nlink); 595 ip->i_flag |= IN_CHANGE; 596 } 597 out1: 598 VOP_UNLOCK(vp); 599 out2: 600 VN_KNOTE(vp, NOTE_LINK); 601 VN_KNOTE(dvp, NOTE_WRITE); 602 fstrans_done(mp); 603 return (error); 604 } 605 606 /* 607 * whiteout vnode call 608 */ 609 int 610 ulfs_whiteout(void *v) 611 { 612 struct vop_whiteout_args /* { 613 struct vnode *a_dvp; 614 struct componentname *a_cnp; 615 int a_flags; 616 } */ *ap = v; 617 struct vnode *dvp = ap->a_dvp; 618 struct componentname *cnp = ap->a_cnp; 619 int error; 620 struct ulfsmount *ump = VFSTOULFS(dvp->v_mount); 621 struct lfs *fs = ump->um_lfs; 622 struct ulfs_lookup_results *ulr; 623 624 /* XXX should handle this material another way */ 625 ulr = &VTOI(dvp)->i_crap; 626 ULFS_CHECK_CRAPCOUNTER(VTOI(dvp)); 627 628 error = 0; 629 switch (ap->a_flags) { 630 case LOOKUP: 631 /* 4.4 format directories support whiteout operations */ 632 if (fs->um_maxsymlinklen > 0) 633 return (0); 634 return (EOPNOTSUPP); 635 636 case CREATE: 637 /* create a new directory whiteout */ 638 fstrans_start(dvp->v_mount, FSTRANS_SHARED); 639 #ifdef DIAGNOSTIC 640 if (fs->um_maxsymlinklen <= 0) 641 panic("ulfs_whiteout: old format filesystem"); 642 #endif 643 644 error = ulfs_direnter(dvp, ulr, NULL, 645 cnp, ULFS_WINO, LFS_DT_WHT, NULL); 646 break; 647 648 case DELETE: 649 /* remove an existing directory whiteout */ 650 fstrans_start(dvp->v_mount, FSTRANS_SHARED); 651 #ifdef DIAGNOSTIC 652 if (fs->um_maxsymlinklen <= 0) 653 panic("ulfs_whiteout: old format filesystem"); 654 #endif 655 656 cnp->cn_flags &= ~DOWHITEOUT; 657 error = ulfs_dirremove(dvp, ulr, NULL, cnp->cn_flags, 0); 658 break; 659 default: 660 panic("ulfs_whiteout: unknown op"); 661 /* NOTREACHED */ 662 } 663 fstrans_done(dvp->v_mount); 664 return (error); 665 } 666 667 int 668 ulfs_rmdir(void *v) 669 { 670 struct vop_rmdir_args /* { 671 struct vnode *a_dvp; 672 struct vnode *a_vp; 673 struct componentname *a_cnp; 674 } */ *ap = v; 675 struct vnode *vp, *dvp; 676 struct componentname *cnp; 677 struct inode *ip, *dp; 678 int error; 679 struct ulfs_lookup_results *ulr; 680 681 vp = ap->a_vp; 682 dvp = ap->a_dvp; 683 cnp = ap->a_cnp; 684 ip = VTOI(vp); 685 dp = VTOI(dvp); 686 687 /* XXX should handle this material another way */ 688 ulr = &dp->i_crap; 689 ULFS_CHECK_CRAPCOUNTER(dp); 690 691 /* 692 * No rmdir "." or of mounted directories please. 693 */ 694 if (dp == ip || vp->v_mountedhere != NULL) { 695 if (dp == ip) 696 vrele(dvp); 697 else 698 vput(dvp); 699 vput(vp); 700 return (EINVAL); 701 } 702 703 fstrans_start(dvp->v_mount, FSTRANS_SHARED); 704 705 /* 706 * Do not remove a directory that is in the process of being renamed. 707 * Verify that the directory is empty (and valid). (Rmdir ".." won't 708 * be valid since ".." will contain a reference to the current 709 * directory and thus be non-empty.) 710 */ 711 error = 0; 712 if (ip->i_nlink != 2 || 713 !ulfs_dirempty(ip, dp->i_number, cnp->cn_cred)) { 714 error = ENOTEMPTY; 715 goto out; 716 } 717 if ((dp->i_flags & APPEND) || 718 (ip->i_flags & (IMMUTABLE | APPEND))) { 719 error = EPERM; 720 goto out; 721 } 722 /* 723 * Delete reference to directory before purging 724 * inode. If we crash in between, the directory 725 * will be reattached to lost+found, 726 */ 727 error = ulfs_dirremove(dvp, ulr, ip, cnp->cn_flags, 1); 728 if (error) { 729 goto out; 730 } 731 VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK); 732 cache_purge(dvp); 733 /* 734 * Truncate inode. The only stuff left in the directory is "." and 735 * "..". The "." reference is inconsequential since we're quashing 736 * it. 737 */ 738 dp->i_nlink--; 739 DIP_ASSIGN(dp, nlink, dp->i_nlink); 740 dp->i_flag |= IN_CHANGE; 741 ip->i_nlink--; 742 DIP_ASSIGN(ip, nlink, ip->i_nlink); 743 ip->i_flag |= IN_CHANGE; 744 error = lfs_truncate(vp, (off_t)0, IO_SYNC, cnp->cn_cred); 745 cache_purge(vp); 746 #ifdef LFS_DIRHASH 747 if (ip->i_dirhash != NULL) 748 ulfsdirhash_free(ip); 749 #endif 750 out: 751 VN_KNOTE(vp, NOTE_DELETE); 752 vput(vp); 753 fstrans_done(dvp->v_mount); 754 vput(dvp); 755 return (error); 756 } 757 758 /* 759 * Vnode op for reading directories. 760 * 761 * This routine handles converting from the on-disk directory format 762 * "struct lfs_direct" to the in-memory format "struct dirent" as well as 763 * byte swapping the entries if necessary. 764 */ 765 int 766 ulfs_readdir(void *v) 767 { 768 struct vop_readdir_args /* { 769 struct vnode *a_vp; 770 struct uio *a_uio; 771 kauth_cred_t a_cred; 772 int *a_eofflag; 773 off_t **a_cookies; 774 int *ncookies; 775 } */ *ap = v; 776 struct vnode *vp = ap->a_vp; 777 LFS_DIRHEADER *cdp, *ecdp; 778 struct dirent *ndp; 779 char *cdbuf, *ndbuf, *endp; 780 struct uio auio, *uio; 781 struct iovec aiov; 782 int error; 783 size_t count, ccount, rcount, cdbufsz, ndbufsz; 784 off_t off, *ccp; 785 off_t startoff; 786 size_t skipbytes; 787 struct ulfsmount *ump = VFSTOULFS(vp->v_mount); 788 struct lfs *fs = ump->um_lfs; 789 uio = ap->a_uio; 790 count = uio->uio_resid; 791 rcount = count - ((uio->uio_offset + count) & (fs->um_dirblksiz - 1)); 792 793 if (rcount < LFS_DIRECTSIZ(fs, 0) || count < _DIRENT_MINSIZE(ndp)) 794 return EINVAL; 795 796 startoff = uio->uio_offset & ~(fs->um_dirblksiz - 1); 797 skipbytes = uio->uio_offset - startoff; 798 rcount += skipbytes; 799 800 auio.uio_iov = &aiov; 801 auio.uio_iovcnt = 1; 802 auio.uio_offset = startoff; 803 auio.uio_resid = rcount; 804 UIO_SETUP_SYSSPACE(&auio); 805 auio.uio_rw = UIO_READ; 806 cdbufsz = rcount; 807 cdbuf = kmem_alloc(cdbufsz, KM_SLEEP); 808 aiov.iov_base = cdbuf; 809 aiov.iov_len = rcount; 810 error = VOP_READ(vp, &auio, 0, ap->a_cred); 811 if (error != 0) { 812 kmem_free(cdbuf, cdbufsz); 813 return error; 814 } 815 816 rcount -= auio.uio_resid; 817 818 cdp = (LFS_DIRHEADER *)(void *)cdbuf; 819 ecdp = (LFS_DIRHEADER *)(void *)&cdbuf[rcount]; 820 821 ndbufsz = count; 822 ndbuf = kmem_alloc(ndbufsz, KM_SLEEP); 823 ndp = (struct dirent *)(void *)ndbuf; 824 endp = &ndbuf[count]; 825 826 off = uio->uio_offset; 827 if (ap->a_cookies) { 828 ccount = rcount / _DIRENT_RECLEN(ndp, 1); 829 ccp = *(ap->a_cookies) = malloc(ccount * sizeof(*ccp), 830 M_TEMP, M_WAITOK); 831 } else { 832 /* XXX: GCC */ 833 ccount = 0; 834 ccp = NULL; 835 } 836 837 while (cdp < ecdp) { 838 if (skipbytes > 0) { 839 if (lfs_dir_getreclen(fs, cdp) <= skipbytes) { 840 skipbytes -= lfs_dir_getreclen(fs, cdp); 841 cdp = LFS_NEXTDIR(fs, cdp); 842 continue; 843 } 844 /* 845 * invalid cookie. 846 */ 847 error = EINVAL; 848 goto out; 849 } 850 if (lfs_dir_getreclen(fs, cdp) == 0) { 851 struct dirent *ondp = ndp; 852 ndp->d_reclen = _DIRENT_MINSIZE(ndp); 853 ndp = _DIRENT_NEXT(ndp); 854 ondp->d_reclen = 0; 855 cdp = ecdp; 856 break; 857 } 858 ndp->d_type = lfs_dir_gettype(fs, cdp); 859 ndp->d_namlen = lfs_dir_getnamlen(fs, cdp); 860 ndp->d_reclen = _DIRENT_RECLEN(ndp, ndp->d_namlen); 861 if ((char *)(void *)ndp + ndp->d_reclen + 862 _DIRENT_MINSIZE(ndp) > endp) 863 break; 864 ndp->d_fileno = lfs_dir_getino(fs, cdp); 865 (void)memcpy(ndp->d_name, lfs_dir_nameptr(fs, cdp), 866 ndp->d_namlen); 867 memset(&ndp->d_name[ndp->d_namlen], 0, 868 ndp->d_reclen - _DIRENT_NAMEOFF(ndp) - ndp->d_namlen); 869 off += lfs_dir_getreclen(fs, cdp); 870 if (ap->a_cookies) { 871 KASSERT(ccp - *(ap->a_cookies) < ccount); 872 *(ccp++) = off; 873 } 874 ndp = _DIRENT_NEXT(ndp); 875 cdp = LFS_NEXTDIR(fs, cdp); 876 } 877 878 count = ((char *)(void *)ndp - ndbuf); 879 error = uiomove(ndbuf, count, uio); 880 out: 881 if (ap->a_cookies) { 882 if (error) { 883 free(*(ap->a_cookies), M_TEMP); 884 *(ap->a_cookies) = NULL; 885 *(ap->a_ncookies) = 0; 886 } else { 887 *ap->a_ncookies = ccp - *(ap->a_cookies); 888 } 889 } 890 uio->uio_offset = off; 891 kmem_free(ndbuf, ndbufsz); 892 kmem_free(cdbuf, cdbufsz); 893 *ap->a_eofflag = VTOI(vp)->i_size <= uio->uio_offset; 894 return error; 895 } 896 897 /* 898 * Return target name of a symbolic link 899 */ 900 int 901 ulfs_readlink(void *v) 902 { 903 struct vop_readlink_args /* { 904 struct vnode *a_vp; 905 struct uio *a_uio; 906 kauth_cred_t a_cred; 907 } */ *ap = v; 908 struct vnode *vp = ap->a_vp; 909 struct inode *ip = VTOI(vp); 910 struct ulfsmount *ump = VFSTOULFS(vp->v_mount); 911 struct lfs *fs = ump->um_lfs; 912 int isize; 913 914 isize = ip->i_size; 915 if (isize < fs->um_maxsymlinklen || 916 (fs->um_maxsymlinklen == 0 && DIP(ip, blocks) == 0)) { 917 uiomove((char *)SHORTLINK(ip), isize, ap->a_uio); 918 return (0); 919 } 920 return (lfs_bufrd(vp, ap->a_uio, 0, ap->a_cred)); 921 } 922 923 /* 924 * Print out the contents of an inode. 925 */ 926 int 927 ulfs_print(void *v) 928 { 929 struct vop_print_args /* { 930 struct vnode *a_vp; 931 } */ *ap = v; 932 struct vnode *vp; 933 struct inode *ip; 934 935 vp = ap->a_vp; 936 ip = VTOI(vp); 937 printf("tag VT_ULFS, ino %llu, on dev %llu, %llu", 938 (unsigned long long)ip->i_number, 939 (unsigned long long)major(ip->i_dev), 940 (unsigned long long)minor(ip->i_dev)); 941 printf(" flags 0x%x, nlink %d\n", 942 ip->i_flag, ip->i_nlink); 943 printf("\tmode 0%o, owner %d, group %d, size %qd", 944 ip->i_mode, ip->i_uid, ip->i_gid, 945 (long long)ip->i_size); 946 if (vp->v_type == VFIFO) 947 VOCALL(fifo_vnodeop_p, VOFFSET(vop_print), v); 948 printf("\n"); 949 return (0); 950 } 951 952 /* 953 * Read wrapper for special devices. 954 */ 955 int 956 ulfsspec_read(void *v) 957 { 958 struct vop_read_args /* { 959 struct vnode *a_vp; 960 struct uio *a_uio; 961 int a_ioflag; 962 kauth_cred_t a_cred; 963 } */ *ap = v; 964 965 /* 966 * Set access flag. 967 */ 968 if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0) 969 VTOI(ap->a_vp)->i_flag |= IN_ACCESS; 970 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap)); 971 } 972 973 /* 974 * Write wrapper for special devices. 975 */ 976 int 977 ulfsspec_write(void *v) 978 { 979 struct vop_write_args /* { 980 struct vnode *a_vp; 981 struct uio *a_uio; 982 int a_ioflag; 983 kauth_cred_t a_cred; 984 } */ *ap = v; 985 986 /* 987 * Set update and change flags. 988 */ 989 if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0) 990 VTOI(ap->a_vp)->i_flag |= IN_MODIFY; 991 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap)); 992 } 993 994 /* 995 * Read wrapper for fifo's 996 */ 997 int 998 ulfsfifo_read(void *v) 999 { 1000 struct vop_read_args /* { 1001 struct vnode *a_vp; 1002 struct uio *a_uio; 1003 int a_ioflag; 1004 kauth_cred_t a_cred; 1005 } */ *ap = v; 1006 1007 /* 1008 * Set access flag. 1009 */ 1010 VTOI(ap->a_vp)->i_flag |= IN_ACCESS; 1011 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap)); 1012 } 1013 1014 /* 1015 * Write wrapper for fifo's. 1016 */ 1017 int 1018 ulfsfifo_write(void *v) 1019 { 1020 struct vop_write_args /* { 1021 struct vnode *a_vp; 1022 struct uio *a_uio; 1023 int a_ioflag; 1024 kauth_cred_t a_cred; 1025 } */ *ap = v; 1026 1027 /* 1028 * Set update and change flags. 1029 */ 1030 VTOI(ap->a_vp)->i_flag |= IN_MODIFY; 1031 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap)); 1032 } 1033 1034 /* 1035 * Return POSIX pathconf information applicable to ulfs filesystems. 1036 */ 1037 int 1038 ulfs_pathconf(void *v) 1039 { 1040 struct vop_pathconf_args /* { 1041 struct vnode *a_vp; 1042 int a_name; 1043 register_t *a_retval; 1044 } */ *ap = v; 1045 1046 switch (ap->a_name) { 1047 case _PC_LINK_MAX: 1048 *ap->a_retval = LINK_MAX; 1049 return (0); 1050 case _PC_NAME_MAX: 1051 *ap->a_retval = LFS_MAXNAMLEN; 1052 return (0); 1053 case _PC_PATH_MAX: 1054 *ap->a_retval = PATH_MAX; 1055 return (0); 1056 case _PC_PIPE_BUF: 1057 *ap->a_retval = PIPE_BUF; 1058 return (0); 1059 case _PC_CHOWN_RESTRICTED: 1060 *ap->a_retval = 1; 1061 return (0); 1062 case _PC_NO_TRUNC: 1063 *ap->a_retval = 1; 1064 return (0); 1065 case _PC_SYNC_IO: 1066 *ap->a_retval = 1; 1067 return (0); 1068 case _PC_FILESIZEBITS: 1069 *ap->a_retval = 42; 1070 return (0); 1071 case _PC_SYMLINK_MAX: 1072 *ap->a_retval = MAXPATHLEN; 1073 return (0); 1074 case _PC_2_SYMLINKS: 1075 *ap->a_retval = 1; 1076 return (0); 1077 default: 1078 return (EINVAL); 1079 } 1080 /* NOTREACHED */ 1081 } 1082 1083 /* 1084 * Advisory record locking support 1085 */ 1086 int 1087 ulfs_advlock(void *v) 1088 { 1089 struct vop_advlock_args /* { 1090 struct vnode *a_vp; 1091 void * a_id; 1092 int a_op; 1093 struct flock *a_fl; 1094 int a_flags; 1095 } */ *ap = v; 1096 struct inode *ip; 1097 1098 ip = VTOI(ap->a_vp); 1099 return lf_advlock(ap, &ip->i_lockf, ip->i_size); 1100 } 1101 1102 /* 1103 * Initialize the vnode associated with a new inode, handle aliased 1104 * vnodes. 1105 */ 1106 void 1107 ulfs_vinit(struct mount *mntp, int (**specops)(void *), int (**fifoops)(void *), 1108 struct vnode **vpp) 1109 { 1110 struct timeval tv; 1111 struct inode *ip; 1112 struct vnode *vp; 1113 dev_t rdev; 1114 struct ulfsmount *ump; 1115 1116 vp = *vpp; 1117 ip = VTOI(vp); 1118 switch(vp->v_type = IFTOVT(ip->i_mode)) { 1119 case VCHR: 1120 case VBLK: 1121 vp->v_op = specops; 1122 ump = ip->i_ump; 1123 // XXX clean this up 1124 if (ump->um_fstype == ULFS1) 1125 rdev = (dev_t)ulfs_rw32(ip->i_din->u_32.di_rdev, 1126 ULFS_MPNEEDSWAP(ump->um_lfs)); 1127 else 1128 rdev = (dev_t)ulfs_rw64(ip->i_din->u_64.di_rdev, 1129 ULFS_MPNEEDSWAP(ump->um_lfs)); 1130 spec_node_init(vp, rdev); 1131 break; 1132 case VFIFO: 1133 vp->v_op = fifoops; 1134 break; 1135 case VNON: 1136 case VBAD: 1137 case VSOCK: 1138 case VLNK: 1139 case VDIR: 1140 case VREG: 1141 break; 1142 } 1143 if (ip->i_number == ULFS_ROOTINO) 1144 vp->v_vflag |= VV_ROOT; 1145 /* 1146 * Initialize modrev times 1147 */ 1148 getmicrouptime(&tv); 1149 ip->i_modrev = (uint64_t)(uint)tv.tv_sec << 32 1150 | tv.tv_usec * 4294u; 1151 *vpp = vp; 1152 } 1153 1154 /* 1155 * Allocate a new inode. 1156 */ 1157 int 1158 ulfs_makeinode(struct vattr *vap, struct vnode *dvp, 1159 const struct ulfs_lookup_results *ulr, 1160 struct vnode **vpp, struct componentname *cnp) 1161 { 1162 struct inode *ip; 1163 struct vnode *tvp; 1164 int error; 1165 1166 error = vcache_new(dvp->v_mount, dvp, vap, cnp->cn_cred, &tvp); 1167 if (error) 1168 return error; 1169 error = vn_lock(tvp, LK_EXCLUSIVE); 1170 if (error) { 1171 vrele(tvp); 1172 return error; 1173 } 1174 lfs_mark_vnode(tvp); 1175 *vpp = tvp; 1176 ip = VTOI(tvp); 1177 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 1178 ip->i_nlink = 1; 1179 DIP_ASSIGN(ip, nlink, 1); 1180 1181 /* Authorize setting SGID if needed. */ 1182 if (ip->i_mode & ISGID) { 1183 error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_WRITE_SECURITY, 1184 tvp, NULL, genfs_can_chmod(tvp->v_type, cnp->cn_cred, ip->i_uid, 1185 ip->i_gid, MAKEIMODE(vap->va_type, vap->va_mode))); 1186 if (error) { 1187 ip->i_mode &= ~ISGID; 1188 DIP_ASSIGN(ip, mode, ip->i_mode); 1189 } 1190 } 1191 1192 if (cnp->cn_flags & ISWHITEOUT) { 1193 ip->i_flags |= UF_OPAQUE; 1194 DIP_ASSIGN(ip, flags, ip->i_flags); 1195 } 1196 1197 /* 1198 * Make sure inode goes to disk before directory entry. 1199 */ 1200 if ((error = lfs_update(tvp, NULL, NULL, UPDATE_DIROP)) != 0) 1201 goto bad; 1202 error = ulfs_direnter(dvp, ulr, tvp, 1203 cnp, ip->i_number, LFS_IFTODT(ip->i_mode), NULL); 1204 if (error) 1205 goto bad; 1206 *vpp = tvp; 1207 return (0); 1208 1209 bad: 1210 /* 1211 * Write error occurred trying to update the inode 1212 * or the directory so must deallocate the inode. 1213 */ 1214 ip->i_nlink = 0; 1215 DIP_ASSIGN(ip, nlink, 0); 1216 ip->i_flag |= IN_CHANGE; 1217 /* If IN_ADIROP, account for it */ 1218 lfs_unmark_vnode(tvp); 1219 vput(tvp); 1220 return (error); 1221 } 1222 1223 /* 1224 * Allocate len bytes at offset off. 1225 */ 1226 int 1227 ulfs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags, 1228 kauth_cred_t cred) 1229 { 1230 struct inode *ip = VTOI(vp); 1231 int error, delta, bshift, bsize; 1232 UVMHIST_FUNC("ulfs_gop_alloc"); UVMHIST_CALLED(ubchist); 1233 1234 error = 0; 1235 bshift = vp->v_mount->mnt_fs_bshift; 1236 bsize = 1 << bshift; 1237 1238 delta = off & (bsize - 1); 1239 off -= delta; 1240 len += delta; 1241 1242 while (len > 0) { 1243 bsize = MIN(bsize, len); 1244 1245 error = lfs_balloc(vp, off, bsize, cred, flags, NULL); 1246 if (error) { 1247 goto out; 1248 } 1249 1250 /* 1251 * increase file size now, lfs_balloc() requires that 1252 * EOF be up-to-date before each call. 1253 */ 1254 1255 if (ip->i_size < off + bsize) { 1256 UVMHIST_LOG(ubchist, "vp %p old 0x%x new 0x%x", 1257 vp, ip->i_size, off + bsize, 0); 1258 ip->i_size = off + bsize; 1259 DIP_ASSIGN(ip, size, ip->i_size); 1260 } 1261 1262 off += bsize; 1263 len -= bsize; 1264 } 1265 1266 out: 1267 return error; 1268 } 1269 1270 void 1271 ulfs_gop_markupdate(struct vnode *vp, int flags) 1272 { 1273 u_int32_t mask = 0; 1274 1275 if ((flags & GOP_UPDATE_ACCESSED) != 0) { 1276 mask = IN_ACCESS; 1277 } 1278 if ((flags & GOP_UPDATE_MODIFIED) != 0) { 1279 if (vp->v_type == VREG) { 1280 mask |= IN_CHANGE | IN_UPDATE; 1281 } else { 1282 mask |= IN_MODIFY; 1283 } 1284 } 1285 if (mask) { 1286 struct inode *ip = VTOI(vp); 1287 1288 ip->i_flag |= mask; 1289 } 1290 } 1291 1292 int 1293 ulfs_bufio(enum uio_rw rw, struct vnode *vp, void *buf, size_t len, off_t off, 1294 int ioflg, kauth_cred_t cred, size_t *aresid, struct lwp *l) 1295 { 1296 struct iovec iov; 1297 struct uio uio; 1298 int error; 1299 1300 KASSERT(ISSET(ioflg, IO_NODELOCKED)); 1301 KASSERT(VOP_ISLOCKED(vp)); 1302 KASSERT(rw != UIO_WRITE || VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 1303 1304 iov.iov_base = buf; 1305 iov.iov_len = len; 1306 uio.uio_iov = &iov; 1307 uio.uio_iovcnt = 1; 1308 uio.uio_resid = len; 1309 uio.uio_offset = off; 1310 uio.uio_rw = rw; 1311 UIO_SETUP_SYSSPACE(&uio); 1312 1313 switch (rw) { 1314 case UIO_READ: 1315 error = lfs_bufrd(vp, &uio, ioflg, cred); 1316 break; 1317 case UIO_WRITE: 1318 error = lfs_bufwr(vp, &uio, ioflg, cred); 1319 break; 1320 default: 1321 panic("invalid uio rw: %d", (int)rw); 1322 } 1323 1324 if (aresid) 1325 *aresid = uio.uio_resid; 1326 else if (uio.uio_resid && error == 0) 1327 error = EIO; 1328 1329 KASSERT(VOP_ISLOCKED(vp)); 1330 KASSERT(rw != UIO_WRITE || VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 1331 return error; 1332 } 1333