case TypeOrphanList:
{
struct orphan_md *m = &li->md.orphan;
- m->nextfree = 0; /* FIXME should I could size of file
- * or something? */
+ /* This will be set via lafs_count_orphans */
+ m->nextfree = 0;
m->reserved = 0;
break;
}
* Either the orphan file is wrong, or the
* linkcount is wrong.
* It is safest to assume the later - either
- * was an FS check would be needed to fix it.
+ * way an FS check would be needed to fix it.
*/
/* FIXME set a superblock flag requesting
* directory linkage checking
void lafs_add_orphan(struct fs *fs, struct datablock *db);
void lafs_orphan_forget(struct fs *fs, struct datablock *db);
struct datablock *lafs_find_orphan(struct inode *ino);
+int lafs_count_orphans(struct inode *ino);
+void lafs_add_orphans(struct fs *fs, struct inode *ino, int count);
/* Segment.c */
int lafs_prealloc(struct block *b, int type);
spin_unlock(&fs->lock);
return NULL;
}
+
+int lafs_count_orphans(struct inode *ino)
+{
+ /* Count how many active orphan slots there are
+ * in this file (which is the orphan file).
+ * We simply iterate all the slots until we
+ * find an empty one
+ */
+ int bnum = -1;
+ int slots = 1 << (ino->i_blkbits - 4);
+ int slot;
+
+ do {
+ struct datablock *db;
+ struct orphan *or;
+
+ bnum++;
+ slot = 0;
+
+ db = lafs_get_block(ino, bnum, NULL, GFP_KERNEL, MKREF(count_orphans));
+ if (!db)
+ break;
+ if (lafs_read_block(db) < 0) {
+ putdref(db, MKREF(count_orphans));
+ break;
+ }
+
+ or = map_dblock(db);
+ for (slot = 0; slot < slots ; slot++)
+ if (or[slot].type == 0)
+ break;
+
+ unmap_dblock(db, or);
+ putdref(db, MKREF(count_orphans));
+ } while (slot == slots);
+
+ return bnum * slots + slot;
+}
+
+void lafs_add_orphans(struct fs *fs, struct inode *ino, int count)
+{
+ int slots = 1 << (ino->i_blkbits - 4);
+ int last_block = (count + slots - 1) >> (ino->i_blkbits - 4);
+ int bnum;
+
+ for (bnum = 0; bnum < last_block; bnum++) {
+ struct datablock *db = lafs_get_block(ino, bnum, NULL, GFP_KERNEL, MKREF(add_orphans));
+ int bslot = bnum * slots;
+ struct orphan *or;
+ int slot;
+
+ if (!db)
+ continue;
+
+ if (lafs_read_block(db) < 0) {
+ putdref(db, MKREF(add_orphans));
+ continue;
+ }
+
+ or = map_dblock(db);
+ for (slot = 0; slot < slots && bslot + slot < count; slot++) {
+ struct inode *oino;
+ struct datablock *ob;
+
+ if (or[slot].type == 0)
+ continue;
+
+ oino = lafs_iget_fs(fs,
+ le32_to_cpu(or[slot].filesys),
+ le32_to_cpu(or[slot].inum),
+ SYNC);
+ if (IS_ERR(oino))
+ continue;
+
+ ob = lafs_get_block(oino, le32_to_cpu(or[slot].addr), NULL,
+ GFP_KERNEL, MKREF(add_orphan));
+
+ if (!IS_ERR(ob)) {
+ if (!test_and_set_bit(B_Orphan, &ob->b.flags)) {
+ getdref(ob, MKREF(orphan_flag));
+ ob->orphan_slot = bslot + slot;
+ lafs_add_orphan(fs, ob);
+ }
+ putdref(ob, MKREF(add_orphan));
+ }
+ iput(oino);
+ }
+ unmap_dblock(db, or);
+ }
+}
+
+
+
memcpy(buf+offset, data, len);
unmap_dblock(db, buf);
err = lafs_import_inode(inode, db);
- /* WE borrow the orphan list to keep a reference on
+ /* We borrow the orphan list to keep a reference on
* this inode until all processing is finished
* to make sure inodes that are about to get linked
* to get deleted early
lafs_add_active(fs, next);
- /* Now we release all the nlink==0 inode that we found */
+ /* Now we release all the nlink==0 inodes that we found */
while (!list_empty(&fs->pending_orphans)) {
struct datablock *db = list_entry(fs->pending_orphans.next,
struct datablock,
int err;
int d;
struct sb_key *k = fs->prime_sb->s_fs_info;
+ int orphan_count;
fs->rolled = 0;
fs->ss[0].root = root = iget_locked(fs->prime_sb, 0);
SYNC);
/* FIXME check this is a segusage file */
}
+ orphan_count = lafs_count_orphans(fs->orphans);
+ LAFSI(fs->orphans)->md.orphan.nextfree = orphan_count;
+
lafs_checkpoint_lock(fs);
err = roll_forward(fs);
lafs_checkpoint_unlock(fs);
+
+ lafs_add_orphans(fs, fs->orphans, orphan_count);
+
for (d = 0; d < 4; d++) {
fs->cleaner.seg[d].chead = alloc_page(GFP_KERNEL);
INIT_LIST_HEAD(&fs->cleaner.seg[d].cleaning);