Thread (48 messages) 48 messages, 8 authors, 2012-11-14

Re: [PATCH 15/26] Btrfs: add a new source file with device replace code

From: Stefan Behrens <hidden>
Date: 2012-11-12 17:21:02

On Fri, 9 Nov 2012 22:45:16 +0800, Liu Bo wrote:
On Fri, Nov 09, 2012 at 11:19:17AM +0100, Stefan Behrens wrote:
quoted
On Fri, 9 Nov 2012 08:44:01 +0800, Liu Bo wrote:
quoted
On Thu, Nov 08, 2012 at 06:24:36PM +0100, Stefan Behrens wrote:
quoted
On Thu, 8 Nov 2012 22:50:47 +0800, Liu Bo wrote:
quoted
On Tue, Nov 06, 2012 at 05:38:33PM +0100, Stefan Behrens wrote:
quoted
+	trans = btrfs_start_transaction(root, 0);
why a start_transaction here?  Any reasons?
(same question also for some other places)
Without this transaction, there is outstanding I/O which is not flushed.
Pending writes that go only to the old disk need to be flushed before
the mode is switched to write all live data to the source disk and to
the target disk as well. The copy operation that is part of the scrub
code works on the commit root for performance reasons. Every write
request that is performed after the commit root is established needs to
go to both disks. Those requests that already have the bdev assigned
(i.e., btrfs_map_bio() was already called) cannot be duplicated anymore
to write to the new disk as well.

btrfs_dev_replace_finishing() looks similar and goes through a
transaction commit between the steps where the bdev in the mapping tree
is swapped and the step when the old bdev is freed. Otherwise the bdev
would be accessed after being freed.
I see, if you're only about to flush metadata, why not join a transaction?
btrfs_join_transaction() would delay the current transaction and enforce
that the current transaction is used and not a new one.
btrfs_start_transaction() would use either the current transaction, or a
new one. It is less interfering.
hmm...btrfs_start_transaction() would not use the current transaction unless
you're still in the same task, ie. current->journal_info remains unchanged,
otherwise it will be blocked by the current transaction(wait_current_trans()).

If there are several btrfs_start_transaction() being blocked, after the current
one's commit, one of them will allocate a new transaction, and the rest can join it.

But btrfs_join_transaction will join the current as much as possible.

And since here we don't do any reservation and seems to just update chunk/device
tree(which will use global block rsv directly), I perfer btrfs_join_transaction().
I am still not sure, which one is worse or better:
a) to delay a commit by calling btrfs_join_transaction() which joins and thereby delays a transaction, or
b) to go through one additional transaction.

Here is the log message of the commit that added btrfs_join_transaction(). For me, it sounds like one should use btrfs_join_transaction() only when it is _required_ to join a transaction, e.g. when a low level function is required to join the transaction that some higher level function has started:

commit f9295749388f82c8d2f485e99c72cd7c7876a99b
Author: Chris Mason [off-list ref]
Date:   Thu Jul 17 12:54:14 2008 -0400

    btrfs_start_transaction: wait for commits in progress to finish

    btrfs_commit_transaction has to loop waiting for any writers in the
    transaction to finish before it can proceed.  btrfs_start_transaction
    should be polite and not join a transaction that is in the process
    of being finished off.

    There are a few places that can't wait, basically the ones doing IO that
    might be needed to finish the transaction.  For them, btrfs_join_transaction
    is added.


quoted
Since in dev-replace.c it is not required to enforce that a current
transaction is joined, btrfs_start_transaction() is the one to choose
here, as I understood it.

But that's an interesting topic and I would appreciate to get a definite
rule which one to choose when.
  
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help