Blame view

fs/ext4/fsync.c 5.02 KB
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
1
  /*
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
2
   *  linux/fs/ext4/fsync.c
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
3
4
5
6
7
8
9
10
11
   *
   *  Copyright (C) 1993  Stephen Tweedie (sct@redhat.com)
   *  from
   *  Copyright (C) 1992  Remy Card (card@masi.ibp.fr)
   *                      Laboratoire MASI - Institut Blaise Pascal
   *                      Universite Pierre et Marie Curie (Paris VI)
   *  from
   *  linux/fs/minix/truncate.c   Copyright (C) 1991, 1992  Linus Torvalds
   *
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
12
   *  ext4fs fsync primitive
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
   *
   *  Big-endian to little-endian byte-swapping/bitmaps by
   *        David S. Miller (davem@caip.rutgers.edu), 1995
   *
   *  Removed unnecessary code duplication for little endian machines
   *  and excessive __inline__s.
   *        Andi Kleen, 1997
   *
   * Major simplications and cleanup - we only need to do the metadata, because
   * we can depend on generic_block_fdatasync() to sync the data blocks.
   */
  
  #include <linux/time.h>
  #include <linux/fs.h>
  #include <linux/sched.h>
  #include <linux/writeback.h>
dab291af8   Mingming Cao   [PATCH] jbd2: ena...
29
  #include <linux/jbd2.h>
d755fb384   Eric Sandeen   ext4: call blkdev...
30
  #include <linux/blkdev.h>
9bffad1ed   Theodore Ts'o   ext4: convert ins...
31

3dcf54515   Christoph Hellwig   ext4: move header...
32
33
  #include "ext4.h"
  #include "ext4_jbd2.h"
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
34

9bffad1ed   Theodore Ts'o   ext4: convert ins...
35
  #include <trace/events/ext4.h>
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
36
  /*
14ece1028   Frank Mayhar   ext4: Make fsync ...
37
38
39
40
41
42
43
   * If we're not journaling and this is a just-created file, we have to
   * sync our parent directory (if it was freshly created) since
   * otherwise it will only be written by writeback, leaving a huge
   * window during which a crash may lose the file.  This may apply for
   * the parent directory's parent as well, and so on recursively, if
   * they are also freshly created.
   */
0893ed458   Curt Wohlgemuth   ext4: sync the di...
44
  static int ext4_sync_parent(struct inode *inode)
14ece1028   Frank Mayhar   ext4: Make fsync ...
45
46
  {
  	struct dentry *dentry = NULL;
d59729f4e   Theodore Ts'o   ext4: fix races i...
47
  	struct inode *next;
0893ed458   Curt Wohlgemuth   ext4: sync the di...
48
  	int ret = 0;
14ece1028   Frank Mayhar   ext4: Make fsync ...
49

d59729f4e   Theodore Ts'o   ext4: fix races i...
50
51
52
53
  	if (!ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY))
  		return 0;
  	inode = igrab(inode);
  	while (ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) {
14ece1028   Frank Mayhar   ext4: Make fsync ...
54
  		ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY);
9f713878f   Al Viro   ext4: get rid of ...
55
  		dentry = d_find_any_alias(inode);
d59729f4e   Theodore Ts'o   ext4: fix races i...
56
  		if (!dentry)
14ece1028   Frank Mayhar   ext4: Make fsync ...
57
  			break;
d59729f4e   Theodore Ts'o   ext4: fix races i...
58
59
60
61
62
63
  		next = igrab(dentry->d_parent->d_inode);
  		dput(dentry);
  		if (!next)
  			break;
  		iput(inode);
  		inode = next;
0893ed458   Curt Wohlgemuth   ext4: sync the di...
64
65
66
  		ret = sync_mapping_buffers(inode->i_mapping);
  		if (ret)
  			break;
64744e03c   Guo Chao   ext4: use sync_in...
67
  		ret = sync_inode_metadata(inode, 1);
0893ed458   Curt Wohlgemuth   ext4: sync the di...
68
69
  		if (ret)
  			break;
14ece1028   Frank Mayhar   ext4: Make fsync ...
70
  	}
d59729f4e   Theodore Ts'o   ext4: fix races i...
71
  	iput(inode);
0893ed458   Curt Wohlgemuth   ext4: sync the di...
72
  	return ret;
14ece1028   Frank Mayhar   ext4: Make fsync ...
73
  }
02c24a821   Josef Bacik   fs: push i_mutex ...
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  /**
   * __sync_file - generic_file_fsync without the locking and filemap_write
   * @inode:	inode to sync
   * @datasync:	only sync essential metadata if true
   *
   * This is just generic_file_fsync without the locking.  This is needed for
   * nojournal mode to make sure this inodes data/metadata makes it to disk
   * properly.  The i_mutex should be held already.
   */
  static int __sync_inode(struct inode *inode, int datasync)
  {
  	int err;
  	int ret;
  
  	ret = sync_mapping_buffers(inode->i_mapping);
  	if (!(inode->i_state & I_DIRTY))
  		return ret;
  	if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
  		return ret;
  
  	err = sync_inode_metadata(inode, 1);
  	if (ret == 0)
  		ret = err;
  	return ret;
  }
