2 * Copyright (c) 2006-2009 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 * miscellaneous support functions for NFSv4
32 #include <sys/param.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>
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>
52 #include <sys/vmparam.h>
55 #include <kern/clock.h>
57 #include <nfs/rpcv2.h>
58 #include <nfs/nfsproto.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>
67 #include <miscfs/specfs/specdev.h>
69 #include <netinet/in.h>
70 #include <net/kpi_interface.h>
74 * Create the unique client ID to use for this mount.
76 * Format: unique ID + en0_address + server_address + mntfromname + mntonname
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.
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.
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.
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.
93 nfs4_init_clientid(struct nfsmount
*nmp
)
95 struct nfs_client_id
*ncip
, *ncip2
;
96 struct sockaddr
*saddr
;
97 int error
, len
, len2
, cmp
;
98 struct vfsstatfs
*vsfs
;
100 static uint8_t en0addr
[6];
101 static uint8_t en0addr_set
= 0;
103 lck_mtx_lock(nfs_global_mutex
);
105 ifnet_t interface
= NULL
;
106 error
= ifnet_find_by_name("en0", &interface
);
108 error
= ifnet_lladdr_copy_bytes(interface
, en0addr
, sizeof(en0addr
));
110 printf("nfs4_init_clientid: error getting en0 address, %d\n", error
);
114 ifnet_release(interface
);
116 lck_mtx_unlock(nfs_global_mutex
);
118 MALLOC(ncip
, struct nfs_client_id
*, sizeof(struct nfs_client_id
), M_TEMP
, M_WAITOK
);
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
);
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
);
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
))
147 len
= ncip
->nci_idlen
;
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
))
154 len
= ncip
->nci_idlen
;
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
)
162 if (ncip
->nci_idlen
< ncip2
->nci_idlen
)
164 cmp
= bcmp(ncip
->nci_id
+ sizeof(uint32_t),
165 ncip2
->nci_id
+ sizeof(uint32_t),
166 ncip
->nci_idlen
- sizeof(uint32_t));
171 if (*(uint32_t*)ncip
->nci_id
> *(uint32_t*)ncip2
->nci_id
)
173 if (*(uint32_t*)ncip
->nci_id
< *(uint32_t*)ncip2
->nci_id
)
175 *(uint32_t*)ncip
->nci_id
+= 1;
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
);
181 TAILQ_INSERT_BEFORE(ncip2
, ncip
, nci_link
);
183 TAILQ_INSERT_TAIL(&nfsclientids
, ncip
, nci_link
);
184 nmp
->nm_longid
= ncip
;
185 lck_mtx_unlock(nfs_global_mutex
);
194 nfs4_setclientid(struct nfsmount
*nmp
)
196 uint64_t verifier
, xid
;
197 int error
= 0, status
, numops
;
198 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
];
201 struct nfsm_chain nmreq
, nmrep
;
202 struct sockaddr_in sin
;
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
);
211 nfsm_chain_null(&nmreq
);
212 nfsm_chain_null(&nmrep
);
215 error
= nfs4_init_clientid(nmp
);
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
);
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
))
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 */
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 */
255 nfsm_chain_build_done(error
, &nmreq
);
256 nfsm_assert(error
, (numops
== 0), EPROTO
);
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");
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
);
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
);
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
);
279 /* refresh fs attributes too */
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
);
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
);
289 nfsm_chain_build_done(error
, &nmreq
);
290 nfsm_assert(error
, (numops
== 0), EPROTO
);
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
);
297 printf("nfs4_setclientid: confirm error %d\n", error
);
299 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_PUTFH
);
300 nfsm_chain_op_check(error
, &nmrep
, NFS_OP_GETATTR
);
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
);
308 nfsm_chain_cleanup(&nmreq
);
309 nfsm_chain_cleanup(&nmrep
);
310 kauth_cred_unref(&cred
);
312 printf("nfs4_setclientid failed, %d\n", error
);
317 * renew/check lease state on server
320 nfs4_renew(struct nfsmount
*nmp
, int rpcflag
)
322 int error
= 0, status
, numops
;
324 struct nfsm_chain nmreq
, nmrep
;
327 cred
= IS_VALID_CRED(nmp
->nm_mcred
) ? nmp
->nm_mcred
: vfs_context_ucred(vfs_context_kernel());
328 kauth_cred_ref(cred
);
330 nfsm_chain_null(&nmreq
);
331 nfsm_chain_null(&nmrep
);
335 nfsm_chain_build_alloc_init(error
, &nmreq
, 8 * NFSX_UNSIGNED
);
336 nfsm_chain_add_compound_header(error
, &nmreq
, "renew", 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
);
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
);
349 nfsm_chain_cleanup(&nmreq
);
350 nfsm_chain_cleanup(&nmrep
);
351 kauth_cred_unref(&cred
);
357 * periodic timer to renew lease state on server
360 nfs4_renew_timer(void *param0
, __unused
void *param1
)
362 struct nfsmount
*nmp
= param0
;
364 int error
= 0, interval
;
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
);
372 lck_mtx_unlock(&nmp
->nm_lock
);
374 error
= nfs4_renew(nmp
, R_RECOVER
);
376 if (error
== ETIMEDOUT
)
377 nfs_need_reconnect(nmp
);
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
);
388 interval
= nmp
->nm_fsattr
.nfsa_lease
/ (error
? 4 : 2);
389 if ((interval
< 1) || (nmp
->nm_state
& NFSSTA_RECOVER
))
391 lck_mtx_unlock(&nmp
->nm_lock
);
392 nfs_interval_timer_start(nmp
->nm_renew_timer
, interval
* 1000);
396 * Set a vnode attr's supported bits according to the given bitmap
399 nfs_vattr_set_supported(uint32_t *bitmap
, struct vnode_attr
*vap
)
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
);
444 * Parse the attributes that are in the mbuf list and store them in
445 * the given structures.
449 struct nfsm_chain
*nmc
,
450 struct nfs_fsattr
*nfsap
,
451 struct nfs_vattr
*nvap
,
455 int error
= 0, attrbytes
;
456 uint32_t val
, val2
, val3
, i
, j
;
457 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
], len
;
459 struct nfs_fsattr nfsa_dummy
;
460 struct nfs_vattr nva_dummy
;
461 struct dqblk dqb_dummy
;
463 /* if not interested in some values... throw 'em into a local dummy variable */
471 attrbytes
= val
= val2
= val3
= 0;
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
];
481 nfsm_chain_get_32(error
, nmc
, attrbytes
);
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
;
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
;
494 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FH_EXPIRE_TYPE
)) {
495 nfsm_chain_get_32(error
, nmc
, val
);
497 if (val
!= NFS_FH_PERSISTENT
)
498 printf("nfs: warning: non-persistent file handles!\n");
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
;
505 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_CHANGE
)) {
506 nfsm_chain_get_64(error
, nmc
, nvap
->nva_change
);
507 attrbytes
-= 2 * NFSX_UNSIGNED
;
509 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SIZE
)) {
510 nfsm_chain_get_64(error
, nmc
, nvap
->nva_size
);
511 attrbytes
-= 2 * NFSX_UNSIGNED
;
513 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_LINK_SUPPORT
)) {
514 nfsm_chain_get_32(error
, nmc
, val
);
516 nfsap
->nfsa_flags
|= NFS_FSFLAG_LINK
;
518 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_LINK
;
519 attrbytes
-= NFSX_UNSIGNED
;
521 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_SYMLINK_SUPPORT
)) {
522 nfsm_chain_get_32(error
, nmc
, val
);
524 nfsap
->nfsa_flags
|= NFS_FSFLAG_SYMLINK
;
526 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_SYMLINK
;
527 attrbytes
-= NFSX_UNSIGNED
;
529 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_NAMED_ATTR
)) {
530 nfsm_chain_get_32(error
, nmc
, val
);
532 nvap
->nva_flags
|= NFS_FFLAG_NAMED_ATTR
;
534 nvap
->nva_flags
&= ~NFS_FFLAG_NAMED_ATTR
;
535 attrbytes
-= NFSX_UNSIGNED
;
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
;
542 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_UNIQUE_HANDLES
)) {
543 nfsm_chain_get_32(error
, nmc
, val
);
545 nfsap
->nfsa_flags
|= NFS_FSFLAG_UNIQUE_FH
;
547 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_UNIQUE_FH
;
548 attrbytes
-= NFSX_UNSIGNED
;
550 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_LEASE_TIME
)) {
551 nfsm_chain_get_32(error
, nmc
, nfsap
->nfsa_lease
);
552 attrbytes
-= NFSX_UNSIGNED
;
554 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_RDATTR_ERROR
)) {
555 nfsm_chain_get_32(error
, nmc
, error
);
556 attrbytes
-= NFSX_UNSIGNED
;
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
);
569 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ACLSUPPORT
)) {
570 nfsm_chain_get_32(error
, nmc
, val
);
572 nfsap
->nfsa_flags
|= NFS_FSFLAG_ACL
;
574 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_ACL
;
575 attrbytes
-= NFSX_UNSIGNED
;
577 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_ARCHIVE
)) { /* SF_ARCHIVED */
578 nfsm_chain_get_32(error
, nmc
, val
);
580 nvap
->nva_flags
|= NFS_FFLAG_ARCHIVED
;
582 nvap
->nva_flags
&= ~NFS_FFLAG_ARCHIVED
;
583 attrbytes
-= NFSX_UNSIGNED
;
585 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_CANSETTIME
)) {
586 nfsm_chain_get_32(error
, nmc
, val
);
588 nfsap
->nfsa_flags
|= NFS_FSFLAG_SET_TIME
;
590 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_SET_TIME
;
591 attrbytes
-= NFSX_UNSIGNED
;
593 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_CASE_INSENSITIVE
)) {
594 nfsm_chain_get_32(error
, nmc
, val
);
596 nfsap
->nfsa_flags
|= NFS_FSFLAG_CASE_INSENSITIVE
;
598 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_CASE_INSENSITIVE
;
599 attrbytes
-= NFSX_UNSIGNED
;
601 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_CASE_PRESERVING
)) {
602 nfsm_chain_get_32(error
, nmc
, val
);
604 nfsap
->nfsa_flags
|= NFS_FSFLAG_CASE_PRESERVING
;
606 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_CASE_PRESERVING
;
607 attrbytes
-= NFSX_UNSIGNED
;
609 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_CHOWN_RESTRICTED
)) {
610 nfsm_chain_get_32(error
, nmc
, val
);
612 nfsap
->nfsa_flags
|= NFS_FSFLAG_CHOWN_RESTRICTED
;
614 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_CHOWN_RESTRICTED
;
615 attrbytes
-= NFSX_UNSIGNED
;
617 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FILEHANDLE
)) {
618 nfsm_chain_get_32(error
, nmc
, val
);
621 nfsm_chain_get_opaque(error
, nmc
, nfsm_rndup(val
), fhp
->fh_data
);
623 nfsm_chain_adv(error
, nmc
, nfsm_rndup(val
));
625 attrbytes
-= NFSX_UNSIGNED
+ nfsm_rndup(val
);
627 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_FILEID
)) {
628 nfsm_chain_get_64(error
, nmc
, nvap
->nva_fileid
);
629 attrbytes
-= 2 * NFSX_UNSIGNED
;
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
;
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
;
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
;
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
);
659 nfsm_assert(error
, (attrbytes
>= 0), EBADRPC
);
661 nfsm_assert(error
, (attrbytes
>= 0), EBADRPC
);
663 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_HIDDEN
)) { /* UF_HIDDEN */
664 nfsm_chain_get_32(error
, nmc
, val
);
666 nvap
->nva_flags
|= NFS_FFLAG_HIDDEN
;
668 nvap
->nva_flags
&= ~NFS_FFLAG_HIDDEN
;
669 attrbytes
-= NFSX_UNSIGNED
;
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
);
675 nfsap
->nfsa_flags
|= NFS_FSFLAG_HOMOGENEOUS
;
677 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_HOMOGENEOUS
;
678 attrbytes
-= NFSX_UNSIGNED
;
680 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MAXFILESIZE
)) {
681 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_maxfilesize
);
682 attrbytes
-= 2 * NFSX_UNSIGNED
;
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
;
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
;
696 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MAXREAD
)) {
697 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_maxread
);
698 attrbytes
-= 2 * NFSX_UNSIGNED
;
700 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MAXWRITE
)) {
701 nfsm_chain_get_64(error
, nmc
, nfsap
->nfsa_maxwrite
);
702 attrbytes
-= 2 * NFSX_UNSIGNED
;
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
);
709 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_MODE
)) {
710 nfsm_chain_get_32(error
, nmc
, nvap
->nva_mode
);
711 attrbytes
-= NFSX_UNSIGNED
;
713 if (NFS_BITMAP_ISSET(bitmap
, NFS_FATTR_NO_TRUNC
)) {
714 nfsm_chain_get_32(error
, nmc
, val
);
716 nfsap
->nfsa_flags
|= NFS_FSFLAG_NO_TRUNC
;
718 nfsap
->nfsa_flags
&= ~NFS_FSFLAG_NO_TRUNC
;
719 attrbytes
-= NFSX_UNSIGNED
;
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
;
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
);
732 if ((*s
>= '0') && (*s
<= '9'))
733 nvap
->nva_uid
= strtol(s
, NULL
, 10);
734 else if (!strncmp(s
, "nobody@", 7))
736 else if (!strncmp(s
, "root@", 5))
739 nvap
->nva_uid
= 99; /* unknown */
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
);
747 if ((*s
>= '0') && (*s
<= '9'))
748 nvap
->nva_gid
= strtol(s
, NULL
, 10);
749 else if (!strncmp(s
, "nobody@", 7))
751 else if (!strncmp(s
, "root@", 5))
754 nvap
->nva_gid
= 99; /* unknown */
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
835 /* advance over any leftover attrbytes */
836 nfsm_assert(error
, (attrbytes
>= 0), EBADRPC
);
837 nfsm_chain_adv(error
, nmc
, nfsm_rndup(attrbytes
));
843 * Add an NFSv4 "sattr" structure to an mbuf chain
846 nfsm_chain_add_fattr4_f(struct nfsm_chain
*nmc
, struct vnode_attr
*vap
, struct nfsmount
*nmp
)
848 int error
= 0, attrbytes
, slen
, i
;
849 uint32_t *pattrbytes
;
850 uint32_t bitmap
[NFS_ATTR_BITMAP_LEN
];
854 * Do this in two passes.
855 * First calculate the bitmap, then pack
856 * everything together and set the size.
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)
865 if (VATTR_IS_ACTIVE(vap
, va_flags
)) {
866 NFS_BITMAP_SET(bitmap
, NFS_FATTR_ARCHIVE
);
867 NFS_BITMAP_SET(bitmap
, NFS_FATTR_HIDDEN
);
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
);
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
);
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
];
895 * Now pack it all together:
896 * BITMAP, #BYTES, ATTRS
897 * Keep a pointer to the length so we can set it later.
899 nfsm_chain_add_bitmap(error
, nmc
, bitmap
, NFS_ATTR_BITMAP_LEN
);
901 nfsm_chain_add_32(error
, nmc
, attrbytes
);
902 pattrbytes
= (uint32_t*)(nmc
->nmc_ptr
- NFSX_UNSIGNED
);
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
;
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
;
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
;
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
;
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");
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
);
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");
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
);
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
;
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
;
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
;
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
;
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
;
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
;
978 /* Now, set the attribute data length */
979 *pattrbytes
= txdr_unsigned(attrbytes
);
985 * Recover state for an NFS mount.
987 * Iterates over all open files, reclaiming opens and lock state.
990 nfs4_recover(struct nfsmount
*nmp
)
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();
1002 lck_mtx_lock(&nmp
->nm_lock
);
1004 * First, wait for the state inuse count to go to zero so
1005 * we know there are no state operations in progress.
1008 if ((error
= nfs_sigintr(nmp
, NULL
, NULL
, 1)))
1010 if (!(nmp
->nm_sockflags
& NMSOCK_READY
))
1012 if (nmp
->nm_state
& NFSSTA_FORCE
)
1014 if (nmp
->nm_sockflags
& NMSOCK_UNMOUNT
)
1018 if (nmp
->nm_stateinuse
)
1019 msleep(&nmp
->nm_stateinuse
, &nmp
->nm_lock
, (PZERO
-1), "nfsrecoverstartwait", &ts
);
1020 } while (nmp
->nm_stateinuse
);
1023 printf("nfs recovery reconnecting\n");
1025 printf("nfs recovery aborted\n");
1026 lck_mtx_unlock(&nmp
->nm_lock
);
1030 printf("nfs recovery started\n");
1031 if (++nmp
->nm_stategenid
== 0)
1032 ++nmp
->nm_stategenid
;
1033 lck_mtx_unlock(&nmp
->nm_lock
);
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
))
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
);
1055 * deny-none opens with no locks can just be reopened (later) if reclaim fails.
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
))
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
))
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
))
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
);
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
);
1092 /* open file state lost */
1095 lck_mtx_lock(&nofp
->nof_lock
);
1096 nofp
->nof_flags
&= ~NFS_OPEN_FILE_REOPEN
;
1097 lck_mtx_unlock(&nofp
->nof_lock
);
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
);
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.
1110 TAILQ_FOREACH(nlop
, &nofp
->nof_np
->n_lock_owners
, nlo_link
) {
1111 if (nlop
->nlo_open_owner
!= noop
)
1113 TAILQ_FOREACH_SAFE(nflp
, &nlop
->nlo_locks
, nfl_lolink
, nextnflp
) {
1114 if (nflp
->nfl_flags
& (NFS_FILE_LOCK_DEAD
|NFS_FILE_LOCK_BLOCKED
))
1117 error
= nfs4_lock_rpc(nofp
->nof_np
, nofp
, nflp
, 1, thd
, noop
->noo_cred
);
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
);
1128 /* lock state lost - attempt to close file */
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
);
1139 /* rescan locks so we can drop them all */
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 */
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
);
1158 lck_mtx_unlock(&nofp
->nof_np
->n_openlock
);
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
);
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
);
1181 printf("nfs recovery failed %d\n", error
);