1 /* $NetBSD: lfs_syscalls.c,v 1.142 2012/03/13 18:41:13 elad Exp $ */ 2 3 /*- 4 * Copyright (c) 1999, 2000, 2001, 2002, 2003, 2007, 2007, 2008 5 * The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Konrad E. Schroder <perseant@hhhh.org>. 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 * Copyright (c) 1991, 1993, 1994 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 * @(#)lfs_syscalls.c 8.10 (Berkeley) 5/14/95 61 */ 62 63 #include <sys/cdefs.h> 64 __KERNEL_RCSID(0, "$NetBSD: lfs_syscalls.c,v 1.142 2012/03/13 18:41:13 elad Exp $"); 65 66 #ifndef LFS 67 # define LFS /* for prototypes in syscallargs.h */ 68 #endif 69 70 #include <sys/param.h> 71 #include <sys/systm.h> 72 #include <sys/proc.h> 73 #include <sys/buf.h> 74 #include <sys/mount.h> 75 #include <sys/vnode.h> 76 #include <sys/kernel.h> 77 #include <sys/kauth.h> 78 #include <sys/syscallargs.h> 79 80 #include <ufs/ufs/inode.h> 81 #include <ufs/ufs/ufsmount.h> 82 #include <ufs/ufs/ufs_extern.h> 83 84 #include <ufs/lfs/lfs.h> 85 #include <ufs/lfs/lfs_extern.h> 86 87 struct buf *lfs_fakebuf(struct lfs *, struct vnode *, int, size_t, void *); 88 int lfs_fasthashget(dev_t, ino_t, struct vnode **); 89 90 pid_t lfs_cleaner_pid = 0; 91 92 /* 93 * sys_lfs_markv: 94 * 95 * This will mark inodes and blocks dirty, so they are written into the log. 96 * It will block until all the blocks have been written. The segment create 97 * time passed in the block_info and inode_info structures is used to decide 98 * if the data is valid for each block (in case some process dirtied a block 99 * or inode that is being cleaned between the determination that a block is 100 * live and the lfs_markv call). 101 * 102 * 0 on success 103 * -1/errno is return on error. 104 */ 105 #ifdef USE_64BIT_SYSCALLS 106 int 107 sys_lfs_markv(struct lwp *l, const struct sys_lfs_markv_args *uap, register_t *retval) 108 { 109 /* { 110 syscallarg(fsid_t *) fsidp; 111 syscallarg(struct block_info *) blkiov; 112 syscallarg(int) blkcnt; 113 } */ 114 BLOCK_INFO *blkiov; 115 int blkcnt, error; 116 fsid_t fsid; 117 struct lfs *fs; 118 struct mount *mntp; 119 120 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_LFS, 121 KAUTH_REQ_SYSTEM_LFS_MARKV, NULL, NULL, NULL); 122 if (error) 123 return (error); 124 125 if ((error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t))) != 0) 126 return (error); 127 128 if ((mntp = vfs_getvfs(fsidp)) == NULL) 129 return (ENOENT); 130 fs = VFSTOUFS(mntp)->um_lfs; 131 132 blkcnt = SCARG(uap, blkcnt); 133 if ((u_int) blkcnt > LFS_MARKV_MAXBLKCNT) 134 return (EINVAL); 135 136 KERNEL_LOCK(1, NULL); 137 blkiov = lfs_malloc(fs, blkcnt * sizeof(BLOCK_INFO), LFS_NB_BLKIOV); 138 if ((error = copyin(SCARG(uap, blkiov), blkiov, 139 blkcnt * sizeof(BLOCK_INFO))) != 0) 140 goto out; 141 142 if ((error = lfs_markv(p, &fsid, blkiov, blkcnt)) == 0) 143 copyout(blkiov, SCARG(uap, blkiov), 144 blkcnt * sizeof(BLOCK_INFO)); 145 out: 146 lfs_free(fs, blkiov, LFS_NB_BLKIOV); 147 KERNEL_UNLOCK_ONE(NULL); 148 return error; 149 } 150 #else 151 int 152 sys_lfs_markv(struct lwp *l, const struct sys_lfs_markv_args *uap, register_t *retval) 153 { 154 /* { 155 syscallarg(fsid_t *) fsidp; 156 syscallarg(struct block_info *) blkiov; 157 syscallarg(int) blkcnt; 158 } */ 159 BLOCK_INFO *blkiov; 160 BLOCK_INFO_15 *blkiov15; 161 int i, blkcnt, error; 162 fsid_t fsid; 163 struct lfs *fs; 164 struct mount *mntp; 165 166 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_LFS, 167 KAUTH_REQ_SYSTEM_LFS_MARKV, NULL, NULL, NULL); 168 if (error) 169 return (error); 170 171 if ((error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t))) != 0) 172 return (error); 173 174 if ((mntp = vfs_getvfs(&fsid)) == NULL) 175 return (ENOENT); 176 fs = VFSTOUFS(mntp)->um_lfs; 177 178 blkcnt = SCARG(uap, blkcnt); 179 if ((u_int) blkcnt > LFS_MARKV_MAXBLKCNT) 180 return (EINVAL); 181 182 KERNEL_LOCK(1, NULL); 183 blkiov = lfs_malloc(fs, blkcnt * sizeof(BLOCK_INFO), LFS_NB_BLKIOV); 184 blkiov15 = lfs_malloc(fs, blkcnt * sizeof(BLOCK_INFO_15), LFS_NB_BLKIOV); 185 if ((error = copyin(SCARG(uap, blkiov), blkiov15, 186 blkcnt * sizeof(BLOCK_INFO_15))) != 0) 187 goto out; 188 189 for (i = 0; i < blkcnt; i++) { 190 blkiov[i].bi_inode = blkiov15[i].bi_inode; 191 blkiov[i].bi_lbn = blkiov15[i].bi_lbn; 192 blkiov[i].bi_daddr = blkiov15[i].bi_daddr; 193 blkiov[i].bi_segcreate = blkiov15[i].bi_segcreate; 194 blkiov[i].bi_version = blkiov15[i].bi_version; 195 blkiov[i].bi_bp = blkiov15[i].bi_bp; 196 blkiov[i].bi_size = blkiov15[i].bi_size; 197 } 198 199 if ((error = lfs_markv(l->l_proc, &fsid, blkiov, blkcnt)) == 0) { 200 for (i = 0; i < blkcnt; i++) { 201 blkiov15[i].bi_inode = blkiov[i].bi_inode; 202 blkiov15[i].bi_lbn = blkiov[i].bi_lbn; 203 blkiov15[i].bi_daddr = blkiov[i].bi_daddr; 204 blkiov15[i].bi_segcreate = blkiov[i].bi_segcreate; 205 blkiov15[i].bi_version = blkiov[i].bi_version; 206 blkiov15[i].bi_bp = blkiov[i].bi_bp; 207 blkiov15[i].bi_size = blkiov[i].bi_size; 208 } 209 copyout(blkiov15, SCARG(uap, blkiov), 210 blkcnt * sizeof(BLOCK_INFO_15)); 211 } 212 out: 213 lfs_free(fs, blkiov, LFS_NB_BLKIOV); 214 lfs_free(fs, blkiov15, LFS_NB_BLKIOV); 215 KERNEL_UNLOCK_ONE(NULL); 216 return error; 217 } 218 #endif 219 220 #define LFS_MARKV_MAX_BLOCKS (LFS_MAX_BUFS) 221 222 int 223 lfs_markv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov, 224 int blkcnt) 225 { 226 BLOCK_INFO *blkp; 227 IFILE *ifp; 228 struct buf *bp; 229 struct inode *ip = NULL; 230 struct lfs *fs; 231 struct mount *mntp; 232 struct vnode *vp = NULL; 233 ino_t lastino; 234 daddr_t b_daddr, v_daddr; 235 int cnt, error; 236 int do_again = 0; 237 int numrefed = 0; 238 ino_t maxino; 239 size_t obsize; 240 241 /* number of blocks/inodes that we have already bwrite'ed */ 242 int nblkwritten, ninowritten; 243 244 if ((mntp = vfs_getvfs(fsidp)) == NULL) 245 return (ENOENT); 246 247 fs = VFSTOUFS(mntp)->um_lfs; 248 249 if (fs->lfs_ronly) 250 return EROFS; 251 252 maxino = (fragstoblks(fs, VTOI(fs->lfs_ivnode)->i_ffs1_blocks) - 253 fs->lfs_cleansz - fs->lfs_segtabsz) * fs->lfs_ifpb; 254 255 cnt = blkcnt; 256 257 if ((error = vfs_busy(mntp, NULL)) != 0) 258 return (error); 259 260 /* 261 * This seglock is just to prevent the fact that we might have to sleep 262 * from allowing the possibility that our blocks might become 263 * invalid. 264 * 265 * It is also important to note here that unless we specify SEGM_CKP, 266 * any Ifile blocks that we might be asked to clean will never get 267 * to the disk. 268 */ 269 lfs_seglock(fs, SEGM_CLEAN | SEGM_CKP | SEGM_SYNC); 270 271 /* Mark blocks/inodes dirty. */ 272 error = 0; 273 274 /* these were inside the initialization for the for loop */ 275 v_daddr = LFS_UNUSED_DADDR; 276 lastino = LFS_UNUSED_INUM; 277 nblkwritten = ninowritten = 0; 278 for (blkp = blkiov; cnt--; ++blkp) 279 { 280 /* Bounds-check incoming data, avoid panic for failed VGET */ 281 if (blkp->bi_inode <= 0 || blkp->bi_inode >= maxino) { 282 error = EINVAL; 283 goto err3; 284 } 285 /* 286 * Get the IFILE entry (only once) and see if the file still 287 * exists. 288 */ 289 if (lastino != blkp->bi_inode) { 290 /* 291 * Finish the old file, if there was one. The presence 292 * of a usable vnode in vp is signaled by a valid v_daddr. 293 */ 294 if (v_daddr != LFS_UNUSED_DADDR) { 295 lfs_vunref(vp); 296 numrefed--; 297 } 298 299 /* 300 * Start a new file 301 */ 302 lastino = blkp->bi_inode; 303 if (blkp->bi_inode == LFS_IFILE_INUM) 304 v_daddr = fs->lfs_idaddr; 305 else { 306 LFS_IENTRY(ifp, fs, blkp->bi_inode, bp); 307 /* XXX fix for force write */ 308 v_daddr = ifp->if_daddr; 309 brelse(bp, 0); 310 } 311 if (v_daddr == LFS_UNUSED_DADDR) 312 continue; 313 314 /* Get the vnode/inode. */ 315 error = lfs_fastvget(mntp, blkp->bi_inode, v_daddr, 316 &vp, 317 (blkp->bi_lbn == LFS_UNUSED_LBN 318 ? blkp->bi_bp 319 : NULL)); 320 321 if (!error) { 322 numrefed++; 323 } 324 if (error) { 325 DLOG((DLOG_CLEAN, "lfs_markv: lfs_fastvget" 326 " failed with %d (ino %d, segment %d)\n", 327 error, blkp->bi_inode, 328 dtosn(fs, blkp->bi_daddr))); 329 /* 330 * If we got EAGAIN, that means that the 331 * Inode was locked. This is 332 * recoverable: just clean the rest of 333 * this segment, and let the cleaner try 334 * again with another. (When the 335 * cleaner runs again, this segment will 336 * sort high on the list, since it is 337 * now almost entirely empty.) But, we 338 * still set v_daddr = LFS_UNUSED_ADDR 339 * so as not to test this over and over 340 * again. 341 */ 342 if (error == EAGAIN) { 343 error = 0; 344 do_again++; 345 } 346 #ifdef DIAGNOSTIC 347 else if (error != ENOENT) 348 panic("lfs_markv VFS_VGET FAILED"); 349 #endif 350 /* lastino = LFS_UNUSED_INUM; */ 351 v_daddr = LFS_UNUSED_DADDR; 352 vp = NULL; 353 ip = NULL; 354 continue; 355 } 356 ip = VTOI(vp); 357 ninowritten++; 358 } else if (v_daddr == LFS_UNUSED_DADDR) { 359 /* 360 * This can only happen if the vnode is dead (or 361 * in any case we can't get it...e.g., it is 362 * inlocked). Keep going. 363 */ 364 continue; 365 } 366 367 /* Past this point we are guaranteed that vp, ip are valid. */ 368 369 /* Can't clean VU_DIROP directories in case of truncation */ 370 /* XXX - maybe we should mark removed dirs specially? */ 371 if (vp->v_type == VDIR && (vp->v_uflag & VU_DIROP)) { 372 do_again++; 373 continue; 374 } 375 376 /* If this BLOCK_INFO didn't contain a block, keep going. */ 377 if (blkp->bi_lbn == LFS_UNUSED_LBN) { 378 /* XXX need to make sure that the inode gets written in this case */ 379 /* XXX but only write the inode if it's the right one */ 380 if (blkp->bi_inode != LFS_IFILE_INUM) { 381 LFS_IENTRY(ifp, fs, blkp->bi_inode, bp); 382 if (ifp->if_daddr == blkp->bi_daddr) { 383 mutex_enter(&lfs_lock); 384 LFS_SET_UINO(ip, IN_CLEANING); 385 mutex_exit(&lfs_lock); 386 } 387 brelse(bp, 0); 388 } 389 continue; 390 } 391 392 b_daddr = 0; 393 if (VOP_BMAP(vp, blkp->bi_lbn, NULL, &b_daddr, NULL) || 394 dbtofsb(fs, b_daddr) != blkp->bi_daddr) 395 { 396 if (dtosn(fs, dbtofsb(fs, b_daddr)) == 397 dtosn(fs, blkp->bi_daddr)) 398 { 399 DLOG((DLOG_CLEAN, "lfs_markv: wrong da same seg: %llx vs %llx\n", 400 (long long)blkp->bi_daddr, (long long)dbtofsb(fs, b_daddr))); 401 } 402 do_again++; 403 continue; 404 } 405 406 /* 407 * Check block sizes. The blocks being cleaned come from 408 * disk, so they should have the same size as their on-disk 409 * counterparts. 410 */ 411 if (blkp->bi_lbn >= 0) 412 obsize = blksize(fs, ip, blkp->bi_lbn); 413 else 414 obsize = fs->lfs_bsize; 415 /* Check for fragment size change */ 416 if (blkp->bi_lbn >= 0 && blkp->bi_lbn < NDADDR) { 417 obsize = ip->i_lfs_fragsize[blkp->bi_lbn]; 418 } 419 if (obsize != blkp->bi_size) { 420 DLOG((DLOG_CLEAN, "lfs_markv: ino %d lbn %lld wrong" 421 " size (%ld != %d), try again\n", 422 blkp->bi_inode, (long long)blkp->bi_lbn, 423 (long) obsize, blkp->bi_size)); 424 do_again++; 425 continue; 426 } 427 428 /* 429 * If we get to here, then we are keeping the block. If 430 * it is an indirect block, we want to actually put it 431 * in the buffer cache so that it can be updated in the 432 * finish_meta section. If it's not, we need to 433 * allocate a fake buffer so that writeseg can perform 434 * the copyin and write the buffer. 435 */ 436 if (ip->i_number != LFS_IFILE_INUM && blkp->bi_lbn >= 0) { 437 /* Data Block */ 438 bp = lfs_fakebuf(fs, vp, blkp->bi_lbn, 439 blkp->bi_size, blkp->bi_bp); 440 /* Pretend we used bread() to get it */ 441 bp->b_blkno = fsbtodb(fs, blkp->bi_daddr); 442 } else { 443 /* Indirect block or ifile */ 444 if (blkp->bi_size != fs->lfs_bsize && 445 ip->i_number != LFS_IFILE_INUM) 446 panic("lfs_markv: partial indirect block?" 447 " size=%d\n", blkp->bi_size); 448 bp = getblk(vp, blkp->bi_lbn, blkp->bi_size, 0, 0); 449 if (!(bp->b_oflags & (BO_DONE|BO_DELWRI))) { 450 /* 451 * The block in question was not found 452 * in the cache; i.e., the block that 453 * getblk() returned is empty. So, we 454 * can (and should) copy in the 455 * contents, because we've already 456 * determined that this was the right 457 * version of this block on disk. 458 * 459 * And, it can't have changed underneath 460 * us, because we have the segment lock. 461 */ 462 error = copyin(blkp->bi_bp, bp->b_data, blkp->bi_size); 463 if (error) 464 goto err2; 465 } 466 } 467 if ((error = lfs_bwrite_ext(bp, BW_CLEAN)) != 0) 468 goto err2; 469 470 nblkwritten++; 471 /* 472 * XXX should account indirect blocks and ifile pages as well 473 */ 474 if (nblkwritten + lblkno(fs, ninowritten * sizeof (struct ufs1_dinode)) 475 > LFS_MARKV_MAX_BLOCKS) { 476 DLOG((DLOG_CLEAN, "lfs_markv: writing %d blks %d inos\n", 477 nblkwritten, ninowritten)); 478 lfs_segwrite(mntp, SEGM_CLEAN); 479 nblkwritten = ninowritten = 0; 480 } 481 } 482 483 /* 484 * Finish the old file, if there was one 485 */ 486 if (v_daddr != LFS_UNUSED_DADDR) { 487 lfs_vunref(vp); 488 numrefed--; 489 } 490 491 #ifdef DIAGNOSTIC 492 if (numrefed != 0) 493 panic("lfs_markv: numrefed=%d", numrefed); 494 #endif 495 DLOG((DLOG_CLEAN, "lfs_markv: writing %d blks %d inos (check point)\n", 496 nblkwritten, ninowritten)); 497 498 /* 499 * The last write has to be SEGM_SYNC, because of calling semantics. 500 * It also has to be SEGM_CKP, because otherwise we could write 501 * over the newly cleaned data contained in a checkpoint, and then 502 * we'd be unhappy at recovery time. 503 */ 504 lfs_segwrite(mntp, SEGM_CLEAN | SEGM_CKP | SEGM_SYNC); 505 506 lfs_segunlock(fs); 507 508 vfs_unbusy(mntp, false, NULL); 509 if (error) 510 return (error); 511 else if (do_again) 512 return EAGAIN; 513 514 return 0; 515 516 err2: 517 DLOG((DLOG_CLEAN, "lfs_markv err2\n")); 518 519 /* 520 * XXX we're here because copyin() failed. 521 * XXX it means that we can't trust the cleanerd. too bad. 522 * XXX how can we recover from this? 523 */ 524 525 err3: 526 KERNEL_UNLOCK_ONE(NULL); 527 /* 528 * XXX should do segwrite here anyway? 529 */ 530 531 if (v_daddr != LFS_UNUSED_DADDR) { 532 lfs_vunref(vp); 533 --numrefed; 534 } 535 536 lfs_segunlock(fs); 537 vfs_unbusy(mntp, false, NULL); 538 #ifdef DIAGNOSTIC 539 if (numrefed != 0) 540 panic("lfs_markv: numrefed=%d", numrefed); 541 #endif 542 543 return (error); 544 } 545 546 /* 547 * sys_lfs_bmapv: 548 * 549 * This will fill in the current disk address for arrays of blocks. 550 * 551 * 0 on success 552 * -1/errno is return on error. 553 */ 554 #ifdef USE_64BIT_SYSCALLS 555 int 556 sys_lfs_bmapv(struct lwp *l, const struct sys_lfs_bmapv_args *uap, register_t *retval) 557 { 558 /* { 559 syscallarg(fsid_t *) fsidp; 560 syscallarg(struct block_info *) blkiov; 561 syscallarg(int) blkcnt; 562 } */ 563 BLOCK_INFO *blkiov; 564 int blkcnt, error; 565 fsid_t fsid; 566 struct lfs *fs; 567 struct mount *mntp; 568 569 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_LFS, 570 KAUTH_REQ_SYSTEM_LFS_BMAPV, NULL, NULL, NULL); 571 if (error) 572 return (error); 573 574 if ((error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t))) != 0) 575 return (error); 576 577 if ((mntp = vfs_getvfs(&fsid)) == NULL) 578 return (ENOENT); 579 fs = VFSTOUFS(mntp)->um_lfs; 580 581 blkcnt = SCARG(uap, blkcnt); 582 if ((u_int) blkcnt > SIZE_T_MAX / sizeof(BLOCK_INFO)) 583 return (EINVAL); 584 KERNEL_LOCK(1, NULL); 585 blkiov = lfs_malloc(fs, blkcnt * sizeof(BLOCK_INFO), LFS_NB_BLKIOV); 586 if ((error = copyin(SCARG(uap, blkiov), blkiov, 587 blkcnt * sizeof(BLOCK_INFO))) != 0) 588 goto out; 589 590 if ((error = lfs_bmapv(p, &fsid, blkiov, blkcnt)) == 0) 591 copyout(blkiov, SCARG(uap, blkiov), 592 blkcnt * sizeof(BLOCK_INFO)); 593 out: 594 lfs_free(fs, blkiov, LFS_NB_BLKIOV); 595 KERNEL_UNLOCK_ONE(NULL); 596 return error; 597 } 598 #else 599 int 600 sys_lfs_bmapv(struct lwp *l, const struct sys_lfs_bmapv_args *uap, register_t *retval) 601 { 602 /* { 603 syscallarg(fsid_t *) fsidp; 604 syscallarg(struct block_info *) blkiov; 605 syscallarg(int) blkcnt; 606 } */ 607 BLOCK_INFO *blkiov; 608 BLOCK_INFO_15 *blkiov15; 609 int i, blkcnt, error; 610 fsid_t fsid; 611 struct lfs *fs; 612 struct mount *mntp; 613 614 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_LFS, 615 KAUTH_REQ_SYSTEM_LFS_BMAPV, NULL, NULL, NULL); 616 if (error) 617 return (error); 618 619 if ((error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t))) != 0) 620 return (error); 621 622 if ((mntp = vfs_getvfs(&fsid)) == NULL) 623 return (ENOENT); 624 fs = VFSTOUFS(mntp)->um_lfs; 625 626 blkcnt = SCARG(uap, blkcnt); 627 if ((size_t) blkcnt > SIZE_T_MAX / sizeof(BLOCK_INFO)) 628 return (EINVAL); 629 KERNEL_LOCK(1, NULL); 630 blkiov = lfs_malloc(fs, blkcnt * sizeof(BLOCK_INFO), LFS_NB_BLKIOV); 631 blkiov15 = lfs_malloc(fs, blkcnt * sizeof(BLOCK_INFO_15), LFS_NB_BLKIOV); 632 if ((error = copyin(SCARG(uap, blkiov), blkiov15, 633 blkcnt * sizeof(BLOCK_INFO_15))) != 0) 634 goto out; 635 636 for (i = 0; i < blkcnt; i++) { 637 blkiov[i].bi_inode = blkiov15[i].bi_inode; 638 blkiov[i].bi_lbn = blkiov15[i].bi_lbn; 639 blkiov[i].bi_daddr = blkiov15[i].bi_daddr; 640 blkiov[i].bi_segcreate = blkiov15[i].bi_segcreate; 641 blkiov[i].bi_version = blkiov15[i].bi_version; 642 blkiov[i].bi_bp = blkiov15[i].bi_bp; 643 blkiov[i].bi_size = blkiov15[i].bi_size; 644 } 645 646 if ((error = lfs_bmapv(l->l_proc, &fsid, blkiov, blkcnt)) == 0) { 647 for (i = 0; i < blkcnt; i++) { 648 blkiov15[i].bi_inode = blkiov[i].bi_inode; 649 blkiov15[i].bi_lbn = blkiov[i].bi_lbn; 650 blkiov15[i].bi_daddr = blkiov[i].bi_daddr; 651 blkiov15[i].bi_segcreate = blkiov[i].bi_segcreate; 652 blkiov15[i].bi_version = blkiov[i].bi_version; 653 blkiov15[i].bi_bp = blkiov[i].bi_bp; 654 blkiov15[i].bi_size = blkiov[i].bi_size; 655 } 656 copyout(blkiov15, SCARG(uap, blkiov), 657 blkcnt * sizeof(BLOCK_INFO_15)); 658 } 659 out: 660 lfs_free(fs, blkiov, LFS_NB_BLKIOV); 661 lfs_free(fs, blkiov15, LFS_NB_BLKIOV); 662 KERNEL_UNLOCK_ONE(NULL); 663 return error; 664 } 665 #endif 666 667 int 668 lfs_bmapv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov, int blkcnt) 669 { 670 BLOCK_INFO *blkp; 671 IFILE *ifp; 672 struct buf *bp; 673 struct inode *ip = NULL; 674 struct lfs *fs; 675 struct mount *mntp; 676 struct ufsmount *ump; 677 struct vnode *vp; 678 ino_t lastino; 679 daddr_t v_daddr; 680 int cnt, error; 681 int numrefed = 0; 682 683 lfs_cleaner_pid = p->p_pid; 684 685 if ((mntp = vfs_getvfs(fsidp)) == NULL) 686 return (ENOENT); 687 688 ump = VFSTOUFS(mntp); 689 if ((error = vfs_busy(mntp, NULL)) != 0) 690 return (error); 691 692 cnt = blkcnt; 693 694 fs = VFSTOUFS(mntp)->um_lfs; 695 696 error = 0; 697 698 /* these were inside the initialization for the for loop */ 699 v_daddr = LFS_UNUSED_DADDR; 700 lastino = LFS_UNUSED_INUM; 701 for (blkp = blkiov; cnt--; ++blkp) 702 { 703 /* 704 * Get the IFILE entry (only once) and see if the file still 705 * exists. 706 */ 707 if (lastino != blkp->bi_inode) { 708 /* 709 * Finish the old file, if there was one. The presence 710 * of a usable vnode in vp is signaled by a valid 711 * v_daddr. 712 */ 713 if (v_daddr != LFS_UNUSED_DADDR) { 714 lfs_vunref(vp); 715 if (VTOI(vp)->i_lfs_iflags & LFSI_BMAP) 716 vrecycle(vp, NULL, NULL); 717 numrefed--; 718 } 719 720 /* 721 * Start a new file 722 */ 723 lastino = blkp->bi_inode; 724 if (blkp->bi_inode == LFS_IFILE_INUM) 725 v_daddr = fs->lfs_idaddr; 726 else { 727 LFS_IENTRY(ifp, fs, blkp->bi_inode, bp); 728 v_daddr = ifp->if_daddr; 729 brelse(bp, 0); 730 } 731 if (v_daddr == LFS_UNUSED_DADDR) { 732 blkp->bi_daddr = LFS_UNUSED_DADDR; 733 continue; 734 } 735 /* 736 * A regular call to VFS_VGET could deadlock 737 * here. Instead, we try an unlocked access. 738 */ 739 mutex_enter(&ufs_ihash_lock); 740 vp = ufs_ihashlookup(ump->um_dev, blkp->bi_inode); 741 if (vp != NULL && !(vp->v_iflag & VI_XLOCK)) { 742 ip = VTOI(vp); 743 mutex_enter(vp->v_interlock); 744 mutex_exit(&ufs_ihash_lock); 745 if (lfs_vref(vp)) { 746 v_daddr = LFS_UNUSED_DADDR; 747 continue; 748 } 749 numrefed++; 750 } else { 751 mutex_exit(&ufs_ihash_lock); 752 /* 753 * Don't VFS_VGET if we're being unmounted, 754 * since we hold vfs_busy(). 755 */ 756 if (mntp->mnt_iflag & IMNT_UNMOUNT) { 757 v_daddr = LFS_UNUSED_DADDR; 758 continue; 759 } 760 error = VFS_VGET(mntp, blkp->bi_inode, &vp); 761 if (error) { 762 DLOG((DLOG_CLEAN, "lfs_bmapv: vget ino" 763 "%d failed with %d", 764 blkp->bi_inode,error)); 765 v_daddr = LFS_UNUSED_DADDR; 766 continue; 767 } else { 768 KASSERT(VOP_ISLOCKED(vp)); 769 VTOI(vp)->i_lfs_iflags |= LFSI_BMAP; 770 VOP_UNLOCK(vp); 771 numrefed++; 772 } 773 } 774 ip = VTOI(vp); 775 } else if (v_daddr == LFS_UNUSED_DADDR) { 776 /* 777 * This can only happen if the vnode is dead. 778 * Keep going. Note that we DO NOT set the 779 * bi_addr to anything -- if we failed to get 780 * the vnode, for example, we want to assume 781 * conservatively that all of its blocks *are* 782 * located in the segment in question. 783 * lfs_markv will throw them out if we are 784 * wrong. 785 */ 786 /* blkp->bi_daddr = LFS_UNUSED_DADDR; */ 787 continue; 788 } 789 790 /* Past this point we are guaranteed that vp, ip are valid. */ 791 792 if (blkp->bi_lbn == LFS_UNUSED_LBN) { 793 /* 794 * We just want the inode address, which is 795 * conveniently in v_daddr. 796 */ 797 blkp->bi_daddr = v_daddr; 798 } else { 799 daddr_t bi_daddr; 800 801 /* XXX ondisk32 */ 802 error = VOP_BMAP(vp, blkp->bi_lbn, NULL, 803 &bi_daddr, NULL); 804 if (error) 805 { 806 blkp->bi_daddr = LFS_UNUSED_DADDR; 807 continue; 808 } 809 blkp->bi_daddr = dbtofsb(fs, bi_daddr); 810 /* Fill in the block size, too */ 811 if (blkp->bi_lbn >= 0) 812 blkp->bi_size = blksize(fs, ip, blkp->bi_lbn); 813 else 814 blkp->bi_size = fs->lfs_bsize; 815 } 816 } 817 818 /* 819 * Finish the old file, if there was one. The presence 820 * of a usable vnode in vp is signaled by a valid v_daddr. 821 */ 822 if (v_daddr != LFS_UNUSED_DADDR) { 823 lfs_vunref(vp); 824 /* Recycle as above. */ 825 if (ip->i_lfs_iflags & LFSI_BMAP) 826 vrecycle(vp, NULL, NULL); 827 numrefed--; 828 } 829 830 #ifdef DIAGNOSTIC 831 if (numrefed != 0) 832 panic("lfs_bmapv: numrefed=%d", numrefed); 833 #endif 834 835 vfs_unbusy(mntp, false, NULL); 836 837 return 0; 838 } 839 840 /* 841 * sys_lfs_segclean: 842 * 843 * Mark the segment clean. 844 * 845 * 0 on success 846 * -1/errno is return on error. 847 */ 848 int 849 sys_lfs_segclean(struct lwp *l, const struct sys_lfs_segclean_args *uap, register_t *retval) 850 { 851 /* { 852 syscallarg(fsid_t *) fsidp; 853 syscallarg(u_long) segment; 854 } */ 855 struct lfs *fs; 856 struct mount *mntp; 857 fsid_t fsid; 858 int error; 859 unsigned long segnum; 860 861 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_LFS, 862 KAUTH_REQ_SYSTEM_LFS_SEGCLEAN, NULL, NULL, NULL); 863 if (error) 864 return (error); 865 866 if ((error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t))) != 0) 867 return (error); 868 if ((mntp = vfs_getvfs(&fsid)) == NULL) 869 return (ENOENT); 870 871 fs = VFSTOUFS(mntp)->um_lfs; 872 segnum = SCARG(uap, segment); 873 874 if ((error = vfs_busy(mntp, NULL)) != 0) 875 return (error); 876 877 KERNEL_LOCK(1, NULL); 878 lfs_seglock(fs, SEGM_PROT); 879 error = lfs_do_segclean(fs, segnum); 880 lfs_segunlock(fs); 881 KERNEL_UNLOCK_ONE(NULL); 882 vfs_unbusy(mntp, false, NULL); 883 return error; 884 } 885 886 /* 887 * Actually mark the segment clean. 888 * Must be called with the segment lock held. 889 */ 890 int 891 lfs_do_segclean(struct lfs *fs, unsigned long segnum) 892 { 893 extern int lfs_dostats; 894 struct buf *bp; 895 CLEANERINFO *cip; 896 SEGUSE *sup; 897 898 if (dtosn(fs, fs->lfs_curseg) == segnum) { 899 return (EBUSY); 900 } 901 902 LFS_SEGENTRY(sup, fs, segnum, bp); 903 if (sup->su_nbytes) { 904 DLOG((DLOG_CLEAN, "lfs_segclean: not cleaning segment %lu:" 905 " %d live bytes\n", segnum, sup->su_nbytes)); 906 brelse(bp, 0); 907 return (EBUSY); 908 } 909 if (sup->su_flags & SEGUSE_ACTIVE) { 910 DLOG((DLOG_CLEAN, "lfs_segclean: not cleaning segment %lu:" 911 " segment is active\n", segnum)); 912 brelse(bp, 0); 913 return (EBUSY); 914 } 915 if (!(sup->su_flags & SEGUSE_DIRTY)) { 916 DLOG((DLOG_CLEAN, "lfs_segclean: not cleaning segment %lu:" 917 " segment is already clean\n", segnum)); 918 brelse(bp, 0); 919 return (EALREADY); 920 } 921 922 fs->lfs_avail += segtod(fs, 1); 923 if (sup->su_flags & SEGUSE_SUPERBLOCK) 924 fs->lfs_avail -= btofsb(fs, LFS_SBPAD); 925 if (fs->lfs_version > 1 && segnum == 0 && 926 fs->lfs_start < btofsb(fs, LFS_LABELPAD)) 927 fs->lfs_avail -= btofsb(fs, LFS_LABELPAD) - fs->lfs_start; 928 mutex_enter(&lfs_lock); 929 fs->lfs_bfree += sup->su_nsums * btofsb(fs, fs->lfs_sumsize) + 930 btofsb(fs, sup->su_ninos * fs->lfs_ibsize); 931 fs->lfs_dmeta -= sup->su_nsums * btofsb(fs, fs->lfs_sumsize) + 932 btofsb(fs, sup->su_ninos * fs->lfs_ibsize); 933 if (fs->lfs_dmeta < 0) 934 fs->lfs_dmeta = 0; 935 mutex_exit(&lfs_lock); 936 sup->su_flags &= ~SEGUSE_DIRTY; 937 LFS_WRITESEGENTRY(sup, fs, segnum, bp); 938 939 LFS_CLEANERINFO(cip, fs, bp); 940 ++cip->clean; 941 --cip->dirty; 942 fs->lfs_nclean = cip->clean; 943 cip->bfree = fs->lfs_bfree; 944 mutex_enter(&lfs_lock); 945 cip->avail = fs->lfs_avail - fs->lfs_ravail - fs->lfs_favail; 946 wakeup(&fs->lfs_avail); 947 mutex_exit(&lfs_lock); 948 (void) LFS_BWRITE_LOG(bp); 949 950 if (lfs_dostats) 951 ++lfs_stats.segs_reclaimed; 952 953 return (0); 954 } 955 956 /* 957 * This will block until a segment in file system fsid is written. A timeout 958 * in milliseconds may be specified which will awake the cleaner automatically. 959 * An fsid of -1 means any file system, and a timeout of 0 means forever. 960 */ 961 int 962 lfs_segwait(fsid_t *fsidp, struct timeval *tv) 963 { 964 struct mount *mntp; 965 void *addr; 966 u_long timeout; 967 int error; 968 969 KERNEL_LOCK(1, NULL); 970 if (fsidp == NULL || (mntp = vfs_getvfs(fsidp)) == NULL) 971 addr = &lfs_allclean_wakeup; 972 else 973 addr = &VFSTOUFS(mntp)->um_lfs->lfs_nextseg; 974 /* 975 * XXX THIS COULD SLEEP FOREVER IF TIMEOUT IS {0,0}! 976 * XXX IS THAT WHAT IS INTENDED? 977 */ 978 timeout = tvtohz(tv); 979 error = tsleep(addr, PCATCH | PVFS, "segment", timeout); 980 KERNEL_UNLOCK_ONE(NULL); 981 return (error == ERESTART ? EINTR : 0); 982 } 983 984 /* 985 * sys_lfs_segwait: 986 * 987 * System call wrapper around lfs_segwait(). 988 * 989 * 0 on success 990 * 1 on timeout 991 * -1/errno is return on error. 992 */ 993 int 994 sys___lfs_segwait50(struct lwp *l, const struct sys___lfs_segwait50_args *uap, 995 register_t *retval) 996 { 997 /* { 998 syscallarg(fsid_t *) fsidp; 999 syscallarg(struct timeval *) tv; 1000 } */ 1001 struct timeval atv; 1002 fsid_t fsid; 1003 int error; 1004 1005 /* XXX need we be su to segwait? */ 1006 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_LFS, 1007 KAUTH_REQ_SYSTEM_LFS_SEGWAIT, NULL, NULL, NULL); 1008 if (error) 1009 return (error); 1010 if ((error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t))) != 0) 1011 return (error); 1012 1013 if (SCARG(uap, tv)) { 1014 error = copyin(SCARG(uap, tv), &atv, sizeof(struct timeval)); 1015 if (error) 1016 return (error); 1017 if (itimerfix(&atv)) 1018 return (EINVAL); 1019 } else /* NULL or invalid */ 1020 atv.tv_sec = atv.tv_usec = 0; 1021 return lfs_segwait(&fsid, &atv); 1022 } 1023 1024 /* 1025 * VFS_VGET call specialized for the cleaner. The cleaner already knows the 1026 * daddr from the ifile, so don't look it up again. If the cleaner is 1027 * processing IINFO structures, it may have the ondisk inode already, so 1028 * don't go retrieving it again. 1029 * 1030 * we lfs_vref, and it is the caller's responsibility to lfs_vunref 1031 * when finished. 1032 */ 1033 1034 int 1035 lfs_fasthashget(dev_t dev, ino_t ino, struct vnode **vpp) 1036 { 1037 struct vnode *vp; 1038 1039 mutex_enter(&ufs_ihash_lock); 1040 if ((vp = ufs_ihashlookup(dev, ino)) != NULL) { 1041 mutex_enter(vp->v_interlock); 1042 mutex_exit(&ufs_ihash_lock); 1043 if (vp->v_iflag & VI_XLOCK) { 1044 DLOG((DLOG_CLEAN, "lfs_fastvget: ino %d VI_XLOCK\n", 1045 ino)); 1046 lfs_stats.clean_vnlocked++; 1047 mutex_exit(vp->v_interlock); 1048 return EAGAIN; 1049 } 1050 if (lfs_vref(vp)) { 1051 DLOG((DLOG_CLEAN, "lfs_fastvget: lfs_vref failed" 1052 " for ino %d\n", ino)); 1053 lfs_stats.clean_inlocked++; 1054 return EAGAIN; 1055 } 1056 } else { 1057 mutex_exit(&ufs_ihash_lock); 1058 } 1059 *vpp = vp; 1060 1061 return (0); 1062 } 1063 1064 int 1065 lfs_fastvget(struct mount *mp, ino_t ino, daddr_t daddr, struct vnode **vpp, 1066 struct ufs1_dinode *dinp) 1067 { 1068 struct inode *ip; 1069 struct ufs1_dinode *dip; 1070 struct vnode *vp; 1071 struct ufsmount *ump; 1072 dev_t dev; 1073 int error, retries; 1074 struct buf *bp; 1075 struct lfs *fs; 1076 1077 ump = VFSTOUFS(mp); 1078 dev = ump->um_dev; 1079 fs = ump->um_lfs; 1080 1081 /* 1082 * Wait until the filesystem is fully mounted before allowing vget 1083 * to complete. This prevents possible problems with roll-forward. 1084 */ 1085 mutex_enter(&lfs_lock); 1086 while (fs->lfs_flags & LFS_NOTYET) { 1087 mtsleep(&fs->lfs_flags, PRIBIO+1, "lfs_fnotyet", 0, 1088 &lfs_lock); 1089 } 1090 mutex_exit(&lfs_lock); 1091 1092 /* 1093 * This is playing fast and loose. Someone may have the inode 1094 * locked, in which case they are going to be distinctly unhappy 1095 * if we trash something. 1096 */ 1097 1098 error = lfs_fasthashget(dev, ino, vpp); 1099 if (error != 0 || *vpp != NULL) 1100 return (error); 1101 1102 /* 1103 * getnewvnode(9) will call vfs_busy, which will block if the 1104 * filesystem is being unmounted; but umount(9) is waiting for 1105 * us because we're already holding the fs busy. 1106 * XXXMP 1107 */ 1108 if (mp->mnt_iflag & IMNT_UNMOUNT) { 1109 *vpp = NULL; 1110 return EDEADLK; 1111 } 1112 error = getnewvnode(VT_LFS, mp, lfs_vnodeop_p, NULL, &vp); 1113 if (error) { 1114 *vpp = NULL; 1115 return (error); 1116 } 1117 1118 mutex_enter(&ufs_hashlock); 1119 error = lfs_fasthashget(dev, ino, vpp); 1120 if (error != 0 || *vpp != NULL) { 1121 mutex_exit(&ufs_hashlock); 1122 ungetnewvnode(vp); 1123 return (error); 1124 } 1125 1126 /* Allocate new vnode/inode. */ 1127 lfs_vcreate(mp, ino, vp); 1128 1129 /* 1130 * Put it onto its hash chain and lock it so that other requests for 1131 * this inode will block if they arrive while we are sleeping waiting 1132 * for old data structures to be purged or for the contents of the 1133 * disk portion of this inode to be read. 1134 */ 1135 ip = VTOI(vp); 1136 ufs_ihashins(ip); 1137 mutex_exit(&ufs_hashlock); 1138 1139 #ifdef notyet 1140 /* Not found in the cache => this vnode was loaded only for cleaning. */ 1141 ip->i_lfs_iflags |= LFSI_BMAP; 1142 #endif 1143 1144 /* 1145 * XXX 1146 * This may not need to be here, logically it should go down with 1147 * the i_devvp initialization. 1148 * Ask Kirk. 1149 */ 1150 ip->i_lfs = fs; 1151 1152 /* Read in the disk contents for the inode, copy into the inode. */ 1153 if (dinp) { 1154 error = copyin(dinp, ip->i_din.ffs1_din, sizeof (struct ufs1_dinode)); 1155 if (error) { 1156 DLOG((DLOG_CLEAN, "lfs_fastvget: dinode copyin failed" 1157 " for ino %d\n", ino)); 1158 ufs_ihashrem(ip); 1159 1160 /* Unlock and discard unneeded inode. */ 1161 VOP_UNLOCK(vp); 1162 lfs_vunref(vp); 1163 *vpp = NULL; 1164 return (error); 1165 } 1166 if (ip->i_number != ino) 1167 panic("lfs_fastvget: I was fed the wrong inode!"); 1168 } else { 1169 retries = 0; 1170 again: 1171 error = bread(ump->um_devvp, fsbtodb(fs, daddr), fs->lfs_ibsize, 1172 NOCRED, 0, &bp); 1173 if (error) { 1174 DLOG((DLOG_CLEAN, "lfs_fastvget: bread failed (%d)\n", 1175 error)); 1176 /* 1177 * The inode does not contain anything useful, so it 1178 * would be misleading to leave it on its hash chain. 1179 * Iput() will return it to the free list. 1180 */ 1181 ufs_ihashrem(ip); 1182 1183 /* Unlock and discard unneeded inode. */ 1184 VOP_UNLOCK(vp); 1185 lfs_vunref(vp); 1186 brelse(bp, 0); 1187 *vpp = NULL; 1188 return (error); 1189 } 1190 dip = lfs_ifind(ump->um_lfs, ino, bp); 1191 if (dip == NULL) { 1192 /* Assume write has not completed yet; try again */ 1193 brelse(bp, BC_INVAL); 1194 ++retries; 1195 if (retries > LFS_IFIND_RETRIES) 1196 panic("lfs_fastvget: dinode not found"); 1197 DLOG((DLOG_CLEAN, "lfs_fastvget: dinode not found," 1198 " retrying...\n")); 1199 goto again; 1200 } 1201 *ip->i_din.ffs1_din = *dip; 1202 brelse(bp, 0); 1203 } 1204 lfs_vinit(mp, &vp); 1205 1206 *vpp = vp; 1207 1208 KASSERT(VOP_ISLOCKED(vp)); 1209 VOP_UNLOCK(vp); 1210 1211 return (0); 1212 } 1213 1214 /* 1215 * Make up a "fake" cleaner buffer, copy the data from userland into it. 1216 */ 1217 struct buf * 1218 lfs_fakebuf(struct lfs *fs, struct vnode *vp, int lbn, size_t size, void *uaddr) 1219 { 1220 struct buf *bp; 1221 int error; 1222 1223 KASSERT(VTOI(vp)->i_number != LFS_IFILE_INUM); 1224 1225 bp = lfs_newbuf(VTOI(vp)->i_lfs, vp, lbn, size, LFS_NB_CLEAN); 1226 error = copyin(uaddr, bp->b_data, size); 1227 if (error) { 1228 lfs_freebuf(fs, bp); 1229 return NULL; 1230 } 1231 KDASSERT(bp->b_iodone == lfs_callback); 1232 1233 #if 0 1234 mutex_enter(&lfs_lock); 1235 ++fs->lfs_iocount; 1236 mutex_exit(&lfs_lock); 1237 #endif 1238 bp->b_bufsize = size; 1239 bp->b_bcount = size; 1240 return (bp); 1241 } 1242