diff options
Diffstat (limited to 'fs/ext4/file.c')
-rw-r--r-- | fs/ext4/file.c | 121 |
1 files changed, 98 insertions, 23 deletions
diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 782eecb57e43..3b0e3bdaabfc 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c | |||
@@ -90,11 +90,91 @@ ext4_unaligned_aio(struct inode *inode, const struct iovec *iov, | |||
90 | } | 90 | } |
91 | 91 | ||
92 | static ssize_t | 92 | static ssize_t |
93 | ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov, | ||
94 | unsigned long nr_segs, loff_t pos) | ||
95 | { | ||
96 | struct file *file = iocb->ki_filp; | ||
97 | struct inode *inode = file->f_mapping->host; | ||
98 | struct blk_plug plug; | ||
99 | int unaligned_aio = 0; | ||
100 | ssize_t ret; | ||
101 | int overwrite = 0; | ||
102 | size_t length = iov_length(iov, nr_segs); | ||
103 | |||
104 | if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) && | ||
105 | !is_sync_kiocb(iocb)) | ||
106 | unaligned_aio = ext4_unaligned_aio(inode, iov, nr_segs, pos); | ||
107 | |||
108 | /* Unaligned direct AIO must be serialized; see comment above */ | ||
109 | if (unaligned_aio) { | ||
110 | static unsigned long unaligned_warn_time; | ||
111 | |||
112 | /* Warn about this once per day */ | ||
113 | if (printk_timed_ratelimit(&unaligned_warn_time, 60*60*24*HZ)) | ||
114 | ext4_msg(inode->i_sb, KERN_WARNING, | ||
115 | "Unaligned AIO/DIO on inode %ld by %s; " | ||
116 | "performance will be poor.", | ||
117 | inode->i_ino, current->comm); | ||
118 | mutex_lock(ext4_aio_mutex(inode)); | ||
119 | ext4_aiodio_wait(inode); | ||
120 | } | ||
121 | |||
122 | BUG_ON(iocb->ki_pos != pos); | ||
123 | |||
124 | mutex_lock(&inode->i_mutex); | ||
125 | blk_start_plug(&plug); | ||
126 | |||
127 | iocb->private = &overwrite; | ||
128 | |||
129 | /* check whether we do a DIO overwrite or not */ | ||
130 | if (ext4_should_dioread_nolock(inode) && !unaligned_aio && | ||
131 | !file->f_mapping->nrpages && pos + length <= i_size_read(inode)) { | ||
132 | struct ext4_map_blocks map; | ||
133 | unsigned int blkbits = inode->i_blkbits; | ||
134 | int err, len; | ||
135 | |||
136 | map.m_lblk = pos >> blkbits; | ||
137 | map.m_len = (EXT4_BLOCK_ALIGN(pos + length, blkbits) >> blkbits) | ||
138 | - map.m_lblk; | ||
139 | len = map.m_len; | ||
140 | |||
141 | err = ext4_map_blocks(NULL, inode, &map, 0); | ||
142 | /* | ||
143 | * 'err==len' means that all of blocks has been preallocated no | ||
144 | * matter they are initialized or not. For excluding | ||
145 | * uninitialized extents, we need to check m_flags. There are | ||
146 | * two conditions that indicate for initialized extents. | ||
147 | * 1) If we hit extent cache, EXT4_MAP_MAPPED flag is returned; | ||
148 | * 2) If we do a real lookup, non-flags are returned. | ||
149 | * So we should check these two conditions. | ||
150 | */ | ||
151 | if (err == len && (map.m_flags & EXT4_MAP_MAPPED)) | ||
152 | overwrite = 1; | ||
153 | } | ||
154 | |||
155 | ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos); | ||
156 | mutex_unlock(&inode->i_mutex); | ||
157 | |||
158 | if (ret > 0 || ret == -EIOCBQUEUED) { | ||
159 | ssize_t err; | ||
160 | |||
161 | err = generic_write_sync(file, pos, ret); | ||
162 | if (err < 0 && ret > 0) | ||
163 | ret = err; | ||
164 | } | ||
165 | blk_finish_plug(&plug); | ||
166 | |||
167 | if (unaligned_aio) | ||
168 | mutex_unlock(ext4_aio_mutex(inode)); | ||
169 | |||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | static ssize_t | ||
93 | ext4_file_write(struct kiocb *iocb, const struct iovec *iov, | 174 | ext4_file_write(struct kiocb *iocb, const struct iovec *iov, |
94 | unsigned long nr_segs, loff_t pos) | 175 | unsigned long nr_segs, loff_t pos) |
95 | { | 176 | { |
96 | struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; | 177 | struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; |
97 | int unaligned_aio = 0; | ||
98 | ssize_t ret; | 178 | ssize_t ret; |
99 | 179 | ||
100 | /* | 180 | /* |
@@ -114,29 +194,12 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
114 | nr_segs = iov_shorten((struct iovec *)iov, nr_segs, | 194 | nr_segs = iov_shorten((struct iovec *)iov, nr_segs, |
115 | sbi->s_bitmap_maxbytes - pos); | 195 | sbi->s_bitmap_maxbytes - pos); |
116 | } | 196 | } |
117 | } else if (unlikely((iocb->ki_filp->f_flags & O_DIRECT) && | ||
118 | !is_sync_kiocb(iocb))) { | ||
119 | unaligned_aio = ext4_unaligned_aio(inode, iov, nr_segs, pos); | ||
120 | } | 197 | } |
121 | 198 | ||
122 | /* Unaligned direct AIO must be serialized; see comment above */ | 199 | if (unlikely(iocb->ki_filp->f_flags & O_DIRECT)) |
123 | if (unaligned_aio) { | 200 | ret = ext4_file_dio_write(iocb, iov, nr_segs, pos); |
124 | static unsigned long unaligned_warn_time; | 201 | else |
125 | 202 | ret = generic_file_aio_write(iocb, iov, nr_segs, pos); | |
126 | /* Warn about this once per day */ | ||
127 | if (printk_timed_ratelimit(&unaligned_warn_time, 60*60*24*HZ)) | ||
128 | ext4_msg(inode->i_sb, KERN_WARNING, | ||
129 | "Unaligned AIO/DIO on inode %ld by %s; " | ||
130 | "performance will be poor.", | ||
131 | inode->i_ino, current->comm); | ||
132 | mutex_lock(ext4_aio_mutex(inode)); | ||
133 | ext4_aiodio_wait(inode); | ||
134 | } | ||
135 | |||
136 | ret = generic_file_aio_write(iocb, iov, nr_segs, pos); | ||
137 | |||
138 | if (unaligned_aio) | ||
139 | mutex_unlock(ext4_aio_mutex(inode)); | ||
140 | 203 | ||
141 | return ret; | 204 | return ret; |
142 | } | 205 | } |
@@ -181,9 +244,21 @@ static int ext4_file_open(struct inode * inode, struct file * filp) | |||
181 | path.dentry = mnt->mnt_root; | 244 | path.dentry = mnt->mnt_root; |
182 | cp = d_path(&path, buf, sizeof(buf)); | 245 | cp = d_path(&path, buf, sizeof(buf)); |
183 | if (!IS_ERR(cp)) { | 246 | if (!IS_ERR(cp)) { |
247 | handle_t *handle; | ||
248 | int err; | ||
249 | |||
250 | handle = ext4_journal_start_sb(sb, 1); | ||
251 | if (IS_ERR(handle)) | ||
252 | return PTR_ERR(handle); | ||
253 | err = ext4_journal_get_write_access(handle, sbi->s_sbh); | ||
254 | if (err) { | ||
255 | ext4_journal_stop(handle); | ||
256 | return err; | ||
257 | } | ||
184 | strlcpy(sbi->s_es->s_last_mounted, cp, | 258 | strlcpy(sbi->s_es->s_last_mounted, cp, |
185 | sizeof(sbi->s_es->s_last_mounted)); | 259 | sizeof(sbi->s_es->s_last_mounted)); |
186 | ext4_mark_super_dirty(sb); | 260 | ext4_handle_dirty_super(handle, sb); |
261 | ext4_journal_stop(handle); | ||
187 | } | 262 | } |
188 | } | 263 | } |
189 | /* | 264 | /* |