diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /fs/ext4/file.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'fs/ext4/file.c')
-rw-r--r-- | fs/ext4/file.c | 129 |
1 files changed, 125 insertions, 4 deletions
diff --git a/fs/ext4/file.c b/fs/ext4/file.c index ee92b66d4558..2c0972322009 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c | |||
@@ -55,11 +55,47 @@ static int ext4_release_file(struct inode *inode, struct file *filp) | |||
55 | return 0; | 55 | return 0; |
56 | } | 56 | } |
57 | 57 | ||
58 | static void ext4_aiodio_wait(struct inode *inode) | ||
59 | { | ||
60 | wait_queue_head_t *wq = ext4_ioend_wq(inode); | ||
61 | |||
62 | wait_event(*wq, (atomic_read(&EXT4_I(inode)->i_aiodio_unwritten) == 0)); | ||
63 | } | ||
64 | |||
65 | /* | ||
66 | * This tests whether the IO in question is block-aligned or not. | ||
67 | * Ext4 utilizes unwritten extents when hole-filling during direct IO, and they | ||
68 | * are converted to written only after the IO is complete. Until they are | ||
69 | * mapped, these blocks appear as holes, so dio_zero_block() will assume that | ||
70 | * it needs to zero out portions of the start and/or end block. If 2 AIO | ||
71 | * threads are at work on the same unwritten block, they must be synchronized | ||
72 | * or one thread will zero the other's data, causing corruption. | ||
73 | */ | ||
74 | static int | ||
75 | ext4_unaligned_aio(struct inode *inode, const struct iovec *iov, | ||
76 | unsigned long nr_segs, loff_t pos) | ||
77 | { | ||
78 | struct super_block *sb = inode->i_sb; | ||
79 | int blockmask = sb->s_blocksize - 1; | ||
80 | size_t count = iov_length(iov, nr_segs); | ||
81 | loff_t final_size = pos + count; | ||
82 | |||
83 | if (pos >= inode->i_size) | ||
84 | return 0; | ||
85 | |||
86 | if ((pos & blockmask) || (final_size & blockmask)) | ||
87 | return 1; | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
58 | static ssize_t | 92 | static ssize_t |
59 | ext4_file_write(struct kiocb *iocb, const struct iovec *iov, | 93 | ext4_file_write(struct kiocb *iocb, const struct iovec *iov, |
60 | unsigned long nr_segs, loff_t pos) | 94 | unsigned long nr_segs, loff_t pos) |
61 | { | 95 | { |
62 | struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; | 96 | struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; |
97 | int unaligned_aio = 0; | ||
98 | int ret; | ||
63 | 99 | ||
64 | /* | 100 | /* |
65 | * If we have encountered a bitmap-format file, the size limit | 101 | * If we have encountered a bitmap-format file, the size limit |
@@ -78,9 +114,31 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
78 | nr_segs = iov_shorten((struct iovec *)iov, nr_segs, | 114 | nr_segs = iov_shorten((struct iovec *)iov, nr_segs, |
79 | sbi->s_bitmap_maxbytes - pos); | 115 | sbi->s_bitmap_maxbytes - pos); |
80 | } | 116 | } |
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 | } | ||
121 | |||
122 | /* Unaligned direct AIO must be serialized; see comment above */ | ||
123 | if (unaligned_aio) { | ||
124 | static unsigned long unaligned_warn_time; | ||
125 | |||
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); | ||
81 | } | 134 | } |
82 | 135 | ||
83 | return generic_file_aio_write(iocb, iov, nr_segs, pos); | 136 | ret = generic_file_aio_write(iocb, iov, nr_segs, pos); |
137 | |||
138 | if (unaligned_aio) | ||
139 | mutex_unlock(ext4_aio_mutex(inode)); | ||
140 | |||
141 | return ret; | ||
84 | } | 142 | } |
85 | 143 | ||
86 | static const struct vm_operations_struct ext4_file_vm_ops = { | 144 | static const struct vm_operations_struct ext4_file_vm_ops = { |
@@ -104,6 +162,7 @@ static int ext4_file_open(struct inode * inode, struct file * filp) | |||
104 | { | 162 | { |
105 | struct super_block *sb = inode->i_sb; | 163 | struct super_block *sb = inode->i_sb; |
106 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); | 164 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); |
165 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
107 | struct vfsmount *mnt = filp->f_path.mnt; | 166 | struct vfsmount *mnt = filp->f_path.mnt; |
108 | struct path path; | 167 | struct path path; |
109 | char buf[64], *cp; | 168 | char buf[64], *cp; |
@@ -127,11 +186,74 @@ static int ext4_file_open(struct inode * inode, struct file * filp) | |||
127 | ext4_mark_super_dirty(sb); | 186 | ext4_mark_super_dirty(sb); |
128 | } | 187 | } |
129 | } | 188 | } |
189 | /* | ||
190 | * Set up the jbd2_inode if we are opening the inode for | ||
191 | * writing and the journal is present | ||
192 | */ | ||
193 | if (sbi->s_journal && !ei->jinode && (filp->f_mode & FMODE_WRITE)) { | ||
194 | struct jbd2_inode *jinode = jbd2_alloc_inode(GFP_KERNEL); | ||
195 | |||
196 | spin_lock(&inode->i_lock); | ||
197 | if (!ei->jinode) { | ||
198 | if (!jinode) { | ||
199 | spin_unlock(&inode->i_lock); | ||
200 | return -ENOMEM; | ||
201 | } | ||
202 | ei->jinode = jinode; | ||
203 | jbd2_journal_init_jbd_inode(ei->jinode, inode); | ||
204 | jinode = NULL; | ||
205 | } | ||
206 | spin_unlock(&inode->i_lock); | ||
207 | if (unlikely(jinode != NULL)) | ||
208 | jbd2_free_inode(jinode); | ||
209 | } | ||
130 | return dquot_file_open(inode, filp); | 210 | return dquot_file_open(inode, filp); |
131 | } | 211 | } |
132 | 212 | ||
213 | /* | ||
214 | * ext4_llseek() copied from generic_file_llseek() to handle both | ||
215 | * block-mapped and extent-mapped maxbytes values. This should | ||
216 | * otherwise be identical with generic_file_llseek(). | ||
217 | */ | ||
218 | loff_t ext4_llseek(struct file *file, loff_t offset, int origin) | ||
219 | { | ||
220 | struct inode *inode = file->f_mapping->host; | ||
221 | loff_t maxbytes; | ||
222 | |||
223 | if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) | ||
224 | maxbytes = EXT4_SB(inode->i_sb)->s_bitmap_maxbytes; | ||
225 | else | ||
226 | maxbytes = inode->i_sb->s_maxbytes; | ||
227 | mutex_lock(&inode->i_mutex); | ||
228 | switch (origin) { | ||
229 | case SEEK_END: | ||
230 | offset += inode->i_size; | ||
231 | break; | ||
232 | case SEEK_CUR: | ||
233 | if (offset == 0) { | ||
234 | mutex_unlock(&inode->i_mutex); | ||
235 | return file->f_pos; | ||
236 | } | ||
237 | offset += file->f_pos; | ||
238 | break; | ||
239 | } | ||
240 | |||
241 | if (offset < 0 || offset > maxbytes) { | ||
242 | mutex_unlock(&inode->i_mutex); | ||
243 | return -EINVAL; | ||
244 | } | ||
245 | |||
246 | if (offset != file->f_pos) { | ||
247 | file->f_pos = offset; | ||
248 | file->f_version = 0; | ||
249 | } | ||
250 | mutex_unlock(&inode->i_mutex); | ||
251 | |||
252 | return offset; | ||
253 | } | ||
254 | |||
133 | const struct file_operations ext4_file_operations = { | 255 | const struct file_operations ext4_file_operations = { |
134 | .llseek = generic_file_llseek, | 256 | .llseek = ext4_llseek, |
135 | .read = do_sync_read, | 257 | .read = do_sync_read, |
136 | .write = do_sync_write, | 258 | .write = do_sync_write, |
137 | .aio_read = generic_file_aio_read, | 259 | .aio_read = generic_file_aio_read, |
@@ -146,10 +268,10 @@ const struct file_operations ext4_file_operations = { | |||
146 | .fsync = ext4_sync_file, | 268 | .fsync = ext4_sync_file, |
147 | .splice_read = generic_file_splice_read, | 269 | .splice_read = generic_file_splice_read, |
148 | .splice_write = generic_file_splice_write, | 270 | .splice_write = generic_file_splice_write, |
271 | .fallocate = ext4_fallocate, | ||
149 | }; | 272 | }; |
150 | 273 | ||
151 | const struct inode_operations ext4_file_inode_operations = { | 274 | const struct inode_operations ext4_file_inode_operations = { |
152 | .truncate = ext4_truncate, | ||
153 | .setattr = ext4_setattr, | 275 | .setattr = ext4_setattr, |
154 | .getattr = ext4_getattr, | 276 | .getattr = ext4_getattr, |
155 | #ifdef CONFIG_EXT4_FS_XATTR | 277 | #ifdef CONFIG_EXT4_FS_XATTR |
@@ -159,7 +281,6 @@ const struct inode_operations ext4_file_inode_operations = { | |||
159 | .removexattr = generic_removexattr, | 281 | .removexattr = generic_removexattr, |
160 | #endif | 282 | #endif |
161 | .check_acl = ext4_check_acl, | 283 | .check_acl = ext4_check_acl, |
162 | .fallocate = ext4_fallocate, | ||
163 | .fiemap = ext4_fiemap, | 284 | .fiemap = ext4_fiemap, |
164 | }; | 285 | }; |
165 | 286 | ||