4989a01ed8e157f35e2c5d59ebb12c6e1e9324b2
[openafs.git] / src / afs / LINUX / osi_fetchstore.c
1 /*
2  * Copyright (c) 2009 Simon Wilkinson. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 /* Linux specific store operations
26  *
27  * The idea of these operations is to reduce the number of copies
28  * that data incurs when passing from the disk cache through to the
29  * RX layer, and vice versa.
30  *
31  * In kernels which support it, we use the splice() operation - in
32  * older kernels, the filesystem's sendpage() operation is used directly.
33  * Either way, this means that we can get direct access to the page contents,
34  * rather than getting a copy.
35  */
36
37 #include <afsconfig.h>
38 #include "afs/param.h"
39
40 #include <linux/fs.h>
41 #if defined(HAVE_LINUX_SPLICE_DIRECT_TO_ACTOR)
42 # include <linux/splice.h>
43 #else
44 # include <linux/pipe_fs_i.h>
45 #endif
46
47 #include "afs/sysincludes.h"
48 #include "afsincludes.h"
49
50 #if defined(HAVE_LINUX_SPLICE_DIRECT_TO_ACTOR)
51 static int
52 afs_linux_splice_actor(struct pipe_inode_info *pipe,
53                        struct pipe_buffer *buf,
54                        struct splice_desc *sd)
55 {
56     struct rxfs_storeVariables *svar = sd->u.data;
57     size_t size;
58     int code;
59
60     code = buf->ops->confirm(pipe, buf);
61     if (code)
62         return code;
63
64     size = sd->len;
65
66     /* Eventually, this could be rx_WritePage */
67     code = rx_Write(svar->call, kmap(buf->page), size);
68
69     if (code != size)
70         size = -33; /* Can't get a proper rx error out from here */
71
72     kunmap(buf->page);
73
74     return size;
75 }
76
77 static int
78 afs_linux_ds_actor(struct pipe_inode_info *pipe, struct splice_desc *sd)
79 {
80     return __splice_from_pipe(pipe, sd, afs_linux_splice_actor);
81 }
82
83 /* This is a store proc which uses splice to reduce the number
84  * of page copies. */
85 afs_int32
86 afs_linux_storeproc(struct storeOps *ops, void *rock, struct dcache *tdc,
87                     int *shouldwake, afs_size_t *bytesXferred)
88 {
89     struct rxfs_storeVariables *svar = rock;
90     struct file *cacheFp;
91     struct splice_desc sd = {
92         .len    = 0,
93         .total_len = tdc->f.chunkBytes,
94         .pos    = 0,
95         .u.data = rock
96     };
97     int code;
98
99     /* Open the file, splice its contents */
100     AFS_GUNLOCK();
101     cacheFp = afs_linux_raw_open(&tdc->f.inode);
102     code = splice_direct_to_actor(cacheFp, &sd, afs_linux_ds_actor);
103     filp_close(cacheFp, NULL);
104     AFS_GLOCK();
105
106     /* If we're being called from a backing request, then wake up that
107      * request once the file server says its happy. Potentially, we should
108      * do this each time we rx_Write, but that would mean acquiring the
109      * GLOCK in the middle of our actor */
110     if (shouldwake && *shouldwake && ((*ops->status)(rock) == 0)) {
111         *shouldwake = 0;
112         afs_wakeup(svar->vcache);
113     }
114
115     if (code > 0) {
116         *bytesXferred+=code;
117         return 0;
118     }
119
120     return code;
121 }
122
123 # else
124
125 static int
126 afs_linux_read_actor(read_descriptor_t *desc, struct page *page,
127                      unsigned long offset, unsigned long size)
128 {
129     struct rxfs_storeVariables *svar = desc->arg.data;
130     unsigned long count = desc->count;
131     int code;
132
133     if (size > count)
134         size = count;
135
136     /* Eventually, this could be rx_WritePage */
137     code = rx_Write(svar->call, kmap(page) + offset, size);
138     kunmap(page);
139
140     if (code != size) {
141         return -33; /* Can't get a proper rx error out from here */
142     }
143
144     desc->count = count - size;
145     desc->written += size;
146
147     return size;
148 }
149
150 afs_int32
151 afs_linux_storeproc(struct storeOps *ops, void *rock, struct dcache *tdc,
152                     int *shouldwake, afs_size_t *bytesXferred)
153 {
154     struct rxfs_storeVariables *svar = rock;
155     struct file *cacheFp;
156     int code;
157     loff_t offset = 0;
158
159     /* Open the file, splice its contents */
160     AFS_GUNLOCK();
161     cacheFp = afs_linux_raw_open(&tdc->f.inode);
162     code = cacheFp->f_op->sendfile(cacheFp, &offset, tdc->f.chunkBytes,
163                                    afs_linux_read_actor, rock);
164     filp_close(cacheFp, NULL);
165     AFS_GLOCK();
166
167     /* If we're being called from a backing request, then wake up that
168      * request once the file server says its happy. Potentially, we should
169      * do this each time we rx_Write, but that would mean acquiring the
170      * GLOCK in the middle of our actor */
171     if (shouldwake && *shouldwake && ((*ops->status)(rock) == 0)) {
172         *shouldwake = 0;
173         afs_wakeup(svar->vcache);
174     }
175
176     if (code > 0) {
177         *bytesXferred+=code;
178         return 0;
179     }
180
181     return code;
182 }
183
184 #endif