1 /*
   2     ext2_inode_relocator.c -- ext2 inode relocator
   3     Copyright (C) 1998-2000, 2007 Free Software Foundation, Inc.
   4 
   5     This program is free software; you can redistribute it and/or modify
   6     it under the terms of the GNU General Public License as published by
   7     the Free Software Foundation; either version 3 of the License, or
   8     (at your option) any later version.
   9 
  10     This program is distributed in the hope that it will be useful,
  11     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13     GNU General Public License for more details.
  14 
  15     You should have received a copy of the GNU General Public License
  16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17 */
  18 
  19 #include <config.h>
  20 
  21 #ifndef DISCOVER_ONLY
  22 
  23 #include <stdio.h>
  24 #include <stdlib.h>
  25 #include <sys/stat.h>     /* for S_ISDIR */
  26 #include "ext2.h"
  27 
  28 
  29 
  30 
  31 
  32 
  33 struct ext2_reference
  34 {
  35         blk_t                    block;
  36         off_t                    offset;
  37 };
  38 
  39 struct ext2_inode_entry
  40 {
  41         ino_t                    num;
  42         ino_t                    dest;
  43         unsigned                 numreferences:16;
  44         unsigned                 isdir:1;
  45         struct ext2_reference   *ref;
  46 };
  47 
  48 struct ext2_inode_relocator_state
  49 {
  50         int                      usedentries;
  51         int                      resolvedentries;
  52         struct ext2_inode_entry *inode;
  53         struct ext2_reference   *last;
  54 };
  55 
  56 
  57 
  58 
  59 
  60 static struct ext2_inode_entry *findit(struct ext2_inode_relocator_state *state, ino_t inode)
  61 {
  62         int                      min;
  63         int                      max;
  64         struct ext2_inode_entry *retv;
  65         int                      t;
  66         blk_t                    tval;
  67 
  68         max = state->usedentries - 1;
  69         min = 0;
  70         retv = NULL;
  71 
  72  repeat:
  73         if (min > max)
  74                 goto out;
  75 
  76         t = (min + max) >> 1;
  77         tval = state->inode[t].num;
  78 
  79         t--;
  80         if (tval > inode)
  81                 max = t;
  82 
  83         t += 2;
  84         if (tval < inode)
  85                 min = t;
  86 
  87         t--;
  88 
  89         if (tval != inode)
  90                 goto repeat;
  91 
  92         retv = &state->inode[t];
  93 
  94  out:
  95         return retv;
  96 }
  97 
  98 static int addref(struct ext2_fs *fs, struct ext2_inode_relocator_state *state, ino_t inode, blk_t block, off_t offset)
  99 {
 100         struct ext2_inode_entry *ent;
 101         int i;
 102 
 103         if ((ent = findit(state, inode)) == NULL)
 104                 return 1;
 105 
 106         for (i=0;i<ent->numreferences;i++)
 107                 if (!ent->ref[i].block)
 108                         break;
 109 
 110         if (i == ent->numreferences)
 111         {
 112                 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
 113                         _("Found an inode with a incorrect link count.  "
 114                           "Better go run e2fsck first!"));
 115                 return 0;
 116         }
 117 
 118         if (i == ent->numreferences - 1)
 119                 state->resolvedentries++;
 120 
 121         ent->ref[i].block = block;
 122         ent->ref[i].offset = offset;
 123 
 124         return 1;
 125 }
 126 
 127 static int doblock(struct ext2_fs *fs, struct ext2_inode_relocator_state *state, blk_t blockno)
 128 {
 129         struct ext2_buffer_head *bh;
 130         off_t                    offset;
 131 
 132         bh = ext2_bread(fs, blockno);
 133         if (!bh)
 134                 return 0;
 135 
 136         offset = 0;
 137         do
 138         {
 139                 struct ext2_dir_entry_2 *ptr;
 140 
 141                 ptr = (struct ext2_dir_entry_2 *)(bh->data + offset);
 142 
 143                 if (ptr->name_len)
 144                         if (!addref(fs, state, EXT2_DIRENT_INODE(*ptr), blockno,
 145                                     offset))
 146                                 return 0;
 147 
 148                 PED_ASSERT (ptr->rec_len > 0, return 0);
 149                 offset += EXT2_DIRENT_REC_LEN (*ptr);
 150         } while (offset < fs->blocksize);
 151 
 152         ext2_brelse(bh, 0);
 153         return 1;
 154 }
 155 
 156 static int doindblock(struct ext2_fs *fs, struct ext2_inode_relocator_state *state, blk_t blockno)
 157 {
 158         struct ext2_buffer_head *bh;
 159         blk_t                    blk;
 160         int                      i;
 161 
 162         bh = ext2_bread(fs, blockno);
 163 
 164         for (i=0;i<(fs->blocksize>>2);i++)
 165                 if ((blk = PED_LE32_TO_CPU(((uint32_t *)bh->data)[i])) != 0)
 166                         if (!doblock(fs, state, blk))
 167                                 return 0;
 168 
 169         ext2_brelse(bh, 0);
 170         return 1;
 171 }
 172 
 173 static int dodindblock(struct ext2_fs *fs, struct ext2_inode_relocator_state *state, blk_t blockno)
 174 {
 175         struct ext2_buffer_head *bh;
 176         blk_t                    blk;
 177         int                      i;
 178 
 179         bh = ext2_bread(fs, blockno);
 180         if (!bh)
 181                 return 0;
 182 
 183         for (i=0;i<(fs->blocksize>>2);i++)
 184                 if ((blk = PED_LE32_TO_CPU(((uint32_t *)bh->data)[i])) != 0)
 185                         if (!doindblock(fs, state, blk))
 186                                 return 0;
 187 
 188         ext2_brelse(bh, 0);
 189         return 1;
 190 }
 191 
 192 static int dotindblock(struct ext2_fs *fs, struct ext2_inode_relocator_state *state, blk_t blockno)
 193 {
 194         struct ext2_buffer_head *bh;
 195         blk_t                    blk;
 196         int                      i;
 197 
 198         bh = ext2_bread(fs, blockno);
 199         if (!bh)
 200                 return 0;
 201 
 202         for (i=0;i<(fs->blocksize>>2);i++)
 203                 if ((blk = PED_LE32_TO_CPU(((uint32_t *)bh->data)[i])) != 0)
 204                         if (!dodindblock(fs, state, blk))
 205                                 return 0;
 206 
 207         ext2_brelse(bh, 0);
 208         return 1;
 209 }
 210 
 211 static int doinode(struct ext2_fs *fs, struct ext2_inode_relocator_state *state, ino_t inode)
 212 {
 213         struct ext2_inode buf;
 214         int               i;
 215 
 216         if (!ext2_read_inode(fs, inode, &buf))
 217                 return 0;
 218         if (S_ISDIR(EXT2_INODE_MODE(buf)))
 219         {
 220                 blk_t blk;
 221 
 222                 for (i=0;i<EXT2_NDIR_BLOCKS;i++)
 223                         if ((blk = EXT2_INODE_BLOCK(buf, i)) != 0)
 224                                 if (!doblock(fs, state, blk))
 225                                         return 0;
 226 
 227                 if ((blk = EXT2_INODE_BLOCK(buf, EXT2_IND_BLOCK)) != 0)
 228                         if (!doindblock(fs, state, blk))
 229                                 return 0;
 230 
 231                 if ((blk = EXT2_INODE_BLOCK(buf, EXT2_DIND_BLOCK)) != 0)
 232                         if (!dodindblock(fs, state, blk))
 233                                 return 0;
 234 
 235                 if ((blk = EXT2_INODE_BLOCK(buf, EXT2_TIND_BLOCK)) != 0)
 236                         if (!dotindblock(fs, state, blk))
 237                                 return 0;
 238         }
 239 
 240         return 1;
 241 }
 242 
 243 static int doscangroup(struct ext2_fs *fs, struct ext2_inode_relocator_state *state, int group)
 244 {
 245         struct ext2_buffer_head *bh;
 246         unsigned int             i;
 247         int                      offset;
 248 
 249         if (fs->opt_verbose)
 250                 fprintf(stderr, " scanning group %i.... ", group);
 251 
 252         bh = ext2_bread(fs, EXT2_GROUP_INODE_BITMAP(fs->gd[group]));
 253         offset = group * EXT2_SUPER_INODES_PER_GROUP(fs->sb) + 1;
 254 
 255         for (i=0;i<EXT2_SUPER_INODES_PER_GROUP(fs->sb);i++)
 256                 if (bh->data[i>>3] & _bitmap[i&7])
 257                 {
 258                         if (!doinode(fs, state, offset + i))
 259                         {
 260                                 ext2_brelse(bh, 0);
 261                                 return 0;
 262                         }
 263 
 264                         if (state->resolvedentries == state->usedentries)
 265                                 break;
 266                 }
 267 
 268         ext2_brelse(bh, 0);
 269 
 270         if (fs->opt_verbose)
 271                 fprintf(stderr,
 272                         "%i/%i inodes resolved\r",
 273                         state->resolvedentries,
 274                         state->usedentries);
 275 
 276         return 1;
 277 }
 278 
 279 /* basically: this builds a dependency graph of the inodes in the entire file
 280  * system.  inodes are only referenced by the directory tree (or the magic
 281  * ones implicitly, like the bad blocks inode), so we just walk the directory
 282  * tree adding references.
 283  */
 284 static int doscan(struct ext2_fs *fs, struct ext2_inode_relocator_state *state)
 285 {
 286         int i;
 287 
 288         /* while the journal will usually be inode 8 (and therefore will never
 289          * need to be moved), we don't have any guarantee (grrr).  So, we
 290          * need to be prepared to move it... (and update the reference in the
 291          * super block)
 292          */
 293         if (fs->has_internal_journal)
 294                 addref(fs, state, EXT2_SUPER_JOURNAL_INUM(fs->sb),
 295                        1, offsetof(struct ext2_super_block, s_journal_inum));
 296 
 297         if (!doscangroup(fs, state, 0))
 298                 return 0;
 299 
 300         if (state->resolvedentries != state->usedentries)
 301                 for (i=fs->numgroups-1;i>0;i--)
 302                 {
 303                         if (!doscangroup(fs, state, i))
 304                                 return 0;
 305 
 306                         if (state->resolvedentries == state->usedentries)
 307                                 break;
 308                 }
 309 
 310         if (fs->opt_verbose)
 311                 fputc ('\n', stderr);
 312 
 313         return 1;
 314 }
 315 
 316 
 317 
 318 
 319 
 320 
 321 
 322 static int ext2_inode_relocator_copy(struct ext2_fs *fs, struct ext2_inode_relocator_state *state)
 323 {
 324         int i;
 325 
 326         for (i=0;i<state->usedentries;i++)
 327         {
 328                 struct ext2_inode buf;
 329                 struct ext2_inode_entry *entry;
 330 
 331                 entry = &state->inode[i];
 332 
 333                 if (fs->opt_debug)
 334                         if (!ext2_get_inode_state(fs, entry->num) ||
 335                             ext2_get_inode_state(fs, entry->dest))
 336                                 fputs ("inodebitmaperror\n", stderr);
 337 
 338                 if (!ext2_read_inode(fs, entry->num, &buf))
 339                         return 0;
 340                 if (!ext2_write_inode(fs, entry->dest, &buf))
 341                         return 0;
 342 
 343                 entry->isdir = S_ISDIR(EXT2_INODE_MODE(buf))?1:0;
 344         }
 345 
 346         if (fs->opt_safe)
 347                 if (!ext2_sync(fs))
 348                         return 0;
 349         return 1;
 350 }
 351 
 352 static int ext2_inode_relocator_finish(struct ext2_fs *fs, struct ext2_inode_relocator_state *state)
 353 {
 354         int i;
 355 
 356         for (i=0;i<state->usedentries;i++)
 357         {
 358                 struct ext2_inode_entry *entry;
 359 
 360                 entry = &state->inode[i];
 361                 ext2_set_inode_state(fs, entry->dest, 1, 1);
 362                 ext2_set_inode_state(fs, entry->num, 0, 1);
 363                 ext2_zero_inode(fs, entry->num);
 364         }
 365 
 366         if (fs->opt_safe)
 367                 if (!ext2_sync(fs))
 368                         return 0;
 369         return 1;
 370 }
 371 
 372 static int ext2_inode_relocator_ref(struct ext2_fs *fs, struct ext2_inode_relocator_state *state)
 373 {
 374         int             i;
 375         static int      numerrors = 0;
 376 
 377         for (i=0;i<state->usedentries;i++)
 378         {
 379                 struct ext2_inode_entry *entry;
 380                 int                      j;
 381                 uint32_t                 t;
 382 
 383                 entry = &state->inode[i];
 384                 t = entry->dest;
 385 
 386                 for (j=0;j<entry->numreferences;j++)
 387                 {
 388                         struct ext2_buffer_head *bh;
 389 
 390                         bh = ext2_bread(fs, entry->ref[j].block);
 391                         if (!bh)
 392                                 return 0;
 393 
 394                         if (fs->opt_debug)
 395                         {
 396                                 if (PED_LE32_TO_CPU((*((uint32_t *)(bh->data + entry->ref[j].offset)))) != entry->num)
 397                                 {
 398                                         fprintf(stderr,
 399                                                 "inode %li ref error! (->%li, [%i]={%i, %i})\n",
 400                                                 (long) entry->num,
 401                                                 (long) entry->dest,
 402                                                 j,
 403                                                 entry->ref[j].block,
 404                                                 (int) entry->ref[j].offset);
 405                                         ext2_brelse(bh, 0);
 406 
 407                                         if (numerrors++ < 4)
 408                                                 continue;
 409 
 410                                         fputs ("all is not well!\n", stderr);
 411                                         return 0;
 412                                 }
 413                         }
 414 
 415                         *((uint32_t *)(bh->data + entry->ref[j].offset))
 416                                 = PED_CPU_TO_LE32(t);
 417                         bh->dirty = 1;
 418 
 419                         ext2_brelse(bh, 0);
 420                 }
 421 
 422                 if (entry->isdir)
 423                 {
 424                         int oldgroup;
 425                         int newgroup;
 426 
 427                         oldgroup = (entry->num  - 1)
 428                                         / EXT2_SUPER_INODES_PER_GROUP(fs->sb);
 429                         newgroup = (entry->dest - 1)
 430                                         / EXT2_SUPER_INODES_PER_GROUP(fs->sb);
 431 
 432                         fs->gd[oldgroup].bg_used_dirs_count = PED_CPU_TO_LE16 (
 433                                 EXT2_GROUP_USED_DIRS_COUNT(fs->gd[oldgroup])
 434                                 - 1);
 435                         fs->gd[newgroup].bg_used_dirs_count = PED_CPU_TO_LE16 (
 436                                 EXT2_GROUP_USED_DIRS_COUNT(fs->gd[newgroup])
 437                                 + 1);
 438 
 439                         fs->metadirty = EXT2_META_GD;
 440                 }
 441         }
 442 
 443         if (fs->opt_safe)
 444                 if (!ext2_sync(fs))
 445                         return 0;
 446 
 447         return 1;
 448 }
 449 
 450 static int ext2_inode_relocator_grab_inodes(struct ext2_fs *fs, struct ext2_inode_relocator_state *state)
 451 {
 452         int i;
 453         int ptr;
 454 
 455         ptr = 0;
 456 
 457         for (i=0;i<fs->numgroups;i++)
 458                 if (EXT2_GROUP_FREE_INODES_COUNT(fs->gd[i]))
 459                 {
 460                         struct ext2_buffer_head *bh;
 461                         unsigned int j;
 462                         int offset;
 463 
 464                         bh = ext2_bread(fs, EXT2_GROUP_INODE_BITMAP(fs->gd[i]));
 465                         if (!bh)
 466                                 return 0;
 467                         offset = i * EXT2_SUPER_INODES_PER_GROUP(fs->sb) + 1;
 468 
 469                         j = i ? 0 : 13;
 470                         for (;j<EXT2_SUPER_INODES_PER_GROUP(fs->sb);j++)
 471                                 if (!(bh->data[j>>3] & _bitmap[j&7]))
 472                                 {
 473                                         state->inode[ptr++].dest = offset + j;
 474 
 475                                         if (ptr == state->usedentries)
 476                                         {
 477                                                 ext2_brelse(bh, 0);
 478                                                 return 1;
 479                                         }
 480                                 }
 481 
 482                         ext2_brelse(bh, 0);
 483                 }
 484 
 485         ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
 486                              _("Not enough free inodes!"));
 487         return 0;
 488 }
 489 
 490 static int ext2_inode_relocator_flush(struct ext2_fs *fs, struct ext2_inode_relocator_state *state)
 491 {
 492         if (!state->usedentries)
 493                 return 1;
 494 
 495         if (!doscan(fs, state))
 496                 return 0;
 497 
 498         if (!ext2_inode_relocator_grab_inodes(fs, state))
 499                 return 0;
 500 
 501         if (!ext2_inode_relocator_copy(fs, state))
 502                 return 0;
 503 
 504         if (!ext2_inode_relocator_ref(fs, state))
 505                 return 0;
 506 
 507         if (!ext2_inode_relocator_finish(fs, state))
 508                 return 0;
 509 
 510         state->usedentries = 0;
 511         state->resolvedentries = 0;
 512         state->last = (struct ext2_reference *)fs->relocator_pool_end;
 513 
 514         if (fs->opt_safe)
 515                 if (!ext2_sync(fs))
 516                         return 0;
 517 
 518         return 1;
 519 }
 520 
 521 static int ext2_inode_relocator_mark(struct ext2_fs *fs, struct ext2_inode_relocator_state *state, ino_t inode)
 522 {
 523         struct ext2_inode        buf;
 524         struct ext2_inode_entry *ent;
 525         int                      i;
 526 
 527         if (!ext2_read_inode(fs, inode, &buf))
 528                 return 0;
 529 
 530         {
 531                 register void *adv;
 532                 register void *rec;
 533 
 534                 adv = state->inode + state->usedentries + 1;
 535                 rec = state->last - EXT2_INODE_LINKS_COUNT(buf);
 536 
 537                 if (adv >= rec)
 538                         ext2_inode_relocator_flush(fs, state);
 539         }
 540 
 541         state->last -= EXT2_INODE_LINKS_COUNT(buf);
 542 
 543         ent = &state->inode[state->usedentries];
 544         ent->num = inode;
 545         ent->dest = 0;
 546         ent->numreferences = EXT2_INODE_LINKS_COUNT(buf);
 547         ent->ref = state->last;
 548 
 549         for (i=0;i<ent->numreferences;i++)
 550         {
 551                 ent->ref[i].block = 0;
 552                 ent->ref[i].offset = 0;
 553         }
 554 
 555         state->usedentries++;
 556 
 557         return 1;
 558 }
 559 
 560 
 561 int ext2_inode_relocate(struct ext2_fs *fs, int newgroups)
 562 {
 563         int i;
 564         struct ext2_inode_relocator_state state;
 565 
 566         if (fs->opt_verbose)
 567                 fputs ("ext2_inode_relocate\n", stderr);
 568 
 569         state.usedentries = 0;
 570         state.resolvedentries = 0;
 571         state.inode = (struct ext2_inode_entry *)fs->relocator_pool;
 572         state.last = (struct ext2_reference *)fs->relocator_pool_end;
 573 
 574         for (i=newgroups;i<fs->numgroups;i++)
 575         {
 576                 struct ext2_buffer_head *bh;
 577                 unsigned int             j;
 578                 int                      offset;
 579 
 580                 bh = ext2_bread(fs, EXT2_GROUP_INODE_BITMAP(fs->gd[i]));
 581                 if (!bh)
 582                         return 0;
 583                 offset = i * EXT2_SUPER_INODES_PER_GROUP(fs->sb) + 1;
 584 
 585                 for (j=0;j<EXT2_SUPER_INODES_PER_GROUP(fs->sb);j++)
 586                         if (bh->data[j>>3] & _bitmap[j&7])
 587                                 ext2_inode_relocator_mark(fs, &state,
 588                                                           offset + j);
 589 
 590                 ext2_brelse(bh, 0);
 591         }
 592 
 593         if (!ext2_inode_relocator_flush(fs, &state))
 594                 return 0;
 595 
 596         return 1;
 597 }
 598 #endif /* !DISCOVER_ONLY */
 599