14ece1028   Frank Mayhar   ext4: Make fsync ...
99
  /*
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
100
   * akpm: A new design for ext4_sync_file().
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
101
102
103
104
105
106
107
108
   *
   * This is only called from sys_fsync(), sys_fdatasync() and sys_msync().
   * There cannot be a transaction open by this task.
   * Another task could have dirtied this inode.  Its data can be in any
   * state in the journalling system.
   *
   * What we do is just kick off a commit and wait on it.  This will snapshot the
   * inode to disk.
8d5d02e6b   Mingming Cao   ext4: async direc...
109
110
   *
   * i_mutex lock is held when entering and exiting this function
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
111
   */
02c24a821   Josef Bacik   fs: push i_mutex ...
112
  int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
113
  {
7ea808591   Christoph Hellwig   drop unused dentr...
114
  	struct inode *inode = file->f_mapping->host;
b436b9bef   Jan Kara   ext4: Wait for pr...
115
  	struct ext4_inode_info *ei = EXT4_I(inode);
d755fb384   Eric Sandeen   ext4: call blkdev...
116
  	journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;
a4a39040e   Theodore Ts'o   ext4: check retur...
117
  	int ret, err;
b436b9bef   Jan Kara   ext4: Wait for pr...
118
  	tid_t commit_tid;
93628ffb9   Jan Kara   ext4: fix waiting...
119
  	bool needs_barrier = false;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
120

ac39849dd   Aneesh Kumar K.V   ext4: sparse fixes
121
  	J_ASSERT(ext4_journal_current_handle() == NULL);
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
122

0562e0bad   Jiaying Zhang   ext4: add more tr...
123
  	trace_ext4_sync_file_enter(file, datasync);
ede86cc47   Theodore Ts'o   ext4: Add debuggi...
124

02c24a821   Josef Bacik   fs: push i_mutex ...
125
126
127
128
  	ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
  	if (ret)
  		return ret;
  	mutex_lock(&inode->i_mutex);
b436b9bef   Jan Kara   ext4: Wait for pr...
129
  	if (inode->i_sb->s_flags & MS_RDONLY)
02c24a821   Josef Bacik   fs: push i_mutex ...
130
  		goto out;
b436b9bef   Jan Kara   ext4: Wait for pr...
131

c278531d3   Dmitry Monakhov   ext4: fix ext4_fl...
132
  	ret = ext4_flush_unwritten_io(inode);
8d5d02e6b   Mingming Cao   ext4: async direc...
133
  	if (ret < 0)
0562e0bad   Jiaying Zhang   ext4: add more tr...
134
  		goto out;
60e6679e2   Theodore Ts'o   ext4: Drop whites...
135

14ece1028   Frank Mayhar   ext4: Make fsync ...
136
  	if (!journal) {
02c24a821   Josef Bacik   fs: push i_mutex ...
137
  		ret = __sync_inode(inode, datasync);
b3d9b7a3c   Al Viro   vfs: switch i_den...
138
  		if (!ret && !hlist_empty(&inode->i_dentry))
0893ed458   Curt Wohlgemuth   ext4: sync the di...
139
  			ret = ext4_sync_parent(inode);
0562e0bad   Jiaying Zhang   ext4: add more tr...
140
  		goto out;
14ece1028   Frank Mayhar   ext4: Make fsync ...
141
  	}
b436b9bef   Jan Kara   ext4: Wait for pr...
142

ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
143
  	/*
b436b9bef   Jan Kara   ext4: Wait for pr...
144
  	 * data=writeback,ordered:
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
145
  	 *  The caller's filemap_fdatawrite()/wait will sync the data.
b436b9bef   Jan Kara   ext4: Wait for pr...
146
147
  	 *  Metadata is in the journal, we wait for proper transaction to
  	 *  commit here.
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
148
149
150
  	 *
  	 * data=journal:
  	 *  filemap_fdatawrite won't do anything (the buffers are clean).
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
151
  	 *  ext4_force_commit will write the file data into the journal and
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
152
153
154
155
156
  	 *  will wait on that.
  	 *  filemap_fdatawait() will encounter a ton of newly-dirtied pages
  	 *  (they were dirtied by commit).  But that's OK - the blocks are
  	 *  safe in-journal, which is all fsync() needs to ensure.
  	 */
0562e0bad   Jiaying Zhang   ext4: add more tr...
157
158
159
160
  	if (ext4_should_journal_data(inode)) {
  		ret = ext4_force_commit(inode->i_sb);
  		goto out;
  	}
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
161

b436b9bef   Jan Kara   ext4: Wait for pr...
162
  	commit_tid = datasync ? ei->i_datasync_tid : ei->i_sync_tid;
93628ffb9   Jan Kara   ext4: fix waiting...
163
164
165
166
167
  	if (journal->j_flags & JBD2_BARRIER &&
  	    !jbd2_trans_will_send_data_barrier(journal, commit_tid))
  		needs_barrier = true;
  	jbd2_log_start_commit(journal, commit_tid);
  	ret = jbd2_log_wait_commit(journal, commit_tid);
a4a39040e   Theodore Ts'o   ext4: check retur...
168
169
170
171
172
  	if (needs_barrier) {
  		err = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
  		if (!ret)
  			ret = err;
  	}
0562e0bad   Jiaying Zhang   ext4: add more tr...
173
   out:
02c24a821   Josef Bacik   fs: push i_mutex ...
174
  	mutex_unlock(&inode->i_mutex);
0562e0bad   Jiaying Zhang   ext4: add more tr...
175
  	trace_ext4_sync_file_exit(inode, ret);
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
176
177
  	return ret;
  }