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