summaryrefslogtreecommitdiff
path: root/fs/ext4/ext4_jbd2.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext4/ext4_jbd2.c')
-rw-r--r--fs/ext4/ext4_jbd2.c25
1 files changed, 21 insertions, 4 deletions
diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c
index b4dacd1a89e7..53ddedb52a6f 100644
--- a/fs/ext4/ext4_jbd2.c
+++ b/fs/ext4/ext4_jbd2.c
@@ -358,6 +358,21 @@ int __ext4_journal_get_create_access(const char *where, unsigned int line,
return 0;
}
+static void ext4_inode_attach_mmb(struct inode *inode)
+{
+ struct mapping_metadata_bhs *mmb;
+
+ /*
+ * It's difficult to handle failure when marking buffer dirty without
+ * leaving filesystem corrupted
+ */
+ mmb = kmalloc_obj(*mmb, GFP_NOFS | __GFP_NOFAIL | __GFP_ACCOUNT);
+ mmb_init(mmb, &inode->i_data);
+ /* Someone swapped another mmb before us? */
+ if (cmpxchg(&EXT4_I(inode)->i_metadata_bhs, NULL, mmb))
+ kfree(mmb);
+}
+
int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
handle_t *handle, struct inode *inode,
struct buffer_head *bh)
@@ -397,11 +412,13 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
err);
}
} else {
- if (inode)
- mmb_mark_buffer_dirty(bh,
- &EXT4_I(inode)->i_metadata_bhs);
- else
+ if (inode) {
+ if (!ext4_i_metadata_bhs(inode))
+ ext4_inode_attach_mmb(inode);
+ mmb_mark_buffer_dirty(bh, ext4_i_metadata_bhs(inode));
+ } else {
mark_buffer_dirty(bh);
+ }
if (inode && inode_needs_sync(inode)) {
sync_dirty_buffer(bh);
if (buffer_req(bh) && !buffer_uptodate(bh)) {