ReactOS 0.4.15-dev-7953-g1f49173
readwrite.c
Go to the documentation of this file.
1/* NFSv4.1 client for Windows
2 * Copyright © 2012 The Regents of the University of Michigan
3 *
4 * Olga Kornievskaia <aglo@umich.edu>
5 * Casey Bodley <cbodley@umich.edu>
6 *
7 * This library is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or (at
10 * your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful, but
13 * without any warranty; without even the implied warranty of merchantability
14 * or fitness for a particular purpose. See the GNU Lesser General Public
15 * License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 */
21
22#include <windows.h>
23#include <stdio.h>
24
25#include "nfs41_ops.h"
26#include "name_cache.h"
27#include "upcall.h"
28#include "daemon_debug.h"
29#include "util.h"
30
31
32/* number of times to retry on write/commit verifier mismatch */
33#define MAX_WRITE_RETRIES 6
34
35
36const stateid4 special_read_stateid = {0xffffffff,
37 {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
38
39static int parse_rw(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall)
40{
41 int status;
43
44 status = safe_read(&buffer, &length, &args->len, sizeof(args->len));
45 if (status) goto out;
46 status = safe_read(&buffer, &length, &args->offset, sizeof(args->offset));
47 if (status) goto out;
48 status = safe_read(&buffer, &length, &args->buffer, sizeof(args->buffer));
49 if (status) goto out;
50
51 dprintf(1, "parsing %s len=%lu offset=%llu buf=%p\n",
52 opcode2string(upcall->opcode), args->len, args->offset, args->buffer);
53out:
54 return status;
55}
56
57/* NFS41_READ */
58static int read_from_mds(
60 IN stateid_arg *stateid)
61{
62 nfs41_session *session = upcall->state_ref->session;
63 nfs41_path_fh *file = &upcall->state_ref->file;
65 int status = 0;
66 bool_t eof;
67 unsigned char *p = args->buffer;
68 ULONG to_rcv = args->len, reloffset = 0, len = 0;
69 const uint32_t maxreadsize = max_read_size(session, &file->fh);
70
71 if (to_rcv > maxreadsize)
72 dprintf(1, "handle_nfs41_read: reading %d in chunks of %d\n",
73 to_rcv, maxreadsize);
74
75 while(to_rcv > 0) {
76 uint32_t bytes_read = 0, chunk = min(to_rcv, maxreadsize);
77
78 status = nfs41_read(session, file, stateid, args->offset + reloffset, chunk,
79 p, &bytes_read, &eof);
80 if (status == NFS4ERR_OPENMODE && !len) {
81 stateid->type = STATEID_SPECIAL;
82 memcpy(&stateid->stateid, &special_read_stateid, sizeof(stateid4));
83 continue;
84 } else if (status && !len) {
86 goto out;
87 }
88
89 p += bytes_read;
90 to_rcv -= bytes_read;
91 len += bytes_read;
92 args->offset += bytes_read;
93 if (status) {
95 break;
96 }
97 if (eof) {
98 if (!len)
100 break;
101 }
102 }
103out:
104 args->out_len = len;
105 return status;
106}
107
108static int read_from_pnfs(
110 IN stateid_arg *stateid)
111{
112 readwrite_upcall_args *args = &upcall->args.rw;
114 enum pnfs_status pnfsstat;
115 int status = NO_ERROR;
116
117 if (pnfs_layout_state_open(upcall->state_ref, &layout)) {
119 goto out;
120 }
121
122 pnfsstat = pnfs_read(upcall->root_ref, upcall->state_ref, stateid, layout,
123 args->offset, args->len, args->buffer, &args->out_len);
124 switch (pnfsstat) {
125 case PNFS_SUCCESS:
126 break;
127 case PNFS_READ_EOF:
129 break;
130 default:
132 break;
133 }
134out:
135 return status;
136}
137
139{
140 readwrite_upcall_args *args = &upcall->args.rw;
141 stateid_arg stateid;
142 ULONG pnfs_bytes_read = 0;
143 int status = NO_ERROR;
144
145 nfs41_open_stateid_arg(upcall->state_ref, &stateid);
146
147#ifdef PNFS_ENABLE_READ
148 status = read_from_pnfs(upcall, &stateid);
149
151 goto out;
152
153 if (args->out_len) {
154 pnfs_bytes_read = args->out_len;
155 args->out_len = 0;
156
157 args->offset += pnfs_bytes_read;
158 args->buffer += pnfs_bytes_read;
159 args->len -= pnfs_bytes_read;
160 }
161#endif
162
163 status = read_from_mds(upcall, &stateid);
164
165 args->out_len += pnfs_bytes_read;
166out:
167 return status;
168}
169
170
171/* NFS41_WRITE */
172static int write_to_mds(
174 IN stateid_arg *stateid)
175{
176 nfs41_session *session = upcall->state_ref->session;
177 nfs41_path_fh *file = &upcall->state_ref->file;
178 readwrite_upcall_args *args = &upcall->args.rw;
179 nfs41_write_verf verf;
180 enum stable_how4 stable, committed;
181 unsigned char *p;
182 const uint32_t maxwritesize = max_write_size(session, &file->fh);
183 uint32_t to_send, reloffset, len;
184 int status = 0;
185 /* on write verifier mismatch, retry N times before failing */
186 uint32_t retries = MAX_WRITE_RETRIES;
187 nfs41_file_info info = { 0 };
188
189retry_write:
190 p = args->buffer;
191 to_send = args->len;
192 reloffset = 0;
193 len = 0;
194 stable = to_send <= maxwritesize ? FILE_SYNC4 : UNSTABLE4;
195 committed = FILE_SYNC4;
196
197 if (to_send > maxwritesize)
198 dprintf(1, "handle_nfs41_write: writing %d in chunks of %d\n",
199 to_send, maxwritesize);
200
201 while(to_send > 0) {
202 uint32_t bytes_written = 0, chunk = min(to_send, maxwritesize);
203
204 status = nfs41_write(session, file, stateid, p, chunk,
205 args->offset + reloffset, stable, &bytes_written, &verf, &info);
206 if (status && !len)
207 goto out;
208 p += bytes_written;
209 to_send -= bytes_written;
210 len += bytes_written;
211 reloffset += bytes_written;
212 if (status) {
213 status = 0;
214 break;
215 }
216 if (!verify_write(&verf, &committed)) {
217 if (retries--) goto retry_write;
218 goto out_verify_failed;
219 }
220 }
221 if (committed != FILE_SYNC4) {
222 dprintf(1, "sending COMMIT for offset=%d and len=%d\n", args->offset, len);
223 status = nfs41_commit(session, file, args->offset, len, 1, &verf, &info);
224 if (status)
225 goto out;
226
227 if (!verify_commit(&verf)) {
228 if (retries--) goto retry_write;
229 goto out_verify_failed;
230 }
231 } else if (stable == UNSTABLE4) {
233 bitmap4 attr_request;
234 nfs41_superblock_getattr_mask(file->fh.superblock, &attr_request);
235 status = nfs41_getattr(session, file, &attr_request, &info);
236 if (status)
237 goto out;
238 }
239 args->ctime = info.change;
240out:
241 args->out_len = len;
243
244out_verify_failed:
245 len = 0;
247 goto out;
248}
249
250static int write_to_pnfs(
252 IN stateid_arg *stateid)
253{
254 readwrite_upcall_args *args = &upcall->args.rw;
256 int status = NO_ERROR;
257 nfs41_file_info info = { 0 };
258
259 if (pnfs_layout_state_open(upcall->state_ref, &layout)) {
261 goto out;
262 }
263
264 if (pnfs_write(upcall->root_ref, upcall->state_ref, stateid, layout,
265 args->offset, args->len, args->buffer, &args->out_len, &info)) {
267 goto out;
268 }
269 args->ctime = info.change;
270out:
271 return status;
272}
273
275{
276 readwrite_upcall_args *args = &upcall->args.rw;
277 stateid_arg stateid;
278 uint32_t pnfs_bytes_written = 0;
279 int status;
280
281 nfs41_open_stateid_arg(upcall->state_ref, &stateid);
282
283#ifdef PNFS_ENABLE_WRITE
284 status = write_to_pnfs(upcall, &stateid);
285 if (args->out_len) {
286 pnfs_bytes_written = args->out_len;
287 args->out_len = 0;
288
289 args->offset += pnfs_bytes_written;
290 args->buffer += pnfs_bytes_written;
291 args->len -= pnfs_bytes_written;
292
293 if (args->len == 0)
294 goto out;
295 }
296#endif
297
298 status = write_to_mds(upcall, &stateid);
299out:
300 args->out_len += pnfs_bytes_written;
301 return status;
302}
303
304static int marshall_rw(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall)
305{
306 readwrite_upcall_args *args = &upcall->args.rw;
307 int status;
308 status = safe_write(&buffer, length, &args->out_len, sizeof(args->out_len));
309 if (status) goto out;
310 status = safe_write(&buffer, length, &args->ctime, sizeof(args->ctime));
311out:
312 return status;
313}
314
315
317 parse_rw,
320};
322 parse_rw,
325};
static int marshall_rw(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall)
Definition: readwrite.c:304
static int handle_write(nfs41_upcall *upcall)
Definition: readwrite.c:274
const stateid4 special_read_stateid
Definition: readwrite.c:36
#define MAX_WRITE_RETRIES
Definition: readwrite.c:33
static int read_from_pnfs(IN nfs41_upcall *upcall, IN stateid_arg *stateid)
Definition: readwrite.c:108
static int write_to_mds(IN nfs41_upcall *upcall, IN stateid_arg *stateid)
Definition: readwrite.c:172
static int handle_read(nfs41_upcall *upcall)
Definition: readwrite.c:138
static int write_to_pnfs(IN nfs41_upcall *upcall, IN stateid_arg *stateid)
Definition: readwrite.c:250
static int parse_rw(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall)
Definition: readwrite.c:39
const nfs41_upcall_op nfs41_op_write
Definition: readwrite.c:321
const nfs41_upcall_op nfs41_op_read
Definition: readwrite.c:316
static int read_from_mds(IN nfs41_upcall *upcall, IN stateid_arg *stateid)
Definition: readwrite.c:58
int safe_write(unsigned char **pos, uint32_t *remaining, void *src, uint32_t src_len)
Definition: util.c:44
int safe_read(unsigned char **pos, uint32_t *remaining, void *dest, uint32_t dest_len)
Definition: util.c:33
int nfs_to_windows_error(int status, int default_error)
Definition: util.c:235
uint32_t max_read_size(IN const nfs41_session *session, IN const nfs41_fh *fh)
Definition: util.c:84
bool_t verify_write(IN nfs41_write_verf *verf, IN OUT enum stable_how4 *stable)
Definition: util.c:100
bool_t verify_commit(IN nfs41_write_verf *verf)
Definition: util.c:126
uint32_t max_write_size(IN const nfs41_session *session, IN const nfs41_fh *fh)
Definition: util.c:92
const char * opcode2string(DWORD opcode)
Definition: daemon_debug.c:280
#define NO_ERROR
Definition: dderror.h:5
int32_t bool_t
Definition: types.h:101
UINT32 uint32_t
Definition: types.h:75
#define ERROR_NOT_SUPPORTED
Definition: compat.h:100
GLuint buffer
Definition: glext.h:5915
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLfloat GLfloat p
Definition: glext.h:8902
GLenum GLsizei len
Definition: glext.h:6722
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
static DWORD layout
Definition: bitmap.c:46
#define min(a, b)
Definition: monoChain.cc:55
static __inline void nfs41_superblock_getattr_mask(IN const nfs41_superblock *superblock, OUT bitmap4 *attrs)
Definition: nfs41.h:448
void nfs41_open_stateid_arg(IN nfs41_open_state *state, OUT struct __stateid_arg *arg)
@ NFS4ERR_OPENMODE
Definition: nfs41_const.h:145
@ NFS4ERR_IO
Definition: nfs41_const.h:90
nfs41_updowncall_list upcall
Definition: nfs41_driver.c:273
int nfs41_read(IN nfs41_session *session, IN nfs41_path_fh *file, IN stateid_arg *stateid, IN uint64_t offset, IN uint32_t count, OUT unsigned char *data_out, OUT uint32_t *data_len_out, OUT bool_t *eof_out)
Definition: nfs41_ops.c:774
int nfs41_getattr(IN nfs41_session *session, IN OPTIONAL nfs41_path_fh *file, IN bitmap4 *attr_request, OUT nfs41_file_info *info)
Definition: nfs41_ops.c:1063
int nfs41_write(IN nfs41_session *session, IN nfs41_path_fh *file, IN stateid_arg *stateid, IN unsigned char *data, IN uint32_t data_len, IN uint64_t offset, IN enum stable_how4 stable, OUT uint32_t *bytes_written, OUT nfs41_write_verf *verf, OUT nfs41_file_info *cinfo)
Definition: nfs41_ops.c:685
int nfs41_commit(IN nfs41_session *session, IN nfs41_path_fh *file, IN uint64_t offset, IN uint32_t count, IN bool_t do_getattr, OUT nfs41_write_verf *verf, OUT nfs41_file_info *cinfo)
Definition: nfs41_ops.c:833
stable_how4
Definition: nfs41_ops.h:835
@ FILE_SYNC4
Definition: nfs41_ops.h:838
@ UNSTABLE4
Definition: nfs41_ops.h:836
@ STATEID_SPECIAL
Definition: nfs41_ops.h:281
enum pnfs_status pnfs_write(IN struct __nfs41_root *root, IN struct __nfs41_open_state *state, IN struct __stateid_arg *stateid, IN pnfs_layout_state *layout, IN uint64_t offset, IN uint64_t length, IN unsigned char *buffer, OUT ULONG *len_out, OUT nfs41_file_info *cinfo)
pnfs_status
Definition: pnfs.h:58
@ PNFS_READ_EOF
Definition: pnfs.h:61
@ PNFS_SUCCESS
Definition: pnfs.h:59
enum pnfs_status pnfs_layout_state_open(IN struct __nfs41_open_state *state, OUT pnfs_layout_state **layout_out)
enum pnfs_status pnfs_read(IN struct __nfs41_root *root, IN struct __nfs41_open_state *state, IN struct __stateid_arg *stateid, IN pnfs_layout_state *layout, IN uint64_t offset, IN uint64_t length, OUT unsigned char *buffer_out, OUT ULONG *len_out)
#define dprintf
Definition: regdump.c:33
static FILE * out
Definition: regtests2xml.c:44
_Check_return_ _CRTIMP int __cdecl __cdecl eof(_In_ int _FileHandle)
Definition: match.c:390
Definition: fci.c:127
Definition: ps.c:97
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
#define ERROR_NET_WRITE_FAULT
Definition: winerror.h:172
#define ERROR_WRITE_FAULT
Definition: winerror.h:132
#define ERROR_HANDLE_EOF
Definition: winerror.h:140
#define ERROR_READ_FAULT
Definition: winerror.h:133