diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2006-07-25 17:24:12 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2006-07-25 17:24:12 -0400 |
commit | a9e5f4d0780ec9cda7a70b08294d7718431b62a1 (patch) | |
tree | f21fa310b6ea63f49cf6d710fcd84fe8d66282f3 /fs/gfs2/ops_file.c | |
parent | 52f341cf75d2da84811127582616984eb0602360 (diff) |
[GFS2] Alter direct I/O path
As per comments received, alter the GFS2 direct I/O path so that
it uses the standard read functions "out of the box". Needs a
small change to one of the VFS functions. This reduces the size
of the code quite a lot and also removes the need for one new export.
Some more work remains to be done, but this is the bones of the
thing.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/ops_file.c')
-rw-r--r-- | fs/gfs2/ops_file.c | 170 |
1 files changed, 3 insertions, 167 deletions
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 6764ca69bc52..d13e04e8a96a 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c | |||
@@ -148,170 +148,6 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin) | |||
148 | return error; | 148 | return error; |
149 | } | 149 | } |
150 | 150 | ||
151 | |||
152 | static ssize_t gfs2_direct_IO_read(struct kiocb *iocb, const struct iovec *iov, | ||
153 | loff_t offset, unsigned long nr_segs) | ||
154 | { | ||
155 | struct file *file = iocb->ki_filp; | ||
156 | struct address_space *mapping = file->f_mapping; | ||
157 | ssize_t retval; | ||
158 | |||
159 | retval = filemap_write_and_wait(mapping); | ||
160 | if (retval == 0) { | ||
161 | retval = mapping->a_ops->direct_IO(READ, iocb, iov, offset, | ||
162 | nr_segs); | ||
163 | } | ||
164 | return retval; | ||
165 | } | ||
166 | |||
167 | /** | ||
168 | * __gfs2_file_aio_read - The main GFS2 read function | ||
169 | * | ||
170 | * N.B. This is almost, but not quite the same as __generic_file_aio_read() | ||
171 | * the important subtle different being that inode->i_size isn't valid | ||
172 | * unless we are holding a lock, and we do this _only_ on the O_DIRECT | ||
173 | * path since otherwise locking is done entirely at the page cache | ||
174 | * layer. | ||
175 | */ | ||
176 | static ssize_t __gfs2_file_aio_read(struct kiocb *iocb, | ||
177 | const struct iovec *iov, | ||
178 | unsigned long nr_segs, loff_t *ppos) | ||
179 | { | ||
180 | struct file *filp = iocb->ki_filp; | ||
181 | struct gfs2_inode *ip = GFS2_I(filp->f_mapping->host); | ||
182 | struct gfs2_holder gh; | ||
183 | ssize_t retval; | ||
184 | unsigned long seg; | ||
185 | size_t count; | ||
186 | |||
187 | count = 0; | ||
188 | for (seg = 0; seg < nr_segs; seg++) { | ||
189 | const struct iovec *iv = &iov[seg]; | ||
190 | |||
191 | /* | ||
192 | * If any segment has a negative length, or the cumulative | ||
193 | * length ever wraps negative then return -EINVAL. | ||
194 | */ | ||
195 | count += iv->iov_len; | ||
196 | if (unlikely((ssize_t)(count|iv->iov_len) < 0)) | ||
197 | return -EINVAL; | ||
198 | if (access_ok(VERIFY_WRITE, iv->iov_base, iv->iov_len)) | ||
199 | continue; | ||
200 | if (seg == 0) | ||
201 | return -EFAULT; | ||
202 | nr_segs = seg; | ||
203 | count -= iv->iov_len; /* This segment is no good */ | ||
204 | break; | ||
205 | } | ||
206 | |||
207 | /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ | ||
208 | if (filp->f_flags & O_DIRECT) { | ||
209 | loff_t pos = *ppos, size; | ||
210 | struct address_space *mapping; | ||
211 | struct inode *inode; | ||
212 | |||
213 | mapping = filp->f_mapping; | ||
214 | inode = mapping->host; | ||
215 | retval = 0; | ||
216 | if (!count) | ||
217 | goto out; /* skip atime */ | ||
218 | |||
219 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); | ||
220 | retval = gfs2_glock_nq_m_atime(1, &gh); | ||
221 | if (retval) | ||
222 | goto out; | ||
223 | if (gfs2_is_stuffed(ip)) { | ||
224 | gfs2_glock_dq_m(1, &gh); | ||
225 | gfs2_holder_uninit(&gh); | ||
226 | goto fallback_to_normal; | ||
227 | } | ||
228 | size = i_size_read(inode); | ||
229 | if (pos < size) { | ||
230 | retval = gfs2_direct_IO_read(iocb, iov, pos, nr_segs); | ||
231 | if (retval > 0 && !is_sync_kiocb(iocb)) | ||
232 | retval = -EIOCBQUEUED; | ||
233 | if (retval > 0) | ||
234 | *ppos = pos + retval; | ||
235 | } | ||
236 | file_accessed(filp); | ||
237 | gfs2_glock_dq_m(1, &gh); | ||
238 | gfs2_holder_uninit(&gh); | ||
239 | goto out; | ||
240 | } | ||
241 | |||
242 | fallback_to_normal: | ||
243 | retval = 0; | ||
244 | if (count) { | ||
245 | for (seg = 0; seg < nr_segs; seg++) { | ||
246 | read_descriptor_t desc; | ||
247 | |||
248 | desc.written = 0; | ||
249 | desc.arg.buf = iov[seg].iov_base; | ||
250 | desc.count = iov[seg].iov_len; | ||
251 | if (desc.count == 0) | ||
252 | continue; | ||
253 | desc.error = 0; | ||
254 | do_generic_file_read(filp,ppos,&desc,file_read_actor); | ||
255 | retval += desc.written; | ||
256 | if (desc.error) { | ||
257 | retval = retval ?: desc.error; | ||
258 | break; | ||
259 | } | ||
260 | } | ||
261 | } | ||
262 | out: | ||
263 | return retval; | ||
264 | } | ||
265 | |||
266 | /** | ||
267 | * gfs2_read - Read bytes from a file | ||
268 | * @file: The file to read from | ||
269 | * @buf: The buffer to copy into | ||
270 | * @size: The amount of data requested | ||
271 | * @offset: The current file offset | ||
272 | * | ||
273 | * Outputs: Offset - updated according to number of bytes read | ||
274 | * | ||
275 | * Returns: The number of bytes read, errno on failure | ||
276 | */ | ||
277 | |||
278 | static ssize_t gfs2_read(struct file *filp, char __user *buf, size_t size, | ||
279 | loff_t *offset) | ||
280 | { | ||
281 | struct iovec local_iov = { .iov_base = buf, .iov_len = size }; | ||
282 | struct kiocb kiocb; | ||
283 | ssize_t ret; | ||
284 | |||
285 | init_sync_kiocb(&kiocb, filp); | ||
286 | ret = __gfs2_file_aio_read(&kiocb, &local_iov, 1, offset); | ||
287 | if (-EIOCBQUEUED == ret) | ||
288 | ret = wait_on_sync_kiocb(&kiocb); | ||
289 | return ret; | ||
290 | } | ||
291 | |||
292 | static ssize_t gfs2_file_readv(struct file *filp, const struct iovec *iov, | ||
293 | unsigned long nr_segs, loff_t *ppos) | ||
294 | { | ||
295 | struct kiocb kiocb; | ||
296 | ssize_t ret; | ||
297 | |||
298 | init_sync_kiocb(&kiocb, filp); | ||
299 | ret = __gfs2_file_aio_read(&kiocb, iov, nr_segs, ppos); | ||
300 | if (-EIOCBQUEUED == ret) | ||
301 | ret = wait_on_sync_kiocb(&kiocb); | ||
302 | return ret; | ||
303 | } | ||
304 | |||
305 | static ssize_t gfs2_file_aio_read(struct kiocb *iocb, char __user *buf, | ||
306 | size_t count, loff_t pos) | ||
307 | { | ||
308 | struct iovec local_iov = { .iov_base = buf, .iov_len = count }; | ||
309 | |||
310 | BUG_ON(iocb->ki_pos != pos); | ||
311 | return __gfs2_file_aio_read(iocb, &local_iov, 1, &iocb->ki_pos); | ||
312 | } | ||
313 | |||
314 | |||
315 | /** | 151 | /** |
316 | * filldir_reg_func - Report a directory entry to the caller of gfs2_dir_read() | 152 | * filldir_reg_func - Report a directory entry to the caller of gfs2_dir_read() |
317 | * @opaque: opaque data used by the function | 153 | * @opaque: opaque data used by the function |
@@ -949,9 +785,9 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) | |||
949 | 785 | ||
950 | const struct file_operations gfs2_file_fops = { | 786 | const struct file_operations gfs2_file_fops = { |
951 | .llseek = gfs2_llseek, | 787 | .llseek = gfs2_llseek, |
952 | .read = gfs2_read, | 788 | .read = generic_file_read, |
953 | .readv = gfs2_file_readv, | 789 | .readv = generic_file_readv, |
954 | .aio_read = gfs2_file_aio_read, | 790 | .aio_read = generic_file_aio_read, |
955 | .write = generic_file_write, | 791 | .write = generic_file_write, |
956 | .writev = generic_file_writev, | 792 | .writev = generic_file_writev, |
957 | .aio_write = generic_file_aio_write, | 793 | .aio_write = generic_file_aio_write, |