aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPedro Cuadra <pjcuadra@gmail.com>2019-07-16 19:29:13 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-07-16 22:23:23 -0400
commita9fba24c6ac9b66c09dfc2a0e845ecace187e89c (patch)
treec0985325e935868b52697d0e0167e0023a0e5d9b
parent5bb44810f47a00b608ed2cb9f892ae7ce37b02bd (diff)
coda: add hinting support for partial file caching
This adds support for partial file caching in Coda. Every read, write and mmap informs the userspace cache manager about what part of a file is about to be accessed so that the cache manager can ensure the relevant parts are available before the operation is allowed to proceed. When a read or write operation completes, this is also reported to allow the cache manager to track when partially cached content can be released. If the cache manager does not support partial file caching, or when the entire file has been fetched into the local cache, the cache manager may return an EOPNOTSUPP error to indicate that intent upcalls are no longer necessary until the file is closed. [akpm@linux-foundation.org: little whitespace fixup] Link: http://lkml.kernel.org/r/20190618181301.6960-1-jaharkes@cs.cmu.edu Signed-off-by: Pedro Cuadra <pjcuadra@gmail.com> Signed-off-by: Jan Harkes <jaharkes@cs.cmu.edu> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/coda/coda_fs_i.h1
-rw-r--r--fs/coda/coda_psdev.h3
-rw-r--r--fs/coda/file.c61
-rw-r--r--fs/coda/psdev.c2
-rw-r--r--fs/coda/upcall.c70
-rw-r--r--include/uapi/linux/coda.h29
6 files changed, 139 insertions, 27 deletions
diff --git a/fs/coda/coda_fs_i.h b/fs/coda/coda_fs_i.h
index c99d574d1c43..1763ff95d865 100644
--- a/fs/coda/coda_fs_i.h
+++ b/fs/coda/coda_fs_i.h
@@ -40,6 +40,7 @@ struct coda_file_info {
40 int cfi_magic; /* magic number */ 40 int cfi_magic; /* magic number */
41 struct file *cfi_container; /* container file for this cnode */ 41 struct file *cfi_container; /* container file for this cnode */
42 unsigned int cfi_mapcount; /* nr of times this file is mapped */ 42 unsigned int cfi_mapcount; /* nr of times this file is mapped */
43 bool cfi_access_intent; /* is access intent supported */
43}; 44};
44 45
45/* flags */ 46/* flags */
diff --git a/fs/coda/coda_psdev.h b/fs/coda/coda_psdev.h
index 801423cbbdfc..52da08c770b0 100644
--- a/fs/coda/coda_psdev.h
+++ b/fs/coda/coda_psdev.h
@@ -83,6 +83,9 @@ int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out,
83 size_t nbytes); 83 size_t nbytes);
84int venus_fsync(struct super_block *sb, struct CodaFid *fid); 84int venus_fsync(struct super_block *sb, struct CodaFid *fid);
85int venus_statfs(struct dentry *dentry, struct kstatfs *sfs); 85int venus_statfs(struct dentry *dentry, struct kstatfs *sfs);
86int venus_access_intent(struct super_block *sb, struct CodaFid *fid,
87 bool *access_intent_supported,
88 size_t count, loff_t ppos, int type);
86 89
87/* 90/*
88 * Statistics 91 * Statistics
diff --git a/fs/coda/file.c b/fs/coda/file.c
index 0dbd13ab72e3..128d63df5bfb 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -20,6 +20,7 @@
20#include <linux/string.h> 20#include <linux/string.h>
21#include <linux/slab.h> 21#include <linux/slab.h>
22#include <linux/uaccess.h> 22#include <linux/uaccess.h>
23#include <linux/uio.h>
23 24
24#include <linux/coda.h> 25#include <linux/coda.h>
25#include "coda_psdev.h" 26#include "coda_psdev.h"
@@ -37,9 +38,25 @@ static ssize_t
37coda_file_read_iter(struct kiocb *iocb, struct iov_iter *to) 38coda_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
38{ 39{
39 struct file *coda_file = iocb->ki_filp; 40 struct file *coda_file = iocb->ki_filp;
41 struct inode *coda_inode = file_inode(coda_file);
40 struct coda_file_info *cfi = coda_ftoc(coda_file); 42 struct coda_file_info *cfi = coda_ftoc(coda_file);
43 loff_t ki_pos = iocb->ki_pos;
44 size_t count = iov_iter_count(to);
45 ssize_t ret;
46
47 ret = venus_access_intent(coda_inode->i_sb, coda_i2f(coda_inode),
48 &cfi->cfi_access_intent,
49 count, ki_pos, CODA_ACCESS_TYPE_READ);
50 if (ret)
51 goto finish_read;
41 52
42 return vfs_iter_read(cfi->cfi_container, to, &iocb->ki_pos, 0); 53 ret = vfs_iter_read(cfi->cfi_container, to, &iocb->ki_pos, 0);
54
55finish_read:
56 venus_access_intent(coda_inode->i_sb, coda_i2f(coda_inode),
57 &cfi->cfi_access_intent,
58 count, ki_pos, CODA_ACCESS_TYPE_READ_FINISH);
59 return ret;
43} 60}
44 61
45static ssize_t 62static ssize_t
@@ -48,10 +65,17 @@ coda_file_write_iter(struct kiocb *iocb, struct iov_iter *to)
48 struct file *coda_file = iocb->ki_filp; 65 struct file *coda_file = iocb->ki_filp;
49 struct inode *coda_inode = file_inode(coda_file); 66 struct inode *coda_inode = file_inode(coda_file);
50 struct coda_file_info *cfi = coda_ftoc(coda_file); 67 struct coda_file_info *cfi = coda_ftoc(coda_file);
51 struct file *host_file; 68 struct file *host_file = cfi->cfi_container;
69 loff_t ki_pos = iocb->ki_pos;
70 size_t count = iov_iter_count(to);
52 ssize_t ret; 71 ssize_t ret;
53 72
54 host_file = cfi->cfi_container; 73 ret = venus_access_intent(coda_inode->i_sb, coda_i2f(coda_inode),
74 &cfi->cfi_access_intent,
75 count, ki_pos, CODA_ACCESS_TYPE_WRITE);
76 if (ret)
77 goto finish_write;
78
55 file_start_write(host_file); 79 file_start_write(host_file);
56 inode_lock(coda_inode); 80 inode_lock(coda_inode);
57 ret = vfs_iter_write(cfi->cfi_container, to, &iocb->ki_pos, 0); 81 ret = vfs_iter_write(cfi->cfi_container, to, &iocb->ki_pos, 0);
@@ -60,6 +84,11 @@ coda_file_write_iter(struct kiocb *iocb, struct iov_iter *to)
60 coda_inode->i_mtime = coda_inode->i_ctime = current_time(coda_inode); 84 coda_inode->i_mtime = coda_inode->i_ctime = current_time(coda_inode);
61 inode_unlock(coda_inode); 85 inode_unlock(coda_inode);
62 file_end_write(host_file); 86 file_end_write(host_file);
87
88finish_write:
89 venus_access_intent(coda_inode->i_sb, coda_i2f(coda_inode),
90 &cfi->cfi_access_intent,
91 count, ki_pos, CODA_ACCESS_TYPE_WRITE_FINISH);
63 return ret; 92 return ret;
64} 93}
65 94
@@ -94,29 +123,35 @@ coda_vm_close(struct vm_area_struct *vma)
94static int 123static int
95coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma) 124coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
96{ 125{
97 struct coda_file_info *cfi; 126 struct inode *coda_inode = file_inode(coda_file);
127 struct coda_file_info *cfi = coda_ftoc(coda_file);
128 struct file *host_file = cfi->cfi_container;
129 struct inode *host_inode = file_inode(host_file);
98 struct coda_inode_info *cii; 130 struct coda_inode_info *cii;
99 struct file *host_file;
100 struct inode *coda_inode, *host_inode;
101 struct coda_vm_ops *cvm_ops; 131 struct coda_vm_ops *cvm_ops;
132 loff_t ppos;
133 size_t count;
102 int ret; 134 int ret;
103 135
104 cfi = coda_ftoc(coda_file);
105 host_file = cfi->cfi_container;
106
107 if (!host_file->f_op->mmap) 136 if (!host_file->f_op->mmap)
108 return -ENODEV; 137 return -ENODEV;
109 138
110 if (WARN_ON(coda_file != vma->vm_file)) 139 if (WARN_ON(coda_file != vma->vm_file))
111 return -EIO; 140 return -EIO;
112 141
142 count = vma->vm_end - vma->vm_start;
143 ppos = vma->vm_pgoff * PAGE_SIZE;
144
145 ret = venus_access_intent(coda_inode->i_sb, coda_i2f(coda_inode),
146 &cfi->cfi_access_intent,
147 count, ppos, CODA_ACCESS_TYPE_MMAP);
148 if (ret)
149 return ret;
150
113 cvm_ops = kmalloc(sizeof(struct coda_vm_ops), GFP_KERNEL); 151 cvm_ops = kmalloc(sizeof(struct coda_vm_ops), GFP_KERNEL);
114 if (!cvm_ops) 152 if (!cvm_ops)
115 return -ENOMEM; 153 return -ENOMEM;
116 154
117 coda_inode = file_inode(coda_file);
118 host_inode = file_inode(host_file);
119
120 cii = ITOC(coda_inode); 155 cii = ITOC(coda_inode);
121 spin_lock(&cii->c_lock); 156 spin_lock(&cii->c_lock);
122 coda_file->f_mapping = host_file->f_mapping; 157 coda_file->f_mapping = host_file->f_mapping;
@@ -188,6 +223,8 @@ int coda_open(struct inode *coda_inode, struct file *coda_file)
188 cfi->cfi_magic = CODA_MAGIC; 223 cfi->cfi_magic = CODA_MAGIC;
189 cfi->cfi_mapcount = 0; 224 cfi->cfi_mapcount = 0;
190 cfi->cfi_container = host_file; 225 cfi->cfi_container = host_file;
226 /* assume access intents are supported unless we hear otherwise */
227 cfi->cfi_access_intent = true;
191 228
192 BUG_ON(coda_file->private_data != NULL); 229 BUG_ON(coda_file->private_data != NULL);
193 coda_file->private_data = cfi; 230 coda_file->private_data = cfi;
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index ebfbbea9fa48..240669f51eac 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -388,7 +388,7 @@ MODULE_AUTHOR("Jan Harkes, Peter J. Braam");
388MODULE_DESCRIPTION("Coda Distributed File System VFS interface"); 388MODULE_DESCRIPTION("Coda Distributed File System VFS interface");
389MODULE_ALIAS_CHARDEV_MAJOR(CODA_PSDEV_MAJOR); 389MODULE_ALIAS_CHARDEV_MAJOR(CODA_PSDEV_MAJOR);
390MODULE_LICENSE("GPL"); 390MODULE_LICENSE("GPL");
391MODULE_VERSION("6.11"); 391MODULE_VERSION("7.0");
392 392
393static int __init init_coda(void) 393static int __init init_coda(void)
394{ 394{
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index 15c0e4fdb0e3..eb3b1898da46 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -569,6 +569,47 @@ int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
569 return error; 569 return error;
570} 570}
571 571
572int venus_access_intent(struct super_block *sb, struct CodaFid *fid,
573 bool *access_intent_supported,
574 size_t count, loff_t ppos, int type)
575{
576 union inputArgs *inp;
577 union outputArgs *outp;
578 int insize, outsize, error;
579 bool finalizer =
580 type == CODA_ACCESS_TYPE_READ_FINISH ||
581 type == CODA_ACCESS_TYPE_WRITE_FINISH;
582
583 if (!*access_intent_supported && !finalizer)
584 return 0;
585
586 insize = SIZE(access_intent);
587 UPARG(CODA_ACCESS_INTENT);
588
589 inp->coda_access_intent.VFid = *fid;
590 inp->coda_access_intent.count = count;
591 inp->coda_access_intent.pos = ppos;
592 inp->coda_access_intent.type = type;
593
594 error = coda_upcall(coda_vcp(sb), insize,
595 finalizer ? NULL : &outsize, inp);
596
597 /*
598 * we have to free the request buffer for synchronous upcalls
599 * or when asynchronous upcalls fail, but not when asynchronous
600 * upcalls succeed
601 */
602 if (!finalizer || error)
603 kvfree(inp);
604
605 /* Chunked access is not supported or an old Coda client */
606 if (error == -EOPNOTSUPP) {
607 *access_intent_supported = false;
608 error = 0;
609 }
610 return error;
611}
612
572/* 613/*
573 * coda_upcall and coda_downcall routines. 614 * coda_upcall and coda_downcall routines.
574 */ 615 */
@@ -598,10 +639,12 @@ static void coda_unblock_signals(sigset_t *old)
598 * has seen them, 639 * has seen them,
599 * - CODA_CLOSE or CODA_RELEASE upcall (to avoid reference count problems) 640 * - CODA_CLOSE or CODA_RELEASE upcall (to avoid reference count problems)
600 * - CODA_STORE (to avoid data loss) 641 * - CODA_STORE (to avoid data loss)
642 * - CODA_ACCESS_INTENT (to avoid reference count problems)
601 */ 643 */
602#define CODA_INTERRUPTIBLE(r) (!coda_hard && \ 644#define CODA_INTERRUPTIBLE(r) (!coda_hard && \
603 (((r)->uc_opcode != CODA_CLOSE && \ 645 (((r)->uc_opcode != CODA_CLOSE && \
604 (r)->uc_opcode != CODA_STORE && \ 646 (r)->uc_opcode != CODA_STORE && \
647 (r)->uc_opcode != CODA_ACCESS_INTENT && \
605 (r)->uc_opcode != CODA_RELEASE) || \ 648 (r)->uc_opcode != CODA_RELEASE) || \
606 (r)->uc_flags & CODA_REQ_READ)) 649 (r)->uc_flags & CODA_REQ_READ))
607 650
@@ -687,21 +730,25 @@ static int coda_upcall(struct venus_comm *vcp,
687 goto exit; 730 goto exit;
688 } 731 }
689 732
733 buffer->ih.unique = ++vcp->vc_seq;
734
690 req->uc_data = (void *)buffer; 735 req->uc_data = (void *)buffer;
691 req->uc_flags = 0; 736 req->uc_flags = outSize ? 0 : CODA_REQ_ASYNC;
692 req->uc_inSize = inSize; 737 req->uc_inSize = inSize;
693 req->uc_outSize = *outSize ? *outSize : inSize; 738 req->uc_outSize = (outSize && *outSize) ? *outSize : inSize;
694 req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode; 739 req->uc_opcode = buffer->ih.opcode;
695 req->uc_unique = ++vcp->vc_seq; 740 req->uc_unique = buffer->ih.unique;
696 init_waitqueue_head(&req->uc_sleep); 741 init_waitqueue_head(&req->uc_sleep);
697 742
698 /* Fill in the common input args. */
699 ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
700
701 /* Append msg to pending queue and poke Venus. */ 743 /* Append msg to pending queue and poke Venus. */
702 list_add_tail(&req->uc_chain, &vcp->vc_pending); 744 list_add_tail(&req->uc_chain, &vcp->vc_pending);
703
704 wake_up_interruptible(&vcp->vc_waitq); 745 wake_up_interruptible(&vcp->vc_waitq);
746
747 if (req->uc_flags & CODA_REQ_ASYNC) {
748 mutex_unlock(&vcp->vc_mutex);
749 return 0;
750 }
751
705 /* We can be interrupted while we wait for Venus to process 752 /* We can be interrupted while we wait for Venus to process
706 * our request. If the interrupt occurs before Venus has read 753 * our request. If the interrupt occurs before Venus has read
707 * the request, we dequeue and return. If it occurs after the 754 * the request, we dequeue and return. If it occurs after the
@@ -743,20 +790,20 @@ static int coda_upcall(struct venus_comm *vcp,
743 sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL); 790 sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
744 if (!sig_req) goto exit; 791 if (!sig_req) goto exit;
745 792
746 sig_req->uc_data = kvzalloc(sizeof(struct coda_in_hdr), GFP_KERNEL); 793 sig_inputArgs = kvzalloc(sizeof(struct coda_in_hdr), GFP_KERNEL);
747 if (!sig_req->uc_data) { 794 if (!sig_inputArgs) {
748 kfree(sig_req); 795 kfree(sig_req);
749 goto exit; 796 goto exit;
750 } 797 }
751 798
752 error = -EINTR; 799 error = -EINTR;
753 sig_inputArgs = (union inputArgs *)sig_req->uc_data;
754 sig_inputArgs->ih.opcode = CODA_SIGNAL; 800 sig_inputArgs->ih.opcode = CODA_SIGNAL;
755 sig_inputArgs->ih.unique = req->uc_unique; 801 sig_inputArgs->ih.unique = req->uc_unique;
756 802
757 sig_req->uc_flags = CODA_REQ_ASYNC; 803 sig_req->uc_flags = CODA_REQ_ASYNC;
758 sig_req->uc_opcode = sig_inputArgs->ih.opcode; 804 sig_req->uc_opcode = sig_inputArgs->ih.opcode;
759 sig_req->uc_unique = sig_inputArgs->ih.unique; 805 sig_req->uc_unique = sig_inputArgs->ih.unique;
806 sig_req->uc_data = (void *)sig_inputArgs;
760 sig_req->uc_inSize = sizeof(struct coda_in_hdr); 807 sig_req->uc_inSize = sizeof(struct coda_in_hdr);
761 sig_req->uc_outSize = sizeof(struct coda_in_hdr); 808 sig_req->uc_outSize = sizeof(struct coda_in_hdr);
762 809
@@ -911,4 +958,3 @@ unlock_out:
911 iput(inode); 958 iput(inode);
912 return 0; 959 return 0;
913} 960}
914
diff --git a/include/uapi/linux/coda.h b/include/uapi/linux/coda.h
index 5dba636b6e11..aa34c2dcae8d 100644
--- a/include/uapi/linux/coda.h
+++ b/include/uapi/linux/coda.h
@@ -271,7 +271,8 @@ struct coda_statfs {
271#define CODA_STATFS 34 271#define CODA_STATFS 34
272#define CODA_STORE 35 272#define CODA_STORE 35
273#define CODA_RELEASE 36 273#define CODA_RELEASE 36
274#define CODA_NCALLS 37 274#define CODA_ACCESS_INTENT 37
275#define CODA_NCALLS 38
275 276
276#define DOWNCALL(opcode) (opcode >= CODA_REPLACE && opcode <= CODA_PURGEFID) 277#define DOWNCALL(opcode) (opcode >= CODA_REPLACE && opcode <= CODA_PURGEFID)
277 278
@@ -281,8 +282,12 @@ struct coda_statfs {
281 282
282#define CIOC_KERNEL_VERSION _IOWR('c', 10, size_t) 283#define CIOC_KERNEL_VERSION _IOWR('c', 10, size_t)
283 284
285// CODA_KERNEL_VERSION 0 /* don't care about kernel version number */
286// CODA_KERNEL_VERSION 1 /* The old venus 4.6 compatible interface */
287// CODA_KERNEL_VERSION 2 /* venus_lookup gets an extra parameter */
284// CODA_KERNEL_VERSION 3 /* 128-bit file identifiers */ 288// CODA_KERNEL_VERSION 3 /* 128-bit file identifiers */
285#define CODA_KERNEL_VERSION 4 /* 64-bit timespec */ 289// CODA_KERNEL_VERSION 4 /* 64-bit timespec */
290#define CODA_KERNEL_VERSION 5 /* access intent support */
286 291
287/* 292/*
288 * Venus <-> Coda RPC arguments 293 * Venus <-> Coda RPC arguments
@@ -637,6 +642,25 @@ struct coda_statfs_out {
637 struct coda_statfs stat; 642 struct coda_statfs stat;
638}; 643};
639 644
645#define CODA_ACCESS_TYPE_READ 1
646#define CODA_ACCESS_TYPE_WRITE 2
647#define CODA_ACCESS_TYPE_MMAP 3
648#define CODA_ACCESS_TYPE_READ_FINISH 4
649#define CODA_ACCESS_TYPE_WRITE_FINISH 5
650
651/* coda_access_intent: NO_OUT */
652struct coda_access_intent_in {
653 struct coda_in_hdr ih;
654 struct CodaFid VFid;
655 int count;
656 int pos;
657 int type;
658};
659
660struct coda_access_intent_out {
661 struct coda_out_hdr out;
662};
663
640/* 664/*
641 * Occasionally, we don't cache the fid returned by CODA_LOOKUP. 665 * Occasionally, we don't cache the fid returned by CODA_LOOKUP.
642 * For instance, if the fid is inconsistent. 666 * For instance, if the fid is inconsistent.
@@ -668,6 +692,7 @@ union inputArgs {
668 struct coda_open_by_fd_in coda_open_by_fd; 692 struct coda_open_by_fd_in coda_open_by_fd;
669 struct coda_open_by_path_in coda_open_by_path; 693 struct coda_open_by_path_in coda_open_by_path;
670 struct coda_statfs_in coda_statfs; 694 struct coda_statfs_in coda_statfs;
695 struct coda_access_intent_in coda_access_intent;
671}; 696};
672 697
673union outputArgs { 698union outputArgs {