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 6764ca69bc5..d13e04e8a96 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) return error; } - -static ssize_t gfs2_direct_IO_read(struct kiocb *iocb, const struct iovec *iov, - loff_t offset, unsigned long nr_segs) -{ - struct file *file = iocb->ki_filp; - struct address_space *mapping = file->f_mapping; - ssize_t retval; - - retval = filemap_write_and_wait(mapping); - if (retval == 0) { - retval = mapping->a_ops->direct_IO(READ, iocb, iov, offset, - nr_segs); - } - return retval; -} - -/** - * __gfs2_file_aio_read - The main GFS2 read function - * - * N.B. This is almost, but not quite the same as __generic_file_aio_read() - * the important subtle different being that inode->i_size isn't valid - * unless we are holding a lock, and we do this _only_ on the O_DIRECT - * path since otherwise locking is done entirely at the page cache - * layer. - */ -static ssize_t __gfs2_file_aio_read(struct kiocb *iocb, - const struct iovec *iov, - unsigned long nr_segs, loff_t *ppos) -{ - struct file *filp = iocb->ki_filp; - struct gfs2_inode *ip = GFS2_I(filp->f_mapping->host); - struct gfs2_holder gh; - ssize_t retval; - unsigned long seg; - size_t count; - - count = 0; - for (seg = 0; seg < nr_segs; seg++) { - const struct iovec *iv = &iov[seg]; - - /* - * If any segment has a negative length, or the cumulative - * length ever wraps negative then return -EINVAL. - */ - count += iv->iov_len; - if (unlikely((ssize_t)(count|iv->iov_len) < 0)) - return -EINVAL; - if (access_ok(VERIFY_WRITE, iv->iov_base, iv->iov_len)) - continue; - if (seg == 0) - return -EFAULT; - nr_segs = seg; - count -= iv->iov_len; /* This segment is no good */ - break; - } - - /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ - if (filp->f_flags & O_DIRECT) { - loff_t pos = *ppos, size; - struct address_space *mapping; - struct inode *inode; - - mapping = filp->f_mapping; - inode = mapping->host; - retval = 0; - if (!count) - goto out; /* skip atime */ - - gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); - retval = gfs2_glock_nq_m_atime(1, &gh); - if (retval) - goto out; - if (gfs2_is_stuffed(ip)) { - gfs2_glock_dq_m(1, &gh); - gfs2_holder_uninit(&gh); - goto fallback_to_normal; - } - size = i_size_read(inode); - if (pos < size) { - retval = gfs2_direct_IO_read(iocb, iov, pos, nr_segs); - if (retval > 0 && !is_sync_kiocb(iocb)) - retval = -EIOCBQUEUED; - if (retval > 0) - *ppos = pos + retval; - } - file_accessed(filp); - gfs2_glock_dq_m(1, &gh); - gfs2_holder_uninit(&gh); - goto out; - } - -fallback_to_normal: - retval = 0; - if (count) { - for (seg = 0; seg < nr_segs; seg++) { - read_descriptor_t desc; - - desc.written = 0; - desc.arg.buf = iov[seg].iov_base; - desc.count = iov[seg].iov_len; - if (desc.count == 0) - continue; - desc.error = 0; - do_generic_file_read(filp,ppos,&desc,file_read_actor); - retval += desc.written; - if (desc.error) { - retval = retval ?: desc.error; - break; - } - } - } -out: - return retval; -} - -/** - * gfs2_read - Read bytes from a file - * @file: The file to read from - * @buf: The buffer to copy into - * @size: The amount of data requested - * @offset: The current file offset - * - * Outputs: Offset - updated according to number of bytes read - * - * Returns: The number of bytes read, errno on failure - */ - -static ssize_t gfs2_read(struct file *filp, char __user *buf, size_t size, - loff_t *offset) -{ - struct iovec local_iov = { .iov_base = buf, .iov_len = size }; - struct kiocb kiocb; - ssize_t ret; - - init_sync_kiocb(&kiocb, filp); - ret = __gfs2_file_aio_read(&kiocb, &local_iov, 1, offset); - if (-EIOCBQUEUED == ret) - ret = wait_on_sync_kiocb(&kiocb); - return ret; -} - -static ssize_t gfs2_file_readv(struct file *filp, const struct iovec *iov, - unsigned long nr_segs, loff_t *ppos) -{ - struct kiocb kiocb; - ssize_t ret; - - init_sync_kiocb(&kiocb, filp); - ret = __gfs2_file_aio_read(&kiocb, iov, nr_segs, ppos); - if (-EIOCBQUEUED == ret) - ret = wait_on_sync_kiocb(&kiocb); - return ret; -} - -static ssize_t gfs2_file_aio_read(struct kiocb *iocb, char __user *buf, - size_t count, loff_t pos) -{ - struct iovec local_iov = { .iov_base = buf, .iov_len = count }; - - BUG_ON(iocb->ki_pos != pos); - return __gfs2_file_aio_read(iocb, &local_iov, 1, &iocb->ki_pos); -} - - /** * filldir_reg_func - Report a directory entry to the caller of gfs2_dir_read() * @opaque: opaque data used by the function @@ -949,9 +785,9 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) const struct file_operations gfs2_file_fops = { .llseek = gfs2_llseek, - .read = gfs2_read, - .readv = gfs2_file_readv, - .aio_read = gfs2_file_aio_read, + .read = generic_file_read, + .readv = generic_file_readv, + .aio_read = generic_file_aio_read, .write = generic_file_write, .writev = generic_file_writev, .aio_write = generic_file_aio_write, |