[PATCH 08/10] afs: Add O_DIRECT read support

From: David Howells
Date: Thu Sep 13 2018 - 11:52:49 EST


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 36ba263db749..60f9896e1426 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,
@@ -731,3 +733,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 7c7598856b96..38b48382db52 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -1111,6 +1111,7 @@ extern int afs_fsync(struct file *, loff_t, loff_t, int);
extern vm_fault_t afs_page_mkwrite(struct vm_fault *vmf);
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 9f035386b9c7..46a3a911c682 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;
+}