]> git.neil.brown.name Git - LaFS.git/commitdiff
Separate setting of PinPending out
authorNeilBrown <neilb@suse.de>
Sun, 18 Jul 2010 16:44:12 +0000 (18:44 +0200)
committerNeilBrown <neilb@suse.de>
Sun, 25 Jul 2010 05:34:27 +0000 (15:34 +1000)
We want PinPending set whenever a transaction might be in progress to
ensure that write_page doesn't flush the block early, or that the
cleaner doesn't clean the block in the middle.

We also want the block be completely written if a write has already
been scheduled.

So:
  - set PinPending - after getting an IOlock and ensure the block is
     not in writeback.   This is set before the checkpoint lock is
     taken.
  - Once we have checkpoint lock and call pin_dblock, wait for
    writeout to complete again.  This can only be in writeout
    if the block is being written to the previous phase, and it
    is safe to wait for that inside the checkpoint lock.

Signed-off-by: NeilBrown <neilb@suse.de>
block.c
cluster.c
dir.c
inode.c
io.c
lafs.h
modify.c
orphan.c
roll.c
segments.c

diff --git a/block.c b/block.c
index 529db5e4fb199d6425c5d02152dca17e2e823a1d..b756e0a4c851dbca09cdb34719b9ac155d88eb73 100644 (file)
--- a/block.c
+++ b/block.c
@@ -459,20 +459,16 @@ lafs_pin_dblock(struct datablock *b, int alloc_type)
        } else
                blk = getref(&b->b, MKREF(pindb));
 
+       LAFS_BUG(!test_bit(B_PinPending, &b->b.flags), &b->b);
        if (LAFSI(b->b.inode)->type != TypeSegmentMap) {
-               /* FIXME test is a hack until we get a better
-                * phase wait.  TypeSegmentMap does it's own
-                * dirty management so doesn't need this.
-                */
                LAFS_BUG(!test_phase_locked(fs), &b->b);
-               lafs_phase_wait(blk);
+               lafs_iolock_written(&b->b);
+               lafs_iounlock_block(&b->b);
        }
 
-       set_bit(B_PinPending, &b->b.flags);
        err = lafs_reserve_block(blk, alloc_type);
 
        if (err) {
-               clear_bit(B_PinPending, &b->b.flags);
                putref(blk, MKREF(pindb));
                return err;
        }
index 8c919915aa45648d27b036fbc28f357a314c7396..8eda63ae5233aba9f5565afd1c71bce987dc3a6a 100644 (file)
--- a/cluster.c
+++ b/cluster.c
@@ -661,7 +661,7 @@ int lafs_cluster_allocate(struct block *b, int cnum)
                                b2->parent =
                                        getiref(b->parent, MKREF(child));
                        LAFS_BUG(b->parent != b2->parent, b);
-                       set_bit(B_PinPending, &b2->flags);
+                       set_bit(B_PinPending, &b2->flags);  // FIXME is this right?
                        set_phase(b2, test_bit(B_Phase1,
                                               &b->flags));
                        lafs_refile(b2, 0);
@@ -706,7 +706,7 @@ int lafs_cluster_allocate(struct block *b, int cnum)
                                if (!test_and_clear_bit(B_ICredit, &b2->flags))
                                        credits--;
                }
-               clear_bit(B_PinPending, &b2->flags);
+               clear_bit(B_PinPending, &b2->flags); // FIXME not sure this is right
                LAFS_BUG(credits < 0, b2);
                lafs_space_return(fs, credits);
                /* make sure 'dirty' status is registered */
