]> git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs4_subs.c
xnu-1486.2.11.tar.gz
[apple/xnu.git] / bsd / nfs / nfs4_subs.c
1 /*
2 * Copyright (c) 2006-2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /*
30 * miscellaneous support functions for NFSv4
31 */
32 #include <sys/param.h>
33 #include <sys/proc.h>
34 #include <sys/kauth.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/mount_internal.h>
38 #include <sys/vnode_internal.h>
39 #include <sys/kpi_mbuf.h>
40 #include <sys/socket.h>
41 #include <sys/stat.h>
42 #include <sys/malloc.h>
43 #include <sys/syscall.h>
44 #include <sys/ubc_internal.h>
45 #include <sys/fcntl.h>
46 #include <sys/quota.h>
47 #include <sys/domain.h>
48 #include <libkern/OSAtomic.h>
49 #include <kern/thread_call.h>
50
51 #include <sys/vm.h>
52 #include <sys/vmparam.h>
53
54 #include <sys/time.h>
55 #include <kern/clock.h>
56
57 #include <nfs/rpcv2.h>
58 #include <nfs/nfsproto.h>
59 #include <nfs/nfs.h>
60 #include <nfs/nfsnode.h>
61 #include <nfs/xdr_subs.h>
62 #include <nfs/nfsm_subs.h>
63 #include <nfs/nfs_gss.h>
64 #include <nfs/nfsmount.h>
65 #include <nfs/nfs_lock.h>
66
67 #include <miscfs/specfs/specdev.h>
68
69 #include <netinet/in.h>
70 #include <net/kpi_interface.h>
71
72
73 /*
74 * Create the unique client ID to use for this mount.
75 *
76 * Format: unique ID + en0_address + server_address + mntfromname + mntonname
77 *
78 * We could possibly use one client ID for all mounts of the same server;
79 * however, that would complicate some aspects of state management.
80 *
81 * Each mount socket connection sends a SETCLIENTID. If the ID is the same but
82 * the verifier (mounttime) changes, then all previous (mounts') state gets dropped.
83 *
84 * State is typically managed per-mount and in order to keep it that way
85 * each mount needs to use a separate client ID. However, we also need to
86 * make sure that each mount uses the same client ID each time.
87 *
88 * In an attempt to differentiate mounts we include the mntfromname and mntonname
89 * strings to the client ID (as long as they fit). We also make sure that the
90 * value does not conflict with any existing values in use.
91 */
92 int
93 nfs4_init_clientid(struct nfsmount *nmp)
94 {
95 struct nfs_client_id *ncip, *ncip2;
96 struct sockaddr *saddr;
97 int error, len, len2, cmp;
98 struct vfsstatfs *vsfs;
99
100 static uint8_t en0addr[6];
101 static uint8_t en0addr_set = 0;
102
103 lck_mtx_lock(nfs_global_mutex);
104 if (!en0addr_set) {
105 ifnet_t interface = NULL;
106 error = ifnet_find_by_name("en0", &interface);
107 if (!error)
108 error = ifnet_lladdr_copy_bytes(interface, en0addr, sizeof(en0addr));
109 if (error)
110 printf("nfs4_init_clientid: error getting en0 address, %d\n", error);
111 if (!error)
112 en0addr_set = 1;
113 if (interface)
114 ifnet_release(interface);
115 }
116 lck_mtx_unlock(nfs_global_mutex);
117
118 MALLOC(ncip, struct nfs_client_id *, sizeof(struct nfs_client_id), M_TEMP, M_WAITOK);
119 if (!ncip)
120 return (ENOMEM);
121
122 vsfs = vfs_statfs(nmp->nm_mountp);
123 saddr = mbuf_data(nmp->nm_nam);
124 ncip->nci_idlen = sizeof(uint32_t) + sizeof(en0addr) + saddr->sa_len +
125 strlen(vsfs->f_mntfromname) + 1 + strlen(vsfs->f_mntonname) + 1;
126 if (ncip->nci_idlen > NFS4_OPAQUE_LIMIT)
127 ncip->nci_idlen = NFS4_OPAQUE_LIMIT;
128 MALLOC(ncip->nci_id, char *, ncip->nci_idlen, M_TEMP, M_WAITOK);
129 if (!ncip->nci_id) {
130 FREE(ncip, M_TEMP);
131 return (ENOMEM);
132 }
133
134 *(uint32_t*)ncip->nci_id = 0;
135 len = sizeof(uint32_t);
136 len2 = min(sizeof(en0addr), ncip->nci_idlen-len);
137 bcopy(en0addr, &ncip->nci_id[len], len2);
138 len += sizeof(en0addr);
139 len2 = min(saddr->sa_len, ncip->nci_idlen-len);
140 bcopy(saddr, &ncip->nci_id[len], len2);
141 len += len2;
142 if (len < ncip->nci_idlen) {
143 len2 = strlcpy(&ncip->nci_id[len], vsfs->f_mntfromname, ncip->nci_idlen-len);
144 if (len2 < (ncip->nci_idlen - len))
145 len += len2 + 1;
146 else
147 len = ncip->nci_idlen;
148 }
149 if (len < ncip->nci_idlen) {
150 len2 = strlcpy(&ncip->nci_id[len], vsfs->f_mntonname, ncip->nci_idlen-len);
151 if (len2 < (ncip->nci_idlen - len))
152 len += len2 + 1;
153 else
154 len = ncip->nci_idlen;
155 }
156
157 /* make sure the ID is unique, and add it to the sorted list */
158 lck_mtx_lock(nfs_global_mutex);
159 TAILQ_FOREACH(ncip2, &nfsclientids, nci_link) {
160 if (ncip->nci_idlen > ncip2->nci_idlen)
161 continue;
162 if (ncip->nci_idlen < ncip2->nci_idlen)
163 break;
164 cmp = bcmp(ncip->nci_id + sizeof(uint32_t),
165 ncip2->nci_id + sizeof(uint32_t),
166 ncip->nci_idlen - sizeof(uint32_t));
167 if (cmp > 0)
168 continue;
169 if (cmp < 0)
170 break;
171 if (*(uint32_t*)ncip->nci_id > *(uint32_t*)ncip2->nci_id)
172 continue;
173 if (*(uint32_t*)ncip->nci_id < *(uint32_t*)ncip2->nci_id)
174 break;
175 *(uint32_t*)ncip->nci_id += 1;
176 }
177 if (*(uint32_t*)ncip->nci_id)
178 printf("nfs client ID collision (%d) for %s on %s\n", *(uint32_t*)ncip->nci_id,
179 vsfs->f_mntfromname, vsfs->f_mntonname);
180 if (ncip2)
181 TAILQ_INSERT_BEFORE(ncip2, ncip, nci_link);
182 else
183 TAILQ_INSERT_TAIL(&nfsclientids, ncip, nci_link);
184 nmp->nm_longid = ncip;
185 lck_mtx_unlock(nfs_global_mutex);
186
187 return (0);
188 }
189
190 /*
191 * NFSv4 SETCLIENTID
192 */
193 int
194 nfs4_setclientid(struct nfsmount *nmp)
195 {
196 uint64_t verifier, xid;
197 int error = 0, status, numops;
198 uint32_t bitmap[NFS_ATTR_BITMAP_LEN];
199 thread_t thd;
200 kauth_cred_t cred;
201 struct nfsm_chain nmreq, nmrep;
202 struct sockaddr_in sin;
203 uint8_t *addr;
204 char raddr[32];
205 int ralen = 0;
206
207 thd = current_thread();
208 cred = IS_VALID_CRED(nmp->nm_mcred) ? nmp->nm_mcred : vfs_context_ucred(vfs_context_kernel());
209 kauth_cred_ref(cred);
210
211 nfsm_chain_null(&nmreq);
212 nfsm_chain_null(&nmrep);
213
214 if (!nmp->nm_longid)
215 error = nfs4_init_clientid(nmp);
216
217 // SETCLIENTID
218 numops = 1;
219 nfsm_chain_build_alloc_init(error, &nmreq, 14 * NFSX_UNSIGNED + nmp->nm_longid->nci_idlen);
220 nfsm_chain_add_compound_header(error, &nmreq, "setclid", numops);
221 numops--;
222 nfsm_chain_add_32(error, &nmreq, NFS_OP_SETCLIENTID);
223 /* nfs_client_id4 client; */
224 nfsm_chain_add_64(error, &nmreq, nmp->nm_mounttime);
225 nfsm_chain_add_32(error, &nmreq, nmp->nm_longid->nci_idlen);
226 nfsm_chain_add_opaque(error, &nmreq, nmp->nm_longid->nci_id, nmp->nm_longid->nci_idlen);
227 /* cb_client4 callback; */
228 if (nmp->nm_cbid && nfs4_cb_port &&
229 !(error = sock_getsockname(nmp->nm_so, (struct sockaddr*)&sin, sizeof(sin)))) {
230 /* assemble r_addr = h1.h2.h3.h4.p1.p2 */
231 /* h = source address of nmp->nm_so */
232 /* p = nfs4_cb_port */
233 addr = (uint8_t*)&sin.sin_addr.s_addr;
234 ralen = snprintf(raddr, sizeof(raddr), "%d.%d.%d.%d.%d.%d",
235 addr[0], addr[1], addr[2], addr[3],
236 ((nfs4_cb_port >> 8) & 0xff),
237 (nfs4_cb_port & 0xff));
238 /* make sure it fit, give up if it didn't */
239 if (ralen >= (int)sizeof(raddr))
240 ralen = 0;
241 }
242 if (ralen > 0) {
243 /* add callback info */
244 nfsm_chain_add_32(error, &nmreq, NFS4_CALLBACK_PROG); /* callback program */
245 nfsm_chain_add_string(error, &nmreq, "tcp", 3); /* callback r_netid */
246 nfsm_chain_add_string(error, &nmreq, raddr, ralen); /* callback r_addr */
247 nfsm_chain_add_32(error, &nmreq, nmp->nm_cbid); /* callback_ident */
248 } else {
249 /* don't provide valid callback info */
250 nfsm_chain_add_32(error, &nmreq, 0); /* callback program */
251 nfsm_chain_add_string(error, &nmreq, "", 0); /* callback r_netid */
252 nfsm_chain_add_string(error, &nmreq, "", 0); /* callback r_addr */
253 nfsm_chain_add_32(error, &nmreq, 0); /* callback_ident */
254 }
255 nfsm_chain_build_done(error, &nmreq);
256 nfsm_assert(error, (numops == 0), EPROTO);
257 nfsmout_if(error);
258 error = nfs_request2(NULL, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND, thd, cred, R_SETUP, &nmrep, &xid, &status);
259 nfsm_chain_skip_tag(error, &nmrep);
260 nfsm_chain_get_32(error, &nmrep, numops);
261 nfsm_chain_op_check(error, &nmrep, NFS_OP_SETCLIENTID);
262 if (error == NFSERR_CLID_INUSE)
263 printf("nfs4_setclientid: client ID in use?\n");
264 nfsmout_if(error);
265 nfsm_chain_get_64(error, &nmrep, nmp->nm_clientid);
266 nfsm_chain_get_64(error, &nmrep, verifier);
267 nfsm_chain_cleanup(&nmreq);
268 nfsm_chain_cleanup(&nmrep);
269
270 // SETCLIENTID_CONFIRM, PUTFH, GETATTR(FS)
271 numops = nmp->nm_dnp ? 3 : 1;
272 nfsm_chain_build_alloc_init(error, &nmreq, 28 * NFSX_UNSIGNED);
273 nfsm_chain_add_compound_header(error, &nmreq, "setclid_conf", numops);
274 numops--;
275 nfsm_chain_add_32(error, &nmreq, NFS_OP_SETCLIENTID_CONFIRM);
276 nfsm_chain_add_64(error, &nmreq, nmp->nm_clientid);
277 nfsm_chain_add_64(error, &nmreq, verifier);
278 if (nmp->nm_dnp) {
279 /* refresh fs attributes too */
280 numops--;
281 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH);
282 nfsm_chain_add_fh(error, &nmreq, nmp->nm_vers, nmp->nm_dnp->n_fhp, nmp->nm_dnp->n_fhsize);
283 numops--;
284 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR);
285 NFS_CLEAR_ATTRIBUTES(bitmap);
286 NFS4_PER_FS_ATTRIBUTES(bitmap);
287 nfsm_chain_add_bitmap(error, &nmreq, bitmap, NFS_ATTR_BITMAP_LEN);
288 }
289 nfsm_chain_build_done(error, &nmreq);
290 nfsm_assert(error, (numops == 0), EPROTO);
291 nfsmout_if(error);
292 error = nfs_request2(NULL, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND, thd, cred, R_SETUP, &nmrep, &xid, &status);
293 nfsm_chain_skip_tag(error, &nmrep);
294 nfsm_chain_get_32(error, &nmrep, numops);
295 nfsm_chain_op_check(error, &nmrep, NFS_OP_SETCLIENTID_CONFIRM);
296 if (error)
297 printf("nfs4_setclientid: confirm error %d\n", error);
298 if (nmp->nm_dnp) {
299 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH);
300 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR);
301 nfsmout_if(error);
302 lck_mtx_lock(&nmp->nm_lock);
303 error = nfs4_parsefattr(&nmrep, &nmp->nm_fsattr, NULL, NULL, NULL);
304 lck_mtx_unlock(&nmp->nm_lock);
305 }
306
307 nfsmout:
308 nfsm_chain_cleanup(&nmreq);
309 nfsm_chain_cleanup(&nmrep);
310 kauth_cred_unref(&cred);
311 if (error)
312 printf("nfs4_setclientid failed, %d\n", error);
313 return (error);
314 }
315
316 /*
317 * renew/check lease state on server
318 */
319 int
320 nfs4_renew(struct nfsmount *nmp, int rpcflag)
321 {
322 int error = 0, status, numops;
323 u_int64_t xid;
324 struct nfsm_chain nmreq, nmrep;
325 kauth_cred_t cred;
326
327 cred = IS_VALID_CRED(nmp->nm_mcred) ? nmp->nm_mcred : vfs_context_ucred(vfs_context_kernel());
328 kauth_cred_ref(cred);
329
330 nfsm_chain_null(&nmreq);
331 nfsm_chain_null(&nmrep);
332
333 // RENEW
334 numops = 1;
335 nfsm_chain_build_alloc_init(error, &nmreq, 8 * NFSX_UNSIGNED);
336 nfsm_chain_add_compound_header(error, &nmreq, "renew", numops);
337 numops--;
338 nfsm_chain_add_32(error, &nmreq, NFS_OP_RENEW);
339 nfsm_chain_add_64(error, &nmreq, nmp->nm_clientid);
340 nfsm_chain_build_done(error, &nmreq);
341 nfsm_assert(error, (numops == 0), EPROTO);
342 nfsmout_if(error);
343 error = nfs_request2(NULL, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND,
344 current_thread(), cred, rpcflag, &nmrep, &xid, &status);
345 nfsm_chain_skip_tag(error, &nmrep);
346 nfsm_chain_get_32(error, &nmrep, numops);
347 nfsm_chain_op_check(error, &nmrep, NFS_OP_RENEW);
348 nfsmout:
349 nfsm_chain_cleanup(&nmreq);
350 nfsm_chain_cleanup(&nmrep);
351 kauth_cred_unref(&cred);
352 return (error);
353 }
354
355
356 /*
357 * periodic timer to renew lease state on server
358 */
359 void
360 nfs4_renew_timer(void *param0, __unused void *param1)
361 {
362 struct nfsmount *nmp = param0;
363 u_int64_t clientid;
364 int error = 0, interval;
365
366 lck_mtx_lock(&nmp->nm_lock);
367 clientid = nmp->nm_clientid;
368 if ((nmp->nm_state & NFSSTA_RECOVER) || !(nmp->nm_sockflags & NMSOCK_READY)) {
369 lck_mtx_unlock(&nmp->nm_lock);
370 goto out;
371 }
372 lck_mtx_unlock(&nmp->nm_lock);
373
374 error = nfs4_renew(nmp, R_RECOVER);
375 out:
376 if (error == ETIMEDOUT)
377 nfs_need_reconnect(nmp);
378 else if (error)
379 printf("nfs4_renew_timer: error %d\n", error);
380 lck_mtx_lock(&nmp->nm_lock);
381 if (error && (error != ETIMEDOUT) &&
382 (nmp->nm_clientid == clientid) && !(nmp->nm_state & NFSSTA_RECOVER)) {
383 printf("nfs4_renew_timer: error %d, initiating recovery\n", error);
384 nmp->nm_state |= NFSSTA_RECOVER;
385 nfs_mount_sock_thread_wake(nmp);
386 }
387
388 interval = nmp->nm_fsattr.nfsa_lease / (error ? 4 : 2);
389 if ((interval < 1) || (nmp->nm_state & NFSSTA_RECOVER))
390 interval = 1;
391 lck_mtx_unlock(&nmp->nm_lock);
392 nfs_interval_timer_start(nmp->nm_renew_timer, interval * 1000);
393 }
394
395 /*
396 * Set a vnode attr's supported bits according to the given bitmap
397 */
398 void
399 nfs_vattr_set_supported(uint32_t *bitmap, struct vnode_attr *vap)
400 {
401 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TYPE))
402 VATTR_SET_SUPPORTED(vap, va_type);
403 // if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_CHANGE))
404 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SIZE))
405 VATTR_SET_SUPPORTED(vap, va_data_size);
406 // if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_NAMED_ATTR))
407 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FSID))
408 VATTR_SET_SUPPORTED(vap, va_fsid);
409 // if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ACL))
410 // VATTR_SET_SUPPORTED(vap, va_acl);
411 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ARCHIVE))
412 VATTR_SET_SUPPORTED(vap, va_flags);
413 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FILEID))
414 VATTR_SET_SUPPORTED(vap, va_fileid);
415 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_HIDDEN))
416 VATTR_SET_SUPPORTED(vap, va_flags);
417 // if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MIMETYPE))
418 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MODE))
419 VATTR_SET_SUPPORTED(vap, va_mode);
420 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_NUMLINKS))
421 VATTR_SET_SUPPORTED(vap, va_nlink);
422 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_OWNER))
423 VATTR_SET_SUPPORTED(vap, va_uid);
424 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_OWNER_GROUP))
425 VATTR_SET_SUPPORTED(vap, va_gid);
426 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_RAWDEV))
427 VATTR_SET_SUPPORTED(vap, va_rdev);
428 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SPACE_USED))
429 VATTR_SET_SUPPORTED(vap, va_total_alloc);
430 // if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SYSTEM))
431 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_ACCESS))
432 VATTR_SET_SUPPORTED(vap, va_access_time);
433 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_BACKUP))
434 VATTR_SET_SUPPORTED(vap, va_backup_time);
435 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_CREATE))
436 VATTR_SET_SUPPORTED(vap, va_create_time);
437 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_METADATA))
438 VATTR_SET_SUPPORTED(vap, va_change_time);
439 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_MODIFY))
440 VATTR_SET_SUPPORTED(vap, va_modify_time);
441 }
442
443 /*
444 * Parse the attributes that are in the mbuf list and store them in
445 * the given structures.
446 */
447 int
448 nfs4_parsefattr(
449 struct nfsm_chain *nmc,
450 struct nfs_fsattr *nfsap,
451 struct nfs_vattr *nvap,
452 fhandle_t *fhp,
453 struct dqblk *dqbp)
454 {
455 int error = 0, attrbytes;
456 uint32_t val, val2, val3, i, j;
457 uint32_t bitmap[NFS_ATTR_BITMAP_LEN], len;
458 char *s;
459 struct nfs_fsattr nfsa_dummy;
460 struct nfs_vattr nva_dummy;
461 struct dqblk dqb_dummy;
462
463 /* if not interested in some values... throw 'em into a local dummy variable */
464 if (!nfsap)
465 nfsap = &nfsa_dummy;
466 if (!nvap)
467 nvap = &nva_dummy;
468 if (!dqbp)
469 dqbp = &dqb_dummy;
470
471 attrbytes = val = val2 = val3 = 0;
472
473 len = NFS_ATTR_BITMAP_LEN;
474 nfsm_chain_get_bitmap(error, nmc, bitmap, len);
475 /* add bits to object/fs attr bitmaps */
476 for (i=0; i < NFS_ATTR_BITMAP_LEN; i++) {
477 nvap->nva_bitmap[i] |= bitmap[i] & nfs_object_attr_bitmap[i];
478 nfsap->nfsa_bitmap[i] |= bitmap[i] & nfs_fs_attr_bitmap[i];
479 }
480
481 nfsm_chain_get_32(error, nmc, attrbytes);
482 nfsmout_if(error);
483
484 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SUPPORTED_ATTRS)) {
485 len = NFS_ATTR_BITMAP_LEN;
486 nfsm_chain_get_bitmap(error, nmc, nfsap->nfsa_supp_attr, len);
487 attrbytes -= (len + 1) * NFSX_UNSIGNED;
488 }
489 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TYPE)) {
490 nfsm_chain_get_32(error, nmc, val);
491 nvap->nva_type = nfstov_type(val, NFS_VER4);
492 attrbytes -= NFSX_UNSIGNED;
493 }
494 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FH_EXPIRE_TYPE)) {
495 nfsm_chain_get_32(error, nmc, val);
496 nfsmout_if(error);
497 if (val != NFS_FH_PERSISTENT)
498 printf("nfs: warning: non-persistent file handles!\n");
499 if (val & ~0xff)
500 printf("nfs: warning unknown fh type: 0x%x\n", val);
501 nfsap->nfsa_flags &= ~NFS_FSFLAG_FHTYPE_MASK;
502 nfsap->nfsa_flags |= val << NFS_FSFLAG_FHTYPE_SHIFT;
503 attrbytes -= NFSX_UNSIGNED;
504 }
505 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_CHANGE)) {
506 nfsm_chain_get_64(error, nmc, nvap->nva_change);
507 attrbytes -= 2 * NFSX_UNSIGNED;
508 }
509 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SIZE)) {
510 nfsm_chain_get_64(error, nmc, nvap->nva_size);
511 attrbytes -= 2 * NFSX_UNSIGNED;
512 }
513 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_LINK_SUPPORT)) {
514 nfsm_chain_get_32(error, nmc, val);
515 if (val)
516 nfsap->nfsa_flags |= NFS_FSFLAG_LINK;
517 else
518 nfsap->nfsa_flags &= ~NFS_FSFLAG_LINK;
519 attrbytes -= NFSX_UNSIGNED;
520 }
521 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SYMLINK_SUPPORT)) {
522 nfsm_chain_get_32(error, nmc, val);
523 if (val)
524 nfsap->nfsa_flags |= NFS_FSFLAG_SYMLINK;
525 else
526 nfsap->nfsa_flags &= ~NFS_FSFLAG_SYMLINK;
527 attrbytes -= NFSX_UNSIGNED;
528 }
529 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_NAMED_ATTR)) {
530 nfsm_chain_get_32(error, nmc, val);
531 if (val)
532 nvap->nva_flags |= NFS_FFLAG_NAMED_ATTR;
533 else
534 nvap->nva_flags &= ~NFS_FFLAG_NAMED_ATTR;
535 attrbytes -= NFSX_UNSIGNED;
536 }
537 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FSID)) {
538 nfsm_chain_get_64(error, nmc, nvap->nva_fsid.major);
539 nfsm_chain_get_64(error, nmc, nvap->nva_fsid.minor);
540 attrbytes -= 4 * NFSX_UNSIGNED;
541 }
542 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_UNIQUE_HANDLES)) {
543 nfsm_chain_get_32(error, nmc, val);
544 if (val)
545 nfsap->nfsa_flags |= NFS_FSFLAG_UNIQUE_FH;
546 else
547 nfsap->nfsa_flags &= ~NFS_FSFLAG_UNIQUE_FH;
548 attrbytes -= NFSX_UNSIGNED;
549 }
550 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_LEASE_TIME)) {
551 nfsm_chain_get_32(error, nmc, nfsap->nfsa_lease);
552 attrbytes -= NFSX_UNSIGNED;
553 }
554 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_RDATTR_ERROR)) {
555 nfsm_chain_get_32(error, nmc, error);
556 attrbytes -= NFSX_UNSIGNED;
557 nfsmout_if(error);
558 }
559 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ACL)) { /* skip for now */
560 nfsm_chain_get_32(error, nmc, val); /* ACE count */
561 for (i=0; !error && (i < val); i++) {
562 nfsm_chain_adv(error, nmc, 3 * NFSX_UNSIGNED);
563 nfsm_chain_get_32(error, nmc, val2); /* string length */
564 nfsm_chain_adv(error, nmc, nfsm_rndup(val2));
565 attrbytes -= 4*NFSX_UNSIGNED + nfsm_rndup(val2);
566 nfsm_assert(error, (attrbytes >= 0), EBADRPC);
567 }
568 }
569 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ACLSUPPORT)) {
570 nfsm_chain_get_32(error, nmc, val);
571 if (val)
572 nfsap->nfsa_flags |= NFS_FSFLAG_ACL;
573 else
574 nfsap->nfsa_flags &= ~NFS_FSFLAG_ACL;
575 attrbytes -= NFSX_UNSIGNED;
576 }
577 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ARCHIVE)) { /* SF_ARCHIVED */
578 nfsm_chain_get_32(error, nmc, val);
579 if (val)
580 nvap->nva_flags |= NFS_FFLAG_ARCHIVED;
581 else
582 nvap->nva_flags &= ~NFS_FFLAG_ARCHIVED;
583 attrbytes -= NFSX_UNSIGNED;
584 }
585 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_CANSETTIME)) {
586 nfsm_chain_get_32(error, nmc, val);
587 if (val)
588 nfsap->nfsa_flags |= NFS_FSFLAG_SET_TIME;
589 else
590 nfsap->nfsa_flags &= ~NFS_FSFLAG_SET_TIME;
591 attrbytes -= NFSX_UNSIGNED;
592 }
593 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_CASE_INSENSITIVE)) {
594 nfsm_chain_get_32(error, nmc, val);
595 if (val)
596 nfsap->nfsa_flags |= NFS_FSFLAG_CASE_INSENSITIVE;
597 else
598 nfsap->nfsa_flags &= ~NFS_FSFLAG_CASE_INSENSITIVE;
599 attrbytes -= NFSX_UNSIGNED;
600 }
601 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_CASE_PRESERVING)) {
602 nfsm_chain_get_32(error, nmc, val);
603 if (val)
604 nfsap->nfsa_flags |= NFS_FSFLAG_CASE_PRESERVING;
605 else
606 nfsap->nfsa_flags &= ~NFS_FSFLAG_CASE_PRESERVING;
607 attrbytes -= NFSX_UNSIGNED;
608 }
609 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_CHOWN_RESTRICTED)) {
610 nfsm_chain_get_32(error, nmc, val);
611 if (val)
612 nfsap->nfsa_flags |= NFS_FSFLAG_CHOWN_RESTRICTED;
613 else
614 nfsap->nfsa_flags &= ~NFS_FSFLAG_CHOWN_RESTRICTED;
615 attrbytes -= NFSX_UNSIGNED;
616 }
617 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FILEHANDLE)) {
618 nfsm_chain_get_32(error, nmc, val);
619 if (fhp) {
620 fhp->fh_len = val;
621 nfsm_chain_get_opaque(error, nmc, nfsm_rndup(val), fhp->fh_data);
622 } else {
623 nfsm_chain_adv(error, nmc, nfsm_rndup(val));
624 }
625 attrbytes -= NFSX_UNSIGNED + nfsm_rndup(val);
626 }
627 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FILEID)) {
628 nfsm_chain_get_64(error, nmc, nvap->nva_fileid);
629 attrbytes -= 2 * NFSX_UNSIGNED;
630 }
631 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FILES_AVAIL)) {
632 nfsm_chain_get_64(error, nmc, nfsap->nfsa_files_avail);
633 attrbytes -= 2 * NFSX_UNSIGNED;
634 }
635 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FILES_FREE)) {
636 nfsm_chain_get_64(error, nmc, nfsap->nfsa_files_free);
637 attrbytes -= 2 * NFSX_UNSIGNED;
638 }
639 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FILES_TOTAL)) {
640 nfsm_chain_get_64(error, nmc, nfsap->nfsa_files_total);
641 attrbytes -= 2 * NFSX_UNSIGNED;
642 }
643 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FS_LOCATIONS)) { /* skip for now */
644 nfsm_chain_get_32(error, nmc, val); /* root path length */
645 nfsm_chain_adv(error, nmc, nfsm_rndup(val)); /* root path */
646 attrbytes -= (2 * NFSX_UNSIGNED) + nfsm_rndup(val);
647 nfsm_chain_get_32(error, nmc, val); /* location count */
648 for (i=0; !error && (i < val); i++) {
649 nfsm_chain_get_32(error, nmc, val2); /* server string length */
650 nfsm_chain_adv(error, nmc, nfsm_rndup(val2)); /* server string */
651 attrbytes -= (2 * NFSX_UNSIGNED) + nfsm_rndup(val2);
652 nfsm_chain_get_32(error, nmc, val2); /* pathname component count */
653 for (j=0; !error && (j < val2); j++) {
654 nfsm_chain_get_32(error, nmc, val3); /* component length */
655 nfsm_chain_adv(error, nmc, nfsm_rndup(val3)); /* component */
656 attrbytes -= NFSX_UNSIGNED + nfsm_rndup(val3);
657 nfsm_assert(error, (attrbytes >= 0), EBADRPC);
658 }
659 nfsm_assert(error, (attrbytes >= 0), EBADRPC);
660 }
661 nfsm_assert(error, (attrbytes >= 0), EBADRPC);
662 }
663 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_HIDDEN)) { /* UF_HIDDEN */
664 nfsm_chain_get_32(error, nmc, val);
665 if (val)
666 nvap->nva_flags |= NFS_FFLAG_HIDDEN;
667 else
668 nvap->nva_flags &= ~NFS_FFLAG_HIDDEN;
669 attrbytes -= NFSX_UNSIGNED;
670 }
671 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_HOMOGENEOUS)) {
672 /* XXX If NOT homogeneous, we may need to clear flags on the mount */
673 nfsm_chain_get_32(error, nmc, val);
674 if (val)
675 nfsap->nfsa_flags |= NFS_FSFLAG_HOMOGENEOUS;
676 else
677 nfsap->nfsa_flags &= ~NFS_FSFLAG_HOMOGENEOUS;
678 attrbytes -= NFSX_UNSIGNED;
679 }
680 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MAXFILESIZE)) {
681 nfsm_chain_get_64(error, nmc, nfsap->nfsa_maxfilesize);
682 attrbytes -= 2 * NFSX_UNSIGNED;
683 }
684 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MAXLINK)) {
685 nfsm_chain_get_32(error, nmc, nvap->nva_maxlink);
686 if (!error && (nfsap->nfsa_maxlink > INT32_MAX))
687 nfsap->nfsa_maxlink = INT32_MAX;
688 attrbytes -= NFSX_UNSIGNED;
689 }
690 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MAXNAME)) {
691 nfsm_chain_get_32(error, nmc, nfsap->nfsa_maxname);
692 if (!error && (nfsap->nfsa_maxname > INT32_MAX))
693 nfsap->nfsa_maxname = INT32_MAX;
694 attrbytes -= NFSX_UNSIGNED;
695 }
696 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MAXREAD)) {
697 nfsm_chain_get_64(error, nmc, nfsap->nfsa_maxread);
698 attrbytes -= 2 * NFSX_UNSIGNED;
699 }
700 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MAXWRITE)) {
701 nfsm_chain_get_64(error, nmc, nfsap->nfsa_maxwrite);
702 attrbytes -= 2 * NFSX_UNSIGNED;
703 }
704 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MIMETYPE)) {
705 nfsm_chain_get_32(error, nmc, val);
706 nfsm_chain_adv(error, nmc, nfsm_rndup(val));
707 attrbytes -= NFSX_UNSIGNED + nfsm_rndup(val);
708 }
709 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MODE)) {
710 nfsm_chain_get_32(error, nmc, nvap->nva_mode);
711 attrbytes -= NFSX_UNSIGNED;
712 }
713 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_NO_TRUNC)) {
714 nfsm_chain_get_32(error, nmc, val);
715 if (val)
716 nfsap->nfsa_flags |= NFS_FSFLAG_NO_TRUNC;
717 else
718 nfsap->nfsa_flags &= ~NFS_FSFLAG_NO_TRUNC;
719 attrbytes -= NFSX_UNSIGNED;
720 }
721 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_NUMLINKS)) {
722 nfsm_chain_get_32(error, nmc, val);
723 nvap->nva_nlink = val;
724 attrbytes -= NFSX_UNSIGNED;
725 }
726 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_OWNER)) {
727 /* XXX Need ID mapping infrastructure - use ugly hack for now */
728 nfsm_chain_get_32(error, nmc, len);
729 nfsm_chain_get_opaque_pointer(error, nmc, len, s);
730 attrbytes -= NFSX_UNSIGNED + nfsm_rndup(len);
731 nfsmout_if(error);
732 if ((*s >= '0') && (*s <= '9'))
733 nvap->nva_uid = strtol(s, NULL, 10);
734 else if (!strncmp(s, "nobody@", 7))
735 nvap->nva_uid = -2;
736 else if (!strncmp(s, "root@", 5))
737 nvap->nva_uid = 0;
738 else
739 nvap->nva_uid = 99; /* unknown */
740 }
741 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_OWNER_GROUP)) {
742 /* XXX Need ID mapping infrastructure - use ugly hack for now */
743 nfsm_chain_get_32(error, nmc, len);
744 nfsm_chain_get_opaque_pointer(error, nmc, len, s);
745 attrbytes -= NFSX_UNSIGNED + nfsm_rndup(len);
746 nfsmout_if(error);
747 if ((*s >= '0') && (*s <= '9'))
748 nvap->nva_gid = strtol(s, NULL, 10);
749 else if (!strncmp(s, "nobody@", 7))
750 nvap->nva_gid = -2;
751 else if (!strncmp(s, "root@", 5))
752 nvap->nva_uid = 0;
753 else
754 nvap->nva_gid = 99; /* unknown */
755 }
756 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_QUOTA_AVAIL_HARD)) {
757 nfsm_chain_get_64(error, nmc, dqbp->dqb_bhardlimit);
758 attrbytes -= 2 * NFSX_UNSIGNED;
759 }
760 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_QUOTA_AVAIL_SOFT)) {
761 nfsm_chain_get_64(error, nmc, dqbp->dqb_bsoftlimit);
762 attrbytes -= 2 * NFSX_UNSIGNED;
763 }
764 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_QUOTA_USED)) {
765 nfsm_chain_get_64(error, nmc, dqbp->dqb_curbytes);
766 attrbytes -= 2 * NFSX_UNSIGNED;
767 }
768 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_RAWDEV)) {
769 nfsm_chain_get_32(error, nmc, nvap->nva_rawdev.specdata1);
770 nfsm_chain_get_32(error, nmc, nvap->nva_rawdev.specdata2);
771 attrbytes -= 2 * NFSX_UNSIGNED;
772 }
773 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SPACE_AVAIL)) {
774 nfsm_chain_get_64(error, nmc, nfsap->nfsa_space_avail);
775 attrbytes -= 2 * NFSX_UNSIGNED;
776 }
777 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SPACE_FREE)) {
778 nfsm_chain_get_64(error, nmc, nfsap->nfsa_space_free);
779 attrbytes -= 2 * NFSX_UNSIGNED;
780 }
781 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SPACE_TOTAL)) {
782 nfsm_chain_get_64(error, nmc, nfsap->nfsa_space_total);
783 attrbytes -= 2 * NFSX_UNSIGNED;
784 }
785 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SPACE_USED)) {
786 nfsm_chain_get_64(error, nmc, nvap->nva_bytes);
787 attrbytes -= 2 * NFSX_UNSIGNED;
788 }
789 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SYSTEM)) {
790 /* we'd support this if we had a flag to map it to... */
791 nfsm_chain_adv(error, nmc, NFSX_UNSIGNED);
792 attrbytes -= NFSX_UNSIGNED;
793 }
794 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_ACCESS)) {
795 nfsm_chain_get_64(error, nmc, nvap->nva_timesec[NFSTIME_ACCESS]);
796 nfsm_chain_get_32(error, nmc, nvap->nva_timensec[NFSTIME_ACCESS]);
797 attrbytes -= 3 * NFSX_UNSIGNED;
798 }
799 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_ACCESS_SET)) {
800 nfsm_chain_adv(error, nmc, 4*NFSX_UNSIGNED); /* just skip it */
801 attrbytes -= 4 * NFSX_UNSIGNED;
802 }
803 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_BACKUP)) {
804 nfsm_chain_get_64(error, nmc, nvap->nva_timesec[NFSTIME_BACKUP]);
805 nfsm_chain_get_32(error, nmc, nvap->nva_timensec[NFSTIME_BACKUP]);
806 attrbytes -= 3 * NFSX_UNSIGNED;
807 }
808 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_CREATE)) {
809 nfsm_chain_get_64(error, nmc, nvap->nva_timesec[NFSTIME_CREATE]);
810 nfsm_chain_get_32(error, nmc, nvap->nva_timensec[NFSTIME_CREATE]);
811 attrbytes -= 3 * NFSX_UNSIGNED;
812 }
813 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_DELTA)) { /* skip for now */
814 nfsm_chain_adv(error, nmc, 3*NFSX_UNSIGNED);
815 attrbytes -= 3 * NFSX_UNSIGNED;
816 }
817 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_METADATA)) {
818 nfsm_chain_get_64(error, nmc, nvap->nva_timesec[NFSTIME_CHANGE]);
819 nfsm_chain_get_32(error, nmc, nvap->nva_timensec[NFSTIME_CHANGE]);
820 attrbytes -= 3 * NFSX_UNSIGNED;
821 }
822 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_MODIFY)) {
823 nfsm_chain_get_64(error, nmc, nvap->nva_timesec[NFSTIME_MODIFY]);
824 nfsm_chain_get_32(error, nmc, nvap->nva_timensec[NFSTIME_MODIFY]);
825 attrbytes -= 3 * NFSX_UNSIGNED;
826 }
827 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_MODIFY_SET)) {
828 nfsm_chain_adv(error, nmc, 4*NFSX_UNSIGNED); /* just skip it */
829 attrbytes -= 4 * NFSX_UNSIGNED;
830 }
831 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MOUNTED_ON_FILEID)) { /* skip for now */
832 nfsm_chain_adv(error, nmc, 2*NFSX_UNSIGNED);
833 attrbytes -= 2 * NFSX_UNSIGNED;
834 }
835 /* advance over any leftover attrbytes */
836 nfsm_assert(error, (attrbytes >= 0), EBADRPC);
837 nfsm_chain_adv(error, nmc, nfsm_rndup(attrbytes));
838 nfsmout:
839 return (error);
840 }
841
842 /*
843 * Add an NFSv4 "sattr" structure to an mbuf chain
844 */
845 int
846 nfsm_chain_add_fattr4_f(struct nfsm_chain *nmc, struct vnode_attr *vap, struct nfsmount *nmp)
847 {
848 int error = 0, attrbytes, slen, i;
849 uint32_t *pattrbytes;
850 uint32_t bitmap[NFS_ATTR_BITMAP_LEN];
851 char s[32];
852
853 /*
854 * Do this in two passes.
855 * First calculate the bitmap, then pack
856 * everything together and set the size.
857 */
858
859 NFS_CLEAR_ATTRIBUTES(bitmap);
860 if (VATTR_IS_ACTIVE(vap, va_data_size))
861 NFS_BITMAP_SET(bitmap, NFS_FATTR_SIZE);
862 if (VATTR_IS_ACTIVE(vap, va_acl)) {
863 // NFS_BITMAP_SET(bitmap, NFS_FATTR_ACL)
864 }
865 if (VATTR_IS_ACTIVE(vap, va_flags)) {
866 NFS_BITMAP_SET(bitmap, NFS_FATTR_ARCHIVE);
867 NFS_BITMAP_SET(bitmap, NFS_FATTR_HIDDEN);
868 }
869 // NFS_BITMAP_SET(bitmap, NFS_FATTR_MIMETYPE)
870 if (VATTR_IS_ACTIVE(vap, va_mode))
871 NFS_BITMAP_SET(bitmap, NFS_FATTR_MODE);
872 if (VATTR_IS_ACTIVE(vap, va_uid))
873 NFS_BITMAP_SET(bitmap, NFS_FATTR_OWNER);
874 if (VATTR_IS_ACTIVE(vap, va_gid))
875 NFS_BITMAP_SET(bitmap, NFS_FATTR_OWNER_GROUP);
876 // NFS_BITMAP_SET(bitmap, NFS_FATTR_SYSTEM)
877 if (vap->va_vaflags & VA_UTIMES_NULL) {
878 NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_ACCESS_SET);
879 NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_MODIFY_SET);
880 } else {
881 if (VATTR_IS_ACTIVE(vap, va_access_time))
882 NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_ACCESS_SET);
883 if (VATTR_IS_ACTIVE(vap, va_modify_time))
884 NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_MODIFY_SET);
885 }
886 if (VATTR_IS_ACTIVE(vap, va_backup_time))
887 NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_BACKUP);
888 if (VATTR_IS_ACTIVE(vap, va_create_time))
889 NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_CREATE);
890 /* and limit to what is supported by server */
891 for (i=0; i < NFS_ATTR_BITMAP_LEN; i++)
892 bitmap[i] &= nmp->nm_fsattr.nfsa_supp_attr[i];
893
894 /*
895 * Now pack it all together:
896 * BITMAP, #BYTES, ATTRS
897 * Keep a pointer to the length so we can set it later.
898 */
899 nfsm_chain_add_bitmap(error, nmc, bitmap, NFS_ATTR_BITMAP_LEN);
900 attrbytes = 0;
901 nfsm_chain_add_32(error, nmc, attrbytes);
902 pattrbytes = (uint32_t*)(nmc->nmc_ptr - NFSX_UNSIGNED);
903
904 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SIZE)) {
905 nfsm_chain_add_64(error, nmc, vap->va_data_size);
906 attrbytes += 2*NFSX_UNSIGNED;
907 }
908 // NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ACL)
909 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ARCHIVE)) {
910 nfsm_chain_add_32(error, nmc, (vap->va_flags & SF_ARCHIVED) ? 1 : 0);
911 attrbytes += NFSX_UNSIGNED;
912 }
913 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_HIDDEN)) {
914 nfsm_chain_add_32(error, nmc, (vap->va_flags & UF_HIDDEN) ? 1 : 0);
915 attrbytes += NFSX_UNSIGNED;
916 }
917 // NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MIMETYPE)
918 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MODE)) {
919 nfsm_chain_add_32(error, nmc, vap->va_mode);
920 attrbytes += NFSX_UNSIGNED;
921 }
922 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_OWNER)) {
923 /* XXX Need ID mapping infrastructure - use ugly hack for now */
924 if (vap->va_uid == 0)
925 slen = snprintf(s, sizeof(s), "root@localdomain");
926 else if (vap->va_uid == (uid_t)-2)
927 slen = snprintf(s, sizeof(s), "nobody@localdomain");
928 else
929 slen = snprintf(s, sizeof(s), "%d", vap->va_uid);
930 nfsm_chain_add_string(error, nmc, s, slen);
931 attrbytes += NFSX_UNSIGNED + nfsm_rndup(slen);
932 }
933 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_OWNER_GROUP)) {
934 /* XXX Need ID mapping infrastructure - use ugly hack for now */
935 if (vap->va_gid == 0)
936 slen = snprintf(s, sizeof(s), "root@localdomain");
937 else if (vap->va_gid == (gid_t)-2)
938 slen = snprintf(s, sizeof(s), "nobody@localdomain");
939 else
940 slen = snprintf(s, sizeof(s), "%d", vap->va_gid);
941 nfsm_chain_add_string(error, nmc, s, slen);
942 attrbytes += NFSX_UNSIGNED + nfsm_rndup(slen);
943 }
944 // NFS_BITMAP_SET(bitmap, NFS_FATTR_SYSTEM)
945 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_ACCESS_SET)) {
946 if (vap->va_vaflags & VA_UTIMES_NULL) {
947 nfsm_chain_add_32(error, nmc, NFS4_TIME_SET_TO_SERVER);
948 attrbytes += NFSX_UNSIGNED;
949 } else {
950 nfsm_chain_add_32(error, nmc, NFS4_TIME_SET_TO_CLIENT);
951 nfsm_chain_add_64(error, nmc, vap->va_access_time.tv_sec);
952 nfsm_chain_add_32(error, nmc, vap->va_access_time.tv_nsec);
953 attrbytes += 4*NFSX_UNSIGNED;
954 }
955 }
956 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_BACKUP)) {
957 nfsm_chain_add_64(error, nmc, vap->va_backup_time.tv_sec);
958 nfsm_chain_add_32(error, nmc, vap->va_backup_time.tv_nsec);
959 attrbytes += 3*NFSX_UNSIGNED;
960 }
961 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_CREATE)) {
962 nfsm_chain_add_64(error, nmc, vap->va_create_time.tv_sec);
963 nfsm_chain_add_32(error, nmc, vap->va_create_time.tv_nsec);
964 attrbytes += 3*NFSX_UNSIGNED;
965 }
966 if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_MODIFY_SET)) {
967 if (vap->va_vaflags & VA_UTIMES_NULL) {
968 nfsm_chain_add_32(error, nmc, NFS4_TIME_SET_TO_SERVER);
969 attrbytes += NFSX_UNSIGNED;
970 } else {
971 nfsm_chain_add_32(error, nmc, NFS4_TIME_SET_TO_CLIENT);
972 nfsm_chain_add_64(error, nmc, vap->va_modify_time.tv_sec);
973 nfsm_chain_add_32(error, nmc, vap->va_modify_time.tv_nsec);
974 attrbytes += 4*NFSX_UNSIGNED;
975 }
976 }
977 nfsmout_if(error);
978 /* Now, set the attribute data length */
979 *pattrbytes = txdr_unsigned(attrbytes);
980 nfsmout:
981 return (error);
982 }
983
984 /*
985 * Recover state for an NFS mount.
986 *
987 * Iterates over all open files, reclaiming opens and lock state.
988 */
989 void
990 nfs4_recover(struct nfsmount *nmp)
991 {
992 struct timespec ts = { 1, 0 };
993 int error, lost, reopen;
994 struct nfs_open_owner *noop;
995 struct nfs_open_file *nofp;
996 struct nfs_file_lock *nflp, *nextnflp;
997 struct nfs_lock_owner *nlop;
998 thread_t thd = current_thread();
999
1000 restart:
1001 error = 0;
1002 lck_mtx_lock(&nmp->nm_lock);
1003 /*
1004 * First, wait for the state inuse count to go to zero so
1005 * we know there are no state operations in progress.
1006 */
1007 do {
1008 if ((error = nfs_sigintr(nmp, NULL, NULL, 1)))
1009 break;
1010 if (!(nmp->nm_sockflags & NMSOCK_READY))
1011 error = EPIPE;
1012 if (nmp->nm_state & NFSSTA_FORCE)
1013 error = ENXIO;
1014 if (nmp->nm_sockflags & NMSOCK_UNMOUNT)
1015 error = ENXIO;
1016 if (error)
1017 break;
1018 if (nmp->nm_stateinuse)
1019 msleep(&nmp->nm_stateinuse, &nmp->nm_lock, (PZERO-1), "nfsrecoverstartwait", &ts);
1020 } while (nmp->nm_stateinuse);
1021 if (error) {
1022 if (error == EPIPE)
1023 printf("nfs recovery reconnecting\n");
1024 else
1025 printf("nfs recovery aborted\n");
1026 lck_mtx_unlock(&nmp->nm_lock);
1027 return;
1028 }
1029
1030 printf("nfs recovery started\n");
1031 if (++nmp->nm_stategenid == 0)
1032 ++nmp->nm_stategenid;
1033 lck_mtx_unlock(&nmp->nm_lock);
1034
1035 /* for each open owner... */
1036 TAILQ_FOREACH(noop, &nmp->nm_open_owners, noo_link) {
1037 /* for each of its opens... */
1038 TAILQ_FOREACH(nofp, &noop->noo_opens, nof_oolink) {
1039 if (!nofp->nof_access || (nofp->nof_flags & NFS_OPEN_FILE_LOST))
1040 continue;
1041 lost = reopen = 0;
1042 if (nofp->nof_rw_drw)
1043 error = nfs4_open_reclaim_rpc(nofp, NFS_OPEN_SHARE_ACCESS_BOTH, NFS_OPEN_SHARE_DENY_BOTH);
1044 if (!error && nofp->nof_w_drw)
1045 error = nfs4_open_reclaim_rpc(nofp, NFS_OPEN_SHARE_ACCESS_WRITE, NFS_OPEN_SHARE_DENY_BOTH);
1046 if (!error && nofp->nof_r_drw)
1047 error = nfs4_open_reclaim_rpc(nofp, NFS_OPEN_SHARE_ACCESS_READ, NFS_OPEN_SHARE_DENY_BOTH);
1048 if (!error && nofp->nof_rw_dw)
1049 error = nfs4_open_reclaim_rpc(nofp, NFS_OPEN_SHARE_ACCESS_BOTH, NFS_OPEN_SHARE_DENY_WRITE);
1050 if (!error && nofp->nof_w_dw)
1051 error = nfs4_open_reclaim_rpc(nofp, NFS_OPEN_SHARE_ACCESS_WRITE, NFS_OPEN_SHARE_DENY_WRITE);
1052 if (!error && nofp->nof_r_dw)
1053 error = nfs4_open_reclaim_rpc(nofp, NFS_OPEN_SHARE_ACCESS_READ, NFS_OPEN_SHARE_DENY_WRITE);
1054 /*
1055 * deny-none opens with no locks can just be reopened (later) if reclaim fails.
1056 */
1057 if (!error && nofp->nof_rw) {
1058 error = nfs4_open_reclaim_rpc(nofp, NFS_OPEN_SHARE_ACCESS_BOTH, NFS_OPEN_SHARE_DENY_NONE);
1059 if ((error == NFSERR_ADMIN_REVOKED) || (error == NFSERR_EXPIRED) || (error == NFSERR_NO_GRACE))
1060 reopen = 1;
1061 }
1062 if (!error && nofp->nof_w) {
1063 error = nfs4_open_reclaim_rpc(nofp, NFS_OPEN_SHARE_ACCESS_WRITE, NFS_OPEN_SHARE_DENY_NONE);
1064 if ((error == NFSERR_ADMIN_REVOKED) || (error == NFSERR_EXPIRED) || (error == NFSERR_NO_GRACE))
1065 reopen = 1;
1066 }
1067 if (!error && nofp->nof_r) {
1068 error = nfs4_open_reclaim_rpc(nofp, NFS_OPEN_SHARE_ACCESS_READ, NFS_OPEN_SHARE_DENY_NONE);
1069 if ((error == NFSERR_ADMIN_REVOKED) || (error == NFSERR_EXPIRED) || (error == NFSERR_NO_GRACE))
1070 reopen = 1;
1071 }
1072
1073 if (error) {
1074 /* restart recovery? */
1075 if ((error == ETIMEDOUT) || nfs_mount_state_error_should_restart(error)) {
1076 if (error == ETIMEDOUT)
1077 nfs_need_reconnect(nmp);
1078 tsleep(&lbolt, (PZERO-1), "nfsrecoverrestart", 0);
1079 printf("nfs recovery restarting %d\n", error);
1080 goto restart;
1081 }
1082 if (reopen && (nfs4_check_for_locks(noop, nofp) == 0)) {
1083 /* just reopen the file on next access */
1084 const char *vname = vnode_getname(NFSTOV(nofp->nof_np));
1085 printf("nfs4_recover: %d, need reopen for %s\n", error, vname ? vname : "???");
1086 vnode_putname(vname);
1087 lck_mtx_lock(&nofp->nof_lock);
1088 nofp->nof_flags |= NFS_OPEN_FILE_REOPEN;
1089 lck_mtx_unlock(&nofp->nof_lock);
1090 error = 0;
1091 } else {
1092 /* open file state lost */
1093 lost = 1;
1094 error = 0;
1095 lck_mtx_lock(&nofp->nof_lock);
1096 nofp->nof_flags &= ~NFS_OPEN_FILE_REOPEN;
1097 lck_mtx_unlock(&nofp->nof_lock);
1098 }
1099 } else {
1100 /* no error, so make sure the reopen flag isn't set */
1101 lck_mtx_lock(&nofp->nof_lock);
1102 nofp->nof_flags &= ~NFS_OPEN_FILE_REOPEN;
1103 lck_mtx_unlock(&nofp->nof_lock);
1104 }
1105 /*
1106 * Scan this node's lock owner list for entries with this open owner,
1107 * then walk the lock owner's held lock list recovering each lock.
1108 */
1109 rescanlocks:
1110 TAILQ_FOREACH(nlop, &nofp->nof_np->n_lock_owners, nlo_link) {
1111 if (nlop->nlo_open_owner != noop)
1112 continue;
1113 TAILQ_FOREACH_SAFE(nflp, &nlop->nlo_locks, nfl_lolink, nextnflp) {
1114 if (nflp->nfl_flags & (NFS_FILE_LOCK_DEAD|NFS_FILE_LOCK_BLOCKED))
1115 continue;
1116 if (!lost) {
1117 error = nfs4_lock_rpc(nofp->nof_np, nofp, nflp, 1, thd, noop->noo_cred);
1118 if (!error)
1119 continue;
1120 /* restart recovery? */
1121 if ((error == ETIMEDOUT) || nfs_mount_state_error_should_restart(error)) {
1122 if (error == ETIMEDOUT)
1123 nfs_need_reconnect(nmp);
1124 tsleep(&lbolt, (PZERO-1), "nfsrecoverrestart", 0);
1125 printf("nfs recovery restarting %d\n", error);
1126 goto restart;
1127 }
1128 /* lock state lost - attempt to close file */
1129 lost = 1;
1130 error = nfs4_close_rpc(nofp->nof_np, nofp, NULL, noop->noo_cred, R_RECOVER);
1131 if ((error == ETIMEDOUT) || nfs_mount_state_error_should_restart(error)) {
1132 if (error == ETIMEDOUT)
1133 nfs_need_reconnect(nmp);
1134 tsleep(&lbolt, (PZERO-1), "nfsrecoverrestart", 0);
1135 printf("nfs recovery restarting %d\n", error);
1136 goto restart;
1137 }
1138 error = 0;
1139 /* rescan locks so we can drop them all */
1140 goto rescanlocks;
1141 }
1142 if (lost) {
1143 /* kill/remove the lock */
1144 lck_mtx_lock(&nofp->nof_np->n_openlock);
1145 nflp->nfl_flags |= NFS_FILE_LOCK_DEAD;
1146 lck_mtx_lock(&nlop->nlo_lock);
1147 nextnflp = TAILQ_NEXT(nflp, nfl_lolink);
1148 TAILQ_REMOVE(&nlop->nlo_locks, nflp, nfl_lolink);
1149 lck_mtx_unlock(&nlop->nlo_lock);
1150 if (nflp->nfl_blockcnt) {
1151 /* wake up anyone blocked on this lock */
1152 wakeup(nflp);
1153 } else {
1154 /* remove nflp from lock list and destroy */
1155 TAILQ_REMOVE(&nofp->nof_np->n_locks, nflp, nfl_link);
1156 nfs_file_lock_destroy(nflp);
1157 }
1158 lck_mtx_unlock(&nofp->nof_np->n_openlock);
1159 }
1160 }
1161 }
1162 if (lost) {
1163 /* revoke open file state */
1164 lck_mtx_lock(&nofp->nof_lock);
1165 nofp->nof_flags |= NFS_OPEN_FILE_LOST;
1166 lck_mtx_unlock(&nofp->nof_lock);
1167 const char *vname = vnode_getname(NFSTOV(nofp->nof_np));
1168 printf("nfs4_recover: state lost for %s\n", vname ? vname : "???");
1169 vnode_putname(vname);
1170 }
1171 }
1172 }
1173
1174 if (!error) {
1175 lck_mtx_lock(&nmp->nm_lock);
1176 nmp->nm_state &= ~NFSSTA_RECOVER;
1177 wakeup(&nmp->nm_state);
1178 printf("nfs recovery completed\n");
1179 lck_mtx_unlock(&nmp->nm_lock);
1180 } else {
1181 printf("nfs recovery failed %d\n", error);
1182 }
1183 }
1184