]> git.neil.brown.name Git - LaFS.git/commitdiff
Orphan: simplify orphan creation.
authorNeilBrown <neilb@suse.de>
Thu, 27 Aug 2009 01:45:56 +0000 (11:45 +1000)
committerNeilBrown <neilb@suse.de>
Thu, 27 Aug 2009 01:45:56 +0000 (11:45 +1000)
We don't need to synchronise orphan creation with other parts of
direct ops etc.  We just make the block into an orphan if we
think that might be needed.  If this gets committed in a previous
checkpoint, there is no problem.

This simplifies things a lot and lets us get rid of some races.

block.c
dir.c
inode.c
lafs.h
orphan.c
state.h

diff --git a/block.c b/block.c
index 8a57b1b2e66e21a67c341554a9a108441340d335..03ecd1b029f0ac59426ccf038bb8fbc8e97f88b2 100644 (file)
--- a/block.c
+++ b/block.c
@@ -130,8 +130,6 @@ lafs_get_block(struct inode *ino, unsigned long index, struct page *p,
                        b[i].b.chain = NULL;
 
                        b[i].my_inode = NULL;
-                       if (fs_from_inode(ino)->orphans == ino)
-                               atomic_set(&b[i].pincnt, 0);
 
                        /* FIXME what else needs to be initialised? */
                }
diff --git a/dir.c b/dir.c
index 60d6d9e99efb3b01219db1f6e032e8e6bd7e1fa9..b15852a5e7f7dfcc5b01da6c05317ee4210f1f39 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -170,25 +170,8 @@ struct dirop_handle {
        u32     hash;
        u8      index;
        int     chainoffset;
-       struct orphan_info oi;
 };
 
-static void dir_add_orphan(struct datablock *b)
-{
-       struct inode *dir = b->b.inode;
-       /* i_mutex protects dirorphans */
-       LAFS_BUG(!mutex_is_locked(&dir->i_mutex), &b->b);
-       if (list_empty(&b->orphans)) {
-               getdref(b, MKREF(dirorphan));
-               list_add(&b->orphans, &LAFSI(dir)->md.file.dirorphans);
-               if (list_empty(&LAFSI(dir)->orphans)) {
-                       struct fs *fs = fs_from_inode(dir);
-                       spin_lock(&fs->lock);
-//                     list_add(&LAFSI(dir)->orphans, &fs->pending_orphans);
-                       spin_unlock(&fs->lock);
-               }
-       }
-}
 /*............................................................................
  * Creating an entry in a directory.
  * This is split into pre_create and commit_create
@@ -398,7 +381,7 @@ dir_delete_prepare(struct fs *fs, struct inode *dir,
        /* FIXME should I check if the orphanage is needed
         * before committing this block to it?
         */
-       err = lafs_orphan_prepare(fs, &doh->oi);
+       err = lafs_make_orphan(fs, doh->dirent_block);
        return err;
 }
 
@@ -427,10 +410,9 @@ dir_delete_commit(struct dirop_handle *doh,
         *    If we end up leaving that first entry, make me an orphan so
         *    the we can check if the chain continues in a previous block.
         */
-       if (((doh->hash+1) & 0x7fff) == doh->dirent_block->b.fileaddr) {
+       if (((doh->hash+1) & 0x7fff) == doh->dirent_block->b.fileaddr)
                unmap_dblock(doh->dirent_block, buf);
-               lafs_orphan_commit(&doh->oi);
-       } else if (lafs_dir_find(buf, bits, seed, doh->hash+1, &ignore) == 0) {
+       else if (lafs_dir_find(buf, bits, seed, doh->hash+1, &ignore) == 0) {
                /* This is the end of a chain, clean up */
                u8 firstpiece;
                u8 piece;
@@ -448,17 +430,9 @@ dir_delete_commit(struct dirop_handle *doh,
                                          NULL)->target == 0);
 
                unmap_dblock(doh->dirent_block, buf);
-
-               if (piece == firstpiece && de.target == 0)
-                       lafs_orphan_commit(&doh->oi);
-               else
-                       lafs_orphan_abort(&doh->oi);
-       } else {
+       } else
                unmap_dblock(doh->dirent_block, buf);
 
-               lafs_orphan_abort(&doh->oi);
-       }
-
        clear_bit(B_PinPending, &doh->dirent_block->b.flags);
        lafs_dirty_dblock(doh->dirent_block);
        putdref(doh->dirent_block, MKREF(dir_blk));