diff --git a/dir.c b/dir.c
index a4f862d828251cccd44dea054fd4b56c241437e8..f53c674a893d9e4ad50e76e2306fd295f42eda67 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -294,6 +294,7 @@ static int dir_create_prepare(struct fs *fs, struct inode *dir,
        memcpy(buf, n1, blocksize);
        unmap_dblock(doh->new, buf);
        set_bit(B_Valid, &doh->new->b.flags);
+       set_bit(B_PinPending, &doh->new->b.flags);
        kfree(n1);
        doh->temp = n2;
        return 0;
@@ -748,6 +749,9 @@ lafs_unlink(struct inode *dir, struct dentry *de)
                err = lafs_make_orphan(fs, inodb);
        if (err)
                goto abort;
+       lafs_iolock_block(&inodb->b);
+       set_bit(B_PinPending, &inodb->b.flags);
+       lafs_iounlock_block(&inodb->b);
 retry:
        lafs_checkpoint_lock(fs);
 
@@ -831,6 +835,9 @@ lafs_rmdir(struct inode *dir, struct dentry *de)
                err = lafs_make_orphan(fs, inodb);
        if (err)
                goto abort;
+       lafs_iolock_block(&inodb->b);
+       set_bit(B_PinPending, &inodb->b.flags);
+       lafs_iounlock_block(&inodb->b);
 retry:
        lafs_checkpoint_lock(fs);
 
@@ -895,6 +902,7 @@ lafs_symlink(struct inode *dir, struct dentry *de,
                iput(ino);
                return -ENOMEM;
        }
+       set_bit(B_PinPending, &b->b.flags);
 
        err = dir_create_prepare(fs, dir, de->d_name.name, de->d_name.len,
                                 ino->i_ino, DT_LNK, &doh);
@@ -1145,6 +1153,9 @@ lafs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        err = PTR_ERR(newdb);
                if (last && !err)
                        err = lafs_make_orphan(fs, newdb);
+               lafs_iolock_block(&newdb->b);
+               set_bit(B_PinPending, &newdb->b.flags);
+               lafs_iounlock_block(&newdb->b);
        } else
                /* create new link */
                err = dir_create_prepare(fs, new_dir,
@@ -1157,6 +1168,9 @@ lafs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (err)
                goto abort;
 
+       lafs_iolock_block(&olddb->b);
+       set_bit(B_PinPending, &olddb->b.flags);
+       lafs_iounlock_block(&olddb->b);
 retry:
        lafs_checkpoint_lock(fs);
 
@@ -1279,6 +1293,11 @@ int lafs_dir_handle_orphan(struct datablock *b)
 
        dprintk("HANDLE ORPHAN h=%x %s\n", (unsigned)hash, strblk(&b->b));
 
+       if (!lafs_iolock_written_async(&b->b))
+               return -EAGAIN;
+       set_bit(B_PinPending, &b->b.flags);
+       lafs_iounlock_block(&b->b);
+
        lafs_checkpoint_lock(fs);
 
        if (!test_bit(B_Valid, &b->b.flags)) {
@@ -1338,7 +1357,6 @@ int lafs_dir_handle_orphan(struct datablock *b)
                                                  NULL)->target == 0);
                        unmap_dblock(b, buf);
                        lafs_dirty_dblock(b);
-                       clear_bit(B_PinPending, &b->b.flags);
                } else
                        unmap_dblock(b2, buf2);
                buf = map_dblock(b);
@@ -1381,7 +1399,6 @@ int lafs_dir_handle_orphan(struct datablock *b)
                buf = map_dblock(b);
                lafs_dir_del_ent(buf, bits, seed, hash);
                lafs_dirty_dblock(b);
-               clear_bit(B_PinPending, &b->b.flags);
        }
 
        if (lafs_dir_empty(buf)) {
@@ -1418,7 +1435,6 @@ int lafs_dir_handle_orphan(struct datablock *b)
                        lafs_dirty_inode(dir);
                }
                lafs_erase_dblock(b);
-               clear_bit(B_PinPending, &b->b.flags);
        } else
                unmap_dblock(b, buf);
 
@@ -1426,6 +1442,7 @@ int lafs_dir_handle_orphan(struct datablock *b)
        err = 0;
 
 abort:
+       clear_bit(B_PinPending, &b->b.flags);
        putdref(b2, MKREF(dir_orphan));
        lafs_checkpoint_unlock(fs);
        return err;
diff --git a/inode.c b/inode.c
index 2bc79e02ff9d56eb8891cc411c7e8fafe98cc09e..d573dfb73bac9eb01adb326f5dde4e7ff482721b 100644 (file)
--- a/inode.c
+++ b/inode.c
@@ -1333,6 +1333,10 @@ retry:
                        return -EINVAL;
                goto retry;
        }
+       lafs_iolock_written(&imni->mb->b);
+       set_bit(B_PinPending, &imni->mb->b.flags);
+       lafs_iounlock_block(&imni->mb->b);
+       set_bit(B_PinPending, &b->b.flags);
        b->my_inode = NULL;
        imni->ib = b;
        return 0;
