From: NeilBrown Date: Sat, 15 Aug 2009 07:09:20 +0000 (+1000) Subject: Simplify iolocking in get_flushable X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=0f3f31c3315629e75ec05ff693894a49ed0576cf;p=LaFS.git Simplify iolocking in get_flushable The difference between data and index block is not really supportable, and we cannot just avoid waiting for some blocks. But we cannot always for a full iowait as block that have been allocated to a cluster do not complete until the cluster is written and we don't want to wait for a cluster to be written, especially as we there thread that is supposed to do that. So create an intermediate iowait which wait for iolock to be dropped or the block to be placed on a list. Once it is on a list we can be sure not to lose it. So we wait while incorporation or truncation happens, but not while writeout happens. --- diff --git a/checkpoint.c b/checkpoint.c index baad30e..686d2cc 100644 --- a/checkpoint.c +++ b/checkpoint.c @@ -303,30 +303,20 @@ struct block *lafs_get_flushable(struct fs *fs, int phase) b = list_entry(fs->phase_leafs[phase].next, struct block, lru); else b = NULL; - if (b) { + if (b) /* the list counted a reference. Now we hold it */ list_del_init(&b->lru); - - if (!test_bit(B_Index, &b->flags)) { - if (test_and_set_bit(B_IOLock, &b->flags)) { - /* someone else is invalidating this block, - * so I can just skip it. Better drop the ref. - */ - spin_unlock(&fs->lock); - putref(b, MKREF(leaf)); - goto retry; - } else - set_iolock_info(b); - } - } spin_unlock(&fs->lock); - if (b && test_bit(B_Index, &b->flags)) - /* we couldn't iolock in the spinlock because there might - * be an intermediate incorporation happening that - * would block us. So we get the lock now, waiting if - * needed. + if (b) + /* Need an iolock, but if the list gets put on another + * lru (like a cluster or back on leafs) then we lose + * interest. */ - lafs_iolock_block(b); + if (lafs_iolock_block_empty(b) == 0) { + /* gave up on the lock */ + putref(b, MKREF(leaf)); + goto retry; + } return b; } diff --git a/cluster.c b/cluster.c index ea52e2e..7dd6aa8 100644 --- a/cluster.c +++ b/cluster.c @@ -731,7 +731,8 @@ unsigned long long lafs_cluster_allocate(struct block *b, int cnum) /* won't fit */ // printk("Wont fit - used = %d\n", used); cluster_flush(fs, cnum); - } + } else + lafs_io_wake(b); } while (used < 0); if (used > 0) diff --git a/index.c b/index.c index 7a9e65b..bbbf405 100644 --- a/index.c +++ b/index.c @@ -818,6 +818,7 @@ void lafs_refile(struct block *b, int dec) getref(b, MKREF(leaf)); } spin_unlock(&fs->lock); + lafs_io_wake(b); } /* check the ->parent link */ if (atomic_read(&b->refcnt) == dec) { diff --git a/io.c b/io.c index b37eafb..bc51f15 100644 --- a/io.c +++ b/io.c @@ -187,9 +187,14 @@ lafs_super_wait(struct fs *fs) static DECLARE_WAIT_QUEUE_HEAD(block_wait); /* need more of these later FIXME */ -void -_lafs_iolock_block(struct block *b) +void lafs_io_wake(struct block *b) +{ + wake_up(&block_wait); +} +int +_lafs_iolock_block(struct block *b, int checkempty) { + int locked = 1; if (test_and_set_bit(B_IOLock, &b->flags)) { DEFINE_WAIT(wq); #ifdef DEBUG_IOLOCK @@ -199,13 +204,17 @@ _lafs_iolock_block(struct block *b) #endif for (;;) { prepare_to_wait(&block_wait, &wq, TASK_UNINTERRUPTIBLE); - if (test_and_set_bit(B_IOLock, &b->flags)) - schedule(); - else + if (checkempty && !list_empty_careful(&b->lru)) { + locked = 0; break; + } + if (!test_and_set_bit(B_IOLock, &b->flags)) + break; + schedule(); } finish_wait(&block_wait, &wq); } + return locked; } void @@ -222,7 +231,7 @@ lafs_iounlock_block(struct block *b, int bit) !db->page || !db->page->private || (!PageLocked(db->page) && !PageWriteback(db->page))) { clear_bit(B_IOLock, &b->flags); - wake_up(&block_wait); + lafs_io_wake(b); if (test_bit(B_Async, &b->flags)) lafs_wake_cleaner(fs_from_inode(b->inode)); dprintk("unlock non-data block\n"); @@ -253,7 +262,7 @@ lafs_iounlock_block(struct block *b, int bit) end_page_writeback(db->page); } - wake_up(&block_wait); + lafs_io_wake(b); if (test_bit(B_Async, &b->flags)) lafs_wake_cleaner(fs_from_inode(b->inode)); } diff --git a/lafs.h b/lafs.h index 4d67fff..02f88e1 100644 --- a/lafs.h +++ b/lafs.h @@ -102,13 +102,15 @@ struct indexblock *lafs_leaf_find(struct inode *inode, u32 addr, int adopt, u32 *next, int async, REFARG); u32 lafs_leaf_next(struct indexblock *ib, u32 start); #ifdef DEBUG_IOLOCK -#define set_iolock_info(b) do { (b)->iolock_file = __FILE__; (b)->iolock_line = __LINE__; } while (0) +#define set_iolock_info(b) ( (b)->iolock_file = __FILE__, (b)->iolock_line = __LINE__) #else -#define set_iolock_info(b) do {} while(0) +#define set_iolock_info(b) (0) #endif -#define lafs_iolock_block(b) do { _lafs_iolock_block(b); set_iolock_info(b); } while(0) +#define lafs_iolock_block(b) do { _lafs_iolock_block(b, 0); set_iolock_info(b); } while(0) +#define lafs_iolock_block_empty(b) (_lafs_iolock_block(b, 1) ? ( set_iolock_info(b), 1): 0) -void _lafs_iolock_block(struct block *b); +void lafs_io_wake(struct block *b); +int _lafs_iolock_block(struct block *b, int checkempty); void lafs_iounlock_block(struct block *b, int bit); void lafs_super_write(struct fs *fs, int dev, u64 addr, char *buf, int size);