ReactOS  0.4.12-dev-14-gd0c8636
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 
36 const stateid4 special_read_stateid = {0xffffffff,
37  {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
38 
39 static int parse_rw(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall)
40 {
41  int status;
42  readwrite_upcall_args *args = &upcall->args.rw;
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);
53 out:
54  return status;
55 }
56 
57 /* NFS41_READ */
58 static 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;
64  readwrite_upcall_args *args = &upcall->args.rw;
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) {
94  status = NO_ERROR;
95  break;
96  }
97  if (eof) {
98  if (!len)
99  status = ERROR_HANDLE_EOF;
100  break;
101  }
102  }
103 out:
104  args->out_len = len;
105  return status;
106 }
107 
108 static 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)) {
118  status = ERROR_NOT_SUPPORTED;
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:
128  status = ERROR_HANDLE_EOF;
129  break;
130  default:
131  status = ERROR_READ_FAULT;
132  break;
133  }
134 out:
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 
150  if (status == NO_ERROR || status == ERROR_HANDLE_EOF)
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;
166 out:
167  return status;
168 }
169 
170 
171 /* NFS41_WRITE */
172 static 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 
189 retry_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;
240 out:
241  args->out_len = len;
243 
244 out_verify_failed:
245  len = 0;
246  status = NFS4ERR_IO;
247  goto out;
248 }
249 
250 static 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)) {
260  status = ERROR_NOT_SUPPORTED;
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)) {
266  status = ERROR_WRITE_FAULT;
267  goto out;
268  }
269  args->ctime = info.change;
270 out:
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);
299 out:
300  args->out_len += pnfs_bytes_written;
301  return status;
302 }
303 
304 static 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));
311 out:
312  return status;
313 }
314 
315 
317  parse_rw,
318  handle_read,
320 };
322  parse_rw,
323  handle_write,
325 };
pnfs_status
Definition: pnfs.h:58
#define IN
Definition: typedefs.h:38
int nfs_to_windows_error(int status, int default_error)
Definition: util.c:235
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
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
struct __nfs41_superblock * superblock
Definition: nfs41_types.h:56
int32_t bool_t
Definition: types.h:101
const nfs41_upcall_op nfs41_op_write
Definition: readwrite.c:321
static int parse_rw(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall)
Definition: readwrite.c:39
static int read_from_mds(IN nfs41_upcall *upcall, IN stateid_arg *stateid)
Definition: readwrite.c:58
GLuint buffer
Definition: glext.h:5915
#define NO_ERROR
Definition: dderror.h:5
Definition: match.c:390
struct _test_info info[]
Definition: SetCursorPos.c:19
#define ERROR_WRITE_FAULT
Definition: winerror.h:132
uint32_t max_read_size(IN const nfs41_session *session, IN const nfs41_fh *fh)
Definition: util.c:84
stable_how4
Definition: nfs41_ops.h:835
nfs41_open_state * state_ref
Definition: upcall.h:207
#define dprintf
Definition: regdump.c:33
enum pnfs_status pnfs_layout_state_open(IN struct __nfs41_open_state *state, OUT pnfs_layout_state **layout_out)
void nfs41_open_stateid_arg(IN nfs41_open_state *state, OUT struct __stateid_arg *arg)
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
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
const stateid4 special_read_stateid
Definition: readwrite.c:36
static int write_to_pnfs(IN nfs41_upcall *upcall, IN stateid_arg *stateid)
Definition: readwrite.c:250
upcall_args args
Definition: upcall.h:198
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
readwrite_upcall_args rw
Definition: upcall.h:179
bool_t verify_commit(IN nfs41_write_verf *verf)
Definition: util.c:126
static FILE * out
Definition: regtests2xml.c:44
int safe_write(unsigned char **pos, uint32_t *remaining, void *src, uint32_t src_len)
Definition: util.c:44
ULONGLONG offset
Definition: upcall.h:70
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
static DWORD layout
Definition: bitmap.c:46
static int handle_write(nfs41_upcall *upcall)
Definition: readwrite.c:274
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
const nfs41_upcall_op nfs41_op_read
Definition: readwrite.c:316
static int marshall_rw(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall)
Definition: readwrite.c:304
_Check_return_ _CRTIMP int __cdecl __cdecl eof(_In_ int _FileHandle)
uint32_t opcode
Definition: upcall.h:195
#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
UINT32 uint32_t
Definition: types.h:75
const char * opcode2string(DWORD opcode)
Definition: daemon_debug.c:280
nfs41_updowncall_list upcall
Definition: nfs41_driver.c:273
#define ERROR_NOT_SUPPORTED
Definition: compat.h:90
static int read_from_pnfs(IN nfs41_upcall *upcall, IN stateid_arg *stateid)
Definition: readwrite.c:108
unsigned char * buffer
Definition: upcall.h:69
bool_t verify_write(IN nfs41_write_verf *verf, IN OUT enum stable_how4 *stable)
Definition: util.c:100
unsigned int ULONG
Definition: retypes.h:1
#define ERROR_HANDLE_EOF
Definition: winerror.h:140
#define ERROR_NET_WRITE_FAULT
Definition: winerror.h:172
int safe_read(unsigned char **pos, uint32_t *remaining, void *dest, uint32_t dest_len)
Definition: util.c:33
#define ERROR_READ_FAULT
Definition: winerror.h:133
GLfloat GLfloat p
Definition: glext.h:8902
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)
static SERVICE_STATUS status
Definition: service.c:31
uint32_t max_write_size(IN const nfs41_session *session, IN const nfs41_fh *fh)
Definition: util.c:92
#define MAX_WRITE_RETRIES
Definition: readwrite.c:33
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)
Definition: fci.c:126
Definition: ps.c:97