@@ -1364,7 +1368,6 @@ inode_map_new_commit(struct inode_map_new_info *imni)
                lafs_erase_dblock(imni->mb);
        else
                lafs_dirty_dblock(imni->mb);
-       clear_bit(B_PinPending, &imni->ib->b.flags);
        putdref(imni->ib, MKREF(cfi_ino));
        putdref(imni->mb, MKREF(cfi_map));
 }
@@ -1438,7 +1441,6 @@ retry:
        } else
                lafs_cluster_update_commit(&ui, b, 0,
                                           LAFSI(ino)->metadata_size);
-       clear_bit(B_PinPending, &b->b.flags);
        LAFS_BUG(LAFSI(ino)->dblock != b, &b->b);
        LAFS_BUG(b->my_inode != ino, &b->b);
        lafs_checkpoint_unlock(fs);
@@ -1478,6 +1480,9 @@ static int inode_map_free(struct fs *fs, struct inode *filesys, u32 inum)
                putdref(b, MKREF(inode_map_free));
                return err;
        }
+       lafs_iolock_written(&b->b);
+       set_bit(B_PinPending, &b->b.flags);
+       lafs_iounlock_block(&b->b);
 retry:
        lafs_checkpoint_lock(fs);
        err = lafs_pin_dblock(b, ReleaseSpace);
@@ -1510,6 +1515,13 @@ int lafs_setattr(struct dentry *dentry, struct iattr *attr)
        if (err)
                return err;
 
+       /* We don't need iolock_written here as we don't
+        * actually change the inode block yet
+        */
+       lafs_iolock_block(&db->b);
+       set_bit(B_PinPending, &db->b.flags);
+       lafs_iounlock_block(&db->b);
+
        /* FIXME quota stuff */
 
 again:
diff --git a/io.c b/io.c
index abecfa843548b50dbbaf43b569c60a7bb74bb135..a7756abd21a599dbe992916ccd2bd9d30682d64c 100644 (file)
--- a/io.c
+++ b/io.c
@@ -387,7 +387,7 @@ static void wait_writeback(struct block *b)
 
 void _lafs_iolock_written(struct block *b)
 {
-       lafs_iolock_block(b);
+       _lafs_iolock_block(b);
        wait_writeback(b);
 }
 
diff --git a/lafs.h b/lafs.h
index 0331018a5dc6e4e8057c1ae4afbfd7966b68401c..cc21d4df97db1e180c53f24f742e16a83fc73bf8 100644 (file)
--- a/lafs.h
+++ b/lafs.h
@@ -594,7 +594,6 @@ void lafs_destroy_inode(struct inode *inode);
 void lafs_checkpoint_lock(struct fs *fs);
 void lafs_checkpoint_unlock(struct fs *fs);
 void lafs_checkpoint_unlock_wait(struct fs *fs);
-void lafs_phase_wait(struct block *b);
 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);
index 1720f6ffba30f4f7185467ff7be87862744e3e53..2d4d1afe9a2c6becc1eff27c7b883cda04d570e1 100644 (file)
--- a/modify.c
+++ b/modify.c
@@ -1981,19 +1981,3 @@ retry:
 
        return -ENOSPC;
 }
-
-/* If a datablock is dirty and pinned to the previous phase,
- * we may not change it in this phase.  So we have to wait
- * at least until it is written.  We actually wait until the
- * phase passes
- * The same applies to InoIdx blocks.
- * FIXME should I encourage this with a cluster_flush ??
- */
-void lafs_phase_wait(struct block *b)
-{
-       struct fs *fs = fs_from_inode(b->inode);
-
-       wait_event(fs->phase_wait,
-                  !test_bit(B_Pinned, &b->flags) ||
-                  (!!test_bit(B_Phase1, &b->flags)) == fs->phase);
-}
index 44acf8a6c804a68edba2348f4254ac5af2d3f13d..34005e9379bdc4eaf44f6dd0af6347a1c89f1bd2 100644 (file)
--- a/orphan.c
+++ b/orphan.c
@@ -128,6 +128,9 @@ static int orphan_prepare(struct fs *fs, int async)
        } else
                err = -ENOMEM;
        mutex_unlock(&fs->orphans->i_mutex);
