xref: /reactos/base/services/nfsd/nfs41_ops.c (revision c2c66aff)
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