Add synchronous O_DIRECT read support to AFS (no AIO yet). It can theoretically handle reads up to the maximum size describable by loff_t - and given an iterator with sufficiently capacity to handle that and given support on the server. Signed-off-by: David Howells <dhowells@xxxxxxxxxx> --- fs/afs/file.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/afs/internal.h | 1 + fs/afs/write.c | 8 +++++++ 3 files changed, 70 insertions(+) diff --git a/fs/afs/file.c b/fs/afs/file.c index 7d65efe69929..095ef4b4a0e7 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -27,6 +27,7 @@ static int afs_releasepage(struct page *page, gfp_t gfp_flags); static int afs_readpages(struct file *filp, struct address_space *mapping, struct list_head *pages, unsigned nr_pages); +static ssize_t afs_direct_IO(struct kiocb *iocb, struct iov_iter *iter); const struct file_operations afs_file_operations = { .open = afs_open, @@ -55,6 +56,7 @@ const struct address_space_operations afs_fs_aops = { .launder_page = afs_launder_page, .releasepage = afs_releasepage, .invalidatepage = afs_invalidatepage, + .direct_IO = afs_direct_IO, .write_begin = afs_write_begin, .write_end = afs_write_end, .writepage = afs_writepage, @@ -732,3 +734,62 @@ static int afs_file_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_ops = &afs_vm_ops; return ret; } + +/* + * Direct file read operation for an AFS file. + */ +static ssize_t afs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter) +{ + struct file *file = iocb->ki_filp; + struct address_space *mapping = file->f_mapping; + struct afs_vnode *vnode = AFS_FS_I(mapping->host); + struct afs_read *req; + struct key *key = afs_file_key(file); + ssize_t ret; + size_t count = iov_iter_count(iter), transferred = 0; + + if (!count) + return 0; + if (!is_sync_kiocb(iocb)) + return -EOPNOTSUPP; + + req = kzalloc(sizeof(struct afs_read), GFP_KERNEL); + if (!req) + return -ENOMEM; + + refcount_set(&req->usage, 1); + req->pos = iocb->ki_pos; + req->len = count; + req->iter = *iter; + + task_io_account_read(count); + + + // TODO afs_start_io_direct(inode); + ret = afs_fetch_data(vnode, key, req); + if (ret == 0) + transferred = req->actual_len; + *iter = req->iter; + afs_put_read(req); + + // TODO afs_end_io_direct(inode); + + BUG_ON(ret == -EIOCBQUEUED); // TODO + + if (ret == 0) + ret = transferred; + + return ret; +} + +/* + * Do direct I/O. + */ +static ssize_t afs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) +{ + VM_BUG_ON(iov_iter_count(iter) != PAGE_SIZE); + + if (iov_iter_rw(iter) == READ) + return afs_file_direct_read(iocb, iter); + return afs_file_direct_write(iocb, iter); +} diff --git a/fs/afs/internal.h b/fs/afs/internal.h index b12566b640f6..ac763e651c42 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -1110,6 +1110,7 @@ extern int afs_fsync(struct file *, loff_t, loff_t, int); extern int afs_page_mkwrite(struct vm_fault *); extern void afs_prune_wb_keys(struct afs_vnode *); extern int afs_launder_page(struct page *); +extern ssize_t afs_file_direct_write(struct kiocb *, struct iov_iter *); /* * xattr.c diff --git a/fs/afs/write.c b/fs/afs/write.c index 8ce5142f0f08..18b836b473f2 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c @@ -874,3 +874,11 @@ int afs_launder_page(struct page *page) #endif return ret; } + +/* + * Direct file write operation for an AFS file. + */ +ssize_t afs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) +{ + return -EOPNOTSUPP; +}