@@ -471,12 +445,6 @@ dir_delete_pin(struct dirop_handle *doh)
        err = lafs_pin_dblock(doh->dirent_block);
        if (err)
                return err;
-
-       err = lafs_orphan_pin(&doh->oi, doh->dirent_block, 1);
-       if (err)
-               return err;
-               
-       dir_add_orphan(doh->dirent_block);
        return 0;
 }
 
@@ -487,8 +455,6 @@ dir_delete_abort(struct dirop_handle *doh)
            !IS_ERR(doh->dirent_block)) {
                clear_bit(B_PinPending, &doh->dirent_block->b.flags);
                putdref(doh->dirent_block, MKREF(dir_blk));
-
-               lafs_orphan_abort(&doh->oi);
        }
 }
 
@@ -732,7 +698,6 @@ lafs_unlink(struct inode *dir, struct dentry *de)
        struct inode *inode = de->d_inode;
        int last = (inode->i_nlink == 1);
        struct dirop_handle doh;
-       struct orphan_info oi;
        struct update_handle uh;
        struct datablock *inodb;
        int err;
@@ -742,11 +707,11 @@ lafs_unlink(struct inode *dir, struct dentry *de)
        err = dir_delete_prepare(fs, dir, de->d_name.name, de->d_name.len,
                                 &doh);
        err = dir_log_prepare(&uh, fs, &de->d_name) ?: err;
-       if (last)
-               err = lafs_orphan_prepare(fs, &oi) ?: err;
        inodb = lafs_inode_dblock(inode, 0, MKREF(inode_update));
        if (IS_ERR(inodb))
                err = PTR_ERR(inodb);
+       if (last && !err)
+               err = lafs_make_orphan(fs, inodb);
        if (err)
                goto abort;
  retry:
@@ -755,8 +720,6 @@ lafs_unlink(struct inode *dir, struct dentry *de)
        err = dir_delete_pin(&doh);
        err = err ?: lafs_cluster_update_pin(&uh);
        err = err ?: lafs_pin_dblock(inodb);
