]> git.neil.brown.name Git - LaFS.git/commitdiff
orphan.c: lots of refcount fixes.
authorNeilBrown <neilb@suse.de>
Sun, 29 Mar 2009 21:11:20 +0000 (08:11 +1100)
committerNeilBrown <neilb@suse.de>
Sun, 29 Mar 2009 21:11:20 +0000 (08:11 +1100)
Choose better ref names, and make sure were put them
appropriately.

orphan.c

index 4d2df8fa1a1c6802815f609ad6f6f421e9515ac5..7cd68f5911994d0a3a86e3727d54c7c2f645fbe0 100644 (file)
--- a/orphan.c
+++ b/orphan.c
  * InodeFile
  *   The inode may have a linkcount of 0 and if so, it should
  *   be truncated and removed
+ *   The inode might have blocks beyond EOF in which case they
+ *   should be truncated.
  * Directory
- *   An index block might not have been incorporated into the
- *     index tree yet.
- *   An index block might be under full and so need to be merged
- *     with a neighbour
- *   A leaf block may be completely empty and so should be
- *     moved from the part-free list to the free-list
+ *   An internal chain from this block might be being released...
+ *   see dir.c for further details.
  *
  * Each entry in the orphan file is 16 bytes holding 4 u32s
  * in little_endian.
@@ -101,11 +99,12 @@ int lafs_orphan_prepare(struct fs *fs, struct orphan_info *oi)
        bnum = (om->nextfree + om->reserved) >>
                (fs->prime_sb->s_blocksize_bits-4);
 
-       b = lafs_get_block(fs->orphans, bnum, NULL, GFP_KERNEL, MKREF(orphan));
+       b = lafs_get_block(fs->orphans, bnum, NULL, GFP_KERNEL, 
+                          MKREF(orphan_reserve));
        if (b) {
                err = lafs_read_block(b);
                if (err) {
-                       putdref(b, MKREF(orphan));
+                       putdref(b, MKREF(orphan_reserve));
                        oi->reserved = 0;
                } else {
                        om->reserved++;
@@ -140,6 +139,7 @@ int lafs_orphan_pin(struct orphan_info *oi, struct datablock *b, int n)
        ob = lafs_get_block(fs->orphans, bnum, NULL, GFP_KERNEL, MKREF(orphan));
        /* that *must* succeed as we own a reference on the block already */
        BUG_ON(ob == NULL);
+
        lafs_phase_wait(&ob->b);
        oi->ob = ob;
        atomic_inc(&ob->pincnt);
@@ -147,6 +147,8 @@ int lafs_orphan_pin(struct orphan_info *oi, struct datablock *b, int n)
        if (err) {
                atomic_dec(&ob->pincnt);
                mutex_unlock(&fs->orphans->i_mutex);
+               putdref(ob, MKREF(orphan));
+               oi->ob = NULL;
                return err;
        }
        b->orphan_slot = slot;
@@ -158,6 +160,7 @@ int lafs_orphan_pin(struct orphan_info *oi, struct datablock *b, int n)
        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));
@@ -172,11 +175,11 @@ int lafs_orphan_pin(struct orphan_info *oi, struct datablock *b, int n)
 
 void lafs_orphan_commit(struct orphan_info *oi)
 {
-       /* All the interesting work was done in _lock.
+       /* 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 nothing to do here
+        * So there is not much to do here
         */
        if (oi->ob) {
                BUG_ON(!test_bit(B_PinPending, &oi->ob->b.flags));
@@ -184,8 +187,15 @@ void lafs_orphan_commit(struct orphan_info *oi)
                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));
+               /* 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
+        */
+       lafs_orphan_abort(oi);
 }
 
 /* Note that we don't 'unmark' the block from being an orphan.
@@ -218,14 +228,15 @@ void lafs_orphan_abort(struct orphan_info *oi)
                    != bnum)
                        lafs_erase_dblock(b);
 
-               putdref(b, MKREF(orphan));
+               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));
+               //putdref(oi->ob, MKREF(orphan));
                oi->ob = NULL;
        }
 }
@@ -250,9 +261,18 @@ 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));
+                            GFP_KERNEL, MKREF(orphan_release));
+       /* We already own an 'orphan' reference on this block, so we
+        * don't need this one
+        */
+       BUG_ON(ob1 == NULL);
+       putdref(ob1, MKREF(orphan_release));
 
        lafs_phase_wait(&ob1->b);
 
