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 <strsafe.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <time.h>
27
28 #include "nfs41_ops.h"
29 #include "nfs41_compound.h"
30 #include "nfs41_xdr.h"
31 #include "name_cache.h"
32 #include "delegation.h"
33 #include "daemon_debug.h"
34 #include "util.h"
35
nfs41_exchange_id(IN nfs41_rpc_clnt * rpc,IN client_owner4 * owner,IN uint32_t flags_in,OUT nfs41_exchange_id_res * res_out)36 int nfs41_exchange_id(
37 IN nfs41_rpc_clnt *rpc,
38 IN client_owner4 *owner,
39 IN uint32_t flags_in,
40 OUT nfs41_exchange_id_res *res_out)
41 {
42 int status = 0;
43 nfs41_compound compound;
44 nfs_argop4 argop;
45 nfs_resop4 resop;
46 nfs41_exchange_id_args ex_id;
47
48 compound_init(&compound, &argop, &resop, "exchange_id");
49
50 compound_add_op(&compound, OP_EXCHANGE_ID, &ex_id, res_out);
51 ex_id.eia_clientowner = owner;
52 ex_id.eia_flags = flags_in;
53 ex_id.eia_state_protect.spa_how = SP4_NONE;
54 ex_id.eia_client_impl_id = NULL;
55
56 res_out->server_owner.so_major_id_len = NFS4_OPAQUE_LIMIT;
57 res_out->server_scope_len = NFS4_OPAQUE_LIMIT;
58
59 status = nfs41_send_compound(rpc, (char *)&compound.args,
60 (char *)&compound.res);
61 if (status)
62 goto out;
63
64 compound_error(status = compound.res.status);
65 out:
66 return status;
67 }
68
69 // AGLO: 10/07/2009 we might want lookup these values from the registry
set_fore_channel_attrs(IN nfs41_rpc_clnt * rpc,IN uint32_t max_req,OUT nfs41_channel_attrs * attrs)70 static int set_fore_channel_attrs(
71 IN nfs41_rpc_clnt *rpc,
72 IN uint32_t max_req,
73 OUT nfs41_channel_attrs *attrs)
74 {
75 attrs->ca_headerpadsize = 0;
76 attrs->ca_maxrequestsize = rpc->wsize;
77 attrs->ca_maxresponsesize = rpc->rsize;
78 attrs->ca_maxresponsesize_cached = NFS41_MAX_SERVER_CACHE;
79 attrs->ca_maxoperations = 0xffffffff;
80 attrs->ca_maxrequests = max_req;
81 attrs->ca_rdma_ird = NULL;
82 return 0;
83 }
84
85 // AGLO: 10/07/2009 we might want lookup these values from the registry
set_back_channel_attrs(IN nfs41_rpc_clnt * rpc,IN uint32_t max_req,OUT nfs41_channel_attrs * attrs)86 static int set_back_channel_attrs(
87 IN nfs41_rpc_clnt *rpc,
88 IN uint32_t max_req,
89 OUT nfs41_channel_attrs *attrs)
90 {
91 attrs->ca_headerpadsize = 0;
92 attrs->ca_maxrequestsize = rpc->wsize;
93 attrs->ca_maxresponsesize = rpc->rsize;
94 attrs->ca_maxresponsesize_cached = NFS41_MAX_SERVER_CACHE;
95 attrs->ca_maxoperations = 0xffffffff;
96 attrs->ca_maxrequests = max_req;
97 attrs->ca_rdma_ird = NULL;
98 return 0;
99 }
100
nfs41_create_session(nfs41_client * clnt,nfs41_session * session,bool_t try_recovery)101 int nfs41_create_session(nfs41_client *clnt, nfs41_session *session, bool_t try_recovery)
102 {
103 int status = 0;
104 nfs41_compound compound;
105 nfs_argop4 argop;
106 nfs_resop4 resop;
107 nfs41_create_session_args req = { 0 };
108 nfs41_create_session_res reply = { 0 };
109
110 compound_init(&compound, &argop, &resop, "create_session");
111
112 compound_add_op(&compound, OP_CREATE_SESSION, &req, &reply);
113
114 AcquireSRWLockShared(&clnt->exid_lock);
115 req.csa_clientid = clnt->clnt_id;
116 req.csa_sequence = clnt->seq_id;
117 ReleaseSRWLockShared(&clnt->exid_lock);
118 req.csa_flags = session->flags;
119 req.csa_cb_program = NFS41_RPC_CBPROGRAM;
120 req.csa_cb_secparams[0].type = 0; /* AUTH_NONE */
121 req.csa_cb_secparams[1].type = 1; /* AUTH_SYS */
122 req.csa_cb_secparams[1].u.auth_sys.machinename = clnt->rpc->server_name;
123 req.csa_cb_secparams[1].u.auth_sys.stamp = (uint32_t)time(NULL);
124
125 // ca_maxrequests should be gotten from the rpc layer
126 set_fore_channel_attrs(clnt->rpc,
127 NFS41_MAX_RPC_REQS, &req.csa_fore_chan_attrs);
128 set_back_channel_attrs(clnt->rpc,
129 1, &req.csa_back_chan_attrs);
130
131 reply.csr_sessionid = session->session_id;
132 reply.csr_fore_chan_attrs = &session->fore_chan_attrs;
133 reply.csr_back_chan_attrs = &session->back_chan_attrs;
134
135 status = compound_encode_send_decode(session, &compound, try_recovery);
136 if (status)
137 goto out;
138
139 if (compound_error(status = compound.res.status))
140 goto out;
141
142 print_hexbuf(1, (unsigned char *)"session id: ", session->session_id, NFS4_SESSIONID_SIZE);
143 // check that csa_sequence is same as csr_sequence
144 if (reply.csr_sequence != clnt->seq_id) {
145 eprintf("ERROR: CREATE_SESSION: csa_sequence %d != "
146 "csr_sequence %d\n", clnt->seq_id, reply.csr_sequence);
147 status = NFS4ERR_SEQ_MISORDERED;
148 goto out;
149 } else clnt->seq_id++;
150
151 if (reply.csr_flags != req.csa_flags) {
152 eprintf("WARNING: requested session flags %x received %x\n",
153 req.csa_flags, reply.csr_flags);
154 if ((session->flags & CREATE_SESSION4_FLAG_CONN_BACK_CHAN) &&
155 !(reply.csr_flags & CREATE_SESSION4_FLAG_CONN_BACK_CHAN))
156 eprintf("WARNING: we asked to use this session for callbacks but "
157 "server refused\n");
158 if ((session->flags & CREATE_SESSION4_FLAG_PERSIST) &&
159 !(reply.csr_flags & CREATE_SESSION4_FLAG_PERSIST))
160 eprintf("WARNING: we asked for persistent session but "
161 "server refused\n");
162 session->flags = reply.csr_flags;
163 }
164 else
165 dprintf(1, "session flags %x\n", reply.csr_flags);
166
167 dprintf(1, "session fore_chan_attrs:\n"
168 " %-32s%d\n %-32s%d\n %-32s%d\n %-32s%d\n %-32s%d\n %-32s%d\n",
169 "headerpadsize", session->fore_chan_attrs.ca_headerpadsize,
170 "maxrequestsize", session->fore_chan_attrs.ca_maxrequestsize,
171 "maxresponsesize", session->fore_chan_attrs.ca_maxresponsesize,
172 "maxresponsesize_cached", session->fore_chan_attrs.ca_maxresponsesize_cached,
173 "maxoperations", session->fore_chan_attrs.ca_maxoperations,
174 "maxrequests", session->fore_chan_attrs.ca_maxrequests);
175 dprintf(1, "client supports %d max rpc slots, but server has %d\n",
176 session->table.max_slots, session->fore_chan_attrs.ca_maxrequests);
177 /* use the server's ca_maxrequests unless it's bigger than our array */
178 session->table.max_slots = min(session->table.max_slots,
179 session->fore_chan_attrs.ca_maxrequests);
180 status = 0;
181 out:
182 return status;
183 }
184
nfs41_bind_conn_to_session(IN nfs41_rpc_clnt * rpc,IN const unsigned char * sessionid,IN enum channel_dir_from_client4 dir)185 enum nfsstat4 nfs41_bind_conn_to_session(
186 IN nfs41_rpc_clnt *rpc,
187 IN const unsigned char *sessionid,
188 IN enum channel_dir_from_client4 dir)
189 {
190 int status;
191 nfs41_compound compound;
192 nfs_argop4 argop;
193 nfs_resop4 resop;
194 nfs41_bind_conn_to_session_args bind_args = { 0 };
195 nfs41_bind_conn_to_session_res bind_res = { 0 };
196
197 compound_init(&compound, &argop, &resop, "bind_conn_to_session");
198
199 compound_add_op(&compound, OP_BIND_CONN_TO_SESSION, &bind_args, &bind_res);
200 bind_args.sessionid = (unsigned char *)sessionid;
201 bind_args.dir = dir;
202
203 status = nfs41_send_compound(rpc,
204 (char*)&compound.args, (char*)&compound.res);
205 if (status)
206 goto out;
207
208 compound_error(status = compound.res.status);
209
210 out:
211 return status;
212 }
213
nfs41_destroy_session(IN nfs41_session * session)214 int nfs41_destroy_session(
215 IN nfs41_session *session)
216 {
217 int status;
218 nfs41_compound compound;
219 nfs_argop4 argop;
220 nfs_resop4 resop;
221 nfs41_destroy_session_args ds_args;
222 nfs41_destroy_session_res ds_res;
223
224 compound_init(&compound, &argop, &resop, "destroy_session");
225
226 compound_add_op(&compound, OP_DESTROY_SESSION, &ds_args, &ds_res);
227 ds_args.dsa_sessionid = session->session_id;
228
229 /* don't attempt to recover from BADSESSION/STALE_CLIENTID */
230 status = compound_encode_send_decode(session, &compound, FALSE);
231 if (status)
232 goto out;
233
234 status = compound.res.status;
235 if (status)
236 eprintf("%s failed with status %d.\n",
237 nfs_opnum_to_string(OP_DESTROY_SESSION), status);
238 out:
239 return status;
240 }
241
nfs41_destroy_clientid(IN nfs41_rpc_clnt * rpc,IN uint64_t clientid)242 int nfs41_destroy_clientid(
243 IN nfs41_rpc_clnt *rpc,
244 IN uint64_t clientid)
245 {
246 int status;
247 nfs41_compound compound;
248 nfs_argop4 argops;
249 nfs_resop4 resops;
250 nfs41_destroy_clientid_args dc_args;
251 nfs41_destroy_clientid_res dc_res;
252
253 compound_init(&compound, &argops, &resops, "destroy_clientid");
254
255 compound_add_op(&compound, OP_DESTROY_CLIENTID, &dc_args, &dc_res);
256 dc_args.dca_clientid = clientid;
257
258 status = nfs41_send_compound(rpc, (char *)&compound.args,
259 (char *)&compound.res);
260 if (status)
261 goto out;
262
263 compound_error(status = compound.res.status);
264 out:
265 return status;
266 }
267
nfs41_reclaim_complete(IN nfs41_session * session)268 enum nfsstat4 nfs41_reclaim_complete(
269 IN nfs41_session *session)
270 {
271 enum nfsstat4 status = NFS4_OK;
272 nfs41_compound compound;
273 nfs_argop4 argops[2];
274 nfs_resop4 resops[2];
275 nfs41_sequence_args sequence_args;
276 nfs41_sequence_res sequence_res;
277 nfs41_reclaim_complete_res reclaim_res;
278
279 compound_init(&compound, argops, resops, "reclaim_complete");
280
281 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
282 nfs41_session_sequence(&sequence_args, session, 0);
283
284 compound_add_op(&compound, OP_RECLAIM_COMPLETE, NULL, &reclaim_res);
285
286 /* don't attempt to recover from BADSESSION */
287 status = compound_encode_send_decode(session, &compound, FALSE);
288 if (status)
289 goto out;
290
291 compound_error(status = compound.res.status);
292 out:
293 return status;
294 }
295
open_delegation_return(IN nfs41_session * session,IN nfs41_path_fh * file,IN open_delegation4 * delegation,IN bool_t try_recovery)296 static void open_delegation_return(
297 IN nfs41_session *session,
298 IN nfs41_path_fh *file,
299 IN open_delegation4 *delegation,
300 IN bool_t try_recovery)
301 {
302 stateid_arg stateid;
303 int status;
304
305 if (delegation->type == OPEN_DELEGATE_NONE ||
306 delegation->type == OPEN_DELEGATE_NONE_EXT)
307 return;
308
309 /* return the delegation */
310 stateid.open = NULL;
311 stateid.delegation = NULL;
312 stateid.type = STATEID_DELEG_FILE;
313 memcpy(&stateid.stateid, &delegation->stateid, sizeof(stateid4));
314
315 status = nfs41_delegreturn(session, file, &stateid, try_recovery);
316
317 /* clear the delegation type returned by nfs41_open() */
318 delegation->type = OPEN_DELEGATE_NONE;
319 }
320
open_update_cache(IN nfs41_session * session,IN nfs41_path_fh * parent,IN nfs41_path_fh * file,IN bool_t try_recovery,IN open_delegation4 * delegation,IN bool_t already_delegated,IN change_info4 * changeinfo,IN nfs41_getattr_res * dir_attrs,IN nfs41_getattr_res * file_attrs)321 static void open_update_cache(
322 IN nfs41_session *session,
323 IN nfs41_path_fh *parent,
324 IN nfs41_path_fh *file,
325 IN bool_t try_recovery,
326 IN open_delegation4 *delegation,
327 IN bool_t already_delegated,
328 IN change_info4 *changeinfo,
329 IN nfs41_getattr_res *dir_attrs,
330 IN nfs41_getattr_res *file_attrs)
331 {
332 struct nfs41_name_cache *cache = session_name_cache(session);
333 uint32_t status;
334
335 /* update the attributes of the parent directory */
336 memcpy(&dir_attrs->info->attrmask, &dir_attrs->obj_attributes.attrmask,
337 sizeof(bitmap4));
338 nfs41_attr_cache_update(cache, parent->fh.fileid, dir_attrs->info);
339
340 /* add the file handle and attributes to the name cache */
341 memcpy(&file_attrs->info->attrmask, &file_attrs->obj_attributes.attrmask,
342 sizeof(bitmap4));
343 retry_cache_insert:
344 AcquireSRWLockShared(&file->path->lock);
345 status = nfs41_name_cache_insert(cache, file->path->path, &file->name,
346 &file->fh, file_attrs->info, changeinfo,
347 already_delegated ? OPEN_DELEGATE_NONE : delegation->type);
348 ReleaseSRWLockShared(&file->path->lock);
349
350 if (status == ERROR_TOO_MANY_OPEN_FILES) {
351 /* the cache won't accept any more delegations; ask the client to
352 * return a delegation to free up a slot in the attribute cache */
353 status = nfs41_client_delegation_return_lru(session->client);
354 if (status == NFS4_OK)
355 goto retry_cache_insert;
356 }
357
358 if (status && delegation->type != OPEN_DELEGATE_NONE) {
359 /* if we can't make room in the cache, return this
360 * delegation immediately to free resources on the server */
361 open_delegation_return(session, file, delegation, try_recovery);
362 goto retry_cache_insert;
363 }
364 }
365
nfs41_open(IN nfs41_session * session,IN nfs41_path_fh * parent,IN nfs41_path_fh * file,IN state_owner4 * owner,IN open_claim4 * claim,IN uint32_t allow,IN uint32_t deny,IN uint32_t create,IN uint32_t how_mode,IN OPTIONAL nfs41_file_info * createattrs,IN bool_t try_recovery,OUT stateid4 * stateid,OUT open_delegation4 * delegation,OUT OPTIONAL nfs41_file_info * info)366 int nfs41_open(
367 IN nfs41_session *session,
368 IN nfs41_path_fh *parent,
369 IN nfs41_path_fh *file,
370 IN state_owner4 *owner,
371 IN open_claim4 *claim,
372 IN uint32_t allow,
373 IN uint32_t deny,
374 IN uint32_t create,
375 IN uint32_t how_mode,
376 IN OPTIONAL nfs41_file_info *createattrs,
377 IN bool_t try_recovery,
378 OUT stateid4 *stateid,
379 OUT open_delegation4 *delegation,
380 OUT OPTIONAL nfs41_file_info *info)
381 {
382 int status;
383 nfs41_compound compound;
384 nfs_argop4 argops[8];
385 nfs_resop4 resops[8];
386 nfs41_sequence_args sequence_args;
387 nfs41_sequence_res sequence_res;
388 nfs41_putfh_args putfh_args[2];
389 nfs41_putfh_res putfh_res[2];
390 nfs41_op_open_args open_args;
391 nfs41_op_open_res open_res;
392 nfs41_getfh_res getfh_res;
393 bitmap4 attr_request;
394 nfs41_getattr_args getattr_args;
395 nfs41_getattr_res getattr_res, pgetattr_res;
396 nfs41_savefh_res savefh_res;
397 nfs41_restorefh_res restorefh_res;
398 nfs41_file_info tmp_info, dir_info;
399 bool_t current_fh_is_dir;
400 bool_t already_delegated = delegation->type == OPEN_DELEGATE_READ
401 || delegation->type == OPEN_DELEGATE_WRITE;
402
403 /* depending on the claim type, OPEN expects CURRENT_FH set
404 * to either the parent directory, or to the file itself */
405 switch (claim->claim) {
406 case CLAIM_NULL:
407 case CLAIM_DELEGATE_CUR:
408 case CLAIM_DELEGATE_PREV:
409 /* CURRENT_FH: directory */
410 current_fh_is_dir = TRUE;
411 /* SEQUENCE; PUTFH(dir); SAVEFH; OPEN;
412 * GETFH(file); GETATTR(file); RESTOREFH(dir); GETATTR */
413 nfs41_superblock_getattr_mask(parent->fh.superblock, &attr_request);
414 break;
415 case CLAIM_PREVIOUS:
416 case CLAIM_FH:
417 case CLAIM_DELEG_CUR_FH:
418 case CLAIM_DELEG_PREV_FH:
419 default:
420 /* CURRENT_FH: file being opened */
421 current_fh_is_dir = FALSE;
422 /* SEQUENCE; PUTFH(file); OPEN; GETATTR(file); PUTFH(dir); GETATTR */
423 nfs41_superblock_getattr_mask(file->fh.superblock, &attr_request);
424 break;
425 }
426
427 if (info == NULL)
428 info = &tmp_info;
429
430 attr_request.arr[0] |= FATTR4_WORD0_FSID;
431
432 compound_init(&compound, argops, resops, "open");
433
434 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
435 nfs41_session_sequence(&sequence_args, session, 1);
436
437 if (current_fh_is_dir) {
438 /* CURRENT_FH: directory */
439 compound_add_op(&compound, OP_PUTFH, &putfh_args[0], &putfh_res[0]);
440 putfh_args[0].file = parent;
441 putfh_args[0].in_recovery = 0;
442
443 compound_add_op(&compound, OP_SAVEFH, NULL, &savefh_res);
444 } else {
445 /* CURRENT_FH: file being opened */
446 compound_add_op(&compound, OP_PUTFH, &putfh_args[0], &putfh_res[0]);
447 putfh_args[0].file = file;
448 putfh_args[0].in_recovery = 0;
449 }
450
451 compound_add_op(&compound, OP_OPEN, &open_args, &open_res);
452 open_args.seqid = 0;
453 #ifdef DISABLE_FILE_DELEGATIONS
454 open_args.share_access = allow | OPEN4_SHARE_ACCESS_WANT_NO_DELEG;
455 #else
456 open_args.share_access = allow;
457 #endif
458 open_args.share_deny = deny;
459 open_args.owner = owner;
460 open_args.openhow.opentype = create;
461 open_args.openhow.how.mode = how_mode;
462 open_args.openhow.how.createattrs = createattrs;
463 if (how_mode == EXCLUSIVE4_1) {
464 DWORD tid = GetCurrentThreadId();
465 time((time_t*)open_args.openhow.how.createverf);
466 memcpy(open_args.openhow.how.createverf+4, &tid, sizeof(tid));
467 /* mask unsupported attributes */
468 nfs41_superblock_supported_attrs_exclcreat(
469 parent->fh.superblock, &createattrs->attrmask);
470 } else if (createattrs) {
471 /* mask unsupported attributes */
472 nfs41_superblock_supported_attrs(
473 parent->fh.superblock, &createattrs->attrmask);
474 }
475 open_args.claim = claim;
476 open_res.resok4.stateid = stateid;
477 open_res.resok4.delegation = delegation;
478
479 if (current_fh_is_dir) {
480 compound_add_op(&compound, OP_GETFH, NULL, &getfh_res);
481 getfh_res.fh = &file->fh;
482 }
483
484 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res);
485 getattr_args.attr_request = &attr_request;
486 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT;
487 getattr_res.info = info;
488
489 if (current_fh_is_dir) {
490 compound_add_op(&compound, OP_RESTOREFH, NULL, &restorefh_res);
491 } else {
492 compound_add_op(&compound, OP_PUTFH, &putfh_args[1], &putfh_res[1]);
493 putfh_args[1].file = parent;
494 putfh_args[1].in_recovery = 0;
495 }
496
497 compound_add_op(&compound, OP_GETATTR, &getattr_args, &pgetattr_res);
498 getattr_args.attr_request = &attr_request;
499 pgetattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT;
500 pgetattr_res.info = &dir_info;
501
502 status = compound_encode_send_decode(session, &compound, try_recovery);
503 if (status)
504 goto out;
505
506 if (compound_error(status = compound.res.status))
507 goto out;
508
509 if (dir_info.type == NF4ATTRDIR) {
510 file->fh.superblock = parent->fh.superblock;
511 goto out;
512 }
513
514 /* fill in the file handle's fileid and superblock */
515 file->fh.fileid = info->fileid;
516 status = nfs41_superblock_for_fh(session, &info->fsid, &parent->fh, file);
517 if (status)
518 goto out;
519
520 if (create == OPEN4_CREATE)
521 nfs41_superblock_space_changed(file->fh.superblock);
522
523 /* update the name/attr cache with the results */
524 open_update_cache(session, parent, file, try_recovery, delegation,
525 already_delegated, &open_res.resok4.cinfo, &pgetattr_res, &getattr_res);
526 out:
527 return status;
528 }
529
nfs41_create(IN nfs41_session * session,IN uint32_t type,IN nfs41_file_info * createattrs,IN OPTIONAL const char * symlink,IN nfs41_path_fh * parent,OUT nfs41_path_fh * file,OUT nfs41_file_info * info)530 int nfs41_create(
531 IN nfs41_session *session,
532 IN uint32_t type,
533 IN nfs41_file_info *createattrs,
534 IN OPTIONAL const char *symlink,
535 IN nfs41_path_fh *parent,
536 OUT nfs41_path_fh *file,
537 OUT nfs41_file_info *info)
538 {
539 int status;
540 nfs41_compound compound;
541 nfs_argop4 argops[8];
542 nfs_resop4 resops[8];
543 nfs41_sequence_args sequence_args;
544 nfs41_sequence_res sequence_res;
545 nfs41_putfh_args putfh_args;
546 nfs41_putfh_res putfh_res;
547 nfs41_create_args create_args;
548 nfs41_create_res create_res;
549 nfs41_getfh_res getfh_res;
550 nfs41_getattr_args getattr_args;
551 nfs41_getattr_res getattr_res, pgetattr_res;
552 bitmap4 attr_request;
553 nfs41_file_info dir_info;
554 nfs41_savefh_res savefh_res;
555 nfs41_restorefh_res restorefh_res;
556
557 nfs41_superblock_getattr_mask(parent->fh.superblock, &attr_request);
558
559 compound_init(&compound, argops, resops, "create");
560
561 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
562 nfs41_session_sequence(&sequence_args, session, 1);
563
564 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
565 putfh_args.file = parent;
566 putfh_args.in_recovery = 0;
567
568 compound_add_op(&compound, OP_SAVEFH, NULL, &savefh_res);
569
570 compound_add_op(&compound, OP_CREATE, &create_args, &create_res);
571 create_args.objtype.type = type;
572 if (type == NF4LNK) {
573 create_args.objtype.u.lnk.linkdata = symlink;
574 create_args.objtype.u.lnk.linkdata_len = (uint32_t)strlen(symlink);
575 }
576 create_args.name = &file->name;
577 create_args.createattrs = createattrs;
578 nfs41_superblock_supported_attrs(
579 parent->fh.superblock, &createattrs->attrmask);
580
581 compound_add_op(&compound, OP_GETFH, NULL, &getfh_res);
582 getfh_res.fh = &file->fh;
583
584 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res);
585 getattr_args.attr_request = &attr_request;
586 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT;
587 getattr_res.info = info;
588
589 compound_add_op(&compound, OP_RESTOREFH, NULL, &restorefh_res);
590
591 compound_add_op(&compound, OP_GETATTR, &getattr_args, &pgetattr_res);
592 getattr_args.attr_request = &attr_request;
593 pgetattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT;
594 pgetattr_res.info = &dir_info;
595
596 status = compound_encode_send_decode(session, &compound, TRUE);
597 if (status)
598 goto out;
599
600 if (compound_error(status = compound.res.status))
601 goto out;
602
603 /* fill in the file handle's fileid and superblock */
604 file->fh.fileid = info->fileid;
605 file->fh.superblock = parent->fh.superblock;
606
607 /* update the attributes of the parent directory */
608 memcpy(&dir_info.attrmask, &pgetattr_res.obj_attributes.attrmask,
609 sizeof(bitmap4));
610 nfs41_attr_cache_update(session_name_cache(session),
611 parent->fh.fileid, &dir_info);
612
613 /* add the new file handle and attributes to the name cache */
614 memcpy(&info->attrmask, &getattr_res.obj_attributes.attrmask,
615 sizeof(bitmap4));
616 AcquireSRWLockShared(&file->path->lock);
617 nfs41_name_cache_insert(session_name_cache(session),
618 file->path->path, &file->name, &file->fh,
619 info, &create_res.cinfo, OPEN_DELEGATE_NONE);
620 ReleaseSRWLockShared(&file->path->lock);
621
622 nfs41_superblock_space_changed(file->fh.superblock);
623 out:
624 return status;
625 }
626
nfs41_close(IN nfs41_session * session,IN nfs41_path_fh * file,IN stateid_arg * stateid)627 int nfs41_close(
628 IN nfs41_session *session,
629 IN nfs41_path_fh *file,
630 IN stateid_arg *stateid)
631 {
632 int status;
633 nfs41_compound compound;
634 nfs_argop4 argops[4];
635 nfs_resop4 resops[4];
636 nfs41_sequence_args sequence_args;
637 nfs41_sequence_res sequence_res;
638 nfs41_putfh_args putfh_args;
639 nfs41_putfh_res putfh_res;
640 nfs41_op_close_args close_args;
641 nfs41_op_close_res close_res;
642 nfs41_getattr_args getattr_args;
643 nfs41_getattr_res getattr_res;
644 bitmap4 attr_request;
645 nfs41_file_info info;
646
647 nfs41_superblock_getattr_mask(file->fh.superblock, &attr_request);
648
649 compound_init(&compound, argops, resops, "close");
650
651 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
652 nfs41_session_sequence(&sequence_args, session, 1);
653
654 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
655 putfh_args.file = file;
656 putfh_args.in_recovery = 0;
657
658 compound_add_op(&compound, OP_CLOSE, &close_args, &close_res);
659 close_args.stateid = stateid;
660
661 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res);
662 getattr_args.attr_request = &attr_request;
663 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT;
664 getattr_res.info = &info;
665
666 status = compound_encode_send_decode(session, &compound, TRUE);
667 if (status)
668 goto out;
669
670 if (compound_error(status = compound.res.status))
671 goto out;
672
673 if (info.type == NF4NAMEDATTR)
674 goto out;
675
676 /* update the attributes of the parent directory */
677 memcpy(&info.attrmask, &getattr_res.obj_attributes.attrmask,
678 sizeof(bitmap4));
679 nfs41_attr_cache_update(session_name_cache(session),
680 file->fh.fileid, &info);
681 out:
682 return status;
683 }
684
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)685 int nfs41_write(
686 IN nfs41_session *session,
687 IN nfs41_path_fh *file,
688 IN stateid_arg *stateid,
689 IN unsigned char *data,
690 IN uint32_t data_len,
691 IN uint64_t offset,
692 IN enum stable_how4 stable,
693 OUT uint32_t *bytes_written,
694 OUT nfs41_write_verf *verf,
695 OUT nfs41_file_info *cinfo)
696 {
697 int status;
698 nfs41_compound compound;
699 nfs_argop4 argops[4];
700 nfs_resop4 resops[4];
701 nfs41_sequence_args sequence_args;
702 nfs41_sequence_res sequence_res;
703 nfs41_putfh_args putfh_args;
704 nfs41_putfh_res putfh_res;
705 nfs41_write_args write_args;
706 nfs41_write_res write_res;
707 nfs41_getattr_args getattr_args;
708 nfs41_getattr_res getattr_res = {0};
709 bitmap4 attr_request;
710 nfs41_file_info info = { 0 }, *pinfo;
711
712 nfs41_superblock_getattr_mask(file->fh.superblock, &attr_request);
713
714 compound_init(&compound, argops, resops,
715 stateid->stateid.seqid == 0 ? "ds write" : "write");
716
717 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
718 nfs41_session_sequence(&sequence_args, session, 0);
719
720 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
721 putfh_args.file = file;
722 putfh_args.in_recovery = 0;
723
724 compound_add_op(&compound, OP_WRITE, &write_args, &write_res);
725 write_args.stateid = stateid;
726 write_args.offset = offset;
727 write_args.stable = stable;
728 write_args.data_len = data_len;
729 write_args.data = data;
730 write_res.resok4.verf = verf;
731
732 if (cinfo) pinfo = cinfo;
733 else pinfo = &info;
734
735 if (stable != UNSTABLE4) {
736 /* if the write is stable, we can't rely on COMMIT to update
737 * the attribute cache, so we do the GETATTR here */
738 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res);
739 getattr_args.attr_request = &attr_request;
740 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT;
741 getattr_res.info = pinfo;
742 }
743
744 status = compound_encode_send_decode(session, &compound, TRUE);
745 if (status)
746 goto out;
747
748 if (compound_error(status = compound.res.status))
749 goto out;
750
751 if (stable != UNSTABLE4 && pinfo->type != NF4NAMEDATTR) {
752 /* update the attribute cache */
753 memcpy(&pinfo->attrmask, &getattr_res.obj_attributes.attrmask,
754 sizeof(bitmap4));
755 nfs41_attr_cache_update(session_name_cache(session),
756 file->fh.fileid, pinfo);
757 }
758
759 *bytes_written = write_res.resok4.count;
760
761 /* we shouldn't ever see this, but a buggy server could
762 * send us into an infinite loop. return NFS4ERR_IO */
763 if (!write_res.resok4.count) {
764 status = NFS4ERR_IO;
765 eprintf("WRITE succeeded with count=0; returning %s\n",
766 nfs_error_string(status));
767 }
768
769 nfs41_superblock_space_changed(file->fh.superblock);
770 out:
771 return status;
772 }
773
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)774 int nfs41_read(
775 IN nfs41_session *session,
776 IN nfs41_path_fh *file,
777 IN stateid_arg *stateid,
778 IN uint64_t offset,
779 IN uint32_t count,
780 OUT unsigned char *data_out,
781 OUT uint32_t *data_len_out,
782 OUT bool_t *eof_out)
783 {
784 int status;
785 nfs41_compound compound;
786 nfs_argop4 argops[4];
787 nfs_resop4 resops[4];
788 nfs41_sequence_args sequence_args;
789 nfs41_sequence_res sequence_res;
790 nfs41_putfh_args putfh_args;
791 nfs41_putfh_res putfh_res;
792 nfs41_read_args read_args;
793 nfs41_read_res read_res;
794
795 compound_init(&compound, argops, resops,
796 stateid->stateid.seqid == 0 ? "ds read" : "read");
797
798 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
799 nfs41_session_sequence(&sequence_args, session, 0);
800
801 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
802 putfh_args.file = file;
803 putfh_args.in_recovery = 0;
804
805 compound_add_op(&compound, OP_READ, &read_args, &read_res);
806 read_args.stateid = stateid;
807 read_args.offset = offset;
808 read_args.count = count;
809 read_res.resok4.data_len = count;
810 read_res.resok4.data = data_out;
811
812 status = compound_encode_send_decode(session, &compound, TRUE);
813 if (status)
814 goto out;
815
816 if (compound_error(status = compound.res.status))
817 goto out;
818
819 *data_len_out = read_res.resok4.data_len;
820 *eof_out = read_res.resok4.eof;
821
822 /* we shouldn't ever see this, but a buggy server could
823 * send us into an infinite loop. return NFS4ERR_IO */
824 if (!read_res.resok4.data_len && !read_res.resok4.eof) {
825 status = NFS4ERR_IO;
826 eprintf("READ succeeded with len=0 and eof=0; returning %s\n",
827 nfs_error_string(status));
828 }
829 out:
830 return status;
831 }
832
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)833 int nfs41_commit(
834 IN nfs41_session *session,
835 IN nfs41_path_fh *file,
836 IN uint64_t offset,
837 IN uint32_t count,
838 IN bool_t do_getattr,
839 OUT nfs41_write_verf *verf,
840 OUT nfs41_file_info *cinfo)
841 {
842 int status;
843 nfs41_compound compound;
844 nfs_argop4 argops[4];
845 nfs_resop4 resops[4];
846 nfs41_sequence_args sequence_args;
847 nfs41_sequence_res sequence_res;
848 nfs41_putfh_args putfh_args;
849 nfs41_putfh_res putfh_res;
850 nfs41_commit_args commit_args;
851 nfs41_commit_res commit_res;
852 nfs41_getattr_args getattr_args;
853 nfs41_getattr_res getattr_res = {0};
854 bitmap4 attr_request;
855 nfs41_file_info info, *pinfo;
856
857 compound_init(&compound, argops, resops,
858 do_getattr ? "commit" : "ds commit");
859
860 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
861 nfs41_session_sequence(&sequence_args, session, 1);
862
863 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
864 putfh_args.file = file;
865 putfh_args.in_recovery = 0;
866
867 compound_add_op(&compound, OP_COMMIT, &commit_args, &commit_res);
868 commit_args.offset = offset;
869 commit_args.count = count;
870 commit_res.verf = verf;
871
872 /* send a GETATTR request to update the attribute cache,
873 * but not if we're talking to a data server! */
874 if (cinfo) pinfo = cinfo;
875 else pinfo = &info;
876 if (do_getattr) {
877 nfs41_superblock_getattr_mask(file->fh.superblock, &attr_request);
878
879 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res);
880 getattr_args.attr_request = &attr_request;
881 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT;
882 getattr_res.info = pinfo;
883 }
884
885 status = compound_encode_send_decode(session, &compound, TRUE);
886 if (status)
887 goto out;
888
889 if (compound_error(status = compound.res.status))
890 goto out;
891
892 if (do_getattr) {
893 /* update the attribute cache */
894 memcpy(&pinfo->attrmask, &getattr_res.obj_attributes.attrmask,
895 sizeof(bitmap4));
896 nfs41_attr_cache_update(session_name_cache(session),
897 file->fh.fileid, pinfo);
898 }
899 nfs41_superblock_space_changed(file->fh.superblock);
900 out:
901 return status;
902 }
903
nfs41_lock(IN nfs41_session * session,IN nfs41_path_fh * file,IN state_owner4 * owner,IN uint32_t type,IN uint64_t offset,IN uint64_t length,IN bool_t reclaim,IN bool_t try_recovery,IN OUT stateid_arg * stateid)904 int nfs41_lock(
905 IN nfs41_session *session,
906 IN nfs41_path_fh *file,
907 IN state_owner4 *owner,
908 IN uint32_t type,
909 IN uint64_t offset,
910 IN uint64_t length,
911 IN bool_t reclaim,
912 IN bool_t try_recovery,
913 IN OUT stateid_arg *stateid)
914 {
915 int status;
916 nfs41_compound compound;
917 nfs_argop4 argops[3];
918 nfs_resop4 resops[3];
919 nfs41_sequence_args sequence_args;
920 nfs41_sequence_res sequence_res;
921 nfs41_putfh_args putfh_args;
922 nfs41_putfh_res putfh_res;
923 nfs41_lock_args lock_args;
924 nfs41_lock_res lock_res;
925
926 compound_init(&compound, argops, resops, "lock");
927
928 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
929 nfs41_session_sequence(&sequence_args, session, 0);
930
931 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
932 putfh_args.file = file;
933 putfh_args.in_recovery = 0;
934
935 compound_add_op(&compound, OP_LOCK, &lock_args, &lock_res);
936 lock_args.locktype = type;
937 lock_args.reclaim = reclaim;
938 lock_args.offset = offset;
939 lock_args.length = length;
940 if (stateid->type == STATEID_LOCK) {
941 lock_args.locker.new_lock_owner = 0;
942 lock_args.locker.u.lock_owner.lock_stateid = stateid;
943 lock_args.locker.u.lock_owner.lock_seqid = 0; /* ignored */
944 } else {
945 lock_args.locker.new_lock_owner = 1;
946 lock_args.locker.u.open_owner.open_seqid = 0; /* ignored */
947 lock_args.locker.u.open_owner.open_stateid = stateid;
948 lock_args.locker.u.open_owner.lock_seqid = 0; /* ignored */
949 lock_args.locker.u.open_owner.lock_owner = owner;
950 }
951 lock_res.u.resok4.lock_stateid = &stateid->stateid;
952 lock_res.u.denied.owner.owner_len = NFS4_OPAQUE_LIMIT;
953
954 status = compound_encode_send_decode(session, &compound, try_recovery);
955 if (status)
956 goto out;
957
958 if (compound_error(status = compound.res.status))
959 goto out;
960
961 stateid->type = STATEID_LOCK; /* returning a lock stateid */
962 out:
963 return status;
964 }
965
nfs41_unlock(IN nfs41_session * session,IN nfs41_path_fh * file,IN uint64_t offset,IN uint64_t length,IN OUT stateid_arg * stateid)966 int nfs41_unlock(
967 IN nfs41_session *session,
968 IN nfs41_path_fh *file,
969 IN uint64_t offset,
970 IN uint64_t length,
971 IN OUT stateid_arg *stateid)
972 {
973 int status;
974 nfs41_compound compound;
975 nfs_argop4 argops[3];
976 nfs_resop4 resops[3];
977 nfs41_sequence_args sequence_args;
978 nfs41_sequence_res sequence_res;
979 nfs41_putfh_args putfh_args;
980 nfs41_putfh_res putfh_res;
981 nfs41_locku_args locku_args;
982 nfs41_locku_res locku_res;
983
984 compound_init(&compound, argops, resops, "unlock");
985
986 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
987 nfs41_session_sequence(&sequence_args, session, 0);
988
989 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
990 putfh_args.file = file;
991 putfh_args.in_recovery = 0;
992
993 compound_add_op(&compound, OP_LOCKU, &locku_args, &locku_res);
994 /* 18.12.3: the server MUST accept any legal value for locktype */
995 locku_args.locktype = READ_LT;
996 locku_args.offset = offset;
997 locku_args.length = length;
998 locku_args.lock_stateid = stateid;
999 locku_res.lock_stateid = &stateid->stateid;
1000
1001 status = compound_encode_send_decode(session, &compound, TRUE);
1002 if (status)
1003 goto out;
1004
1005 compound_error(status = compound.res.status);
1006 out:
1007 return status;
1008 }
1009
nfs41_readdir(IN nfs41_session * session,IN nfs41_path_fh * file,IN bitmap4 * attr_request,IN nfs41_readdir_cookie * cookie,OUT unsigned char * entries,IN OUT uint32_t * entries_len,OUT bool_t * eof_out)1010 int nfs41_readdir(
1011 IN nfs41_session *session,
1012 IN nfs41_path_fh *file,
1013 IN bitmap4 *attr_request,
1014 IN nfs41_readdir_cookie *cookie,
1015 OUT unsigned char *entries,
1016 IN OUT uint32_t *entries_len,
1017 OUT bool_t *eof_out)
1018 {
1019 int status;
1020 nfs41_compound compound;
1021 nfs_argop4 argops[3];
1022 nfs_resop4 resops[3];
1023 nfs41_sequence_args sequence_args;
1024 nfs41_sequence_res sequence_res;
1025 nfs41_putfh_args putfh_args;
1026 nfs41_putfh_res putfh_res;
1027 nfs41_readdir_args readdir_args;
1028 nfs41_readdir_res readdir_res;
1029
1030 compound_init(&compound, argops, resops, "readdir");
1031
1032 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
1033 nfs41_session_sequence(&sequence_args, session, 0);
1034
1035 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
1036 putfh_args.file = file;
1037 putfh_args.in_recovery = 0;
1038
1039 compound_add_op(&compound, OP_READDIR, &readdir_args, &readdir_res);
1040 readdir_args.cookie.cookie = cookie->cookie;
1041 memcpy(readdir_args.cookie.verf, cookie->verf, NFS4_VERIFIER_SIZE);
1042 readdir_args.dircount = *entries_len;
1043 readdir_args.maxcount = *entries_len + sizeof(nfs41_readdir_res);
1044 readdir_args.attr_request = attr_request;
1045 readdir_res.reply.entries_len = *entries_len;
1046 readdir_res.reply.entries = entries;
1047 ZeroMemory(entries, readdir_args.dircount);
1048
1049 status = compound_encode_send_decode(session, &compound, TRUE);
1050 if (status)
1051 goto out;
1052
1053 if (compound_error(status = compound.res.status))
1054 goto out;
1055
1056 *entries_len = readdir_res.reply.entries_len;
1057 *eof_out = readdir_res.reply.eof;
1058 memcpy(cookie->verf, readdir_res.cookieverf, NFS4_VERIFIER_SIZE);
1059 out:
1060 return status;
1061 }
1062
nfs41_getattr(IN nfs41_session * session,IN OPTIONAL nfs41_path_fh * file,IN bitmap4 * attr_request,OUT nfs41_file_info * info)1063 int nfs41_getattr(
1064 IN nfs41_session *session,
1065 IN OPTIONAL nfs41_path_fh *file,
1066 IN bitmap4 *attr_request,
1067 OUT nfs41_file_info *info)
1068 {
1069 int status;
1070 nfs41_compound compound;
1071 nfs_argop4 argops[3];
1072 nfs_resop4 resops[3];
1073 nfs41_sequence_args sequence_args;
1074 nfs41_sequence_res sequence_res;
1075 nfs41_putfh_args putfh_args;
1076 nfs41_putfh_res putfh_res;
1077 nfs41_getattr_args getattr_args;
1078 nfs41_getattr_res getattr_res;
1079
1080 compound_init(&compound, argops, resops, "getattr");
1081
1082 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
1083 nfs41_session_sequence(&sequence_args, session, 0);
1084
1085 if (file) {
1086 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
1087 putfh_args.file = file;
1088 putfh_args.in_recovery = 0;
1089 } else {
1090 compound_add_op(&compound, OP_PUTROOTFH, NULL, &putfh_res);
1091 }
1092
1093 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res);
1094 getattr_args.attr_request = attr_request;
1095 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT;
1096 getattr_res.info = info;
1097
1098 status = compound_encode_send_decode(session, &compound, TRUE);
1099 if (status)
1100 goto out;
1101
1102 if (compound_error(status = compound.res.status))
1103 goto out;
1104
1105 if (file) {
1106 /* update the name cache with whatever attributes we got */
1107 memcpy(&info->attrmask, &getattr_res.obj_attributes.attrmask,
1108 sizeof(bitmap4));
1109 nfs41_attr_cache_update(session_name_cache(session),
1110 file->fh.fileid, info);
1111 }
1112 out:
1113 return status;
1114 }
1115
nfs41_superblock_getattr(IN nfs41_session * session,IN nfs41_path_fh * file,IN bitmap4 * attr_request,OUT nfs41_file_info * info,OUT bool_t * supports_named_attrs)1116 int nfs41_superblock_getattr(
1117 IN nfs41_session *session,
1118 IN nfs41_path_fh *file,
1119 IN bitmap4 *attr_request,
1120 OUT nfs41_file_info *info,
1121 OUT bool_t *supports_named_attrs)
1122 {
1123 int status;
1124 nfs41_compound compound;
1125 nfs_argop4 argops[4];
1126 nfs_resop4 resops[4];
1127 nfs41_sequence_args sequence_args;
1128 nfs41_sequence_res sequence_res;
1129 nfs41_putfh_args putfh_args;
1130 nfs41_putfh_res putfh_res;
1131 nfs41_getattr_args getattr_args;
1132 nfs41_getattr_res getattr_res;
1133 nfs41_openattr_args openattr_args;
1134 nfs41_openattr_res openattr_res;
1135
1136 compound_init(&compound, argops, resops, "getfsattr");
1137
1138 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
1139 nfs41_session_sequence(&sequence_args, session, 0);
1140
1141 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
1142 putfh_args.file = file;
1143 putfh_args.in_recovery = 0;
1144
1145 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res);
1146 getattr_args.attr_request = attr_request;
1147 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT;
1148 getattr_res.info = info;
1149
1150 compound_add_op(&compound, OP_OPENATTR, &openattr_args, &openattr_res);
1151 openattr_args.createdir = 0;
1152
1153 status = compound_encode_send_decode(session, &compound, TRUE);
1154 if (status)
1155 goto out;
1156
1157 status = sequence_res.sr_status;
1158 if (status) goto out;
1159 status = putfh_res.status;
1160 if (status) goto out;
1161 status = getattr_res.status;
1162 if (status) goto out;
1163
1164 switch (status = openattr_res.status) {
1165 case NFS4ERR_NOTSUPP:
1166 *supports_named_attrs = 0;
1167 status = NFS4_OK;
1168 break;
1169
1170 case NFS4ERR_NOENT:
1171 case NFS4_OK:
1172 *supports_named_attrs = 1;
1173 status = NFS4_OK;
1174 break;
1175 }
1176 out:
1177 return status;
1178 }
1179
nfs41_remove(IN nfs41_session * session,IN nfs41_path_fh * parent,IN const nfs41_component * target,IN uint64_t fileid)1180 int nfs41_remove(
1181 IN nfs41_session *session,
1182 IN nfs41_path_fh *parent,
1183 IN const nfs41_component *target,
1184 IN uint64_t fileid)
1185 {
1186 int status;
1187 nfs41_compound compound;
1188 nfs_argop4 argops[4];
1189 nfs_resop4 resops[4];
1190 nfs41_sequence_args sequence_args;
1191 nfs41_sequence_res sequence_res;
1192 nfs41_putfh_args putfh_args;
1193 nfs41_putfh_res putfh_res;
1194 nfs41_remove_args remove_args;
1195 nfs41_remove_res remove_res;
1196 nfs41_getattr_args getattr_args;
1197 nfs41_getattr_res getattr_res;
1198 bitmap4 attr_request;
1199 nfs41_file_info info;
1200
1201 nfs41_superblock_getattr_mask(parent->fh.superblock, &attr_request);
1202
1203 compound_init(&compound, argops, resops, "remove");
1204
1205 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
1206 nfs41_session_sequence(&sequence_args, session, 1);
1207
1208 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
1209 putfh_args.file = parent;
1210 putfh_args.in_recovery = 0;
1211
1212 compound_add_op(&compound, OP_REMOVE, &remove_args, &remove_res);
1213 remove_args.target = target;
1214
1215 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res);
1216 getattr_args.attr_request = &attr_request;
1217 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT;
1218 getattr_res.info = &info;
1219
1220 status = compound_encode_send_decode(session, &compound, TRUE);
1221 if (status)
1222 goto out;
1223
1224 if (compound_error(status = compound.res.status))
1225 goto out;
1226
1227 if (info.type == NF4ATTRDIR)
1228 goto out;
1229
1230 /* update the attributes of the parent directory */
1231 memcpy(&info.attrmask, &getattr_res.obj_attributes.attrmask,
1232 sizeof(bitmap4));
1233 nfs41_attr_cache_update(session_name_cache(session),
1234 parent->fh.fileid, &info);
1235
1236 /* remove the target file from the cache */
1237 AcquireSRWLockShared(&parent->path->lock);
1238 nfs41_name_cache_remove(session_name_cache(session),
1239 parent->path->path, target, fileid, &remove_res.cinfo);
1240 ReleaseSRWLockShared(&parent->path->lock);
1241
1242 nfs41_superblock_space_changed(parent->fh.superblock);
1243 out:
1244 return status;
1245 }
1246
nfs41_rename(IN nfs41_session * session,IN nfs41_path_fh * src_dir,IN const nfs41_component * src_name,IN nfs41_path_fh * dst_dir,IN const nfs41_component * dst_name)1247 int nfs41_rename(
1248 IN nfs41_session *session,
1249 IN nfs41_path_fh *src_dir,
1250 IN const nfs41_component *src_name,
1251 IN nfs41_path_fh *dst_dir,
1252 IN const nfs41_component *dst_name)
1253 {
1254 int status;
1255 nfs41_compound compound;
1256 nfs_argop4 argops[8];
1257 nfs_resop4 resops[8];
1258 nfs41_sequence_args sequence_args;
1259 nfs41_sequence_res sequence_res;
1260 nfs41_putfh_args src_putfh_args;
1261 nfs41_putfh_res src_putfh_res;
1262 nfs41_savefh_res savefh_res;
1263 nfs41_putfh_args dst_putfh_args;
1264 nfs41_putfh_res dst_putfh_res;
1265 nfs41_rename_args rename_args;
1266 nfs41_rename_res rename_res;
1267 nfs41_getattr_args getattr_args;
1268 nfs41_getattr_res src_getattr_res, dst_getattr_res;
1269 nfs41_file_info src_info, dst_info;
1270 bitmap4 attr_request;
1271 nfs41_restorefh_res restorefh_res;
1272
1273 nfs41_superblock_getattr_mask(src_dir->fh.superblock, &attr_request);
1274
1275 compound_init(&compound, argops, resops, "rename");
1276
1277 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
1278 nfs41_session_sequence(&sequence_args, session, 1);
1279
1280 compound_add_op(&compound, OP_PUTFH, &src_putfh_args, &src_putfh_res);
1281 src_putfh_args.file = src_dir;
1282 src_putfh_args.in_recovery = 0;
1283
1284 compound_add_op(&compound, OP_SAVEFH, NULL, &savefh_res);
1285
1286 compound_add_op(&compound, OP_PUTFH, &dst_putfh_args, &dst_putfh_res);
1287 dst_putfh_args.file = dst_dir;
1288 dst_putfh_args.in_recovery = 0;
1289
1290 compound_add_op(&compound, OP_RENAME, &rename_args, &rename_res);
1291 rename_args.oldname = src_name;
1292 rename_args.newname = dst_name;
1293
1294 compound_add_op(&compound, OP_GETATTR, &getattr_args, &dst_getattr_res);
1295 getattr_args.attr_request = &attr_request;
1296 dst_getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT;
1297 dst_getattr_res.info = &dst_info;
1298
1299 compound_add_op(&compound, OP_RESTOREFH, NULL, &restorefh_res);
1300
1301 compound_add_op(&compound, OP_GETATTR, &getattr_args, &src_getattr_res);
1302 src_getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT;
1303 src_getattr_res.info = &src_info;
1304
1305 status = compound_encode_send_decode(session, &compound, TRUE);
1306 if (status)
1307 goto out;
1308
1309 if (compound_error(status = compound.res.status))
1310 goto out;
1311
1312 /* update the attributes of the source directory */
1313 memcpy(&src_info.attrmask, &src_getattr_res.obj_attributes.attrmask,
1314 sizeof(bitmap4));
1315 nfs41_attr_cache_update(session_name_cache(session),
1316 src_dir->fh.fileid, &src_info);
1317
1318 /* update the attributes of the destination directory */
1319 memcpy(&dst_info.attrmask, &dst_getattr_res.obj_attributes.attrmask,
1320 sizeof(bitmap4));
1321 nfs41_attr_cache_update(session_name_cache(session),
1322 dst_dir->fh.fileid, &dst_info);
1323
1324 if (src_dir->path == dst_dir->path) {
1325 /* source and destination are the same, only lock it once */
1326 AcquireSRWLockShared(&src_dir->path->lock);
1327 } else if (src_dir->path < dst_dir->path) {
1328 /* lock the lowest memory address first */
1329 AcquireSRWLockShared(&src_dir->path->lock);
1330 AcquireSRWLockShared(&dst_dir->path->lock);
1331 } else {
1332 AcquireSRWLockShared(&dst_dir->path->lock);
1333 AcquireSRWLockShared(&src_dir->path->lock);
1334 }
1335
1336 /* move/rename the target file's name cache entry */
1337 nfs41_name_cache_rename(session_name_cache(session),
1338 src_dir->path->path, src_name, &rename_res.source_cinfo,
1339 dst_dir->path->path, dst_name, &rename_res.target_cinfo);
1340
1341 if (src_dir->path == dst_dir->path) {
1342 ReleaseSRWLockShared(&src_dir->path->lock);
1343 } else {
1344 ReleaseSRWLockShared(&src_dir->path->lock);
1345 ReleaseSRWLockShared(&dst_dir->path->lock);
1346 }
1347 out:
1348 return status;
1349 }
1350
nfs41_setattr(IN nfs41_session * session,IN nfs41_path_fh * file,IN stateid_arg * stateid,IN nfs41_file_info * info)1351 int nfs41_setattr(
1352 IN nfs41_session *session,
1353 IN nfs41_path_fh *file,
1354 IN stateid_arg *stateid,
1355 IN nfs41_file_info *info)
1356 {
1357 int status;
1358 nfs41_compound compound;
1359 nfs_argop4 argops[4];
1360 nfs_resop4 resops[4];
1361 nfs41_sequence_args sequence_args;
1362 nfs41_sequence_res sequence_res;
1363 nfs41_putfh_args putfh_args;
1364 nfs41_putfh_res putfh_res;
1365 nfs41_setattr_args setattr_args;
1366 nfs41_setattr_res setattr_res;
1367 nfs41_getattr_args getattr_args;
1368 nfs41_getattr_res getattr_res;
1369 bitmap4 attr_request;
1370
1371 compound_init(&compound, argops, resops, "setattr");
1372
1373 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
1374 nfs41_session_sequence(&sequence_args, session, 0);
1375
1376 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
1377 putfh_args.file = file;
1378 putfh_args.in_recovery = 0;
1379
1380 compound_add_op(&compound, OP_SETATTR, &setattr_args, &setattr_res);
1381 setattr_args.stateid = stateid;
1382 setattr_args.info = info;
1383
1384 nfs41_superblock_getattr_mask(file->fh.superblock, &attr_request);
1385 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res);
1386 getattr_args.attr_request = &attr_request;
1387 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT;
1388 getattr_res.info = info;
1389
1390 status = compound_encode_send_decode(session, &compound, TRUE);
1391 if (status)
1392 goto out;
1393
1394 if (compound_error(status = compound.res.status))
1395 goto out;
1396
1397 memcpy(&info->attrmask, &attr_request, sizeof(bitmap4));
1398 nfs41_attr_cache_update(session_name_cache(session),
1399 file->fh.fileid, info);
1400
1401 if (setattr_res.attrsset.arr[0] & FATTR4_WORD0_SIZE)
1402 nfs41_superblock_space_changed(file->fh.superblock);
1403 out:
1404 return status;
1405 }
1406
nfs41_link(IN nfs41_session * session,IN nfs41_path_fh * src,IN nfs41_path_fh * dst_dir,IN const nfs41_component * target,OUT nfs41_file_info * cinfo)1407 int nfs41_link(
1408 IN nfs41_session *session,
1409 IN nfs41_path_fh *src,
1410 IN nfs41_path_fh *dst_dir,
1411 IN const nfs41_component *target,
1412 OUT nfs41_file_info *cinfo)
1413 {
1414 int status;
1415 nfs41_compound compound;
1416 nfs_argop4 argops[9];
1417 nfs_resop4 resops[9];
1418 nfs41_sequence_args sequence_args;
1419 nfs41_sequence_res sequence_res;
1420 nfs41_putfh_args putfh_args[2];
1421 nfs41_putfh_res putfh_res[2];
1422 nfs41_savefh_res savefh_res;
1423 nfs41_link_args link_args;
1424 nfs41_link_res link_res;
1425 nfs41_lookup_args lookup_args;
1426 nfs41_lookup_res lookup_res;
1427 nfs41_getfh_res getfh_res;
1428 nfs41_getattr_args getattr_args[2];
1429 nfs41_getattr_res getattr_res[2];
1430 nfs41_file_info info = { 0 };
1431 nfs41_path_fh file;
1432
1433 nfs41_superblock_getattr_mask(src->fh.superblock, &info.attrmask);
1434 nfs41_superblock_getattr_mask(dst_dir->fh.superblock, &cinfo->attrmask);
1435 cinfo->attrmask.arr[0] |= FATTR4_WORD0_FSID;
1436
1437 compound_init(&compound, argops, resops, "link");
1438
1439 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
1440 nfs41_session_sequence(&sequence_args, session, 1);
1441
1442 /* PUTFH(src) */
1443 compound_add_op(&compound, OP_PUTFH, &putfh_args[0], &putfh_res[0]);
1444 putfh_args[0].file = src;
1445 putfh_args[0].in_recovery = 0;
1446
1447 compound_add_op(&compound, OP_SAVEFH, NULL, &savefh_res);
1448
1449 /* PUTFH(dst_dir) */
1450 compound_add_op(&compound, OP_PUTFH, &putfh_args[1], &putfh_res[1]);
1451 putfh_args[1].file = dst_dir;
1452 putfh_args[1].in_recovery = 0;
1453
1454 compound_add_op(&compound, OP_LINK, &link_args, &link_res);
1455 link_args.newname = target;
1456
1457 /* GETATTR(dst_dir) */
1458 compound_add_op(&compound, OP_GETATTR, &getattr_args[0], &getattr_res[0]);
1459 getattr_args[0].attr_request = &info.attrmask;
1460 getattr_res[0].obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT;
1461 getattr_res[0].info = &info;
1462
1463 /* LOOKUP(target) */
1464 compound_add_op(&compound, OP_LOOKUP, &lookup_args, &lookup_res);
1465 lookup_args.name = target;
1466
1467 /* GETATTR(target) */
1468 compound_add_op(&compound, OP_GETATTR, &getattr_args[1], &getattr_res[1]);
1469 getattr_args[1].attr_request = &cinfo->attrmask;
1470 getattr_res[1].obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT;
1471 getattr_res[1].info = cinfo;
1472
1473 /* GETFH(target) */
1474 compound_add_op(&compound, OP_GETFH, NULL, &getfh_res);
1475 getfh_res.fh = &file.fh;
1476
1477 status = compound_encode_send_decode(session, &compound, TRUE);
1478 if (status)
1479 goto out;
1480
1481 if (compound_error(status = compound.res.status))
1482 goto out;
1483
1484 /* fill in the file handle's fileid and superblock */
1485 file.fh.fileid = cinfo->fileid;
1486 status = nfs41_superblock_for_fh(session,
1487 &cinfo->fsid, &dst_dir->fh, &file);
1488 if (status)
1489 goto out;
1490
1491 /* update the attributes of the destination directory */
1492 memcpy(&info.attrmask, &getattr_res[0].obj_attributes.attrmask,
1493 sizeof(bitmap4));
1494 nfs41_attr_cache_update(session_name_cache(session),
1495 info.fileid, &info);
1496
1497 /* add the new file handle and attributes to the name cache */
1498 memcpy(&cinfo->attrmask, &getattr_res[1].obj_attributes.attrmask,
1499 sizeof(bitmap4));
1500 AcquireSRWLockShared(&dst_dir->path->lock);
1501 nfs41_name_cache_insert(session_name_cache(session),
1502 dst_dir->path->path, target, &file.fh,
1503 cinfo, &link_res.cinfo, OPEN_DELEGATE_NONE);
1504 ReleaseSRWLockShared(&dst_dir->path->lock);
1505
1506 nfs41_superblock_space_changed(dst_dir->fh.superblock);
1507 out:
1508 return status;
1509 }
1510
nfs41_readlink(IN nfs41_session * session,IN nfs41_path_fh * file,IN uint32_t max_len,OUT char * link_out,OUT uint32_t * len_out)1511 int nfs41_readlink(
1512 IN nfs41_session *session,
1513 IN nfs41_path_fh *file,
1514 IN uint32_t max_len,
1515 OUT char *link_out,
1516 OUT uint32_t *len_out)
1517 {
1518 int status;
1519 nfs41_compound compound;
1520 nfs_argop4 argops[3];
1521 nfs_resop4 resops[3];
1522 nfs41_sequence_args sequence_args;
1523 nfs41_sequence_res sequence_res;
1524 nfs41_putfh_args putfh_args;
1525 nfs41_putfh_res putfh_res;
1526 nfs41_readlink_res readlink_res;
1527
1528 compound_init(&compound, argops, resops, "readlink");
1529
1530 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
1531 nfs41_session_sequence(&sequence_args, session, 0);
1532
1533 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
1534 putfh_args.file = file;
1535 putfh_args.in_recovery = 0;
1536
1537 compound_add_op(&compound, OP_READLINK, NULL, &readlink_res);
1538 readlink_res.link_len = max_len - 1;
1539 readlink_res.link = link_out;
1540
1541 status = compound_encode_send_decode(session, &compound, TRUE);
1542 if (status)
1543 goto out;
1544
1545 if (compound_error(status = compound.res.status))
1546 goto out;
1547
1548 link_out[readlink_res.link_len] = '\0';
1549 *len_out = readlink_res.link_len;
1550 out:
1551 return status;
1552 }
1553
nfs41_access(IN nfs41_session * session,IN nfs41_path_fh * file,IN uint32_t requested,OUT uint32_t * supported OPTIONAL,OUT uint32_t * access OPTIONAL)1554 int nfs41_access(
1555 IN nfs41_session *session,
1556 IN nfs41_path_fh *file,
1557 IN uint32_t requested,
1558 OUT uint32_t *supported OPTIONAL,
1559 OUT uint32_t *access OPTIONAL)
1560 {
1561 int status;
1562 nfs41_compound compound;
1563 nfs_argop4 argops[3];
1564 nfs_resop4 resops[3];
1565 nfs41_sequence_args sequence_args;
1566 nfs41_sequence_res sequence_res;
1567 nfs41_putfh_args putfh_args;
1568 nfs41_putfh_res putfh_res;
1569 nfs41_access_args access_args;
1570 nfs41_access_res access_res;
1571
1572 compound_init(&compound, argops, resops, "access");
1573
1574 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
1575 nfs41_session_sequence(&sequence_args, session, 0);
1576
1577 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
1578 putfh_args.file = file;
1579 putfh_args.in_recovery = 0;
1580
1581 compound_add_op(&compound, OP_ACCESS, &access_args, &access_res);
1582 access_args.access = requested;
1583
1584 status = compound_encode_send_decode(session, &compound, TRUE);
1585 if (status)
1586 goto out;
1587
1588 if (compound_error(status = compound.res.status))
1589 goto out;
1590
1591 if (supported)
1592 *supported = access_res.supported;
1593 if (access)
1594 *access = access_res.access;
1595 out:
1596 return status;
1597 }
1598
nfs41_send_sequence(IN nfs41_session * session)1599 int nfs41_send_sequence(
1600 IN nfs41_session *session)
1601 {
1602 int status;
1603 nfs41_compound compound;
1604 nfs_argop4 argops[1];
1605 nfs_resop4 resops[1];
1606 nfs41_sequence_args sequence_args;
1607 nfs41_sequence_res sequence_res;
1608
1609 compound_init(&compound, argops, resops, "sequence");
1610
1611 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
1612 nfs41_session_sequence(&sequence_args, session, 0);
1613
1614 status = compound_encode_send_decode(session, &compound, TRUE);
1615 if (status)
1616 goto out;
1617
1618 if (compound_error(status = compound.res.status))
1619 goto out;
1620 out:
1621 return status;
1622 }
1623
nfs41_want_delegation(IN nfs41_session * session,IN nfs41_path_fh * file,IN deleg_claim4 * claim,IN uint32_t want,IN bool_t try_recovery,OUT open_delegation4 * delegation)1624 enum nfsstat4 nfs41_want_delegation(
1625 IN nfs41_session *session,
1626 IN nfs41_path_fh *file,
1627 IN deleg_claim4 *claim,
1628 IN uint32_t want,
1629 IN bool_t try_recovery,
1630 OUT open_delegation4 *delegation)
1631 {
1632 enum nfsstat4 status;
1633 nfs41_compound compound;
1634 nfs_argop4 argops[3];
1635 nfs_resop4 resops[3];
1636 nfs41_sequence_args sequence_args;
1637 nfs41_sequence_res sequence_res;
1638 nfs41_putfh_args putfh_args;
1639 nfs41_putfh_res putfh_res;
1640 nfs41_want_delegation_args wd_args;
1641 nfs41_want_delegation_res wd_res;
1642
1643 compound_init(&compound, argops, resops, "want_delegation");
1644
1645 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
1646 nfs41_session_sequence(&sequence_args, session, 0);
1647
1648 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
1649 putfh_args.file = file;
1650 putfh_args.in_recovery = 0;
1651
1652 compound_add_op(&compound, OP_WANT_DELEGATION, &wd_args, &wd_res);
1653 wd_args.claim = claim;
1654 wd_args.want = want;
1655 wd_res.delegation = delegation;
1656
1657 status = compound_encode_send_decode(session, &compound, try_recovery);
1658 if (status)
1659 goto out;
1660
1661 compound_error(status = compound.res.status);
1662 out:
1663 return status;
1664 }
1665
nfs41_delegpurge(IN nfs41_session * session)1666 int nfs41_delegpurge(
1667 IN nfs41_session *session)
1668 {
1669 int status;
1670 nfs41_compound compound;
1671 nfs_argop4 argops[2];
1672 nfs_resop4 resops[2];
1673 nfs41_sequence_args sequence_args;
1674 nfs41_sequence_res sequence_res;
1675 nfs41_delegpurge_res dp_res;
1676
1677 compound_init(&compound, argops, resops, "delegpurge");
1678
1679 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
1680 nfs41_session_sequence(&sequence_args, session, 0);
1681
1682 compound_add_op(&compound, OP_DELEGPURGE, NULL, &dp_res);
1683
1684 status = compound_encode_send_decode(session, &compound, TRUE);
1685 if (status)
1686 goto out;
1687
1688 compound_error(status = compound.res.status);
1689 out:
1690 return status;
1691 }
1692
nfs41_delegreturn(IN nfs41_session * session,IN nfs41_path_fh * file,IN stateid_arg * stateid,IN bool_t try_recovery)1693 int nfs41_delegreturn(
1694 IN nfs41_session *session,
1695 IN nfs41_path_fh *file,
1696 IN stateid_arg *stateid,
1697 IN bool_t try_recovery)
1698 {
1699 int status;
1700 nfs41_compound compound;
1701 nfs_argop4 argops[3];
1702 nfs_resop4 resops[3];
1703 nfs41_sequence_args sequence_args;
1704 nfs41_sequence_res sequence_res;
1705 nfs41_putfh_args putfh_args;
1706 nfs41_putfh_res putfh_res;
1707 nfs41_delegreturn_args dr_args;
1708 nfs41_delegreturn_res dr_res;
1709
1710 compound_init(&compound, argops, resops, "delegreturn");
1711
1712 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
1713 nfs41_session_sequence(&sequence_args, session, 0);
1714
1715 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
1716 putfh_args.file = file;
1717 putfh_args.in_recovery = 0;
1718
1719 compound_add_op(&compound, OP_DELEGRETURN, &dr_args, &dr_res);
1720 dr_args.stateid = stateid;
1721
1722 status = compound_encode_send_decode(session, &compound, try_recovery);
1723 if (status)
1724 goto out;
1725
1726 if (compound_error(status = compound.res.status))
1727 goto out;
1728
1729 AcquireSRWLockShared(&file->path->lock);
1730 nfs41_name_cache_delegreturn(session_name_cache(session),
1731 file->fh.fileid, file->path->path, &file->name);
1732 ReleaseSRWLockShared(&file->path->lock);
1733 out:
1734 return status;
1735 }
1736
nfs41_fs_locations(IN nfs41_session * session,IN nfs41_path_fh * parent,IN const nfs41_component * name,OUT fs_locations4 * locations)1737 enum nfsstat4 nfs41_fs_locations(
1738 IN nfs41_session *session,
1739 IN nfs41_path_fh *parent,
1740 IN const nfs41_component *name,
1741 OUT fs_locations4 *locations)
1742 {
1743 enum nfsstat4 status;
1744 nfs41_compound compound;
1745 nfs_argop4 argops[4];
1746 nfs_resop4 resops[4];
1747 nfs41_sequence_args sequence_args;
1748 nfs41_sequence_res sequence_res;
1749 nfs41_putfh_args putfh_args;
1750 nfs41_putfh_res putfh_res;
1751 nfs41_lookup_args lookup_args;
1752 nfs41_lookup_res lookup_res;
1753 nfs41_getattr_args getattr_args;
1754 nfs41_getattr_res getattr_res;
1755 bitmap4 attr_request = { 1, { FATTR4_WORD0_FS_LOCATIONS } };
1756 nfs41_file_info info;
1757
1758 compound_init(&compound, argops, resops, "fs_locations");
1759
1760 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
1761 nfs41_session_sequence(&sequence_args, session, 0);
1762
1763 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
1764 putfh_args.file = parent;
1765 putfh_args.in_recovery = 0;
1766
1767 compound_add_op(&compound, OP_LOOKUP, &lookup_args, &lookup_res);
1768 lookup_args.name = name;
1769
1770 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res);
1771 getattr_args.attr_request = &attr_request;
1772 info.fs_locations = locations;
1773 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT;
1774 getattr_res.info = &info;
1775
1776 status = compound_encode_send_decode(session, &compound, TRUE);
1777 if (status)
1778 goto out;
1779
1780 compound_error(status = compound.res.status);
1781 out:
1782 return status;
1783 }
1784
nfs41_secinfo(IN nfs41_session * session,IN nfs41_path_fh * file,IN const nfs41_component * name,OUT nfs41_secinfo_info * secinfo)1785 int nfs41_secinfo(
1786 IN nfs41_session *session,
1787 IN nfs41_path_fh *file,
1788 IN const nfs41_component *name,
1789 OUT nfs41_secinfo_info *secinfo)
1790 {
1791 int status;
1792 nfs41_compound compound;
1793 nfs_argop4 argops[3];
1794 nfs_resop4 resops[3];
1795 nfs41_sequence_args sequence_args;
1796 nfs41_sequence_res sequence_res;
1797 nfs41_putfh_args putfh_args;
1798 nfs41_putfh_res putfh_res;
1799 nfs41_secinfo_args secinfo_args;
1800 nfs41_secinfo_noname_res secinfo_res;
1801
1802 compound_init(&compound, argops, resops, "secinfo");
1803
1804 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
1805 nfs41_session_sequence(&sequence_args, session, 0);
1806
1807 if (file == NULL)
1808 compound_add_op(&compound, OP_PUTROOTFH, NULL, &putfh_res);
1809 else {
1810 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
1811 putfh_args.file = file;
1812 putfh_args.in_recovery = 0;
1813 }
1814
1815 compound_add_op(&compound, OP_SECINFO, &secinfo_args, &secinfo_res);
1816 secinfo_args.name = name;
1817 secinfo_res.secinfo = secinfo;
1818
1819 status = compound_encode_send_decode(session, &compound, FALSE);
1820 if (status)
1821 goto out;
1822
1823 compound_error(status = compound.res.status);
1824 out:
1825 return status;
1826 }
1827
nfs41_secinfo_noname(IN nfs41_session * session,IN nfs41_path_fh * file,OUT nfs41_secinfo_info * secinfo)1828 int nfs41_secinfo_noname(
1829 IN nfs41_session *session,
1830 IN nfs41_path_fh *file,
1831 OUT nfs41_secinfo_info *secinfo)
1832 {
1833 int status;
1834 nfs41_compound compound;
1835 nfs_argop4 argops[3];
1836 nfs_resop4 resops[3];
1837 nfs41_sequence_args sequence_args;
1838 nfs41_sequence_res sequence_res;
1839 nfs41_putfh_args putfh_args;
1840 nfs41_putfh_res putfh_res;
1841 nfs41_secinfo_noname_args noname_args;
1842 nfs41_secinfo_noname_res noname_res;
1843
1844 compound_init(&compound, argops, resops, "secinfo_no_name");
1845
1846 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
1847 nfs41_session_sequence(&sequence_args, session, 0);
1848
1849 if (file == NULL)
1850 compound_add_op(&compound, OP_PUTROOTFH, NULL, &putfh_res);
1851 else {
1852 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
1853 putfh_args.file = file;
1854 putfh_args.in_recovery = 0;
1855 }
1856
1857 compound_add_op(&compound, OP_SECINFO_NO_NAME, &noname_args, &noname_res);
1858 noname_args.type = SECINFO_STYLE4_CURRENT_FH;
1859 noname_res.secinfo = secinfo;
1860
1861 status = compound_encode_send_decode(session, &compound, FALSE);
1862 if (status)
1863 goto out;
1864
1865 compound_error(status = compound.res.status);
1866 out:
1867 return status;
1868 }
1869
nfs41_free_stateid(IN nfs41_session * session,IN stateid4 * stateid)1870 enum nfsstat4 nfs41_free_stateid(
1871 IN nfs41_session *session,
1872 IN stateid4 *stateid)
1873 {
1874 enum nfsstat4 status;
1875 nfs41_compound compound;
1876 nfs_argop4 argops[2];
1877 nfs_resop4 resops[2];
1878 nfs41_sequence_args sequence_args;
1879 nfs41_sequence_res sequence_res;
1880 nfs41_free_stateid_args freestateid_args;
1881 nfs41_free_stateid_res freestateid_res;
1882
1883 compound_init(&compound, argops, resops, "free_stateid");
1884
1885 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
1886 nfs41_session_sequence(&sequence_args, session, 0);
1887
1888 compound_add_op(&compound, OP_FREE_STATEID, &freestateid_args, &freestateid_res);
1889 freestateid_args.stateid = stateid;
1890
1891 status = compound_encode_send_decode(session, &compound, FALSE);
1892 if (status)
1893 goto out;
1894
1895 compound_error(status = compound.res.status);
1896 out:
1897 return status;
1898 }
1899
nfs41_test_stateid(IN nfs41_session * session,IN stateid_arg * stateid_array,IN uint32_t count,OUT uint32_t * status_array)1900 enum nfsstat4 nfs41_test_stateid(
1901 IN nfs41_session *session,
1902 IN stateid_arg *stateid_array,
1903 IN uint32_t count,
1904 OUT uint32_t *status_array)
1905 {
1906 enum nfsstat4 status;
1907 nfs41_compound compound;
1908 nfs_argop4 argops[2];
1909 nfs_resop4 resops[2];
1910 nfs41_sequence_args sequence_args;
1911 nfs41_sequence_res sequence_res;
1912 nfs41_test_stateid_args teststateid_args;
1913 nfs41_test_stateid_res teststateid_res;
1914
1915 compound_init(&compound, argops, resops, "test_stateid");
1916
1917 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
1918 nfs41_session_sequence(&sequence_args, session, 0);
1919
1920 compound_add_op(&compound, OP_TEST_STATEID, &teststateid_args, &teststateid_res);
1921 teststateid_args.stateids = stateid_array;
1922 teststateid_args.count = count;
1923 teststateid_res.resok.status = status_array;
1924 teststateid_res.resok.count = count;
1925
1926 status = compound_encode_send_decode(session, &compound, FALSE);
1927 if (status)
1928 goto out;
1929
1930 compound_error(status = compound.res.status);
1931 out:
1932 return status;
1933 }
1934
pnfs_rpc_layoutget(IN nfs41_session * session,IN nfs41_path_fh * file,IN stateid_arg * stateid,IN enum pnfs_iomode iomode,IN uint64_t offset,IN uint64_t minlength,IN uint64_t length,OUT pnfs_layoutget_res_ok * layoutget_res_ok)1935 enum nfsstat4 pnfs_rpc_layoutget(
1936 IN nfs41_session *session,
1937 IN nfs41_path_fh *file,
1938 IN stateid_arg *stateid,
1939 IN enum pnfs_iomode iomode,
1940 IN uint64_t offset,
1941 IN uint64_t minlength,
1942 IN uint64_t length,
1943 OUT pnfs_layoutget_res_ok *layoutget_res_ok)
1944 {
1945 enum nfsstat4 status;
1946 nfs41_compound compound;
1947 nfs_argop4 argops[3];
1948 nfs_resop4 resops[3];
1949 nfs41_sequence_args sequence_args;
1950 nfs41_sequence_res sequence_res;
1951 nfs41_putfh_args putfh_args;
1952 nfs41_putfh_res putfh_res;
1953 pnfs_layoutget_args layoutget_args;
1954 pnfs_layoutget_res layoutget_res = { 0 };
1955 uint32_t i;
1956 struct list_entry *entry;
1957
1958 compound_init(&compound, argops, resops, "layoutget");
1959
1960 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
1961 nfs41_session_sequence(&sequence_args, session, 0);
1962
1963 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
1964 putfh_args.file = file;
1965 putfh_args.in_recovery = 0;
1966
1967 compound_add_op(&compound, OP_LAYOUTGET, &layoutget_args, &layoutget_res);
1968 layoutget_args.signal_layout_avail = 0;
1969 layoutget_args.layout_type = PNFS_LAYOUTTYPE_FILE;
1970 layoutget_args.iomode = iomode;
1971 layoutget_args.offset = offset;
1972 layoutget_args.minlength = minlength;
1973 layoutget_args.length = length;
1974 layoutget_args.stateid = stateid;
1975 layoutget_args.maxcount = session->fore_chan_attrs.ca_maxresponsesize - READ_OVERHEAD;
1976
1977 layoutget_res.u.res_ok = layoutget_res_ok;
1978
1979 status = compound_encode_send_decode(session, &compound, TRUE);
1980 if (status)
1981 goto out;
1982
1983 if (compound_error(status = compound.res.status))
1984 goto out;
1985
1986 /* point each file handle to the meta server's superblock */
1987 list_for_each(entry, &layoutget_res_ok->layouts) {
1988 pnfs_layout *base = list_container(entry, pnfs_layout, entry);
1989 if (base->type == PNFS_LAYOUTTYPE_FILE) {
1990 pnfs_file_layout *layout = (pnfs_file_layout*)base;
1991 for (i = 0; i < layout->filehandles.count; i++)
1992 layout->filehandles.arr[i].fh.superblock = file->fh.superblock;
1993 }
1994 }
1995 out:
1996 return status;
1997 }
1998
pnfs_rpc_layoutcommit(IN nfs41_session * session,IN nfs41_path_fh * file,IN stateid4 * stateid,IN uint64_t offset,IN uint64_t length,IN OPTIONAL uint64_t * new_last_offset,IN OPTIONAL nfstime4 * new_time_modify,OUT nfs41_file_info * info)1999 enum nfsstat4 pnfs_rpc_layoutcommit(
2000 IN nfs41_session *session,
2001 IN nfs41_path_fh *file,
2002 IN stateid4 *stateid,
2003 IN uint64_t offset,
2004 IN uint64_t length,
2005 IN OPTIONAL uint64_t *new_last_offset,
2006 IN OPTIONAL nfstime4 *new_time_modify,
2007 OUT nfs41_file_info *info)
2008 {
2009 enum nfsstat4 status;
2010 nfs41_compound compound;
2011 nfs_argop4 argops[4];
2012 nfs_resop4 resops[4];
2013 nfs41_sequence_args sequence_args;
2014 nfs41_sequence_res sequence_res;
2015 nfs41_putfh_args putfh_args;
2016 nfs41_putfh_res putfh_res;
2017 pnfs_layoutcommit_args lc_args;
2018 pnfs_layoutcommit_res lc_res;
2019 nfs41_getattr_args getattr_args;
2020 nfs41_getattr_res getattr_res;
2021 bitmap4 attr_request;
2022
2023 nfs41_superblock_getattr_mask(file->fh.superblock, &attr_request);
2024
2025 compound_init(&compound, argops, resops, "layoutcommit");
2026
2027 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
2028 nfs41_session_sequence(&sequence_args, session, 0);
2029
2030 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
2031 putfh_args.file = file;
2032 putfh_args.in_recovery = 0;
2033
2034 compound_add_op(&compound, OP_LAYOUTCOMMIT, &lc_args, &lc_res);
2035 lc_args.offset = offset;
2036 lc_args.length = length;
2037 lc_args.stateid = stateid;
2038 lc_args.new_time = new_time_modify;
2039 lc_args.new_offset = new_last_offset;
2040
2041 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res);
2042 getattr_args.attr_request = &attr_request;
2043 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT;
2044 getattr_res.info = info;
2045
2046 status = compound_encode_send_decode(session, &compound, TRUE);
2047 if (status)
2048 goto out;
2049
2050 if (compound_error(status = compound.res.status))
2051 goto out;
2052
2053 /* update the attribute cache */
2054 memcpy(&info->attrmask, &getattr_res.obj_attributes.attrmask,
2055 sizeof(bitmap4));
2056 nfs41_attr_cache_update(session_name_cache(session),
2057 file->fh.fileid, info);
2058 out:
2059 return status;
2060 }
2061
pnfs_rpc_layoutreturn(IN nfs41_session * session,IN nfs41_path_fh * file,IN enum pnfs_layout_type type,IN enum pnfs_iomode iomode,IN uint64_t offset,IN uint64_t length,IN stateid4 * stateid,OUT pnfs_layoutreturn_res * layoutreturn_res)2062 enum nfsstat4 pnfs_rpc_layoutreturn(
2063 IN nfs41_session *session,
2064 IN nfs41_path_fh *file,
2065 IN enum pnfs_layout_type type,
2066 IN enum pnfs_iomode iomode,
2067 IN uint64_t offset,
2068 IN uint64_t length,
2069 IN stateid4 *stateid,
2070 OUT pnfs_layoutreturn_res *layoutreturn_res)
2071 {
2072 enum nfsstat4 status;
2073 nfs41_compound compound;
2074 nfs_argop4 argops[3];
2075 nfs_resop4 resops[3];
2076 nfs41_sequence_args sequence_args;
2077 nfs41_sequence_res sequence_res;
2078 nfs41_putfh_args putfh_args;
2079 nfs41_putfh_res putfh_res;
2080 pnfs_layoutreturn_args layoutreturn_args;
2081
2082 compound_init(&compound, argops, resops, "layoutreturn");
2083
2084 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
2085 nfs41_session_sequence(&sequence_args, session, 0);
2086
2087 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
2088 putfh_args.file = file;
2089 putfh_args.in_recovery = 0;
2090
2091 compound_add_op(&compound, OP_LAYOUTRETURN, &layoutreturn_args, layoutreturn_res);
2092 layoutreturn_args.reclaim = 0;
2093 layoutreturn_args.type = type;
2094 layoutreturn_args.iomode = iomode;
2095 layoutreturn_args.return_type = PNFS_RETURN_FILE;
2096 layoutreturn_args.offset = offset;
2097 layoutreturn_args.length = length;
2098 layoutreturn_args.stateid = stateid;
2099
2100 status = compound_encode_send_decode(session, &compound, TRUE);
2101 if (status)
2102 goto out;
2103
2104 compound_error(status = compound.res.status);
2105 out:
2106 return status;
2107 }
2108
pnfs_rpc_getdeviceinfo(IN nfs41_session * session,IN unsigned char * deviceid,OUT pnfs_file_device * device)2109 enum nfsstat4 pnfs_rpc_getdeviceinfo(
2110 IN nfs41_session *session,
2111 IN unsigned char *deviceid,
2112 OUT pnfs_file_device *device)
2113 {
2114 enum nfsstat4 status;
2115 nfs41_compound compound;
2116 nfs_argop4 argops[2];
2117 nfs_resop4 resops[2];
2118 nfs41_sequence_args sequence_args;
2119 nfs41_sequence_res sequence_res;
2120 pnfs_getdeviceinfo_args getdeviceinfo_args;
2121 pnfs_getdeviceinfo_res getdeviceinfo_res;
2122
2123 compound_init(&compound, argops, resops, "get_deviceinfo");
2124
2125 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
2126 nfs41_session_sequence(&sequence_args, session, 0);
2127
2128 compound_add_op(&compound, OP_GETDEVICEINFO,
2129 &getdeviceinfo_args, &getdeviceinfo_res);
2130 getdeviceinfo_args.deviceid = deviceid;
2131 getdeviceinfo_args.layout_type = PNFS_LAYOUTTYPE_FILE;
2132 getdeviceinfo_args.maxcount = NFS41_MAX_SERVER_CACHE; /* XXX */
2133 getdeviceinfo_args.notify_types.count = 0;
2134 getdeviceinfo_res.u.res_ok.device = device;
2135
2136 status = compound_encode_send_decode(session, &compound, TRUE);
2137 if (status)
2138 goto out;
2139
2140 compound_error(status = compound.res.status);
2141 out:
2142 return status;
2143 }
2144
nfs41_rpc_openattr(IN nfs41_session * session,IN nfs41_path_fh * file,IN bool_t createdir,OUT nfs41_fh * fh_out)2145 enum nfsstat4 nfs41_rpc_openattr(
2146 IN nfs41_session *session,
2147 IN nfs41_path_fh *file,
2148 IN bool_t createdir,
2149 OUT nfs41_fh *fh_out)
2150 {
2151 enum nfsstat4 status;
2152 nfs41_compound compound;
2153 nfs_argop4 argops[4];
2154 nfs_resop4 resops[4];
2155 nfs41_sequence_args sequence_args;
2156 nfs41_sequence_res sequence_res;
2157 nfs41_putfh_args putfh_args;
2158 nfs41_putfh_res putfh_res;
2159 nfs41_openattr_args openattr_args;
2160 nfs41_openattr_res openattr_res;
2161 nfs41_getfh_res getfh_res;
2162
2163 compound_init(&compound, argops, resops, "openattr");
2164
2165 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
2166 nfs41_session_sequence(&sequence_args, session, 0);
2167
2168 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
2169 putfh_args.file = file;
2170 putfh_args.in_recovery = FALSE;
2171
2172 compound_add_op(&compound, OP_OPENATTR, &openattr_args, &openattr_res);
2173 openattr_args.createdir = createdir;
2174
2175 compound_add_op(&compound, OP_GETFH, NULL, &getfh_res);
2176 getfh_res.fh = fh_out;
2177
2178 status = compound_encode_send_decode(session, &compound, TRUE);
2179 if (status)
2180 goto out;
2181
2182 compound_error(status = compound.res.status);
2183
2184 fh_out->superblock = file->fh.superblock;
2185 out:
2186 return status;
2187 }
2188