1 /* $NetBSD: lfs_alloc.c,v 1.147 2025/11/03 22:21:12 perseant Exp $ */ 2 3 /*- 4 * Copyright (c) 1999, 2000, 2001, 2002, 2003, 2007 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Konrad E. Schroder <perseant (at) hhhh.org>. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 /* 32 * Copyright (c) 1991, 1993 33 * The Regents of the University of California. All rights reserved. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 1. Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 3. Neither the name of the University nor the names of its contributors 44 * may be used to endorse or promote products derived from this software 45 * without specific prior written permission. 46 * 47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 57 * SUCH DAMAGE. 58 * 59 * @(#)lfs_alloc.c 8.4 (Berkeley) 1/4/94 60 */ 61 62 #include <sys/cdefs.h> 63 __KERNEL_RCSID(0, "$NetBSD: lfs_alloc.c,v 1.147 2025/11/03 22:21:12 perseant Exp $"); 64 65 #if defined(_KERNEL_OPT) 66 #include "opt_quota.h" 67 #endif 68 69 #include <sys/param.h> 70 #include <sys/systm.h> 71 #include <sys/kernel.h> 72 #include <sys/buf.h> 73 #include <sys/lock.h> 74 #include <sys/vnode.h> 75 #include <sys/syslog.h> 76 #include <sys/mount.h> 77 #include <sys/malloc.h> 78 #include <sys/pool.h> 79 #include <sys/proc.h> 80 #include <sys/kauth.h> 81 82 #include <ufs/lfs/ulfs_quotacommon.h> 83 #include <ufs/lfs/ulfs_inode.h> 84 #include <ufs/lfs/ulfsmount.h> 85 #include <ufs/lfs/ulfs_extern.h> 86 87 #include <ufs/lfs/lfs.h> 88 #include <ufs/lfs/lfs_accessors.h> 89 #include <ufs/lfs/lfs_extern.h> 90 #include <ufs/lfs/lfs_kernel.h> 91 92 int lfs_do_check_freelist = 0; 93 94 /* Constants for inode free bitmap */ 95 #define BMSHIFT 5 /* 2 ** 5 = 32 */ 96 #define BMMASK ((1 << BMSHIFT) - 1) 97 #define SET_BITMAP_FREE(F, I) do { \ 98 DLOG((DLOG_ALLOC, "lfs: ino %d wrd %d bit %d set\n", (int)(I), \ 99 (int)((I) >> BMSHIFT), (int)((I) & BMMASK))); \ 100 (F)->lfs_ino_bitmap[(I) >> BMSHIFT] |= (1U << ((I) & BMMASK)); \ 101 } while (0) 102 #define CLR_BITMAP_FREE(F, I) do { \ 103 DLOG((DLOG_ALLOC, "lfs: ino %d wrd %d bit %d clr\n", (int)(I), \ 104 (int)((I) >> BMSHIFT), (int)((I) & BMMASK))); \ 105 (F)->lfs_ino_bitmap[(I) >> BMSHIFT] &= ~(1U << ((I) & BMMASK)); \ 106 } while(0) 107 108 #define ISSET_BITMAP_FREE(F, I) \ 109 ((F)->lfs_ino_bitmap[(I) >> BMSHIFT] & (1U << ((I) & BMMASK))) 110 111 /* 112 * Add a new block to the Ifile, to accommodate future file creations. 113 * Called with the segment lock held. 114 */ 115 int 116 lfs_extend_ifile(struct lfs *fs, kauth_cred_t cred) 117 { 118 struct vnode *vp; 119 struct inode *ip; 120 IFILE64 *ifp64; 121 IFILE32 *ifp32; 122 IFILE_V1 *ifp_v1; 123 struct buf *bp, *cbp; 124 int error; 125 daddr_t i, blkno, xmax; 126 ino_t oldhead, maxino, tail; 127 CLEANERINFO *cip; 128 129 ASSERT_SEGLOCK(fs); 130 131 /* XXX should check or assert that we aren't readonly. */ 132 133 /* 134 * Get a block and extend the ifile inode. Leave the buffer for 135 * the block in bp. 136 */ 137 138 vp = fs->lfs_ivnode; 139 ip = VTOI(vp); 140 blkno = lfs_lblkno(fs, ip->i_size); 141 if ((error = lfs_balloc(vp, ip->i_size, lfs_sb_getbsize(fs), cred, 0, 142 &bp)) != 0) { 143 return (error); 144 } 145 ip->i_size += lfs_sb_getbsize(fs); 146 lfs_dino_setsize(fs, ip->i_din, ip->i_size); 147 uvm_vnp_setsize(vp, ip->i_size); 148 149 /* 150 * Compute the new number of inodes, and reallocate the in-memory 151 * inode freemap. 152 */ 153 154 maxino = ((ip->i_size >> lfs_sb_getbshift(fs)) - lfs_sb_getcleansz(fs) - 155 lfs_sb_getsegtabsz(fs)) * lfs_sb_getifpb(fs); 156 fs->lfs_ino_bitmap = (lfs_bm_t *) 157 realloc(fs->lfs_ino_bitmap, ((maxino + BMMASK) >> BMSHIFT) * 158 sizeof(lfs_bm_t), M_SEGMENT, M_WAITOK); 159 KASSERT(fs->lfs_ino_bitmap != NULL); 160 161 /* first new inode number */ 162 i = (blkno - lfs_sb_getsegtabsz(fs) - lfs_sb_getcleansz(fs)) * 163 lfs_sb_getifpb(fs); 164 165 /* inode number to stop at (XXX: why *x*max?) */ 166 xmax = i + lfs_sb_getifpb(fs); 167 168 /* 169 * We insert the new inodes at the head of the free list. 170 * Under normal circumstances, the free list is empty here, 171 * so we are also incidentally placing them at the end (which 172 * we must do if we are to keep them in order). 173 */ 174 LFS_GET_HEADFREE(fs, cip, cbp, &oldhead); 175 LFS_PUT_HEADFREE(fs, cip, cbp, i); 176 LFS_GET_TAILFREE(fs, cip, cbp, &tail); 177 DLOG((DLOG_ALLOC, "oldhead=%jd, i=%jd, xmax=%jd, oldtail=%jd\n", 178 (intmax_t)oldhead, (intmax_t)i, (intmax_t)xmax, 179 (intmax_t)tail)); 180 if (tail == LFS_UNUSED_INUM) { 181 tail = xmax - 1; 182 LFS_PUT_TAILFREE(fs, cip, cbp, tail); 183 } 184 KASSERTMSG((lfs_sb_getfreehd(fs) != LFS_UNUSED_INUM), 185 "inode 0 allocated [2]"); 186 187 188 /* 189 * Initialize the ifile block. 190 * 191 * XXX: these loops should be restructured to use the accessor 192 * functions instead of using cutpaste polymorphism. 193 */ 194 195 if (fs->lfs_is64) { 196 for (ifp64 = (IFILE64 *)bp->b_data; i < xmax; ++ifp64) { 197 SET_BITMAP_FREE(fs, i); 198 ifp64->if_version = 1; 199 ifp64->if_daddr = LFS_UNUSED_DADDR; 200 ifp64->if_nextfree = ++i; 201 } 202 ifp64--; 203 ifp64->if_nextfree = oldhead; 204 } else if (lfs_sb_getversion(fs) > 1) { 205 for (ifp32 = (IFILE32 *)bp->b_data; i < xmax; ++ifp32) { 206 SET_BITMAP_FREE(fs, i); 207 ifp32->if_version = 1; 208 ifp32->if_daddr = LFS_UNUSED_DADDR; 209 ifp32->if_nextfree = ++i; 210 } 211 ifp32--; 212 ifp32->if_nextfree = oldhead; 213 } else { 214 for (ifp_v1 = (IFILE_V1 *)bp->b_data; i < xmax; ++ifp_v1) { 215 SET_BITMAP_FREE(fs, i); 216 ifp_v1->if_version = 1; 217 ifp_v1->if_daddr = LFS_UNUSED_DADDR; 218 ifp_v1->if_nextfree = ++i; 219 } 220 ifp_v1--; 221 ifp_v1->if_nextfree = oldhead; 222 } 223 DLOG((DLOG_ALLOC, " now head=%jd tail=%jd\n", 224 (intmax_t)xmax - lfs_sb_getifpb(fs), (intmax_t)tail)); 225 226 /* 227 * Write out the new block. 228 */ 229 230 (void) LFS_BWRITE_LOG(bp); /* Ifile */ 231 232 return 0; 233 } 234 235 /* 236 * Allocate an inode for a new file. 237 * 238 * Takes the segment lock. Also (while holding it) takes lfs_lock 239 * to frob fs->lfs_fmod. 240 * 241 * XXX: the mode argument is unused; should just get rid of it. 242 */ 243 /* ARGSUSED */ 244 /* VOP_BWRITE 2i times */ 245 int 246 lfs_valloc(struct vnode *pvp, int mode, kauth_cred_t cred, 247 ino_t *ino, int *gen) 248 { 249 struct lfs *fs; 250 struct buf *bp, *cbp; 251 IFILE *ifp; 252 int error; 253 CLEANERINFO *cip; 254 255 fs = VTOI(pvp)->i_lfs; 256 if (fs->lfs_ronly) 257 return EROFS; 258 259 if (!(fs->lfs_flags & LFS_NOTYET)) 260 ASSERT_NO_SEGLOCK(fs); 261 262 DEBUG_CHECK_FREELIST(fs); 263 264 lfs_seglock(fs, SEGM_PROT); 265 266 /* Get the head of the freelist. */ 267 LFS_GET_HEADFREE(fs, cip, cbp, ino); 268 269 /* paranoia */ 270 KASSERT(*ino != LFS_UNUSED_INUM && *ino != LFS_IFILE_INUM); 271 DLOG((DLOG_ALLOC, "lfs_valloc: allocate inode %" PRId64 "\n", 272 *ino)); 273 274 /* Update the in-memory inode freemap */ 275 CLR_BITMAP_FREE(fs, *ino); 276 277 /* 278 * Fetch the ifile entry and make sure the inode is really 279 * free. 280 */ 281 LFS_IENTRY(ifp, fs, *ino, bp); 282 if (lfs_if_getdaddr(fs, ifp) != LFS_UNUSED_DADDR) 283 panic("lfs_valloc: inuse inode %" PRId64 " on the free list", 284 *ino); 285 286 /* Update the inode freelist head in the superblock. */ 287 LFS_PUT_HEADFREE(fs, cip, cbp, lfs_if_getnextfree(fs, ifp)); 288 DLOG((DLOG_ALLOC, "lfs_valloc: headfree %" PRId64 " -> %ju\n", 289 *ino, (uintmax_t)lfs_if_getnextfree(fs, ifp))); 290 291 /* 292 * Retrieve the version number from the ifile entry. It was 293 * bumped by vfree, so don't bump it again. 294 */ 295 *gen = lfs_if_getversion(fs, ifp); 296 297 /* Done with ifile entry */ 298 299 /* 300 * Note LFS_ILLEGAL_DADDR == LFS_UNUSED_DADDR 301 * unless DEBUG is set. In that case we 302 * use that address to track inodes that have been 303 * allocated (and so not on the free list) but do not 304 * have proper disk addresses yet. 305 */ 306 lfs_if_setdaddr(fs, ifp, LFS_ILLEGAL_DADDR); 307 lfs_if_setnextfree(fs, ifp, LFS_UNUSED_INUM); 308 LFS_BWRITE_LOG(bp); 309 310 if (lfs_sb_getfreehd(fs) == LFS_UNUSED_INUM) { 311 /* 312 * No more inodes; extend the ifile so that the next 313 * lfs_valloc will succeed. 314 */ 315 if ((error = lfs_extend_ifile(fs, cred)) != 0) { 316 /* restore the freelist */ 317 LFS_PUT_HEADFREE(fs, cip, cbp, *ino); 318 319 /* unlock and return */ 320 lfs_segunlock(fs); 321 return error; 322 } 323 } 324 KASSERTMSG((lfs_sb_getfreehd(fs) != LFS_UNUSED_INUM), 325 "inode 0 allocated [3]"); 326 327 /* Set superblock modified bit */ 328 mutex_enter(&lfs_lock); 329 fs->lfs_fmod = 1; 330 mutex_exit(&lfs_lock); 331 332 /* increment file count */ 333 lfs_sb_addnfiles(fs, 1); 334 335 /* done */ 336 lfs_segunlock(fs); 337 338 DEBUG_CHECK_FREELIST(fs); 339 return 0; 340 } 341 342 /* 343 * Allocate an inode for a new file, with given inode number and 344 * version. 345 * 346 * Called in the same context as lfs_valloc and therefore shares the 347 * same locking assumptions. 348 */ 349 int 350 lfs_valloc_fixed(struct lfs *fs, ino_t ino, int vers) 351 { 352 IFILE *ifp; 353 struct buf *bp, *cbp; 354 ino_t headino, thisino, oldnext, tailino; 355 CLEANERINFO *cip; 356 int extended = 0; 357 358 if (fs->lfs_ronly) 359 return EROFS; 360 361 if (!(fs->lfs_flags & LFS_NOTYET)) 362 ASSERT_NO_SEGLOCK(fs); 363 364 DEBUG_CHECK_FREELIST(fs); 365 366 lfs_seglock(fs, SEGM_PROT); 367 368 /* 369 * If the ifile is too short to contain this inum, extend it. 370 * 371 * XXX: lfs_extend_ifile should take a size instead of always 372 * doing just one block at time. 373 */ 374 while (VTOI(fs->lfs_ivnode)->i_size <= (ino / 375 lfs_sb_getifpb(fs) + lfs_sb_getcleansz(fs) + lfs_sb_getsegtabsz(fs)) 376 << lfs_sb_getbshift(fs)) { 377 DLOG((DLOG_ALLOC, "extend ifile to accommodate ino %jd\n", 378 (intmax_t)ino)); 379 lfs_extend_ifile(fs, NOCRED); 380 extended = 1; 381 } 382 383 /* 384 * Get the inode freelist next pointer. 385 */ 386 LFS_IENTRY(ifp, fs, ino, bp); 387 oldnext = lfs_if_getnextfree(fs, ifp); 388 brelse(bp, 0); 389 390 /* Get fail of inode freelist */ 391 LFS_GET_TAILFREE(fs, cip, cbp, &tailino); 392 393 /* Get head of inode freelist */ 394 LFS_GET_HEADFREE(fs, cip, cbp, &headino); 395 if (headino == ino) { 396 /* Easy case: the inode we wanted was at the head */ 397 LFS_PUT_HEADFREE(fs, cip, cbp, oldnext); 398 } else { 399 ino_t nextfree = 0, maxino, count; /* XXX: gcc */ 400 401 /* Have to find the desired inode in the freelist... */ 402 maxino = ((VTOI(fs->lfs_ivnode)->i_size >> lfs_sb_getbshift(fs)) 403 - lfs_sb_getcleansz(fs) - lfs_sb_getsegtabsz(fs)) 404 * lfs_sb_getifpb(fs); 405 count = 0; 406 407 thisino = headino; 408 while (thisino != LFS_UNUSED_INUM) { 409 /* read this ifile entry */ 410 LFS_IENTRY(ifp, fs, thisino, bp); 411 nextfree = lfs_if_getnextfree(fs, ifp); 412 /* stop if we find it or we hit the end */ 413 if (nextfree == ino || 414 nextfree == LFS_UNUSED_INUM) 415 break; 416 /* nope, keep going... */ 417 thisino = nextfree; 418 brelse(bp, 0); 419 if (++count > maxino) 420 break; 421 } 422 if (count > maxino) { 423 panic("loop in free list"); 424 lfs_segunlock(fs); 425 return ENOENT; 426 } 427 if (nextfree == LFS_UNUSED_INUM) { 428 /* hit the end -- this inode is not available */ 429 brelse(bp, 0); 430 lfs_segunlock(fs); 431 if (extended) 432 panic("extended ifile to accommodate but inode not found"); 433 return ENOENT; 434 } 435 /* found it; update the next pointer */ 436 lfs_if_setnextfree(fs, ifp, oldnext); 437 /* write the ifile block */ 438 LFS_BWRITE_LOG(bp); 439 440 /* If our inode was the tail, thisino is now the tail */ 441 if (tailino == ino) 442 LFS_PUT_TAILFREE(fs, cip, cbp, thisino); 443 } 444 445 /* Clear nextfree, note daddr, and set generation number */ 446 LFS_IENTRY(ifp, fs, ino, bp); 447 lfs_if_setversion(fs, ifp, vers); 448 lfs_if_setnextfree(fs, ifp, LFS_UNUSED_INUM); 449 /* See comment in lfs_valloc */ 450 lfs_if_setdaddr(fs, ifp, LFS_ILLEGAL_DADDR); 451 LFS_BWRITE_LOG(bp); 452 453 if (lfs_sb_getfreehd(fs) == LFS_UNUSED_INUM) { 454 int error; 455 /* 456 * No more inodes; extend the ifile so that the next 457 * lfs_valloc will succeed. 458 */ 459 if ((error = lfs_extend_ifile(fs, NOCRED)) != 0) { 460 /* restore the freelist */ 461 LFS_PUT_HEADFREE(fs, cip, cbp, ino); 462 463 /* unlock and return */ 464 lfs_segunlock(fs); 465 return error; 466 } 467 } 468 KASSERTMSG((lfs_sb_getfreehd(fs) != LFS_UNUSED_INUM), 469 "inode 0 allocated [4]"); 470 471 /* done */ 472 lfs_segunlock(fs); 473 474 DEBUG_CHECK_FREELIST(fs); 475 476 return 0; 477 } 478 479 #if 0 480 /* 481 * Find the highest-numbered allocated inode. 482 * This will be used to shrink the Ifile. 483 */ 484 static inline ino_t 485 lfs_last_alloc_ino(struct lfs *fs) 486 { 487 ino_t ino, maxino; 488 489 maxino = ((fs->lfs_ivnode->v_size >> lfs_sb_getbshift(fs)) - 490 lfs_sb_getcleansz(fs) - lfs_sb_getsegtabsz(fs)) * 491 lfs_sb_getifpb(fs); 492 for (ino = maxino - 1; ino > LFS_UNUSED_INUM; --ino) { 493 if (ISSET_BITMAP_FREE(fs, ino) == 0) 494 break; 495 } 496 return ino; 497 } 498 499 /* 500 * Find the previous (next lowest numbered) free inode, if any. 501 * If there is none, return LFS_UNUSED_INUM. 502 * 503 * XXX: locking? 504 */ 505 static inline ino_t 506 lfs_freelist_prev(struct lfs *fs, ino_t ino) 507 { 508 ino_t tino, bound, bb, freehdbb; 509 510 if (lfs_sb_getfreehd(fs) == LFS_UNUSED_INUM) { 511 /* No free inodes at all */ 512 return LFS_UNUSED_INUM; 513 } 514 515 /* Search our own word first */ 516 bound = ino & ~BMMASK; 517 for (tino = ino - 1; tino >= bound && tino > LFS_UNUSED_INUM; tino--) 518 if (ISSET_BITMAP_FREE(fs, tino)) 519 return tino; 520 /* If there are no lower words to search, just return */ 521 if (ino >> BMSHIFT == 0) 522 return LFS_UNUSED_INUM; 523 524 /* 525 * Find a word with a free inode in it. We have to be a bit 526 * careful here since ino_t is unsigned. 527 */ 528 freehdbb = (lfs_sb_getfreehd(fs) >> BMSHIFT); 529 for (bb = (ino >> BMSHIFT) - 1; bb >= freehdbb && bb > 0; --bb) 530 if (fs->lfs_ino_bitmap[bb]) 531 break; 532 if (fs->lfs_ino_bitmap[bb] == 0) 533 return LFS_UNUSED_INUM; 534 535 /* Search the word we found */ 536 for (tino = (bb << BMSHIFT) | BMMASK; tino >= (bb << BMSHIFT) && 537 tino > LFS_UNUSED_INUM; tino--) 538 if (ISSET_BITMAP_FREE(fs, tino)) 539 break; 540 541 /* Avoid returning reserved inode numbers */ 542 if (tino <= LFS_IFILE_INUM) 543 tino = LFS_UNUSED_INUM; 544 545 return tino; 546 } 547 #endif 548 549 /* 550 * Free an inode. 551 * 552 * Takes lfs_seglock. Also (independently) takes vp->v_interlock. 553 */ 554 /* ARGUSED */ 555 /* VOP_BWRITE 2i times */ 556 int 557 lfs_vfree(struct vnode *vp, ino_t ino, int mode) 558 { 559 SEGUSE *sup; 560 CLEANERINFO *cip; 561 struct buf *cbp, *bp; 562 IFILE *ifp; 563 struct inode *ip; 564 struct lfs *fs; 565 daddr_t old_iaddr; 566 567 /* Get the inode number and file system. */ 568 ip = VTOI(vp); 569 fs = ip->i_lfs; 570 ino = ip->i_number; 571 572 /* XXX: assert not readonly */ 573 574 ASSERT_NO_SEGLOCK(fs); 575 DLOG((DLOG_ALLOC, "lfs_vfree: free ino %lld\n", (long long)ino)); 576 577 /* Drain of pending writes */ 578 mutex_enter(vp->v_interlock); 579 while (lfs_sb_getversion(fs) > 1 && WRITEINPROG(vp)) { 580 cv_wait(&vp->v_cv, vp->v_interlock); 581 } 582 mutex_exit(vp->v_interlock); 583 584 lfs_seglock(fs, SEGM_PROT); 585 586 DEBUG_CHECK_FREELIST(fs); 587 588 /* 589 * If the inode was in a dirop, it isn't now. 590 * 591 * XXX: why are (v_uflag & VU_DIROP) and (ip->i_state & IN_ADIROP) 592 * not updated together in one function? (and why do both exist, 593 * anyway?) 594 */ 595 UNMARK_VNODE(vp); 596 597 mutex_enter(&lfs_lock); 598 if (vp->v_uflag & VU_DIROP) { 599 vp->v_uflag &= ~VU_DIROP; 600 --lfs_dirvcount; 601 --fs->lfs_dirvcount; 602 TAILQ_REMOVE(&fs->lfs_dchainhd, ip, i_lfs_dchain); 603 wakeup(&fs->lfs_dirvcount); 604 wakeup(&lfs_dirvcount); 605 mutex_exit(&lfs_lock); 606 vrele(vp); 607 608 /* 609 * If this inode is not going to be written any more, any 610 * segment accounting left over from its truncation needs 611 * to occur at the end of the next dirops flush. Attach 612 * them to the fs-wide list for that purpose. 613 */ 614 if (LIST_FIRST(&ip->i_lfs_segdhd) != NULL) { 615 struct segdelta *sd; 616 617 while((sd = LIST_FIRST(&ip->i_lfs_segdhd)) != NULL) { 618 LIST_REMOVE(sd, list); 619 LIST_INSERT_HEAD(&fs->lfs_segdhd, sd, list); 620 } 621 } 622 } else { 623 /* 624 * If it's not a dirop, we can finalize right away. 625 */ 626 mutex_exit(&lfs_lock); 627 lfs_finalize_ino_seguse(fs, ip); 628 } 629 630 /* it is no longer an unwritten inode, so update the counts */ 631 KASSERT(!(ip->i_state & IN_CLEANING)); 632 mutex_enter(&lfs_lock); 633 LFS_CLR_UINO(ip, IN_ACCESSED|IN_MODIFIED); 634 mutex_exit(&lfs_lock); 635 636 /* Turn off all inode modification flags */ 637 ip->i_state &= ~IN_ALLMOD; 638 639 /* Mark it deleted */ 640 ip->i_lfs_iflags |= LFSI_DELETED; 641 642 /* Mark it free in the in-memory inode freemap */ 643 SET_BITMAP_FREE(fs, ino); 644 645 /* 646 * Set the ifile's inode entry to unused, increment its version number 647 * and link it onto the free chain. 648 */ 649 650 /* fetch the ifile entry */ 651 LFS_IENTRY(ifp, fs, ino, bp); 652 653 /* update the on-disk address (to "nowhere") */ 654 old_iaddr = lfs_if_getdaddr(fs, ifp); 655 lfs_if_setdaddr(fs, ifp, LFS_UNUSED_DADDR); 656 657 /* bump the version */ 658 lfs_if_setversion(fs, ifp, lfs_if_getversion(fs, ifp) + 1); 659 660 #if 0 661 if (lfs_sb_getversion(fs) == 1) { 662 #endif 663 ino_t nextfree; 664 665 /* insert on freelist */ 666 LFS_GET_HEADFREE(fs, cip, cbp, &nextfree); 667 lfs_if_setnextfree(fs, ifp, nextfree); 668 LFS_PUT_HEADFREE(fs, cip, cbp, ino); 669 670 /* write the ifile block */ 671 (void) LFS_BWRITE_LOG(bp); /* Ifile */ 672 #if 0 673 } else { 674 ino_t tino, onf, otail; 675 676 /* 677 * Clear the freelist next pointer and write the ifile 678 * block. XXX: why? I'm sure there must be a reason but 679 * it seems both silly and dangerous. 680 */ 681 lfs_if_setnextfree(fs, ifp, LFS_UNUSED_INUM); 682 (void) LFS_BWRITE_LOG(bp); /* Ifile */ 683 684 /* 685 * Insert on freelist in order. 686 */ 687 688 /* Find the next lower (by number) free inode */ 689 tino = lfs_freelist_prev(fs, ino); 690 691 if (tino == LFS_UNUSED_INUM) { 692 ino_t nextfree; 693 694 /* 695 * There isn't one; put us on the freelist head. 696 */ 697 698 /* reload the ifile block */ 699 LFS_IENTRY(ifp, fs, ino, bp); 700 /* update the list */ 701 LFS_GET_HEADFREE(fs, cip, cbp, &nextfree); 702 lfs_if_setnextfree(fs, ifp, nextfree); 703 LFS_PUT_HEADFREE(fs, cip, cbp, ino); 704 DLOG((DLOG_ALLOC, "lfs_vfree: headfree %lld -> %lld\n", 705 (long long)nextfree, (long long)ino)); 706 /* write the ifile block */ 707 LFS_BWRITE_LOG(bp); /* Ifile */ 708 709 /* If the list was empty, set tail too */ 710 LFS_GET_TAILFREE(fs, cip, cbp, &otail); 711 if (otail == LFS_UNUSED_INUM) { 712 LFS_PUT_TAILFREE(fs, cip, cbp, ino); 713 DLOG((DLOG_ALLOC, "lfs_vfree: tailfree %lld " 714 "-> %lld\n", (long long)otail, 715 (long long)ino)); 716 } 717 } else { 718 /* 719 * Insert this inode into the list after tino. 720 * We hold the segment lock so we don't have to 721 * worry about blocks being written out of order. 722 */ 723 724 DLOG((DLOG_ALLOC, "lfs_vfree: insert ino %lld " 725 " after %lld\n", ino, tino)); 726 727 /* load the previous inode's ifile block */ 728 LFS_IENTRY(ifp, fs, tino, bp); 729 /* update the list pointer */ 730 onf = lfs_if_getnextfree(fs, ifp); 731 lfs_if_setnextfree(fs, ifp, ino); 732 /* write the block */ 733 LFS_BWRITE_LOG(bp); /* Ifile */ 734 735 /* load this inode's ifile block */ 736 LFS_IENTRY(ifp, fs, ino, bp); 737 /* update the list pointer */ 738 lfs_if_setnextfree(fs, ifp, onf); 739 /* write the block */ 740 LFS_BWRITE_LOG(bp); /* Ifile */ 741 742 /* If we're last, put us on the tail */ 743 if (onf == LFS_UNUSED_INUM) { 744 LFS_GET_TAILFREE(fs, cip, cbp, &otail); 745 LFS_PUT_TAILFREE(fs, cip, cbp, ino); 746 DLOG((DLOG_ALLOC, "lfs_vfree: tailfree %lld " 747 "-> %lld\n", (long long)otail, 748 (long long)ino)); 749 } 750 } 751 } 752 #endif 753 /* XXX: shouldn't this check be further up *before* we trash the fs? */ 754 KASSERTMSG((ino != LFS_UNUSED_INUM), "inode 0 freed"); 755 756 /* 757 * Update the segment summary for the segment where the on-disk 758 * copy used to be. 759 */ 760 if (!DADDR_IS_BAD(old_iaddr)) { 761 /* load it */ 762 LFS_SEGENTRY(sup, fs, lfs_dtosn(fs, old_iaddr), bp); 763 /* the number of bytes in the segment should not become < 0 */ 764 KASSERTMSG((sup->su_nbytes >= DINOSIZE(fs)), 765 "lfs_vfree: negative byte count" 766 " (segment %" PRIu32 " short by %d)\n", 767 lfs_dtosn(fs, old_iaddr), 768 (int)DINOSIZE(fs) - sup->su_nbytes); 769 /* update the number of bytes in the segment */ 770 sup->su_nbytes -= DINOSIZE(fs); 771 /* write the segment entry */ 772 LFS_WRITESEGENTRY(sup, fs, lfs_dtosn(fs, old_iaddr), bp); /* Ifile */ 773 } 774 775 /* Set superblock modified bit. */ 776 mutex_enter(&lfs_lock); 777 fs->lfs_fmod = 1; 778 mutex_exit(&lfs_lock); 779 780 /* Decrement file count. */ 781 lfs_sb_subnfiles(fs, 1); 782 783 lfs_segunlock(fs); 784 785 DEBUG_CHECK_FREELIST(fs); 786 787 return (0); 788 } 789 790 /* 791 * Sort the freelist and set up the free-inode bitmap. 792 * To be called by lfs_mountfs(). 793 * 794 * Takes the segmenet lock. 795 */ 796 void 797 lfs_order_freelist(struct lfs *fs, ino_t **orphanp, size_t *norphanp) 798 { 799 CLEANERINFO *cip; 800 IFILE *ifp = NULL; 801 struct buf *bp; 802 ino_t ino, firstino, lastino, maxino; 803 ino_t *orphan = NULL; 804 size_t norphan = 0; 805 size_t norphan_alloc = 0; 806 807 ASSERT_NO_SEGLOCK(fs); 808 lfs_seglock(fs, SEGM_PROT); 809 810 DEBUG_CHECK_FREELIST(fs); 811 812 /* largest inode on fs */ 813 maxino = ((fs->lfs_ivnode->v_size >> lfs_sb_getbshift(fs)) - 814 lfs_sb_getcleansz(fs) - lfs_sb_getsegtabsz(fs)) * lfs_sb_getifpb(fs); 815 816 /* allocate the in-memory inode freemap */ 817 /* XXX: assert that fs->lfs_ino_bitmap is null here */ 818 fs->lfs_ino_bitmap = 819 malloc(((maxino + BMMASK) >> BMSHIFT) * sizeof(lfs_bm_t), 820 M_SEGMENT, M_WAITOK | M_ZERO); 821 KASSERT(fs->lfs_ino_bitmap != NULL); 822 823 /* 824 * Scan the ifile. 825 */ 826 827 firstino = lastino = LFS_UNUSED_INUM; 828 for (ino = 0; ino < maxino; ino++) { 829 /* Load this inode's ifile entry. */ 830 if (ino % lfs_sb_getifpb(fs) == 0) 831 LFS_IENTRY(ifp, fs, ino, bp); 832 else 833 LFS_IENTRY_NEXT(ifp, fs); 834 835 /* Don't put zero or ifile on the free list */ 836 if (ino == LFS_UNUSED_INUM || ino == LFS_IFILE_INUM) 837 continue; 838 839 /* 840 * Address orphaned files. 841 * 842 * The idea of this is to free inodes belonging to 843 * files that were unlinked but not reclaimed, I guess 844 * because if we're going to scan the whole ifile 845 * anyway it costs very little to do this. I don't 846 * immediately see any reason this should be disabled, 847 * but presumably it doesn't work... not sure what 848 * happens to such files currently. -- dholland 20160806 849 */ 850 if (lfs_if_getnextfree(fs, ifp) == LFS_ORPHAN_NEXTFREE(fs)) { 851 if (orphan == NULL) { 852 norphan_alloc = 32; /* XXX pulled from arse */ 853 orphan = kmem_zalloc(sizeof(orphan[0]) * 854 norphan_alloc, KM_SLEEP); 855 } else if (norphan == norphan_alloc) { 856 ino_t *orphan_new; 857 if (norphan_alloc >= 4096) 858 norphan_alloc += 4096; 859 else 860 norphan_alloc *= 2; 861 orphan_new = kmem_zalloc(sizeof(orphan[0]) * 862 norphan_alloc, KM_SLEEP); 863 memcpy(orphan_new, orphan, sizeof(orphan[0]) * 864 norphan); 865 kmem_free(orphan, sizeof(orphan[0]) * norphan); 866 orphan = orphan_new; 867 } 868 orphan[norphan++] = ino; 869 } 870 871 if (DADDR_IS_BAD(lfs_if_getdaddr(fs, ifp))) { 872 873 /* 874 * This inode is free. Put it on the free list. 875 */ 876 877 if (firstino == LFS_UNUSED_INUM) { 878 /* XXX: assert lastino == LFS_UNUSED_INUM? */ 879 /* remember the first free inode */ 880 firstino = ino; 881 } else { 882 /* release this inode's ifile entry */ 883 brelse(bp, 0); 884 885 /* XXX: assert lastino != LFS_UNUSED_INUM? */ 886 887 /* load lastino's ifile entry */ 888 LFS_IENTRY(ifp, fs, lastino, bp); 889 /* set the list pointer */ 890 lfs_if_setnextfree(fs, ifp, ino); 891 /* write the block */ 892 LFS_BWRITE_LOG(bp); 893 894 /* reload this inode's ifile entry */ 895 LFS_IENTRY(ifp, fs, ino, bp); 896 } 897 /* remember the last free inode seen so far */ 898 lastino = ino; 899 900 /* Mark this inode free in the in-memory freemap */ 901 SET_BITMAP_FREE(fs, ino); 902 } 903 904 /* If moving to the next ifile block, release the buffer. */ 905 if ((ino + 1) % lfs_sb_getifpb(fs) == 0) 906 brelse(bp, 0); 907 } 908 909 /* Write the freelist head and tail pointers */ 910 /* XXX: do we need to mark the superblock dirty? */ 911 LFS_PUT_HEADFREE(fs, cip, bp, firstino); 912 LFS_PUT_TAILFREE(fs, cip, bp, lastino); 913 914 /* done */ 915 lfs_segunlock(fs); 916 917 /* 918 * Shrink the array of orphans so we don't have to carry around 919 * the allocation size. 920 */ 921 if (norphan < norphan_alloc) { 922 ino_t *orphan_new = kmem_alloc(sizeof(orphan[0]) * norphan, 923 KM_SLEEP); 924 memcpy(orphan_new, orphan, sizeof(orphan[0]) * norphan); 925 kmem_free(orphan, sizeof(orphan[0]) * norphan_alloc); 926 orphan = orphan_new; 927 norphan_alloc = norphan; 928 } 929 930 *orphanp = orphan; 931 *norphanp = norphan; 932 933 DEBUG_CHECK_FREELIST(fs); 934 } 935 936 /* 937 * Handle files deleted from the file system namespace. 938 * 939 * When inodes are reclaimed, they are added back to the free list as 940 * usual; but if the system crashes before they can be reclaimed, they 941 * will need to be reclaimed at next mount. We therefore set their 942 * nextfree field to the magic value LFS_ORPHAN_NEXTFREE so we can 943 * identify them. 944 * 945 * 946 * The caller holds a reference to vp, and the buffer cache provides 947 * exclusive access to the "nextfree" entry. 948 */ 949 void 950 lfs_orphan(struct lfs *fs, struct vnode *vp) 951 { 952 IFILE *ifp; 953 struct buf *bp; 954 struct inode *ip; 955 ino_t nextfree; 956 int mincount; 957 958 ip = VTOI(vp); 959 960 KASSERT(ip->i_nlink == 0); 961 962 /* 963 * Check reference count. 964 * 965 * Even if the file is not still referenced, it holds a 966 * reference associated with VU_DIROP. This creates an 967 * opportunity for fhopen() to re-open the file, which is 968 * illegal. Therefore we count the number of references that 969 * would come from VDIROP and IN_CLEANING, and compare that 970 * against the vnode ref count. If the usecount can be 971 * accounted for by VDIROP and IN_CLEANING, mark the node 972 * IN_DEAD. 973 */ 974 mincount = 1; /* The caller holds one */ 975 mutex_enter(&lfs_lock); 976 if (ip->i_state & IN_CLEANING) 977 ++mincount; 978 if (vp->v_uflag & VU_DIROP) 979 ++mincount; 980 mutex_exit(&lfs_lock); 981 mutex_enter(vp->v_interlock); 982 if (vp->v_usecount <= mincount) 983 ip->i_state |= IN_DEAD; 984 mutex_exit(vp->v_interlock); 985 986 /* If not already done, mark this inode orphaned. */ 987 LFS_IENTRY(ifp, fs, ip->i_number, bp); 988 nextfree = lfs_if_getnextfree(fs, ifp); 989 if (nextfree == LFS_ORPHAN_NEXTFREE(fs)) { 990 brelse(bp, 0); 991 return; 992 } 993 KASSERT(nextfree == LFS_UNUSED_INUM); 994 lfs_if_setnextfree(fs, ifp, LFS_ORPHAN_NEXTFREE(fs)); 995 LFS_BWRITE_LOG(bp); 996 } 997 998 /* 999 * Free orphans discovered during mount. 1000 * XXX merge this with lfs_order_freelist. 1001 */ 1002 void 1003 lfs_free_orphans(struct lfs *fs, ino_t *orphan, size_t norphan) 1004 { 1005 size_t i; 1006 1007 DEBUG_CHECK_FREELIST(fs); 1008 1009 for (i = 0; i < norphan; i++) { 1010 ino_t ino = orphan[i]; 1011 unsigned segno; 1012 struct vnode *vp; 1013 struct inode *ip; 1014 struct buf *bp; 1015 IFILE *ifp; 1016 SEGUSE *sup; 1017 int error; 1018 1019 /* Get the segment the inode is in on disk. */ 1020 LFS_IENTRY(ifp, fs, ino, bp); 1021 KASSERT(!DADDR_IS_BAD(lfs_if_getdaddr(fs, ifp))); 1022 segno = lfs_dtosn(fs, lfs_if_getdaddr(fs, ifp)); 1023 brelse(bp, 0); 1024 1025 /* 1026 * Try to get the vnode. If we can't, tough -- hope 1027 * you have backups! 1028 */ 1029 error = VFS_VGET(fs->lfs_ivnode->v_mount, ino, LK_EXCLUSIVE, 1030 &vp); 1031 if (error) { 1032 printf("orphan %jd vget error %d\n", (intmax_t)ino, 1033 error); 1034 continue; 1035 } 1036 1037 /* 1038 * Sanity-check the inode. 1039 * 1040 * XXX What to do if it is still referenced? 1041 */ 1042 ip = VTOI(vp); 1043 if (ip->i_nlink != 0) 1044 printf("orphan %jd nlink %d\n", (intmax_t)ino, 1045 ip->i_nlink); 1046 1047 /* 1048 * Truncate the inode, to free any blocks allocated for 1049 * it, and release it, to free the inode number. 1050 * 1051 * XXX Isn't it redundant to truncate? Won't vput do 1052 * that for us? 1053 */ 1054 error = lfs_truncate(vp, 0, 0, NOCRED); 1055 if (error) 1056 printf("orphan %jd truncate error %d", (intmax_t)ino, 1057 error); 1058 vput(vp); 1059 1060 /* Update the number of bytes in the segment summary. */ 1061 LFS_SEGENTRY(sup, fs, segno, bp); 1062 KASSERT(sup->su_nbytes >= DINOSIZE(fs)); 1063 sup->su_nbytes -= DINOSIZE(fs); 1064 LFS_WRITESEGENTRY(sup, fs, segno, bp); 1065 1066 /* Drop the on-disk address. */ 1067 LFS_IENTRY(ifp, fs, ino, bp); 1068 lfs_if_setdaddr(fs, ifp, LFS_UNUSED_DADDR); 1069 LFS_BWRITE_LOG(bp); 1070 } 1071 1072 if (orphan) 1073 kmem_free(orphan, sizeof(orphan[0]) * norphan); 1074 1075 DEBUG_CHECK_FREELIST(fs); 1076 } 1077 1078 #ifdef DEBUG 1079 static void dump_freelist(struct lfs *); 1080 1081 void 1082 lfs_check_freelist(struct lfs *fs, const char *func, int line) 1083 { 1084 ino_t i, headino, maxino, thisino, tailino, nextfree; 1085 int nfree, count; 1086 struct inode *ip; 1087 IFILE *ifp; 1088 CLEANERINFO *cip; 1089 struct buf *bp; 1090 1091 if (!lfs_do_check_freelist) 1092 return; 1093 1094 lfs_seglock(fs, SEGM_PROT); 1095 1096 ip = VTOI(fs->lfs_ivnode); 1097 maxino = ((ip->i_size >> lfs_sb_getbshift(fs)) - lfs_sb_getcleansz(fs) - 1098 lfs_sb_getsegtabsz(fs)) * lfs_sb_getifpb(fs); 1099 1100 /* 1101 * First, check every node. Every inode that doesn't have a disk 1102 * address must have a nextfree pointer, the only exception 1103 * being the tail of the free list. 1104 */ 1105 LFS_GET_TAILFREE(fs, cip, bp, &tailino); 1106 nfree = 0; 1107 for (i = LFS_IFILE_INUM + 1; i < maxino; ++i) { 1108 LFS_IENTRY(ifp, fs, i, bp); 1109 if (lfs_if_getdaddr(fs, ifp) == LFS_UNUSED_DADDR) { 1110 ++nfree; 1111 if (lfs_if_getnextfree(fs, ifp) == LFS_UNUSED_INUM 1112 && i != tailino) { 1113 brelse(bp, 0); 1114 dump_freelist(fs); 1115 printf("At %s:%d:\n", func, line); 1116 printf("tailino=%jd, but ino=%jd" 1117 " neither daddr nor nextfree\n", 1118 (intmax_t)tailino, (intmax_t)i); 1119 panic("Free list leak\n"); 1120 } 1121 } 1122 if (i == tailino 1123 || (!INUM_IS_BAD(fs, lfs_if_getnextfree(fs, ifp)))) { 1124 if (lfs_if_getdaddr(fs, ifp) != LFS_UNUSED_DADDR) { 1125 brelse(bp, 0); 1126 dump_freelist(fs); 1127 printf("At %s:%d:\n", func, line); 1128 printf("with tailino=%jd, ino=%jd" 1129 " daddr=0x%jx, nextfree=0x%jx\n", 1130 (intmax_t)tailino, 1131 (intmax_t)i, 1132 (intmax_t)lfs_if_getdaddr(fs, ifp), 1133 (intmax_t)lfs_if_getnextfree(fs, ifp)); 1134 panic("In use inode on free list\n"); 1135 } 1136 } 1137 brelse(bp, 0); 1138 } 1139 1140 /* 1141 * Walk the free list from head to tail. We should end up with 1142 * the same number of free inodes as we counted above. 1143 */ 1144 1145 /* Get head of inode freelist */ 1146 LFS_GET_HEADFREE(fs, cip, bp, &headino); 1147 count = 0; 1148 thisino = headino; 1149 while (thisino != LFS_UNUSED_INUM) { 1150 if (++count > maxino) 1151 break; 1152 /* read this ifile entry */ 1153 LFS_IENTRY(ifp, fs, thisino, bp); 1154 nextfree = lfs_if_getnextfree(fs, ifp); 1155 brelse(bp, 0); 1156 if (nextfree == LFS_UNUSED_INUM) 1157 break; 1158 thisino = nextfree; 1159 } 1160 if (count > maxino) { 1161 dump_freelist(fs); 1162 printf("At %s:%d:\n", func, line); 1163 printf("count=%jd, maxino=%jd:\n", 1164 (intmax_t)count, (intmax_t)maxino); 1165 panic("loop in free list"); 1166 } 1167 if (count != nfree) { 1168 dump_freelist(fs); 1169 printf("At %s:%d:\n", func, line); 1170 printf("%d inodes without addresses, %d on free list\n", 1171 nfree, count); 1172 panic("Bad free list count"); 1173 } 1174 if (thisino != tailino) { 1175 dump_freelist(fs); 1176 printf("At %s:%d:\n", func, line); 1177 printf("Last ino %jd but tail %jd\n", 1178 (intmax_t)thisino, (intmax_t)tailino); 1179 panic("Bad tail"); 1180 } 1181 lfs_segunlock(fs); 1182 } 1183 1184 static void 1185 dump_freelist(struct lfs *fs) 1186 { 1187 ino_t i, ni, maxino, headino, tailino; 1188 struct inode *ip; 1189 IFILE *ifp; 1190 CLEANERINFO *cip; 1191 struct buf *bp; 1192 int count; 1193 1194 ip = VTOI(fs->lfs_ivnode); 1195 maxino = ((ip->i_size >> lfs_sb_getbshift(fs)) - lfs_sb_getcleansz(fs) - 1196 lfs_sb_getsegtabsz(fs)) * lfs_sb_getifpb(fs); 1197 1198 LFS_GET_HEADFREE(fs, cip, bp, &headino); 1199 printf(" head: %jd\n", (intmax_t)headino); 1200 LFS_GET_TAILFREE(fs, cip, bp, &tailino); 1201 printf(" tail: %jd\n", (intmax_t)tailino); 1202 count = 0; 1203 for (i = LFS_IFILE_INUM + 1; i < maxino; ++i) { 1204 LFS_IENTRY(ifp, fs, i, bp); 1205 ni = lfs_if_getnextfree(fs, ifp); 1206 if (ni != LFS_UNUSED_DADDR) { 1207 printf("%jd -> %jd\n", 1208 (intmax_t)i, (intmax_t)ni); 1209 if (++count > 30) { 1210 printf("...\n"); 1211 i = maxino; /* terminate loop */ 1212 } 1213 } 1214 brelse(bp, 0); 1215 } 1216 } 1217 #endif /* DEBUG */ 1218