1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1980, 1986, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #if 0 33 #endif 34 #include <sys/cdefs.h> 35 #include <sys/param.h> 36 #include <sys/stat.h> 37 #include <sys/sysctl.h> 38 39 #include <ufs/ufs/dinode.h> 40 #include <ufs/ufs/dir.h> 41 #include <ufs/ffs/fs.h> 42 43 #include <err.h> 44 #include <limits.h> 45 #include <stdint.h> 46 #include <string.h> 47 48 #include "fsck.h" 49 50 static ufs2_daddr_t badblk; 51 static ufs2_daddr_t dupblk; 52 static ino_t lastino; /* last inode in use */ 53 54 static int checkinode(ino_t inumber, struct inodesc *, int rebuiltcg); 55 56 void 57 pass1(void) 58 { 59 struct inostat *info; 60 struct inodesc idesc; 61 struct bufarea *cgbp; 62 struct cg *cgp; 63 ino_t inumber, inosused, mininos; 64 ufs2_daddr_t i, cgd; 65 u_int8_t *cp; 66 int c, rebuiltcg; 67 68 badblk = dupblk = lastino = 0; 69 70 /* 71 * Set file system reserved blocks in used block map. 72 */ 73 for (c = 0; c < sblock.fs_ncg; c++) { 74 cgd = cgdmin(&sblock, c); 75 if (c == 0) { 76 i = cgbase(&sblock, c); 77 } else 78 i = cgsblock(&sblock, c); 79 for (; i < cgd; i++) 80 setbmap(i); 81 } 82 i = sblock.fs_csaddr; 83 cgd = i + howmany(sblock.fs_cssize, sblock.fs_fsize); 84 for (; i < cgd; i++) 85 setbmap(i); 86 87 /* 88 * Find all allocated blocks. 89 */ 90 memset(&idesc, 0, sizeof(struct inodesc)); 91 idesc.id_func = pass1check; 92 n_files = n_blks = 0; 93 for (c = 0; c < sblock.fs_ncg; c++) { 94 inumber = c * sblock.fs_ipg; 95 cgbp = cglookup(c); 96 cgp = cgbp->b_un.b_cg; 97 rebuiltcg = 0; 98 if (!check_cgmagic(c, cgbp)) { 99 if (!reply("REBUILD CYLINDER GROUP")) { 100 cgheader_corrupt = 1; 101 if (!nflag) { 102 pwarn("YOU WILL NEED TO RERUN FSCK.\n"); 103 rerun = 1; 104 } 105 } else { 106 rebuild_cg(c, cgbp); 107 rebuiltcg = 1; 108 } 109 } 110 if (!rebuiltcg && sblock.fs_magic == FS_UFS2_MAGIC) { 111 inosused = cgp->cg_initediblk; 112 if (inosused > sblock.fs_ipg) { 113 pfatal("Too many initialized inodes (%ju > %d) " 114 "in cylinder group %d\nReset to %d\n", 115 (uintmax_t)inosused, sblock.fs_ipg, c, 116 sblock.fs_ipg); 117 inosused = sblock.fs_ipg; 118 } 119 } else { 120 inosused = sblock.fs_ipg; 121 } 122 if (got_siginfo) { 123 printf("%s: phase 1: cyl group %d of %d (%d%%)\n", 124 cdevname, c, sblock.fs_ncg, 125 c * 100 / sblock.fs_ncg); 126 got_siginfo = 0; 127 } 128 if (got_sigalarm) { 129 setproctitle("%s p1 %d%%", cdevname, 130 c * 100 / sblock.fs_ncg); 131 got_sigalarm = 0; 132 } 133 /* 134 * If we are using soft updates, then we can trust the 135 * cylinder group inode allocation maps to tell us which 136 * inodes are allocated. We will scan the used inode map 137 * to find the inodes that are really in use, and then 138 * read only those inodes in from disk. 139 */ 140 if ((preen || inoopt) && usedsoftdep && !rebuiltcg) { 141 cp = &cg_inosused(cgp)[(inosused - 1) / CHAR_BIT]; 142 for ( ; inosused != 0; cp--) { 143 if (*cp == 0) { 144 if (inosused > CHAR_BIT) 145 inosused -= CHAR_BIT; 146 else 147 inosused = 0; 148 continue; 149 } 150 for (i = 1 << (CHAR_BIT - 1); i > 0; i >>= 1) { 151 if (*cp & i) 152 break; 153 inosused--; 154 } 155 break; 156 } 157 } 158 /* 159 * Allocate inoinfo structures for the allocated inodes. 160 */ 161 inostathead[c].il_numalloced = inosused; 162 if (inosused == 0) { 163 inostathead[c].il_stat = NULL; 164 continue; 165 } 166 info = Calloc((unsigned)inosused, sizeof(struct inostat)); 167 if (info == NULL) 168 errx(EEXIT, "cannot alloc %u bytes for inoinfo", 169 (unsigned)(sizeof(struct inostat) * inosused)); 170 inostathead[c].il_stat = info; 171 /* 172 * Scan the allocated inodes. 173 */ 174 setinodebuf(c, inosused); 175 for (i = 0; i < inosused; i++, inumber++) { 176 if (inumber < UFS_ROOTINO) { 177 (void)getnextinode(inumber, rebuiltcg); 178 continue; 179 } 180 /* 181 * NULL return indicates probable end of allocated 182 * inodes during cylinder group rebuild attempt. 183 * We always keep trying until we get to the minimum 184 * valid number for this cylinder group. 185 */ 186 if (checkinode(inumber, &idesc, rebuiltcg) == 0 && 187 i > cgp->cg_initediblk) 188 break; 189 } 190 /* 191 * This optimization speeds up future runs of fsck 192 * by trimming down the number of inodes in cylinder 193 * groups that formerly had many inodes but now have 194 * fewer in use. 195 */ 196 mininos = roundup(inosused + INOPB(&sblock), INOPB(&sblock)); 197 if (inoopt && !preen && !rebuiltcg && 198 sblock.fs_magic == FS_UFS2_MAGIC && 199 cgp->cg_initediblk > 2 * INOPB(&sblock) && 200 mininos < cgp->cg_initediblk) { 201 i = cgp->cg_initediblk; 202 if (mininos < 2 * INOPB(&sblock)) 203 cgp->cg_initediblk = 2 * INOPB(&sblock); 204 else 205 cgp->cg_initediblk = mininos; 206 pwarn("CYLINDER GROUP %d: RESET FROM %ju TO %d %s\n", 207 c, i, cgp->cg_initediblk, "VALID INODES"); 208 cgdirty(cgbp); 209 } 210 if (inosused < sblock.fs_ipg) 211 continue; 212 lastino += 1; 213 if (lastino < (c * sblock.fs_ipg)) 214 inosused = 0; 215 else 216 inosused = lastino - (c * sblock.fs_ipg); 217 if (rebuiltcg && inosused > cgp->cg_initediblk && 218 sblock.fs_magic == FS_UFS2_MAGIC) { 219 cgp->cg_initediblk = roundup(inosused, INOPB(&sblock)); 220 pwarn("CYLINDER GROUP %d: FOUND %d VALID INODES\n", c, 221 cgp->cg_initediblk); 222 } 223 /* 224 * If we were not able to determine in advance which inodes 225 * were in use, then reduce the size of the inoinfo structure 226 * to the size necessary to describe the inodes that we 227 * really found. Always leave map space in the first cylinder 228 * group in case we need to a root or lost+found directory. 229 */ 230 if (inumber == lastino || c == 0) 231 continue; 232 inostathead[c].il_numalloced = inosused; 233 if (inosused == 0) { 234 free(inostathead[c].il_stat); 235 inostathead[c].il_stat = NULL; 236 continue; 237 } 238 info = Calloc((unsigned)inosused, sizeof(struct inostat)); 239 if (info == NULL) 240 errx(EEXIT, "cannot alloc %u bytes for inoinfo", 241 (unsigned)(sizeof(struct inostat) * inosused)); 242 memmove(info, inostathead[c].il_stat, inosused * sizeof(*info)); 243 free(inostathead[c].il_stat); 244 inostathead[c].il_stat = info; 245 } 246 freeinodebuf(); 247 } 248 249 static int 250 checkinode(ino_t inumber, struct inodesc *idesc, int rebuiltcg) 251 { 252 struct inode ip; 253 union dinode *dp; 254 ufs2_daddr_t ndb; 255 mode_t mode; 256 intmax_t size, fixsize; 257 int j, ret, offset; 258 259 if ((dp = getnextinode(inumber, rebuiltcg)) == NULL) { 260 pfatal("INVALID INODE"); 261 goto unknown; 262 } 263 mode = DIP(dp, di_mode) & IFMT; 264 if (mode == 0) { 265 if ((sblock.fs_magic == FS_UFS1_MAGIC && 266 (memcmp(dp->dp1.di_db, zino.dp1.di_db, 267 UFS_NDADDR * sizeof(ufs1_daddr_t)) || 268 memcmp(dp->dp1.di_ib, zino.dp1.di_ib, 269 UFS_NIADDR * sizeof(ufs1_daddr_t)) || 270 dp->dp1.di_mode || dp->dp1.di_size)) || 271 (sblock.fs_magic == FS_UFS2_MAGIC && 272 (memcmp(dp->dp2.di_db, zino.dp2.di_db, 273 UFS_NDADDR * sizeof(ufs2_daddr_t)) || 274 memcmp(dp->dp2.di_ib, zino.dp2.di_ib, 275 UFS_NIADDR * sizeof(ufs2_daddr_t)) || 276 dp->dp2.di_mode || dp->dp2.di_size))) { 277 pfatal("PARTIALLY ALLOCATED INODE I=%lu", 278 (u_long)inumber); 279 if (reply("CLEAR") == 1) { 280 ginode(inumber, &ip); 281 clearinode(ip.i_dp); 282 inodirty(&ip); 283 irelse(&ip); 284 } 285 } 286 inoinfo(inumber)->ino_state = USTATE; 287 return (1); 288 } 289 lastino = inumber; 290 if (chkfilesize(mode, DIP(dp, di_size)) == 0) { 291 pfatal("BAD FILE SIZE"); 292 goto unknown; 293 } 294 if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) { 295 ginode(inumber, &ip); 296 dp = ip.i_dp; 297 DIP_SET(dp, di_size, sblock.fs_fsize); 298 DIP_SET(dp, di_mode, IFREG|0600); 299 inodirty(&ip); 300 irelse(&ip); 301 } 302 if ((mode == IFBLK || mode == IFCHR || mode == IFIFO || 303 mode == IFSOCK) && DIP(dp, di_size) != 0) { 304 if (debug) 305 printf("bad special-file size %ju:", 306 (uintmax_t)DIP(dp, di_size)); 307 pfatal("BAD SPECIAL-FILE SIZE"); 308 goto unknown; 309 } 310 if ((mode == IFBLK || mode == IFCHR) && 311 (dev_t)DIP(dp, di_rdev) == NODEV) { 312 if (debug) 313 printf("bad special-file rdev NODEV:"); 314 pfatal("BAD SPECIAL-FILE RDEV"); 315 goto unknown; 316 } 317 ndb = howmany(DIP(dp, di_size), sblock.fs_bsize); 318 if (ndb < 0) { 319 if (debug) 320 printf("negative size %ju ndb %ju:", 321 (uintmax_t)DIP(dp, di_size), (uintmax_t)ndb); 322 pfatal("NEGATIVE FILE SIZE"); 323 goto unknown; 324 } 325 if (mode == IFBLK || mode == IFCHR) 326 ndb++; 327 if (mode == IFLNK) { 328 /* 329 * Fake ndb value so direct/indirect block checks below 330 * will detect any garbage after symlink string. 331 */ 332 if (DIP(dp, di_size) < (off_t)sblock.fs_maxsymlinklen) { 333 if (sblock.fs_magic == FS_UFS1_MAGIC) 334 ndb = howmany(DIP(dp, di_size), 335 sizeof(ufs1_daddr_t)); 336 else 337 ndb = howmany(DIP(dp, di_size), 338 sizeof(ufs2_daddr_t)); 339 if (ndb > UFS_NDADDR) { 340 j = ndb - UFS_NDADDR; 341 for (ndb = 1; j > 1; j--) 342 ndb *= NINDIR(&sblock); 343 ndb += UFS_NDADDR; 344 } 345 } 346 } 347 for (j = ndb; ndb < UFS_NDADDR && j < UFS_NDADDR; j++) { 348 if (DIP(dp, di_db[j]) == 0) 349 continue; 350 if (debug) 351 printf("invalid direct addr[%d]: %ju\n", j, 352 (uintmax_t)DIP(dp, di_db[j])); 353 pfatal("INVALID DIRECT BLOCK"); 354 ginode(inumber, &ip); 355 prtinode(&ip); 356 if (reply("CLEAR") == 1) { 357 DIP_SET(ip.i_dp, di_db[j], 0); 358 inodirty(&ip); 359 } 360 irelse(&ip); 361 } 362 for (j = 0, ndb -= UFS_NDADDR; ndb > 0; j++) 363 ndb /= NINDIR(&sblock); 364 for (; j < UFS_NIADDR; j++) { 365 if (DIP(dp, di_ib[j]) == 0) 366 continue; 367 if (debug) 368 printf("invalid indirect addr: %ju\n", 369 (uintmax_t)DIP(dp, di_ib[j])); 370 pfatal("INVALID INDIRECT BLOCK"); 371 ginode(inumber, &ip); 372 prtinode(&ip); 373 if (reply("CLEAR") == 1) { 374 DIP_SET(ip.i_dp, di_ib[j], 0); 375 inodirty(&ip); 376 } 377 irelse(&ip); 378 } 379 if (ftypeok(dp) == 0) { 380 pfatal("UNKNOWN FILE TYPE"); 381 goto unknown; 382 } 383 n_files++; 384 inoinfo(inumber)->ino_linkcnt = DIP(dp, di_nlink); 385 if (mode == IFDIR) { 386 if (DIP(dp, di_size) == 0) { 387 inoinfo(inumber)->ino_state = DCLEAR; 388 } else if (DIP(dp, di_nlink) == 0) { 389 inoinfo(inumber)->ino_state = DZLINK; 390 } else { 391 inoinfo(inumber)->ino_state = DSTATE; 392 } 393 cacheino(dp, inumber); 394 countdirs++; 395 } else if (DIP(dp, di_nlink) <= 0) 396 inoinfo(inumber)->ino_state = FZLINK; 397 else 398 inoinfo(inumber)->ino_state = FSTATE; 399 inoinfo(inumber)->ino_type = IFTODT(mode); 400 badblk = dupblk = 0; 401 idesc->id_number = inumber; 402 if (DIP(dp, di_flags) & SF_SNAPSHOT) 403 inoinfo(inumber)->ino_idtype = SNAP; 404 else 405 inoinfo(inumber)->ino_idtype = ADDR; 406 idesc->id_type = inoinfo(inumber)->ino_idtype; 407 (void)ckinode(dp, idesc); 408 if (sblock.fs_magic == FS_UFS2_MAGIC && dp->dp2.di_extsize > 0) { 409 ndb = howmany(dp->dp2.di_extsize, sblock.fs_bsize); 410 for (j = 0; j < UFS_NXADDR; j++) { 411 if (--ndb == 0 && 412 (offset = blkoff(&sblock, dp->dp2.di_extsize)) != 0) 413 idesc->id_numfrags = numfrags(&sblock, 414 fragroundup(&sblock, offset)); 415 else 416 idesc->id_numfrags = sblock.fs_frag; 417 if (dp->dp2.di_extb[j] == 0) 418 continue; 419 idesc->id_blkno = dp->dp2.di_extb[j]; 420 ret = (*idesc->id_func)(idesc); 421 if (ret & STOP) 422 break; 423 } 424 } 425 if (sblock.fs_magic == FS_UFS2_MAGIC) 426 eascan(idesc, &dp->dp2); 427 idesc->id_entryno *= btodb(sblock.fs_fsize); 428 if (DIP(dp, di_blocks) != idesc->id_entryno) { 429 pwarn("INCORRECT BLOCK COUNT I=%lu (%ju should be %ju)", 430 (u_long)inumber, (uintmax_t)DIP(dp, di_blocks), 431 (uintmax_t)idesc->id_entryno); 432 if (preen) 433 printf(" (CORRECTED)\n"); 434 else if (reply("CORRECT") == 0) 435 return (1); 436 if (bkgrdflag == 0) { 437 ginode(inumber, &ip); 438 DIP_SET(ip.i_dp, di_blocks, idesc->id_entryno); 439 inodirty(&ip); 440 irelse(&ip); 441 } else { 442 cmd.value = idesc->id_number; 443 cmd.size = idesc->id_entryno - DIP(dp, di_blocks); 444 if (debug) 445 printf("adjblkcnt ino %ju amount %lld\n", 446 (uintmax_t)cmd.value, (long long)cmd.size); 447 if (sysctl(adjblkcnt, MIBSIZE, 0, 0, 448 &cmd, sizeof cmd) == -1) 449 rwerror("ADJUST INODE BLOCK COUNT", cmd.value); 450 } 451 } 452 /* 453 * UFS does not allow files to end with a hole; it requires that 454 * the last block of a file be allocated. The last allocated block 455 * in a file is tracked in id_lballoc. Here, we check for a size 456 * past the last allocated block of the file and if that is found, 457 * shorten the file to reference the last allocated block to avoid 458 * having it reference a hole at its end. 459 * 460 * Soft updates will always ensure that the file size is correct 461 * for files that contain only direct block pointers. However 462 * soft updates does not roll back sizes for files with indirect 463 * blocks that it has set to unallocated because their contents 464 * have not yet been written to disk. Hence, the file can appear 465 * to have a hole at its end because the block pointer has been 466 * rolled back to zero. Thus finding a hole at the end of a file 467 * that is located in an indirect block receives only a warning 468 * while finding a hole at the end of a file in a direct block 469 * receives a fatal error message. 470 */ 471 size = DIP(dp, di_size); 472 if (idesc->id_lballoc < lblkno(&sblock, size - 1) && 473 /* exclude embedded symbolic links */ 474 ((mode != IFLNK) || size >= sblock.fs_maxsymlinklen)) { 475 fixsize = lblktosize(&sblock, idesc->id_lballoc + 1); 476 if (size > UFS_NDADDR * sblock.fs_bsize) 477 pwarn("INODE %lu: FILE SIZE %ju BEYOND END OF " 478 "ALLOCATED FILE, SIZE SHOULD BE %ju", 479 (u_long)inumber, size, fixsize); 480 else 481 pfatal("INODE %lu: FILE SIZE %ju BEYOND END OF " 482 "ALLOCATED FILE, SIZE SHOULD BE %ju", 483 (u_long)inumber, size, fixsize); 484 if (preen) 485 printf(" (ADJUSTED)\n"); 486 else if (reply("ADJUST") == 0) 487 return (1); 488 if (bkgrdflag == 0) { 489 ginode(inumber, &ip); 490 DIP_SET(ip.i_dp, di_size, fixsize); 491 inodirty(&ip); 492 irelse(&ip); 493 } else { 494 cmd.value = idesc->id_number; 495 cmd.size = fixsize; 496 if (debug) 497 printf("setsize ino %ju size set to %ju\n", 498 (uintmax_t)cmd.value, (uintmax_t)cmd.size); 499 if (sysctl(setsize, MIBSIZE, 0, 0, 500 &cmd, sizeof cmd) == -1) 501 rwerror("SET INODE SIZE", cmd.value); 502 } 503 504 } 505 return (1); 506 unknown: 507 ginode(inumber, &ip); 508 prtinode(&ip); 509 inoinfo(inumber)->ino_state = USTATE; 510 if (reply("CLEAR") == 1) { 511 clearinode(ip.i_dp); 512 inodirty(&ip); 513 } 514 irelse(&ip); 515 return (1); 516 } 517 518 int 519 pass1check(struct inodesc *idesc) 520 { 521 int res = KEEPON; 522 int anyout, nfrags; 523 ufs2_daddr_t blkno = idesc->id_blkno; 524 struct dups *dlp; 525 struct dups *new; 526 527 if (idesc->id_type == SNAP) { 528 if (blkno == BLK_NOCOPY) 529 return (KEEPON); 530 if (idesc->id_number == cursnapshot) { 531 if (blkno == blkstofrags(&sblock, idesc->id_lbn)) 532 return (KEEPON); 533 if (blkno == BLK_SNAP) { 534 blkno = blkstofrags(&sblock, idesc->id_lbn); 535 idesc->id_entryno -= idesc->id_numfrags; 536 } 537 } else { 538 if (blkno == BLK_SNAP) 539 return (KEEPON); 540 } 541 } 542 if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) { 543 blkerror(idesc->id_number, "BAD", blkno); 544 if (badblk++ >= MAXBAD) { 545 pwarn("EXCESSIVE BAD BLKS I=%lu", 546 (u_long)idesc->id_number); 547 if (preen) 548 printf(" (SKIPPING)\n"); 549 else if (reply("CONTINUE") == 0) { 550 ckfini(0); 551 exit(EEXIT); 552 } 553 rerun = 1; 554 return (STOP); 555 } 556 } 557 for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { 558 if (anyout && chkrange(blkno, 1)) { 559 res = SKIP; 560 } else if (!testbmap(blkno)) { 561 n_blks++; 562 setbmap(blkno); 563 } else { 564 blkerror(idesc->id_number, "DUP", blkno); 565 if (dupblk++ >= MAXDUP) { 566 pwarn("EXCESSIVE DUP BLKS I=%lu", 567 (u_long)idesc->id_number); 568 if (preen) 569 printf(" (SKIPPING)\n"); 570 else if (reply("CONTINUE") == 0) { 571 ckfini(0); 572 exit(EEXIT); 573 } 574 rerun = 1; 575 return (STOP); 576 } 577 new = (struct dups *)Malloc(sizeof(struct dups)); 578 if (new == NULL) { 579 pfatal("DUP TABLE OVERFLOW."); 580 if (reply("CONTINUE") == 0) { 581 ckfini(0); 582 exit(EEXIT); 583 } 584 rerun = 1; 585 return (STOP); 586 } 587 new->dup = blkno; 588 if (muldup == NULL) { 589 duplist = muldup = new; 590 new->next = NULL; 591 } else { 592 new->next = muldup->next; 593 muldup->next = new; 594 } 595 for (dlp = duplist; dlp != muldup; dlp = dlp->next) 596 if (dlp->dup == blkno) 597 break; 598 if (dlp == muldup && dlp->dup != blkno) 599 muldup = new; 600 } 601 /* 602 * count the number of blocks found in id_entryno 603 */ 604 idesc->id_entryno++; 605 } 606 if (idesc->id_level == 0 && idesc->id_lballoc < idesc->id_lbn) 607 idesc->id_lballoc = idesc->id_lbn; 608 return (res); 609 } 610