@@ -265,14 +285,14 @@ void lafs_orphan_release(struct fs *fs, struct datablock *b)
                /* need to swap in the last entry */
                struct datablock *bfs, *bi, *bbl;
                ob2 = lafs_get_block(fs->orphans, (om->nextfree-1) >> shift,
-                                    NULL, GFP_KERNEL, MKREF(orphan));
+                                    NULL, GFP_KERNEL, MKREF(orphan_move));
                if (!ob2) {
                        /* Oh dear, we cannot effect the swap - sad */
                        printk("OUCH 1\n");
                        goto ouch;
                }
                if (lafs_read_block(ob2) != 0) {
-                       putdref(ob2, MKREF(orphan));
+                       putdref(ob2, MKREF(orphan_move));
                        printk("OUCH 2\n");
                        goto ouch;
                }
@@ -288,21 +308,21 @@ void lafs_orphan_release(struct fs *fs, struct datablock *b)
                /* FIXME these should not create the block if it
                 * doesn't exist */
                bfs = lafs_get_block(fs->ss[0].root, le32_to_cpu(last.filesys),
-                                    NULL, GFP_KERNEL, MKREF(orphan));
+                                    NULL, GFP_KERNEL, MKREF(orphan_fs));
                if (bfs && bfs->my_inode)
                        bi = lafs_get_block(bfs->my_inode,
                                            le32_to_cpu(last.inum),
-                                           NULL, GFP_KERNEL, MKREF(orphan));
+                                           NULL, GFP_KERNEL, MKREF(orphan_ino));
                else
                        bi = NULL;
-               putdref(bfs, MKREF(orphan));
+               putdref(bfs, MKREF(orphan_fs));
                if (bi && bi->my_inode)
                        bbl = lafs_get_block(bi->my_inode,
                                             le32_to_cpu(last.addr),
-                                            NULL, GFP_KERNEL, MKREF(orphan));
+                                            NULL, GFP_KERNEL, MKREF(orphan_blk));
                else
                        bbl = NULL;
-               putdref(bi, MKREF(orphan));
+               putdref(bi, MKREF(orphan_ino));
                dprintk("O bfs=%p(%p) bi=%p bbl=%p lastent=%d "
                        "fs=%d in=%d a=%d\n",
                       bfs, bfs->my_inode, bi, bbl, lastent,
@@ -311,7 +331,7 @@ void lafs_orphan_release(struct fs *fs, struct datablock *b)
                       le32_to_cpu(last.addr)
                       );
                if (!bbl) {
-                       putdref(ob2, MKREF(orphan));
+                       putdref(ob2, MKREF(orphan_release2));
                        printk("OUCH 3\n");
                        BUG();
                        goto ouch;
@@ -322,20 +342,24 @@ void lafs_orphan_release(struct fs *fs, struct datablock *b)
                or = map_dblock(ob1);
                or[ent] = last;
                bbl->orphan_slot = b->orphan_slot;
-               putdref(bbl, MKREF(orphan));
+               putdref(bbl, MKREF(orphan_blk));
                lafs_dirty_dblock(ob1);
                lafs_dirty_dblock(ob2);
                unmap_dblock(ob1, or);
 
-               /* no longer hold a reservation reference
-                * on this block, but do now on ob2
+               /* The orphan reference on ob2 has moved to ob1
+                * and ob2 is now a 'reservation' reference.
+                * So we drop ob2 and extra time, but not ob1 at all.
                 */
-               putdref(ob1, MKREF(orphan));
+               getdref(ob2, MKREF(orphan_reserve));
+               putdref(ob2, MKREF(orphan_move));
+               putdref(ob2, MKREF(orphan));
        } else {
                or = map_dblock(ob1);
                or[ent].type = 0;
                unmap_dblock(ob1, or);
                lafs_dirty_dblock(ob1);
+               getdref(ob1, MKREF(orphan_reserve));
                putdref(ob1, MKREF(orphan));
        }
        om->nextfree--;
@@ -345,11 +369,12 @@ void lafs_orphan_release(struct fs *fs, struct datablock *b)
        /* Now drop the reservation we just synthesised */
        om->reserved--;
        bnum = (om->nextfree + om->reserved) >> (b->b.inode->i_blkbits-4);
-       b = lafs_get_block(fs->orphans, bnum, NULL, GFP_KERNEL, MKREF(orphan));
+       b = lafs_get_block(fs->orphans, bnum, NULL, GFP_KERNEL,
+                          MKREF(orphan_release3));
        /* 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(orphan));
+       putdref(b, MKREF(orphan_release3));
 
        /* If this was the last block in the file,
         * we need to punch a hole
@@ -359,7 +384,7 @@ void lafs_orphan_release(struct fs *fs, struct datablock *b)
                /* FIXME share code with orphan_abort */
                lafs_erase_dblock(b);
 
-       putdref(b, MKREF(orphan));
+       putdref(b, MKREF(orphan_reserve));
 
  ouch: /* FIXME */
        mutex_unlock(&fs->orphans->i_mutex);