-       if (err == 0 && last)
-               err = lafs_orphan_pin(&oi, inodb, 1);
        if (err == -EAGAIN) {
                lafs_checkpoint_unlock_wait(fs);
                goto retry; /* FIXME should I not unlock ?? */
@@ -768,8 +731,6 @@ lafs_unlink(struct inode *dir, struct dentry *de)
        dir_log_commit(&uh, fs, dir, &de->d_name, inode->i_ino,
                       DIROP_UNLINK, NULL);
        dir_delete_commit(&doh, fs, dir, de->d_name.name, de->d_name.len);
-       if (last)
-               lafs_orphan_commit(&oi);
        lafs_checkpoint_unlock(fs);
        lafs_dirty_inode(inode);
        lafs_inode_checkpin(inode);
@@ -781,8 +742,6 @@ lafs_unlink(struct inode *dir, struct dentry *de)
        clear_bit(B_PinPending, &inodb->b.flags);
        lafs_checkpoint_unlock(fs);
  abort:
-       if (last)
-               lafs_orphan_abort(&oi);
        if (!IS_ERR(inodb))
                putdref(inodb, MKREF(inode_update));
        lafs_cluster_update_abort(&uh);
@@ -796,7 +755,6 @@ lafs_rmdir(struct inode *dir, struct dentry *de)
        struct fs *fs = fs_from_inode(dir);
        struct inode *inode = de->d_inode;
        struct dirop_handle doh;
-       struct orphan_info oi;
        struct update_handle uh;
        struct datablock *inodb;
        int err;
@@ -810,10 +768,11 @@ lafs_rmdir(struct inode *dir, struct dentry *de)
        err = dir_delete_prepare(fs, dir, de->d_name.name, de->d_name.len,
                                 &doh);
        err = dir_log_prepare(&uh, fs, &de->d_name) ?: err;
-       err = lafs_orphan_prepare(fs, &oi) ?: err;
        inodb = lafs_inode_dblock(inode, 0, MKREF(inode_update));
        if (IS_ERR(inodb))
                err = PTR_ERR(inodb);
+       if (!err)
+               err = lafs_make_orphan(fs, inodb);
        if (err)
                goto abort;
  retry:
@@ -822,7 +781,6 @@ lafs_rmdir(struct inode *dir, struct dentry *de)
        err = dir_delete_pin(&doh);
        err = err ?: lafs_cluster_update_pin(&uh);
        err = err ?: lafs_pin_dblock(inodb);
-       err = err ?: lafs_orphan_pin(&oi, inodb, 1);
        if (err == -EAGAIN) {
                lafs_checkpoint_unlock_wait(fs);
                goto retry; /* FIXME should I not unlock ?? */
@@ -836,7 +794,6 @@ lafs_rmdir(struct inode *dir, struct dentry *de)
        dir_log_commit(&uh, fs, dir, &de->d_name, inode->i_ino,
                       DIROP_UNLINK, NULL);
        dir_delete_commit(&doh, fs, dir, de->d_name.name, de->d_name.len);
-       lafs_orphan_commit(&oi);
        lafs_dirty_inode(inode);
        clear_bit(B_PinPending, &inodb->b.flags);
        putdref(inodb, MKREF(inode_update));
@@ -850,7 +807,6 @@ lafs_rmdir(struct inode *dir, struct dentry *de)
        lafs_checkpoint_unlock(fs);
        clear_bit(B_PinPending, &inodb->b.flags);
  abort:
-       lafs_orphan_abort(&oi);
        if (!IS_ERR(inodb))
                putdref(inodb, MKREF(inode_update));
        lafs_cluster_update_abort(&uh);
@@ -1105,7 +1061,6 @@ lafs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        struct dirop_handle old_doh, new_doh;
        struct update_handle old_uh, new_uh;
-       struct orphan_info oi;
        int last = (new_inode && new_inode->i_nlink == 1);
        u32 renhandle;
        int err;
@@ -1137,8 +1092,6 @@ lafs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        if (new_inode) {
                /* unlink object, update name */
-               if (last)
-                       err = lafs_orphan_prepare(fs, &oi) ?: err;
                err = dir_update_prepare(fs, new_dir,
                                         new_dentry->d_name.name,
                                         new_dentry->d_name.len,
@@ -1146,6 +1099,8 @@ lafs_rename(struct inode *old_dir, struct dentry *old_dentry,
                newdb = lafs_inode_dblock(new_inode, 0, MKREF(inode_update));
                if (IS_ERR(newdb))
                        err = PTR_ERR(newdb);
+               if (last && !err)
+                       err = lafs_make_orphan(fs, newdb);
        } else
                /* create new link */
                err = dir_create_prepare(fs, new_dir,
@@ -1167,9 +1122,6 @@ lafs_rename(struct inode *old_dir, struct dentry *old_dentry,
        err = err ?: lafs_pin_dblock(olddb);
        if (new_inode) {
                err = err ?: lafs_pin_dblock(newdb);
-               if (last)
-                       err = err ?:
-                               lafs_orphan_pin(&oi, newdb, 1);
                err = err ?: dir_update_pin(&new_doh);
        } else
                err = err ?: dir_create_pin(&new_doh);
@@ -1191,8 +1143,6 @@ lafs_rename(struct inode *old_dir, struct dentry *old_dentry,
                       new_inode ? DIROP_REN_OLD_TARGET : DIROP_REN_NEW_TARGET,
                       &renhandle);
        if (new_inode) {
-               if (last)
-                       lafs_orphan_commit(&oi);
                dir_update_commit(fs, old_inode->i_ino,
                                  mode_to_dt(old_inode->i_mode),
                                  &new_doh);
@@ -1243,8 +1193,6 @@ lafs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (!IS_ERR(olddb))
                putdref(olddb, MKREF(inode_update));
        if (new_inode) {
-               if (last)
-                       lafs_orphan_abort(&oi);
                dir_update_abort(&new_doh);
                if (!IS_ERR(newdb))
                        putdref(newdb, MKREF(inode_new));
@@ -1387,9 +1335,7 @@ static int dir_handle_orphan(struct inode *dir, struct datablock *b)
                if (lafs_dir_find(buf2, bits, seed, (hash-1) & MaxDirHash,
                                  &piece) &&
                    lafs_dir_extract(buf2, bits, &de, piece, NULL)->target == 0)
-                       /* FIXME not recorded in orphan file...
-                        * I should move the orphan status from b to b2 */
-                       dir_add_orphan(b2);
+                       lafs_make_orphan(fs, b2);
                unmap_dblock(b2, buf2);
                putdref(b2, MKREF(dir_orphan));
                buf = map_dblock(b);
@@ -1440,10 +1386,6 @@ static int dir_handle_orphan(struct inode *dir, struct datablock *b)
        return err;
 }
 
-void lafs_dir_apply_orphan(struct datablock *b, int type)
-{
-       dir_add_orphan(b);
-}
 /*--------------------------------------------------------------------
  * Finally the read-only operations
  */
diff --git a/inode.c b/inode.c
index 4b815685553ae27e756c58b87bf9cffae0a2bc2c..6b3a0ba9fc8efb122fb3be1472d7fa12c46ef65f 100644 (file)
--- a/inode.c
+++ b/inode.c
@@ -1289,22 +1289,21 @@ lafs_new_inode(struct fs *fs, struct inode *dir, int type, int inum, int mode,
        struct inode *filesys = LAFSI(dir)->filesys;
        struct inode *ino;
        struct datablock *b;
-       struct orphan_info oi;
        struct inode_map_new_info imni;
        struct update_handle ui;
        int err;
 
        err = inode_map_new_prepare(fs, inum, filesys, &imni);
-       err = lafs_orphan_prepare(fs, &oi) ?: err;
        err = lafs_cluster_update_prepare(&ui, fs, sizeof(struct la_inode))
                ?: err;
+       if (err == 0)
+               err = lafs_make_orphan(fs, imni.ib);
        if (err)
                goto abort;
  retry:
        lafs_checkpoint_lock(fs);
 
        err = inode_map_new_pin(&imni);
-       err = err ?:  lafs_orphan_pin(&oi, imni.ib, 1);
        err = err ?:  lafs_pin_dblock(imni.ib);
 
        if (err == -EAGAIN) {
@@ -1323,7 +1322,6 @@ lafs_new_inode(struct fs *fs, struct inode *dir, int type, int inum, int mode,
        lafs_iounlock_block(&b->b);
 
        inode_map_new_commit(&imni);
-       lafs_orphan_commit(&oi);
        ino = lafs_iget(dir->i_sb, b->b.fileaddr, 0);
        if (IS_ERR(ino)) {
                lafs_cluster_update_abort(&ui);
@@ -1343,7 +1341,6 @@ lafs_new_inode(struct fs *fs, struct inode *dir, int type, int inum, int mode,
        lafs_checkpoint_unlock(fs);
        err = -ENOSPC;
  abort:
-       lafs_orphan_abort(&oi);
        inode_map_new_abort(&imni);
        lafs_cluster_update_abort(&ui);
        return ERR_PTR(err);
@@ -1433,7 +1430,6 @@ void lafs_truncate(struct inode *ino)
         * has been cleaned up.
         * So just start the background truncate
         */
-       struct orphan_info oi;
        struct fs *fs = fs_from_inode(ino);
        struct datablock *db = lafs_inode_dblock(ino, 0, MKREF(trunc));
 
@@ -1443,9 +1439,8 @@ void lafs_truncate(struct inode *ino)
        wait_event(fs->trunc_wait,
                   !test_bit(I_Trunc, &LAFSI(ino)->iflags));
 
-       lafs_orphan_prepare(fs, &oi);
-       lafs_orphan_pin(&oi, db, 1); /* FIXME need a retry loop here !! */
-       lafs_orphan_commit(&oi);
+       /* FIXME there is nothing I can do with an error here */
+       lafs_make_orphan(fs, db);
 
        set_bit(I_Trunc, &LAFSI(ino)->iflags);
        LAFSI(ino)->trunc_next = (i_size_read(ino) +
diff --git a/lafs.h b/lafs.h
index f32e381fe6398a3b4fdc64253088f2c36c9b30b9..efbf1681c8d5f5b3bb2aadfb859118ad41b38ae6 100644 (file)
--- a/lafs.h
+++ b/lafs.h
@@ -467,12 +467,6 @@ struct dir_ent {
        int type;
 };
 
-struct orphan_info {
-       int reserved;
-       struct fs *fs;
-       struct datablock *ob;
-};
-
 struct update_handle {
        struct fs *fs;
        int reserved;
@@ -585,12 +579,8 @@ unsigned long long lafs_checkpoint_start(struct fs *fs);
 unsigned long lafs_do_checkpoint(struct fs *fs);
 struct block *lafs_get_flushable(struct fs *fs, int phase);
 
-int lafs_orphan_prepare(struct fs *fs, struct orphan_info *oi);
-int lafs_orphan_pin(struct orphan_info *oi, struct datablock *b, int n);
-void lafs_orphan_commit(struct orphan_info *oi);
-void lafs_orphan_abort(struct orphan_info *oi);
+int lafs_make_orphan(struct fs *fs, struct datablock *db);
 void lafs_orphan_release(struct fs *fs, struct datablock *b);
-void lafs_orphan_drop(struct fs *fs, struct datablock *b);
 unsigned long lafs_run_orphans(struct fs *fs);
 
 /* Segment.c */
index f709538e487736fb69cf65f14d873ab1d0c9cf63..8e52ddeb5c050fe34b7e224f0ceedc2b87deb8dc 100644 (file)
--- a/orphan.c
+++ b/orphan.c
@@ -83,7 +83,15 @@ void lafs_dump_orphans(void)
 }
 #endif
 
-int lafs_orphan_prepare(struct fs *fs, struct orphan_info *oi)
+struct orphan_info {
+       struct fs *fs;
+       struct datablock *ob;
+};
+/* Before locking the checkpoint, we need to reserve space to
+ * store the orphan record, and make sure we hold a reference
+ * to the block.
+ */
+static int orphan_prepare(struct fs *fs, struct orphan_info *oi)
 {
        struct orphan_md *om = &LAFSI(fs->orphans)->md.orphan;
        u32 bnum;
@@ -103,22 +111,17 @@ int lafs_orphan_prepare(struct fs *fs, struct orphan_info *oi)
                           MKREF(orphan_reserve));
        if (b) {
                err = lafs_read_block(b);
-               if (err) {
+               if (err)
                        putdref(b, MKREF(orphan_reserve));
-                       oi->reserved = 0;
-               } else {
+               else
                        om->reserved++;
-                       oi->reserved = 1;
-               }
-       } else {
-               oi->reserved = 0;
+       } else
                err = -ENOMEM;
-       }
        mutex_unlock(&fs->orphans->i_mutex);
        return err;
 }
 
-int lafs_orphan_pin(struct orphan_info *oi, struct datablock *b, int n)
+static int orphan_pin(struct orphan_info *oi, struct datablock *b)
 {
        struct fs *fs = oi->fs;
        struct orphan_md *om = &LAFSI(fs->orphans)->md.orphan;
@@ -129,9 +132,6 @@ int lafs_orphan_pin(struct orphan_info *oi, struct datablock *b, int n)
        u32 bnum;
        struct datablock *ob;
 
-       if (test_bit(B_Orphan, &b->b.flags))
-               /* FIXME I need to make sure it stays an orphan... */
-               return 0;
        mutex_lock_nested(&fs->orphans->i_mutex, I_MUTEX_QUOTA);
        slot = om->nextfree;
        bnum = slot >> (fs->prime_sb->s_blocksize_bits-4);
@@ -142,104 +142,108 @@ int lafs_orphan_pin(struct orphan_info *oi, struct datablock *b, int n)
 
        lafs_phase_wait(&ob->b);
        oi->ob = ob;
-       atomic_inc(&ob->pincnt);
        err = lafs_pin_dblock(ob);
        if (err) {
-               atomic_dec(&ob->pincnt);
                mutex_unlock(&fs->orphans->i_mutex);
                putdref(ob, MKREF(orphan));
                oi->ob = NULL;
                return err;
        }
+       /* Committed to being an orphan now */
        b->orphan_slot = slot;
+       spin_lock(&fs->lock);
        set_bit(B_Orphan, &b->b.flags);
+       list_add_tail(&b->orphans, &fs->pending_orphans);
+       spin_unlock(&fs->lock);
        dprintk("%p->orphan_slot=%d (%lu,%lu,%lu) %s\n", b, b->orphan_slot,
                LAFSI(b->b.inode)->filesys->i_ino,
                b->b.inode->i_ino, b->b.fileaddr, strblk(&b->b));
 
-       oi->reserved = 0;
        om->nextfree++;
        om->reserved--;
        putdref(ob, MKREF(orphan_reserve));
 
        or = map_dblock(ob);
        ent = slot - (bnum << (fs->prime_sb->s_blocksize_bits-4));
-       or[ent].type = cpu_to_le32(n);
+       or[ent].type = cpu_to_le32(1);
        or[ent].filesys = cpu_to_le32(LAFSI(b->b.inode)->filesys->i_ino);
        or[ent].inum = cpu_to_le32(b->b.inode->i_ino);
        or[ent].addr = cpu_to_le32(b->b.fileaddr);
        unmap_dblock(ob, or);
+       lafs_dirty_dblock(oi->ob);
+       clear_bit(B_PinPending, &ob->b.flags);
        mutex_unlock(&fs->orphans->i_mutex);
        return 0;
 }
 
-void lafs_orphan_commit(struct orphan_info *oi)
+/* We failed to allocate space to write the update to the orphan
+ * block so we need to revert the reservation done in orphan_pin.
+ * Note that we don't 'unmark' the block from being an orphan.
+ * We let regular orphan processing find that out and release it.
+ * This avoids races.
+ */
+static void orphan_abort(struct orphan_info *oi)
 {
-       /* All the interesting work was done in _pin.
-        * Just mark the block dirty and clean up
-        */
-       /* If block was already an orphan, we didn't do any work in 'pin',
-        * So there is not much to do here
+       struct fs *fs = oi->fs;
+       u32 bnum;
+       struct datablock *b;
+       struct orphan_md *om = &LAFSI(fs->orphans)->md.orphan;
+       mutex_lock_nested(&fs->orphans->i_mutex, I_MUTEX_QUOTA);
+       om->reserved--;
+       bnum = (om->nextfree + om->reserved) >>
+               (fs->prime_sb->s_blocksize_bits-4);
+       b = lafs_get_block(fs->orphans, bnum, NULL, GFP_KERNEL,
+                          MKREF(orphanx));
+       /* Note that we now own two references to this block, one
+        * we just got and one we are trying to get rid of
         */
-       if (oi->ob) {
-               LAFS_BUG(!test_bit(B_PinPending, &oi->ob->b.flags),
-                        &oi->ob->b);
-               lafs_dirty_dblock(oi->ob);
-               if (atomic_dec_and_test(&oi->ob->pincnt))
-                       /* FIXME this is racy */
-                       clear_bit(B_PinPending, &oi->ob->b.flags);
-               /* We don't 'put' the reference.  It is now held through
-                * the B_Orphan flag and the orphan_slot field.
-                */
-               oi->ob = NULL;
-       }
-       /* Otherwise we might still hold a reservation which
-        * we can drop by calling orphan_abort
+       putdref(b, MKREF(orphanx));
+
+       /* If this was the last block in the file,
+        * we need to punch a hole
         */
-       lafs_orphan_abort(oi);
+       if (((om->nextfree + om->reserved + 1) >>
+            (fs->prime_sb->s_blocksize_bits-4))
+           != bnum)
+               lafs_erase_dblock(b);
+
+       putdref(b, MKREF(orphan_reserve));
+       mutex_unlock(&fs->orphans->i_mutex);
 }
 
-/* Note that we don't 'unmark' the block from being an orphan.
- * We let regular orphan processing find that out and release it.
- * This avoids races.
+/* When we are about to make a change which might make a block
+ * into an 'orphan', we call lafs_make_orphan to record the fact.
+ * This sets B_Orphan, put the block on the fs->pending_orphans list
+ * and stores the fs/inode/block number in the orphan file.
+ * The handle_orphans routine for the relevant file type must ensure
+ * that orphan handling doesn't happen until the block is genuinely
+ * an orphan.
+ * For directories, i_mutex is used for this.
+ * For inodes, B_IOLock is used.
  */
-void lafs_orphan_abort(struct orphan_info *oi)
+int lafs_make_orphan(struct fs *fs, struct datablock *db)
 {
-       struct fs *fs = oi->fs;
-       if (oi->reserved) {
-               u32 bnum;
-               struct datablock *b;
-               struct orphan_md *om = &LAFSI(fs->orphans)->md.orphan;
-               mutex_lock_nested(&fs->orphans->i_mutex, I_MUTEX_QUOTA);
-               om->reserved--;
-               bnum = (om->nextfree + om->reserved) >>
-                       (fs->prime_sb->s_blocksize_bits-4);
-               b = lafs_get_block(fs->orphans, bnum, NULL, GFP_KERNEL,
-                       MKREF(orphanx));
-               /* Note that we now own two references to this block, one
-                * we just got and one we are trying to get rid of
-                */
-               putdref(b, MKREF(orphanx));
+       struct orphan_info oi;
+       int err;
 
-               /* If this was the last block in the file,
-                * we need to punch a hole
-                */
-               if (((om->nextfree + om->reserved + 1) >>
-                    (fs->prime_sb->s_blocksize_bits-4))
-                   != bnum)
-                       lafs_erase_dblock(b);
+       if (test_bit(B_Orphan, &db->b.flags))
+               return 0;
 
-               putdref(b, MKREF(orphan_reserve));
-               mutex_unlock(&fs->orphans->i_mutex);
-       }
-       /* FIXME maybe discard this altogether */
-       if (oi->ob) {
-               if (atomic_dec_and_test(&oi->ob->pincnt))
-                       /* FIXME this is racy */
-                       clear_bit(B_PinPending, &oi->ob->b.flags);
-               //putdref(oi->ob, MKREF(orphan));
-               oi->ob = NULL;
+       err = orphan_prepare(fs, &oi);
+       if (err)
+               return err;
+ retry:
+       lafs_checkpoint_lock(fs);
+       err = orphan_pin(&oi, db);
+       if (err == -EAGAIN) {
+               lafs_checkpoint_unlock_wait(fs);
+               goto retry;
        }
+       if (err)
+               orphan_abort(&oi);
+       /* there is no 'commit' - 'pin' did all the work */
+       lafs_checkpoint_unlock(fs);
+       return 0;
 }
 
 /*
@@ -262,10 +266,6 @@ void lafs_orphan_release(struct fs *fs, struct datablock *b)
                return;
 
        mutex_lock_nested(&fs->orphans->i_mutex, I_MUTEX_QUOTA);
-       if (!test_bit(B_Orphan, &b->b.flags)) {
-               mutex_unlock(&fs->orphans->i_mutex);
-               return;
-       }
 
        ob1 = lafs_get_block(fs->orphans, b->orphan_slot >> shift, NULL,
                             GFP_KERNEL, MKREF(orphan_release));
@@ -365,7 +365,10 @@ void lafs_orphan_release(struct fs *fs, struct datablock *b)
        }
        om->nextfree--;
        om->reserved++;
+       spin_lock(&fs->lock);
        clear_bit(B_Orphan, &b->b.flags);
+       list_del_init(&b->orphans);
+       spin_unlock(&fs->lock);
 
        /* Now drop the reservation we just synthesised */
        om->reserved--;
diff --git a/state.h b/state.h
index b3b548154899ea543c505ea27735682b1a915f7b..1016eec7937454a22f5baf7cd599ff9ddb43647c 100644 (file)
--- a/state.h
+++ b/state.h
@@ -344,7 +344,6 @@ struct datablock {
                                           */
        union {
                struct inode *my_inode; /* only valid for block holding an inode */
-               atomic_t        pincnt; /* only valid for blocks in the orphan file */
        };
 };
 struct indexblock {