Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 308506
b: refs/heads/master
c: 169ebd9
h: refs/heads/master
v: v3
  • Loading branch information
Jan Kara authored and Fengguang Wu committed May 6, 2012
1 parent c6188b9 commit 8d419db
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 24 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: dbd5768f87ff6fb0a4fe09c4d7b6c4a24de99430
refs/heads/master: 169ebd90131b2ffca74bb2dbe7eeacd39fb83714
66 changes: 53 additions & 13 deletions trunk/fs/fs-writeback.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,9 +326,12 @@ static int write_inode(struct inode *inode, struct writeback_control *wbc)
}

/*
* Wait for writeback on an inode to complete.
* Wait for writeback on an inode to complete. Called with i_lock held.
* Caller must make sure inode cannot go away when we drop i_lock.
*/
static void inode_wait_for_writeback(struct inode *inode)
static void __inode_wait_for_writeback(struct inode *inode)
__releases(inode->i_lock)
__acquires(inode->i_lock)
{
DEFINE_WAIT_BIT(wq, &inode->i_state, __I_SYNC);
wait_queue_head_t *wqh;
Expand All @@ -341,6 +344,36 @@ static void inode_wait_for_writeback(struct inode *inode)
}
}

/*
* Wait for writeback on an inode to complete. Caller must have inode pinned.
*/
void inode_wait_for_writeback(struct inode *inode)
{
spin_lock(&inode->i_lock);
__inode_wait_for_writeback(inode);
spin_unlock(&inode->i_lock);
}

/*
* Sleep until I_SYNC is cleared. This function must be called with i_lock
* held and drops it. It is aimed for callers not holding any inode reference
* so once i_lock is dropped, inode can go away.
*/
static void inode_sleep_on_writeback(struct inode *inode)
__releases(inode->i_lock)
{
DEFINE_WAIT(wait);
wait_queue_head_t *wqh = bit_waitqueue(&inode->i_state, __I_SYNC);
int sleep;

prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
sleep = inode->i_state & I_SYNC;
spin_unlock(&inode->i_lock);
if (sleep)
schedule();
finish_wait(wqh, &wait);
}

/*
* Find proper writeback list for the inode depending on its current state and
* possibly also change of its state while we were doing writeback. Here we
Expand Down Expand Up @@ -479,9 +512,11 @@ writeback_single_inode(struct inode *inode, struct bdi_writeback *wb,
if (wbc->sync_mode != WB_SYNC_ALL)
goto out;
/*
* It's a data-integrity sync. We must wait.
* It's a data-integrity sync. We must wait. Since callers hold
* inode reference or inode has I_WILL_FREE set, it cannot go
* away under us.
*/
inode_wait_for_writeback(inode);
__inode_wait_for_writeback(inode);
}
WARN_ON(inode->i_state & I_SYNC);
/*
Expand Down Expand Up @@ -620,20 +655,28 @@ static long writeback_sb_inodes(struct super_block *sb,
}
spin_unlock(&wb->list_lock);

__iget(inode);
/*
* We already requeued the inode if it had I_SYNC set and we
* are doing WB_SYNC_NONE writeback. So this catches only the
* WB_SYNC_ALL case.
*/
if (inode->i_state & I_SYNC)
inode_wait_for_writeback(inode);
if (inode->i_state & I_SYNC) {
/* Wait for I_SYNC. This function drops i_lock... */
inode_sleep_on_writeback(inode);
/* Inode may be gone, start again */
continue;
}
inode->i_state |= I_SYNC;
spin_unlock(&inode->i_lock);

write_chunk = writeback_chunk_size(wb->bdi, work);
wbc.nr_to_write = write_chunk;
wbc.pages_skipped = 0;

/*
* We use I_SYNC to pin the inode in memory. While it is set
* evict_inode() will wait so the inode cannot be freed.
*/
__writeback_single_inode(inode, wb, &wbc);

work->nr_pages -= write_chunk - wbc.nr_to_write;
Expand All @@ -645,10 +688,7 @@ static long writeback_sb_inodes(struct super_block *sb,
requeue_inode(inode, wb, &wbc);
inode_sync_complete(inode);
spin_unlock(&inode->i_lock);
spin_unlock(&wb->list_lock);
iput(inode);
cond_resched();
spin_lock(&wb->list_lock);
cond_resched_lock(&wb->list_lock);
/*
* bail out to wb_writeback() often enough to check
* background threshold and other termination conditions.
Expand Down Expand Up @@ -843,8 +883,8 @@ static long wb_writeback(struct bdi_writeback *wb,
inode = wb_inode(wb->b_more_io.prev);
spin_lock(&inode->i_lock);
spin_unlock(&wb->list_lock);
inode_wait_for_writeback(inode);
spin_unlock(&inode->i_lock);
/* This function drops i_lock... */
inode_sleep_on_writeback(inode);
spin_lock(&wb->list_lock);
}
}
Expand Down
8 changes: 7 additions & 1 deletion trunk/fs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,13 @@ static void evict(struct inode *inode)

inode_sb_list_del(inode);

inode_sync_wait(inode);
/*
* Wait for flusher thread to be done with the inode so that filesystem
* does not start destroying it while writeback is still running. Since
* the inode has I_FREEING set, flusher thread won't start new work on
* the inode. We just have to wait for running writeback to finish.
*/
inode_wait_for_writeback(inode);

if (op->evict_inode) {
op->evict_inode(inode);
Expand Down
7 changes: 4 additions & 3 deletions trunk/include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1753,9 +1753,10 @@ struct super_operations {
* anew. Other functions will just ignore such inodes,
* if appropriate. I_NEW is used for waiting.
*
* I_SYNC Synchonized write of dirty inode data. The bits is
* set during data writeback, and cleared with a wakeup
* on the bit address once it is done.
* I_SYNC Writeback of inode is running. The bit is set during
* data writeback, and cleared with a wakeup on the bit
* address once it is done. The bit is also used to pin
* the inode in memory for flusher thread.
*
* I_REFERENCED Marks the inode as recently references on the LRU list.
*
Expand Down
7 changes: 1 addition & 6 deletions trunk/include/linux/writeback.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,19 +95,14 @@ long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages,
enum wb_reason reason);
long wb_do_writeback(struct bdi_writeback *wb, int force_wait);
void wakeup_flusher_threads(long nr_pages, enum wb_reason reason);
void inode_wait_for_writeback(struct inode *inode);

/* writeback.h requires fs.h; it, too, is not included from here. */
static inline void wait_on_inode(struct inode *inode)
{
might_sleep();
wait_on_bit(&inode->i_state, __I_NEW, inode_wait, TASK_UNINTERRUPTIBLE);
}
static inline void inode_sync_wait(struct inode *inode)
{
might_sleep();
wait_on_bit(&inode->i_state, __I_SYNC, inode_wait,
TASK_UNINTERRUPTIBLE);
}


/*
Expand Down

0 comments on commit 8d419db

Please sign in to comment.