diff options
author | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2011-01-16 12:22:02 -0500 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2011-01-25 03:21:13 -0500 |
commit | 944fdef52ca9fc0fe077578f51201ef397e30abe (patch) | |
tree | c24c589edf911fcb66b0b1968fe3b283193787ff /fs/ubifs | |
parent | 18d1d7fbcc260e67d249bf90b454d8cf34288453 (diff) |
UBIFS: do not start the commit if there is nothing to commit
This patch fixes suboptimal UBIFS 'sync_fs()' implementation which causes
flash I/O even if the file-system is synchronized. E.g., a 'printk()'
in the MTD erasure function (e.g., 'nand_erase_nand()') can show that
for every 'sync' shell command UBIFS erases at least one eraseblock.
So '$ while true; do sync; done' will cause huge amount of flash I/O.
The reason for this is that UBIFS commits in 'sync_fs()', and starts the
commit even if there is nothing to commit, e.g., it anyway changes the
log. This patch adds a check in the 'do_commit()' UBIFS functions which
prevents the commit if there is nothing to commit.
Reported-by: Hans J. Koch <hjk@linutronix.de>
Tested-by: John Ogness <john.ogness@linutronix.de>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'fs/ubifs')
-rw-r--r-- | fs/ubifs/commit.c | 58 |
1 files changed, 57 insertions, 1 deletions
diff --git a/fs/ubifs/commit.c b/fs/ubifs/commit.c index 02429d81ca33..b148fbc80f8d 100644 --- a/fs/ubifs/commit.c +++ b/fs/ubifs/commit.c | |||
@@ -48,6 +48,56 @@ | |||
48 | #include <linux/slab.h> | 48 | #include <linux/slab.h> |
49 | #include "ubifs.h" | 49 | #include "ubifs.h" |
50 | 50 | ||
51 | /* | ||
52 | * nothing_to_commit - check if there is nothing to commit. | ||
53 | * @c: UBIFS file-system description object | ||
54 | * | ||
55 | * This is a helper function which checks if there is anything to commit. It is | ||
56 | * used as an optimization to avoid starting the commit if it is not really | ||
57 | * necessary. Indeed, the commit operation always assumes flash I/O (e.g., | ||
58 | * writing the commit start node to the log), and it is better to avoid doing | ||
59 | * this unnecessarily. E.g., 'ubifs_sync_fs()' runs the commit, but if there is | ||
60 | * nothing to commit, it is more optimal to avoid any flash I/O. | ||
61 | * | ||
62 | * This function has to be called with @c->commit_sem locked for writing - | ||
63 | * this function does not take LPT/TNC locks because the @c->commit_sem | ||
64 | * guarantees that we have exclusive access to the TNC and LPT data structures. | ||
65 | * | ||
66 | * This function returns %1 if there is nothing to commit and %0 otherwise. | ||
67 | */ | ||
68 | static int nothing_to_commit(struct ubifs_info *c) | ||
69 | { | ||
70 | /* | ||
71 | * During mounting or remounting from R/O mode to R/W mode we may | ||
72 | * commit for various recovery-related reasons. | ||
73 | */ | ||
74 | if (c->mounting || c->remounting_rw) | ||
75 | return 0; | ||
76 | |||
77 | /* | ||
78 | * If the root TNC node is dirty, we definitely have something to | ||
79 | * commit. | ||
80 | */ | ||
81 | if (c->zroot.znode && test_bit(DIRTY_ZNODE, &c->zroot.znode->flags)) | ||
82 | return 0; | ||
83 | |||
84 | /* | ||
85 | * Even though the TNC is clean, the LPT tree may have dirty nodes. For | ||
86 | * example, this may happen if the budgeting subsystem invoked GC to | ||
87 | * make some free space, and the GC found an LEB with only dirty and | ||
88 | * free space. In this case GC would just change the lprops of this | ||
89 | * LEB (by turning all space into free space) and unmap it. | ||
90 | */ | ||
91 | if (c->nroot && test_bit(DIRTY_CNODE, &c->nroot->flags)) | ||
92 | return 0; | ||
93 | |||
94 | ubifs_assert(atomic_long_read(&c->dirty_zn_cnt) == 0); | ||
95 | ubifs_assert(c->dirty_pn_cnt == 0); | ||
96 | ubifs_assert(c->dirty_nn_cnt == 0); | ||
97 | |||
98 | return 1; | ||
99 | } | ||
100 | |||
51 | /** | 101 | /** |
52 | * do_commit - commit the journal. | 102 | * do_commit - commit the journal. |
53 | * @c: UBIFS file-system description object | 103 | * @c: UBIFS file-system description object |
@@ -70,6 +120,12 @@ static int do_commit(struct ubifs_info *c) | |||
70 | goto out_up; | 120 | goto out_up; |
71 | } | 121 | } |
72 | 122 | ||
123 | if (nothing_to_commit(c)) { | ||
124 | up_write(&c->commit_sem); | ||
125 | err = 0; | ||
126 | goto out_cancel; | ||
127 | } | ||
128 | |||
73 | /* Sync all write buffers (necessary for recovery) */ | 129 | /* Sync all write buffers (necessary for recovery) */ |
74 | for (i = 0; i < c->jhead_cnt; i++) { | 130 | for (i = 0; i < c->jhead_cnt; i++) { |
75 | err = ubifs_wbuf_sync(&c->jheads[i].wbuf); | 131 | err = ubifs_wbuf_sync(&c->jheads[i].wbuf); |
@@ -162,12 +218,12 @@ static int do_commit(struct ubifs_info *c) | |||
162 | if (err) | 218 | if (err) |
163 | goto out; | 219 | goto out; |
164 | 220 | ||
221 | out_cancel: | ||
165 | spin_lock(&c->cs_lock); | 222 | spin_lock(&c->cs_lock); |
166 | c->cmt_state = COMMIT_RESTING; | 223 | c->cmt_state = COMMIT_RESTING; |
167 | wake_up(&c->cmt_wq); | 224 | wake_up(&c->cmt_wq); |
168 | dbg_cmt("commit end"); | 225 | dbg_cmt("commit end"); |
169 | spin_unlock(&c->cs_lock); | 226 | spin_unlock(&c->cs_lock); |
170 | |||
171 | return 0; | 227 | return 0; |
172 | 228 | ||
173 | out_up: | 229 | out_up: |