+       lafs_iolock_written(&b->b);
+       set_bit(B_PinPending, &b->b.flags);
+       lafs_iounlock_block(&b->b);
        return err;
 }
 
@@ -181,7 +184,6 @@ static void orphan_commit(struct fs *fs, struct datablock *b, struct datablock *
        or[ent].addr = cpu_to_le32(b->b.fileaddr);
        unmap_dblock(ob, or);
        lafs_dirty_dblock(ob);
-       clear_bit(B_PinPending, &ob->b.flags);
 }
 
 /* We failed to allocate space to write the update to the orphan
@@ -320,6 +322,8 @@ void lafs_orphan_release(struct fs *fs, struct datablock *b)
        LAFS_BUG(ob1 == NULL, &b->b);
        putdref(ob1, MKREF(orphan_release));
 
+       BUG_ON(!test_bit(B_PinPending, &ob1->b.flags));
+
        lafs_checkpoint_lock(fs);
 
        if (lafs_pin_dblock(ob1, ReleaseSpace) < 0)
@@ -349,6 +353,7 @@ void lafs_orphan_release(struct fs *fs, struct datablock *b)
                        printk("OUCH 2\n");
                        goto out_unlock;
                }
+               BUG_ON(!test_bit(B_PinPending, &ob2->b.flags));
                if (lafs_pin_dblock(ob2, ReleaseSpace) < 0) {
                        putdref(ob2, MKREF(orphan_move));
                        goto out_unlock;
@@ -402,8 +407,6 @@ void lafs_orphan_release(struct fs *fs, struct datablock *b)
                putdref(bbl, MKREF(orphan_blk));
                lafs_dirty_dblock(ob1);
                lafs_dirty_dblock(ob2);
-               clear_bit(B_PinPending, &ob1->b.flags);
-               clear_bit(B_PinPending, &ob2->b.flags);
 
                /* The orphan reference on ob2 has moved to ob1
                 * and ob2 is now a 'reservation' reference.
@@ -417,7 +420,6 @@ void lafs_orphan_release(struct fs *fs, struct datablock *b)
                or[ent].type = 0;
                unmap_dblock(ob1, or);
                lafs_dirty_dblock(ob1);
-               clear_bit(B_PinPending, &ob1->b.flags);
                getdref(ob1, MKREF(orphan_reserve));
                putdref(ob1, MKREF(orphan));
        }
diff --git a/roll.c b/roll.c
index 3417129bc552a53ce9f239c51ea4248df4aacbbc..2dd452f73f9bcc71fa3eebf0da6d35e820d29f7f 100644 (file)
--- a/roll.c
+++ b/roll.c
@@ -340,6 +340,7 @@ roll_block(struct fs *fs, int fsnum, int inum, int trunc, int flg,
                 * Is this really the best approach?
                 * Do I need to release some space here?
                 */
+               set_bit(B_PinPending, &blk->b.flags); /* Don't need iolock as no io yet */
                lafs_pin_dblock(blk, CleanSpace); /* cannot fail during ! ->rolled */
 
                lafs_iolock_block(&blk->b);
index eb07c77db0585ebeac873cb7dfb50cdec31c1259..f6e4da32ad9eaf816685cf840d1c44c245ecdab4 100644 (file)
@@ -318,6 +318,8 @@ int lafs_seg_ref_block(struct block *b, int ssnum)
                        continue;
                }
 
+               /* Don't need iolock here as segusage is very special */
+               set_bit(B_PinPending, &ss->ssblk->b.flags);
                err = lafs_pin_dblock(ss->ssblk, AccountSpace);
                if (err) {
                        ss_put(ss, fs);
@@ -1141,9 +1143,12 @@ again:
                                 * to the two blocks !! */
                                LAFS_BUG(1, db ? &db->b : NULL);
                        lafs_checkpoint_lock(fs);
+                       set_bit(B_PinPending, &ssum->ssblk->b.flags);
                        (void)lafs_pin_dblock(ssum->ssblk, AccountSpace);
-                       if (ssnum == 0)
+                       if (ssnum == 0) {
+                               set_bit(B_PinPending, &ssum->youthblk->b.flags);
                                (void)lafs_pin_dblock(ssum->youthblk, AccountSpace);
+                       }
                        lafs_checkpoint_unlock(fs);
                }
                if (db) {