1/*
2 * Copyright (c) 2000-2001, Boris Popov
3 * All rights reserved.
4 *
5 * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *    This product includes software developed by Boris Popov.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 */
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/proc.h>
39#include <sys/kernel.h>
40#include <sys/sysctl.h>
41#include <sys/vnode.h>
42#include <sys/mount.h>
43#include <sys/stat.h>
44#include <sys/malloc.h>
45#include <sys/sysctl.h>
46#include <libkern/OSAtomic.h>
47
48#include <sys/kauth.h>
49
50#include <sys/syslog.h>
51#include <sys/smb_apple.h>
52#include <sys/mchain.h>
53
54#include <netsmb/smb.h>
55#include <netsmb/smb_2.h>
56#include <netsmb/smb_conn.h>
57#include <netsmb/smb_subr.h>
58#include <netsmb/smb_dev.h>
59#include <netsmb/smb_sleephandler.h>
60#include <netsmb/smb_rq.h>
61
62#include <smbfs/smbfs.h>
63#include <smbfs/smbfs_node.h>
64#include <smbfs/smbfs_subr.h>
65#include <smbfs/smbfs_subr_2.h>
66#include <smbclient/smbclient_internal.h>
67#include "smbfs_security.h"
68#include <Triggers/triggers.h>
69
70#include <sys/buf.h>
71
72int smbfs_module_start(kmod_info_t *ki, void *data);
73int smbfs_module_stop(kmod_info_t *ki, void *data);
74static int smbfs_root(struct mount *, vnode_t *, vfs_context_t);
75
76#define	SMB_FSYNC_TIMO 30
77
78#ifdef SMB_DEBUG
79__attribute__((visibility("hidden"))) int smbfs_loglevel = SMB_LOW_LOG_LEVEL;
80#else // SMB_DEBUG
81__attribute__((visibility("hidden"))) int smbfs_loglevel = SMB_NO_LOG_LEVEL;
82#endif // SMB_DEBUG
83
84__attribute__((visibility("hidden"))) uint32_t smbfs_deadtimer = DEAD_TIMEOUT;
85__attribute__((visibility("hidden"))) uint32_t smbfs_hard_deadtimer = HARD_DEAD_TIMER;
86__attribute__((visibility("hidden"))) uint32_t smbfs_trigger_deadtimer = TRIGGER_DEAD_TIMEOUT;
87
88static int smbfs_version = SMBFS_VERSION;
89static int mount_cnt = 0;
90int dev_open_cnt = 0;
91int unloadInProgress = FALSE;
92
93lck_grp_attr_t *smbfs_group_attr;
94lck_attr_t *smbfs_lock_attr;
95lck_grp_t *smbfs_mutex_group;
96lck_grp_t *smbfs_rwlock_group;
97
98lck_grp_attr_t *co_grp_attr;
99lck_grp_t *co_lck_group;
100lck_attr_t *co_lck_attr;
101
102lck_grp_attr_t *vc_credits_grp_attr;
103lck_grp_t *vc_credits_lck_group;
104lck_attr_t *vc_credits_lck_attr;
105
106lck_grp_attr_t *vcst_grp_attr;
107lck_grp_t *vcst_lck_group;
108lck_attr_t *vcst_lck_attr;
109
110lck_grp_attr_t *ssst_grp_attr;
111lck_grp_t *ssst_lck_group;
112lck_attr_t *ssst_lck_attr;
113
114lck_grp_attr_t *fid_lck_grp_attr;
115lck_grp_t *fid_lck_grp;
116lck_attr_t *fid_lck_attr;
117
118lck_grp_attr_t *iodflags_grp_attr;
119lck_grp_t *iodflags_lck_group;
120lck_attr_t *iodflags_lck_attr;
121
122lck_grp_attr_t *iodrq_grp_attr;
123lck_grp_t *iodrq_lck_group;
124lck_attr_t *iodrq_lck_attr;
125
126lck_grp_attr_t *iodev_grp_attr;
127lck_grp_t *iodev_lck_group;
128lck_attr_t *iodev_lck_attr;
129
130lck_grp_attr_t *srs_grp_attr;
131lck_grp_t *srs_lck_group;
132lck_attr_t *srs_lck_attr;
133
134lck_grp_attr_t *nbp_grp_attr;
135lck_grp_t *nbp_lck_group;
136lck_attr_t *nbp_lck_attr;
137
138lck_grp_attr_t *dev_lck_grp_attr;
139lck_grp_t *dev_lck_grp;
140lck_attr_t *dev_lck_attr;
141lck_rw_t *dev_rw_lck;
142
143lck_grp_attr_t *hash_lck_grp_attr;
144lck_grp_t *hash_lck_grp;
145lck_attr_t *hash_lck_attr;
146
147struct smbmnt_carg {
148	vfs_context_t context;
149	struct mount *mp;
150	int found;
151};
152
153static uint32_t smb_maxsegreadsize = 1024 * 1024 * 2;
154static uint32_t smb_maxsegwritesize = 1024 * 1024 * 2;
155
156SYSCTL_DECL(_net_smb);
157SYSCTL_NODE(_net_smb, OID_AUTO, fs, CTLFLAG_RW, 0, "SMB/CIFS file system");
158SYSCTL_INT(_net_smb_fs, OID_AUTO, version, CTLFLAG_RD, &smbfs_version, 0, "");
159SYSCTL_INT(_net_smb_fs, OID_AUTO, loglevel, CTLFLAG_RW,  &smbfs_loglevel, 0, "");
160SYSCTL_INT(_net_smb_fs, OID_AUTO, kern_deadtimer, CTLFLAG_RW, &smbfs_deadtimer, DEAD_TIMEOUT, "");
161SYSCTL_INT(_net_smb_fs, OID_AUTO, kern_hard_deadtimer, CTLFLAG_RW, &smbfs_hard_deadtimer, HARD_DEAD_TIMER, "");
162SYSCTL_INT(_net_smb_fs, OID_AUTO, kern_soft_deadtimer, CTLFLAG_RW, &smbfs_trigger_deadtimer, TRIGGER_DEAD_TIMEOUT, "");
163SYSCTL_INT(_net_smb_fs, OID_AUTO, maxsegreadsize, CTLFLAG_RW, &smb_maxsegreadsize, 0, "");
164SYSCTL_INT(_net_smb_fs, OID_AUTO, maxsegwritesize, CTLFLAG_RW, &smb_maxsegwritesize, 0, "");
165
166
167extern struct sysctl_oid sysctl__net_smb;
168extern struct sysctl_oid sysctl__net_smb_fs_version;
169extern struct sysctl_oid sysctl__net_smb_fs_loglevel;
170extern struct sysctl_oid sysctl__net_smb_fs_kern_deadtimer;
171extern struct sysctl_oid sysctl__net_smb_fs_kern_hard_deadtimer;
172extern struct sysctl_oid sysctl__net_smb_fs_kern_soft_deadtimer;
173extern struct sysctl_oid sysctl__net_smb_fs_tcpsndbuf;
174extern struct sysctl_oid sysctl__net_smb_fs_tcprcvbuf;
175extern struct sysctl_oid sysctl__net_smb_fs_maxwrite;
176extern struct sysctl_oid sysctl__net_smb_fs_maxread;
177extern struct sysctl_oid sysctl__net_smb_fs_maxsegreadsize;
178extern struct sysctl_oid sysctl__net_smb_fs_maxsegwritesize;
179
180
181MALLOC_DEFINE(M_SMBFSHASH, "SMBFS hash", "SMBFS hash table");
182
183#ifndef VFS_CTL_DISC
184#define VFS_CTL_DISC	0x00010008	/* Server is disconnected */
185#endif
186
187static void
188smbfs_lock_init()
189{
190	hash_lck_attr = lck_attr_alloc_init();
191	hash_lck_grp_attr = lck_grp_attr_alloc_init();
192	hash_lck_grp = lck_grp_alloc_init("smb-hash", hash_lck_grp_attr);
193
194	smbfs_lock_attr    = lck_attr_alloc_init();
195	smbfs_group_attr   = lck_grp_attr_alloc_init();
196	smbfs_mutex_group  = lck_grp_alloc_init("smb-mutex", smbfs_group_attr);
197	smbfs_rwlock_group = lck_grp_alloc_init("smbfs-rwlock", smbfs_group_attr);
198}
199
200static void
201smbfs_lock_uninit()
202{
203	lck_grp_free(smbfs_mutex_group);
204	lck_grp_free(smbfs_rwlock_group);
205	lck_grp_attr_free(smbfs_group_attr);
206	lck_attr_free(smbfs_lock_attr);
207
208	lck_grp_free(hash_lck_grp);
209	lck_grp_attr_free(hash_lck_grp_attr);
210	lck_attr_free(hash_lck_attr);
211}
212
213static void
214smbnet_lock_init()
215{
216	co_lck_attr = lck_attr_alloc_init();
217	co_grp_attr = lck_grp_attr_alloc_init();
218	co_lck_group = lck_grp_alloc_init("smb-co", co_grp_attr);
219
220	vc_credits_lck_attr = lck_attr_alloc_init();
221	vc_credits_grp_attr = lck_grp_attr_alloc_init();
222	vc_credits_lck_group = lck_grp_alloc_init("smb-vc_credits", vc_credits_grp_attr);
223
224	vcst_lck_attr = lck_attr_alloc_init();
225	vcst_grp_attr = lck_grp_attr_alloc_init();
226	vcst_lck_group = lck_grp_alloc_init("smb-vcst", vcst_grp_attr);
227
228	ssst_lck_attr = lck_attr_alloc_init();
229	ssst_grp_attr = lck_grp_attr_alloc_init();
230	ssst_lck_group = lck_grp_alloc_init("smb-ssst", ssst_grp_attr);
231
232	fid_lck_attr = lck_attr_alloc_init();
233	fid_lck_grp_attr = lck_grp_attr_alloc_init();
234	fid_lck_grp = lck_grp_alloc_init("smb-fid", fid_lck_grp_attr);
235
236	iodflags_lck_attr = lck_attr_alloc_init();
237	iodflags_grp_attr = lck_grp_attr_alloc_init();
238	iodflags_lck_group = lck_grp_alloc_init("smb-iodflags", iodflags_grp_attr);
239
240	iodrq_lck_attr = lck_attr_alloc_init();
241	iodrq_grp_attr = lck_grp_attr_alloc_init();
242	iodrq_lck_group = lck_grp_alloc_init("smb-iodrq", iodrq_grp_attr);
243
244	iodev_lck_attr = lck_attr_alloc_init();
245	iodev_grp_attr = lck_grp_attr_alloc_init();
246	iodev_lck_group = lck_grp_alloc_init("smb-iodev", iodev_grp_attr);
247
248	srs_lck_attr = lck_attr_alloc_init();
249	srs_grp_attr = lck_grp_attr_alloc_init();
250	srs_lck_group = lck_grp_alloc_init("smb-srs", srs_grp_attr);
251
252	nbp_lck_attr = lck_attr_alloc_init();
253	nbp_grp_attr = lck_grp_attr_alloc_init();
254	nbp_lck_group = lck_grp_alloc_init("smb-nbp", nbp_grp_attr);
255
256	dev_lck_attr = lck_attr_alloc_init();
257	dev_lck_grp_attr = lck_grp_attr_alloc_init();
258	dev_lck_grp = lck_grp_alloc_init("smb-dev", dev_lck_grp_attr);
259	dev_rw_lck = lck_rw_alloc_init(dev_lck_grp, dev_lck_attr);
260}
261
262static void
263smbnet_lock_uninit()
264{
265	lck_grp_free(dev_lck_grp);
266	lck_grp_attr_free(dev_lck_grp_attr);
267	lck_attr_free(dev_lck_attr);
268
269	lck_grp_free(nbp_lck_group);
270	lck_grp_attr_free(nbp_grp_attr);
271	lck_attr_free(nbp_lck_attr);
272
273	lck_grp_free(srs_lck_group);
274	lck_grp_attr_free(srs_grp_attr);
275	lck_attr_free(srs_lck_attr);
276
277	lck_grp_free(iodev_lck_group);
278	lck_grp_attr_free(iodev_grp_attr);
279	lck_attr_free(iodev_lck_attr);
280
281	lck_grp_free(iodrq_lck_group);
282	lck_grp_attr_free(iodrq_grp_attr);
283	lck_attr_free(iodrq_lck_attr);
284
285	lck_grp_free(iodflags_lck_group);
286	lck_grp_attr_free(iodflags_grp_attr);
287	lck_attr_free(iodflags_lck_attr);
288
289	lck_grp_free(ssst_lck_group);
290	lck_grp_attr_free(ssst_grp_attr);
291	lck_attr_free(ssst_lck_attr);
292
293	lck_grp_free(fid_lck_grp);
294	lck_grp_attr_free(fid_lck_grp_attr);
295	lck_attr_free(fid_lck_attr);
296
297	lck_grp_free(vc_credits_lck_group);
298	lck_grp_attr_free(vc_credits_grp_attr);
299	lck_attr_free(vc_credits_lck_attr);
300
301	lck_grp_free(vcst_lck_group);
302	lck_grp_attr_free(vcst_grp_attr);
303	lck_attr_free(vcst_lck_attr);
304
305	lck_grp_free(co_lck_group);
306	lck_grp_attr_free(co_grp_attr);
307	lck_attr_free(co_lck_attr);
308}
309
310/*
311 * Need to check and make sure the server is in the same domain, if not
312 * then we need to turn off ACL support.
313 */
314static void
315isServerInSameDomian(struct smb_share *share, struct smbmount *smp)
316{
317	/* Just to be safe */
318    if (smp->ntwrk_sids) {
319        SMB_FREE(smp->ntwrk_sids, M_TEMP);
320    }
321
322	smp->ntwrk_sids_cnt = 0;
323	if (SSTOVC(share)->vc_flags & SMBV_NETWORK_SID) {
324		/* See if the VC network SID is known by Directory Service */
325		if ((smp->sm_args.altflags & SMBFS_MNT_DEBUG_ACL_ON) ||
326			(smp->sm_args.altflags & SMBFS_MNT_TIME_MACHINE) ||
327			(smbfs_is_sid_known(&SSTOVC(share)->vc_ntwrk_sid))) {
328			SMB_MALLOC(smp->ntwrk_sids, ntsid_t *, sizeof(ntsid_t), M_TEMP, M_WAITOK);
329			memcpy(smp->ntwrk_sids, &SSTOVC(share)->vc_ntwrk_sid, sizeof(ntsid_t));
330			smp->ntwrk_sids_cnt = 1;
331			return;
332		}
333	}
334	SMBWARNING("%s: can't determine if server is in the same domain, turning off ACLs support.\n",
335			   vfs_statfs(smp->sm_mp)->f_mntfromname);
336	share->ss_attributes &= ~FILE_PERSISTENT_ACLS;
337}
338
339/*
340 * The share needs to be locked before calling this rouitne!
341 *
342 * smbfs_down is called when we have a message that timeout or we are
343 * starting a reconnect. It uses vfs_event_signal() to tell interested parties
344 * the connection with the server is "down".
345 */
346static int
347smbfs_down(struct smb_share *share, int timeToNotify)
348{
349	struct smbmount *smp;
350	int treenct = 1;
351
352	smp = share->ss_mount;
353	/* We have already unmounted or we are being force unmount, we are done */
354	if ((smp == NULL) || (vfs_isforce(smp->sm_mp))) {
355		return 0;
356	}
357
358	/*
359	 * They are attempted to unmount it so don't count this one.
360	 * Still notify them they may want to force unmount it.
361	 */
362	if (vfs_isunmount(smp->sm_mp)) {
363		treenct = 0;
364	}
365
366	/* Attempt to remount the Dfs volume */
367	if (treenct && (smp->sm_args.altflags & SMBFS_MNT_DFS_SHARE) &&
368		!(smp->sm_status & SM_STATUS_REMOUNT)) {
369		smp->sm_status |= SM_STATUS_REMOUNT;
370		/* Never do Dfs failover if the share is FAT or doing Unix Extensions */
371		if ((IPC_PORT_VALID(SSTOVC(share)->vc_gss.gss_mp)) &&
372			(share->ss_fstype != SMB_FS_FAT) && !(UNIX_CAPS(share))) {
373
374			/* Call autofs with the fsid to start the remount */
375			SMBERROR("Remounting %s/%s\n", SSTOVC(share)->vc_srvname,
376					 share->ss_name);
377			if (SMBRemountServer(&(vfs_statfs(smp->sm_mp))->f_fsid,
378								 sizeof(vfs_statfs(smp->sm_mp)->f_fsid),
379								 SSTOVC(share)->vc_gss.gss_asid)) {
380				/* Something went wrong try again next time */
381				SMBERROR("Something went wrong with remounting %s/%s\n",
382						 SSTOVC(share)->vc_srvname, share->ss_name);
383				smp->sm_status &= ~SM_STATUS_REMOUNT;
384			}
385		} else {
386			SMBWARNING("Skipping remounting %s/%s, file system type mismatch\n",
387					   SSTOVC(share)->vc_srvname, share->ss_name);
388		}
389	}
390
391	/* We need to notify and we haven't notified before then notify */
392	if (timeToNotify && !(smp->sm_status & SM_STATUS_DOWN)) {
393		int dontNotify = ((smp->sm_args.altflags & SMBFS_MNT_SOFT) &&
394						  (vfs_flags(smp->sm_mp) & MNT_DONTBROWSE));
395
396		SMBWARNING("Share %s not responding\n", share->ss_name);
397		/* Never notify on soft-mounted nobrowse volumes */
398		if (!dontNotify) {
399			vfs_event_signal(&(vfs_statfs(smp->sm_mp))->f_fsid, VQ_NOTRESP, 0);
400		}
401		smp->sm_status |= SM_STATUS_DOWN;
402	}
403	return treenct;
404}
405
406/*
407 * The share needs to be locked before calling this rouitne!
408 *
409 * smbfs_up is called when we receive a successful response to a message or we have
410 * successfully reconnect. It uses vfs_event_signal() to tell interested parties
411 * the connection is OK again  if the connection was having problems.
412 */
413static void
414smbfs_up(struct smb_share *share, int reconnect)
415{
416	struct smbmount *smp;
417
418	smp = share->ss_mount;
419
420	/* We have already unmounted or we are being force unmount, we are done */
421	if ((smp == NULL) || (vfs_isforce(smp->sm_mp))) {
422		return;
423	}
424
425	if (reconnect) {
426		smbfs_reconnect(smp);
427	}
428
429	/* We are done remounting, either we reconnect or the remount worked */
430	smp->sm_status &= ~SM_STATUS_REMOUNT;
431
432	if (smp->sm_status & SM_STATUS_DOWN) {
433		int dontNotify = ((smp->sm_args.altflags & SMBFS_MNT_SOFT) &&
434						  (vfs_flags(smp->sm_mp) & MNT_DONTBROWSE));
435
436		smp->sm_status &= ~SM_STATUS_DOWN;
437		SMBWARNING("Share %s responding\n", share->ss_name);
438		/* Never notify on soft-mounted nobrowse volumes */
439		if (!dontNotify) {
440			vfs_event_signal(&(vfs_statfs(smp->sm_mp))->f_fsid, VQ_NOTRESP, 1);
441		}
442	}
443}
444
445/*
446 * The share needs to be locked before calling this rouitne!
447 *
448 * smbfs_dead is called when the share is no longer reachable and the dead timer
449 * has gone off. It uses vfs_event_signal() to tell interested parties
450 * the connection is gone. This should cause the mount to get forced unmounted.
451 */
452static void
453smbfs_dead(struct smb_share *share)
454{
455	struct smbmount *smp;
456
457	smp = share->ss_mount;
458	if (smp && !(smp->sm_status & SM_STATUS_DEAD)) {
459		/* If we have a ss_mount then we have a sm_mp */
460		SMBWARNING("Share %s has gone away, unmounting the volume\n",
461				   share->ss_name);
462		vfs_event_signal(&(vfs_statfs(smp->sm_mp))->f_fsid, VQ_DEAD, 0);
463		smp->sm_status |= SM_STATUS_DEAD;
464	}
465}
466
467/*
468 * The share needs to be locked before calling this rouitne!
469 *
470 * See if the volume is being forced unmounted. In the future we will also
471 * check for the share getting changed out because of Dfs trigger remounts.
472 */
473static int
474smbfs_is_going_away(struct smb_share* share)
475{
476    struct smbmount *smp;
477
478    if (share->ss_flags & SMBS_GOING_AWAY) {
479        /* Once marked as going away, always going away */
480        return TRUE;
481    }
482
483    smp = share->ss_mount;
484
485    /* If we have a ss_mount then we have a sm_mp */
486    if (smp && (vfs_isforce(smp->sm_mp))) {
487        share->ss_flags |= SMBS_GOING_AWAY;
488        return TRUE;
489    }
490
491    return FALSE;
492}
493
494/*
495 * Fill in the smb_remount_info structure with all the information that user
496 * land needs to remount the volume.
497 */
498static int
499smbfs_remountInfo(struct mount *mp, struct smb_share *share,
500				  struct smb_remount_info *info)
501{
502#ifdef SMBDEBUG_REMOUNT
503	/* Used for testing only, pretend we are in reconnect. */
504	share->ss_flags |= SMBS_RECONNECTING;
505#endif // SMBDEBUG_REMOUNT
506	SMB_ASSERT(SSTOVC(share)->vc_gss.gss_cpn_len < sizeof(info->mntClientPrincipalName));
507	bzero(info, sizeof(*info));
508	info->version = REMOUNT_INFO_VERSION;
509	info->mntAuthFlags = SSTOVC(share)->vc_flags & SMBV_USER_LAND_MASK;
510	info->mntOwner = VFSTOSMBFS(mp)->sm_args.uid;
511	info->mntGroup = VFSTOSMBFS(mp)->sm_args.gid;
512	/*
513	 * The default is 30 seconds, but this is setable with a sysctl. The timer
514	 * has already started, but normally it takes only a couple of seconds to get
515	 * to this point.
516	 */
517	info->mntDeadTimer = share->ss_dead_timer;
518	if (!info->mntDeadTimer) {
519		/* Never wait less than one second */
520		info->mntDeadTimer = 1;
521	}
522
523	strlcpy(info->mntURL, vfs_statfs(mp)->f_mntfromname, sizeof(info->mntURL));
524	strlcpy(info->mntClientPrincipalName, (char *)SSTOVC(share)->vc_gss.gss_cpn,
525			SSTOVC(share)->vc_gss.gss_cpn_len);
526	info->mntClientPrincipalNameType  = SSTOVC(share)->vc_gss.gss_client_nt;
527	return 0;
528}
529
530/*
531 * Remount the volume by replacing the old share with the new share that was
532 * obtained using the device id.
533 */
534
535static int
536smbfs_remount(int32_t dev, struct mount *mp, struct smbmount *smp,
537			  vfs_context_t context)
538{
539	int error = 0;
540	struct smb_share *share = NULL;
541	struct smb_share *new_share = NULL;
542
543	error = smb_dev2share(dev, &new_share);
544	if (error || !new_share) {
545		return (error) ? error : ENOMEM;
546	}
547	/*
548	 * Can't completely protect from throwing away a perfectly good connection,
549	 * but we can make the window pretty short. So if the old share is not in
550	 * reconnect mode, we should just get out, nothing for us to do here. If
551	 * for some strange reason the  new share is the same as the old share
552	 * just get out. We could have reconnected, found the same share and then
553	 * the connection went down again.
554	 */
555	share = smb_get_share_with_reference(smp);
556	if (!(share->ss_flags & SMBS_RECONNECTING) || (new_share == share)) {
557		/* Done with the new share release the reference */
558		smb_share_rele(new_share, context);
559		/* Mark that the remount completed, so it can be used again. */
560		smp->sm_status &= ~SM_STATUS_REMOUNT;
561		smb_share_rele(share, context);
562		return EEXIST;
563	}
564	smb_share_rele(share, context);
565
566	/*
567	 * We now lock the VFS from accessing either share until we are done here.
568	 * All new VFS operations will be blocked, any old operation will continue
569	 * until they need to access the smp or share again.
570	 */
571	lck_rw_lock_exclusive(&smp->sm_rw_sharelock);
572	/*
573	 * Now block any calls to the new share, since nothing is really happening
574	 * on the share this should be safe. But it could block other access on the
575	 * new vc until we are done, but we never sleep here so that should be ok.
576	 */
577	lck_mtx_lock(&new_share->ss_shlock);
578	/*
579	 * Finally lock the old share, This could block the vc reconnect code, but
580	 * not much we can do about that here. Remember the mount holds a reference
581	 * on the old share and we are under the lock now so we can access it
582	 * directly without any issues.
583	 */
584	share = smp->sm_share;
585	lck_mtx_lock(&share->ss_shlock);
586	if (SSTOVC(new_share)->throttle_info) {
587		/* Taking a reference here will release the old reference */
588		throttle_info_mount_ref(mp, SSTOVC(new_share)->throttle_info);
589	} else if (SSTOVC(share)->throttle_info) {
590		/*
591		 * The new vc doesn't have any throttle info, but we have one on the
592		 * old VC, release the reference.
593		 */
594		throttle_info_mount_rel(mp);
595	}
596	/* Take a volume count, since this share has a mount now */
597	(void)OSAddAtomic(1, &SSTOVC(new_share)->vc_volume_cnt);
598	/*
599	 * We support allowing information to changes on the VC and the share, except
600	 * for information obtained from the smbfs_qfsattr, smbfs_unix_qfsattr,
601	 * isServerInSameDomian, and smbfs_unix_whoami routines. Once ACLs are turned
602	 * on they stay on, Better be in the same domain, nothing we can do about
603	 * this one. So we have really only two issues here:
604	 * 1. The file system types of the two shares don't match, FAT vs NTFS, need
605	 *    to prevent this from happening. We just can't support switching between
606	 *    dot underbar files and named streams, so we should never allow FAT
607	 *    file system to failover and we should never remount a FAT Share.
608	 * 2. One of the shares supports UNIX Extensions and the other doesn't. If
609	 *    the old share is doing UNIX Extensions then never failover. If the new
610	 *    share does UNIX Extensions, ignore those and treat the server like any
611	 *    other Windows system.
612	 */
613	new_share->ss_fstype = share->ss_fstype; /* Always the same file system type */
614	new_share->ss_attributes = share->ss_attributes;
615	new_share->ss_maxfilenamelen = share->ss_maxfilenamelen;
616	new_share->ss_unix_caps = share->ss_unix_caps;
617	new_share->ss_going_away = smbfs_is_going_away;
618	new_share->ss_down = smbfs_down;
619	new_share->ss_up = smbfs_up;
620	new_share->ss_dead = smbfs_dead;
621	new_share->ss_dead_timer = share->ss_dead_timer;
622	/* Now remove the mount point from the old share */
623	share->ss_mount = NULL;
624	/* Now add the mount point to the new share */
625	new_share->ss_mount = smp;
626	/* Now add the new share to the mount point */
627	smp->sm_share = new_share;
628	smp->sm_status |= SM_STATUS_UPDATED;
629	SMBERROR("replacing %s/%s with %s/%s\n",  SSTOVC(share)->vc_srvname,
630			 share->ss_name, SSTOVC(new_share)->vc_srvname, new_share->ss_name);
631	/* Now unlock in reverse order */
632	lck_mtx_unlock(&share->ss_shlock);
633	lck_mtx_unlock(&new_share->ss_shlock);
634	lck_rw_unlock_exclusive(&smp->sm_rw_sharelock);
635	smb_iod_errorout_share_request(share, ETIMEDOUT);
636	/* Remove the old share's volume count, since it no longer has a mount */
637	(void)OSAddAtomic(-1, &SSTOVC(share)->vc_volume_cnt);
638	/* Release the old share */
639	smb_share_rele(share, context);
640	/* Now get the new share and notify everyone we are up */
641	share = smb_get_share_with_reference(smp);
642	smbfs_up(share, TRUE);
643	smb_share_rele(share, context);
644	return 0;
645}
646
647static int
648smbfs_mount(struct mount *mp, vnode_t devvp, user_addr_t data, vfs_context_t context)
649{
650#pragma unused (devvp)
651	struct smb_mount_args *args = NULL;		/* will hold data from mount request */
652	struct smbmount *smp = NULL;
653	struct smb_share *share = NULL;
654	struct vfsioattr smbIOAttr;
655	vnode_t vp;
656	int error;
657    uint32_t stream_flags = 0;
658
659    SMB_LOG_KTRACE(SMB_DBG_MOUNT | DBG_FUNC_START, 0, 0, 0, 0, 0);
660
661	if (data == USER_ADDR_NULL) {
662		SMBDEBUG("missing data argument\n");
663		error = EINVAL;
664		goto bad;
665	}
666
667	SMB_MALLOC(args, struct smb_mount_args *, sizeof(*args), M_SMBFSDATA,
668		   M_WAITOK | M_ZERO);
669	if (!args) {
670		SMBDEBUG("Couldn't malloc the mount arguments!");
671		error = ENOMEM;
672		goto bad;
673	}
674	error = copyin(data, (caddr_t)args, sizeof(*args));
675	if (error) {
676		SMBDEBUG("Couldn't copyin the mount arguments!");
677		goto bad;
678	}
679
680	if (args->version != SMB_IOC_STRUCT_VERSION) {
681		SMBERROR("Mount structure version mismatch: kernel=%d, mount=%d\n",
682				 SMB_IOC_STRUCT_VERSION, args->version);
683		error = EINVAL;
684		goto bad;
685	}
686
687	/* Set the debug level, if set to us. */
688	if (args->KernelLogLevel) {
689		smbfs_loglevel =  args->KernelLogLevel;
690	}
691	/*
692	 * Get the share and retain a reference count until we unmount or complete
693	 * a mount update. The smb vfs policy requires that the share can only be
694	 * passed into a routine if an extra reference has been taken on the share.
695	 * Any routine require accessing the share from the mount point must call
696	 * smb_get_share_with_reference to get a pointer to the share. No routine
697	 * except mount and unmount should every access the mount points share
698	 * directly.
699	 */
700	error = smb_dev2share(args->dev, &share);
701	if (error) {
702		SMBDEBUG("invalid device handle %d (%d)\n", args->dev, error);
703		goto bad;
704	}
705
706	/* Need to deal with the mount update here */
707	if (vfs_isupdate(mp)) {
708		SMBERROR("MNT_UPDATE not supported!");
709		error = ENOTSUP;
710		goto bad;
711	}
712
713	SMB_MALLOC(smp, struct smbmount*, sizeof(*smp), M_SMBFSDATA, M_WAITOK | M_ZERO);
714	if (smp == NULL) {
715		SMBDEBUG("Couldn't malloc the smb mount structure!");
716		error = ENOMEM;
717		goto bad;
718	}
719
720	smp->sm_mp = mp;
721	vfs_setfsprivate(mp, (void *)smp);
722
723    /* alloc hash stuff */
724	smp->sm_hash = hashinit(desiredvnodes, M_SMBFSHASH, &smp->sm_hashlen);
725	if (smp->sm_hash == NULL)
726		goto bad;
727	smp->sm_hashlock = lck_mtx_alloc_init(hash_lck_grp, hash_lck_attr);
728
729	lck_rw_init(&smp->sm_rw_sharelock, smbfs_rwlock_group, smbfs_lock_attr);
730	lck_mtx_init(&smp->sm_statfslock, smbfs_mutex_group, smbfs_lock_attr);
731	lck_mtx_init(&smp->sm_reclaim_lock, smbfs_mutex_group, smbfs_lock_attr);
732    lck_mtx_init(&smp->sm_svrmsg_lock, smbfs_mutex_group, smbfs_lock_attr);
733
734	lck_rw_lock_exclusive(&smp->sm_rw_sharelock);
735	smp->sm_share = share;
736	lck_rw_unlock_exclusive(&smp->sm_rw_sharelock);
737	smp->sm_rvp = NULL;
738	/* Save any passed in arguments that we may need */
739	smp->sm_args.altflags = args->altflags;
740	smp->sm_args.uid = args->uid;
741	smp->sm_args.gid = args->gid;
742	error = kauth_cred_uid2guid(smp->sm_args.uid, &smp->sm_args.uuid);
743	if (error) {
744		SMBERROR("Couldn't get the mounted users UUID, uid = %d error = %d\n",
745				 smp->sm_args.uid, error);
746		goto bad;
747	}
748	smp->sm_args.file_mode = args->file_mode & ACCESSPERMS;
749	smp->sm_args.dir_mode  = args->dir_mode & ACCESSPERMS;
750	if (args->volume_name[0]) {
751		smp->sm_args.volume_name = smb_strndup(args->volume_name,
752											   sizeof(args->volume_name));
753	} else {
754		smp->sm_args.volume_name = NULL;
755	}
756
757	/*
758     * See if they sent use a submount path to use.
759     * This function also checks/cleans up the args->path and args->path_len
760     */
761	if (args->path_len) {
762		smbfs_create_start_path(smp, args, SMB_UNICODE_STRINGS(SSTOVC(share)));
763	}
764
765    /*
766     * Validate the negotiate if SMB 2/3. smb2fs_smb_validate_neg_info will
767     * check for whether the session needs to be validated or not.
768     */
769    if (!(smp->sm_args.altflags & SMBFS_MNT_VALIDATE_NEG_OFF)) {
770        if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
771            error = smb2fs_smb_validate_neg_info(share, context);
772            if (error) {
773                SMBERROR("smb2fs_smb_validate_neg_info failed %d \n", error);
774                goto bad;
775            }
776        }
777    }
778    else {
779        SMBWARNING("Validate Negotiate is off in preferences\n");
780    }
781
782	/*
783	 * This call should be done from mount() in vfs layer. Not sure why each
784	 * file system has to do it here, but go ahead and make an internal call to
785	 * fill in the default values.
786	 */
787	error = smbfs_smb_statfs(smp, vfs_statfs(mp), context);
788	if (error) {
789		SMBDEBUG("smbfs_smb_statfs failed %d\n", error);
790		goto bad;
791	}
792
793	/* Copy in the from name, used for reconnects and other things  */
794	strlcpy(vfs_statfs(mp)->f_mntfromname, args->url_fromname, MAXPATHLEN);
795
796	/* Now get the mounted volumes unique id */
797	smp->sm_args.unique_id_len = args->unique_id_len;
798	SMB_MALLOC(smp->sm_args.unique_id, unsigned char *, smp->sm_args.unique_id_len,
799		   M_SMBFSDATA, M_WAITOK);
800	if (smp->sm_args.unique_id) {
801		bcopy(args->unique_id, smp->sm_args.unique_id, smp->sm_args.unique_id_len);
802	} else {
803		smp->sm_args.unique_id_len = 0;
804	}
805	SMB_FREE(args, M_SMBFSDATA);	/* Done with the args free them */
806
807    if (smp->sm_args.altflags & SMBFS_MNT_TIME_MACHINE) {
808        SMBWARNING("%s mounted using tm flag\n",  vfs_statfs(mp)->f_mntfromname);
809    }
810
811	vfs_getnewfsid(mp);
812
813    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
814        /* Only SMB 2/3 uses File IDs or AAPL create context */
815        if (smp->sm_args.altflags & SMBFS_MNT_FILE_IDS_OFF) {
816            /* Turn off File IDs */
817            SMBWARNING("File IDs has been turned off for %s volume\n",
818                       (smp->sm_args.volume_name) ? smp->sm_args.volume_name : "");
819            SSTOVC(share)->vc_misc_flags &= ~SMBV_HAS_FILEIDS;
820        }
821
822        if (smp->sm_args.altflags & SMBFS_MNT_AAPL_OFF) {
823            /* Turn off AAPL */
824            SMBWARNING("AAPL has been turned off for %s volume\n",
825                       (smp->sm_args.volume_name) ? smp->sm_args.volume_name : "");
826            SSTOVC(share)->vc_misc_flags |= SMBV_OTHER_SERVER;
827        }
828    }
829
830	/*
831	 * Need to get the remote server's file system information
832	 * here before we do anything else. Make sure we have the servers or
833	 * the default value for ss_maxfilenamelen. NOTE: We use it in strnlen.
834	 */
835	smbfs_smb_qfsattr(smp, context);
836
837	/* Its a unix server see if it supports any of the UNIX extensions */
838	if (UNIX_SERVER(SSTOVC(share))) {
839		smbfs_unix_qfsattr(share, context);
840	}
841
842	/*
843	 * This volume was mounted as guest, turn off ACLs and set the mount point to
844	 * ignore ownership. We will always return an owner of 99, and group of 99.
845	 */
846	if (SMBV_HAS_GUEST_ACCESS(SSTOVC(share))) {
847		if (share->ss_attributes & FILE_PERSISTENT_ACLS) {
848			SMB_LOG_ACCESS("%s was mounted as guest turning off ACLs support.\n",
849						   vfs_statfs(mp)->f_mntfromname);
850		}
851		share->ss_attributes &= ~FILE_PERSISTENT_ACLS;
852		vfs_setflags(mp, MNT_IGNORE_OWNERSHIP);
853	}
854
855	/* Make sure the server is in the same domain, if not turn off acls */
856	if (share->ss_attributes & FILE_PERSISTENT_ACLS) {
857		isServerInSameDomian(share, smp);
858	}
859
860	/* See if the server supports the who am I operation */
861	if (UNIX_CAPS(share) & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP) {
862		smbfs_unix_whoami(share, smp, context);
863	}
864
865	error = smbfs_root(mp, &vp, context);
866	if (error) {
867		SMBDEBUG("The smbfs_root failed %d\n", error);
868		goto bad;
869	}
870	/*
871	 * This UNIX Server says it supports the UNIX Extensions, but it doesn't
872	 * support all the options we require. Turn off the UNIX Extensions that
873	 * they don't support.
874	 */
875	if ((UNIX_CAPS(share) & UNIX_QFILEINFO_UNIX_INFO2_CAP) &&
876		((VTOSMB(vp)->n_flags_mask & EXT_REQUIRED_BY_MAC) != EXT_REQUIRED_BY_MAC)) {
877		/* Turn off the UNIX Info2  */
878		UNIX_CAPS(share) &= ~(UNIX_SFILEINFO_UNIX_INFO2_CAP);
879		/* Must be Linux, turn on the unlink call so we can delete symlink files */
880		UNIX_CAPS(share) |= UNIX_SFILEINFO_POSIX_UNLINK_CAP;
881		/* Force the root vnode to forget any UNIX Extensions Info */
882		VTOSMB(vp)->attribute_cache_timer = 0;
883		VTOSMB(vp)->n_uid = KAUTH_UID_NONE;
884		VTOSMB(vp)->n_gid = KAUTH_GID_NONE;
885	}
886	vfs_setauthopaque (mp);
887	/* we can always answer access questions better than local VFS */
888	vfs_setauthopaqueaccess (mp);
889
890	if (share->ss_attributes & FILE_PERSISTENT_ACLS) {
891		guid_t ntwrk_uuid = kauth_null_guid;
892
893		DBG_ASSERT(smp->ntwrk_sids); /* We should always have a network SID */
894		SMB_LOG_ACCESS("%s support ACLs\n", vfs_statfs(mp)->f_mntfromname);
895		vfs_setextendedsecurity(mp);
896		/* Now test to see if we should be mapping the local user to the nework user */
897		if (kauth_cred_ntsid2guid(smp->ntwrk_sids, &ntwrk_uuid)) {
898			smp->sm_flags |= MNT_MAPS_NETWORK_LOCAL_USER;
899		} else if (!kauth_guid_equal(&smp->sm_args.uuid, &ntwrk_uuid)) {
900			smp->sm_flags |= MNT_MAPS_NETWORK_LOCAL_USER;
901		}
902	}
903    else {
904		SMB_LOG_ACCESS("%s doesn't support ACLs\n", vfs_statfs(mp)->f_mntfromname);
905		vfs_clearextendedsecurity (mp);
906	}
907
908    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
909        if (share->ss_attributes & FILE_SUPPORTS_REPARSE_POINTS) {
910            smp->sm_flags |= MNT_SUPPORTS_REPARSE_SYMLINKS;
911        }
912
913        if (!(SSTOVC(share)->vc_misc_flags & SMBV_HAS_COPYCHUNK)) {
914            /* Check for CopyChunk support */
915            if (!smb2fs_smb_cmpd_check_copyfile(share, VTOSMB(vp), context)) {
916                SSTOVC(share)->vc_misc_flags |= SMBV_HAS_COPYCHUNK;
917            }
918        }
919    }
920    else {
921        if ((share->ss_attributes & FILE_SUPPORTS_REPARSE_POINTS) &&
922            (((!UNIX_CAPS(share)) || (SSTOVC(share)->vc_flags & SMBV_DARWIN)))) {
923            smp->sm_flags |= MNT_SUPPORTS_REPARSE_SYMLINKS;
924        }
925    }
926
927	/*
928	 * This is a read-only volume, so change the mount flags so
929	 * the finder will show it as a read-only volume.
930	 */
931	if (share->ss_attributes & FILE_READ_ONLY_VOLUME) {
932		vfs_setflags(mp, MNT_RDONLY);
933	} else if ((share->maxAccessRights & FILE_FULL_WRITE_ACCESS) == 0) {
934		SMB_LOG_ACCESS("Share ACL doesn't allow write access, maxAccessRights are 0x%x\n",
935					   share->maxAccessRights);
936		vfs_setflags(mp, MNT_RDONLY);
937	}
938
939    /*
940     * We now default to have named streams on if the server supports named
941     * streams. The user can turn off named streams by setting the correct
942     * option in the nsmb.conf file. The "nsmb.conf" allows the user to turn
943     * off named streams per share. So now we only check for turning off named
944     * streams since the default is to have them on.
945     */
946    if (share->ss_attributes & FILE_NAMED_STREAMS) {
947        if (!(smp->sm_args.altflags & SMBFS_MNT_STREAMS_ON)) {
948            share->ss_attributes &= ~FILE_NAMED_STREAMS;
949        }
950    }
951
952    if (!(SSTOVC(share)->vc_flags & SMBV_SMB2)) {
953        /*
954         * SMB 1 Only
955         *
956         * We now default to have named streams on if the server supports named
957         * streams. The user can turn off named streams by creating a file on
958         * the top level of the share called ".com.apple.smb.streams.off".
959         *
960         * .com.apple.smb.streams.off - If exist on top level of share means
961         * turn off streams.
962         */
963        if (share->ss_attributes & FILE_NAMED_STREAMS) {
964            if (smbfs_smb_query_info(share, VTOSMB(vp), VREG,
965                                     SMB_STREAMS_OFF, sizeof(SMB_STREAMS_OFF) - 1,
966                                     NULL, context) == 0) {
967                share->ss_attributes &= ~FILE_NAMED_STREAMS;
968            } else if (! UNIX_SERVER(SSTOVC(share)) &&
969                       (smbfs_smb_qstreaminfo(share, VTOSMB(vp), VDIR,
970                                              NULL, 0,
971                                              SFM_DESKTOP_NAME,
972                                              NULL, NULL,
973                                              NULL, NULL,
974                                              &stream_flags, NULL,
975                                              context) == 0)) {
976                /*
977                 * We would like to know if this is a really old Windows server
978                 * with Services For Mac (SFM Volume), we skip this check for
979                 * unix servers.
980                 */
981                smp->sm_flags |= MNT_IS_SFM_VOLUME;
982            }
983        }
984    }
985
986	/*
987	 * The AFP code sets io_devblocksize to one, which is used by the Cluster IO
988	 * code to decide what to do when writing past the eof.  ClusterIO code uses
989	 * the io_devblocksize to decided what size block to use when writing pass
990	 * the eof. So a io_devblocksize of one means only write to the eof. Seems
991	 * like a hack, but not sure what else to do at this point. Talk this over
992	 * with Joe and he wants to get back to it later.
993	 */
994	vfs_ioattr(mp, &smbIOAttr);	/* get the current settings */
995	smbIOAttr.io_devblocksize = 1;
996
997	/*
998     * io_maxreadcnt/io_maxwritecnt is the IO size that we want passed to us
999     * from UBC.
1000     *
1001     * io_maxsegreadsize/io_maxsegwritesize is the hardware limited max size,
1002     * but we are not limited so set to be same as io_maxreadcnt/io_maxwritecnt.
1003     *
1004     * io_segreadcnt/io_segwritecnt is just the segment size / page size. Again,
1005     * no real meaning to us.  VM requires they must be evenly divisible by 4.
1006     * See <rdar://problem/14266574>.
1007     *
1008	 */
1009
1010	if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
1011		/* Never allow more than 4 MB */
1012		if (smb_maxsegreadsize > SMB_IOMAXCACHE) {
1013			smb_maxsegreadsize = SMB_IOMAXCACHE;
1014		}
1015		smbIOAttr.io_segwritecnt = smb_maxsegreadsize / PAGE_SIZE;
1016		/* Never allow more than 4 MB */
1017		if (smb_maxsegwritesize > SMB_IOMAXCACHE) {
1018			smb_maxsegwritesize = SMB_IOMAXCACHE;
1019		}
1020		smbIOAttr.io_segreadcnt = smb_maxsegwritesize / PAGE_SIZE;
1021
1022	} else {
1023        size_t f_iosize = vfs_statfs(mp)->f_iosize;
1024        if (f_iosize < (PAGE_SIZE * 4)) {
1025            f_iosize = PAGE_SIZE * 4; /* Bad Server */
1026        }
1027        smbIOAttr.io_segreadcnt =  (uint32_t)(f_iosize / (PAGE_SIZE * 4)) * 4;
1028        smbIOAttr.io_segwritecnt = smbIOAttr.io_segreadcnt;
1029    }
1030
1031	smbIOAttr.io_maxsegreadsize = smbIOAttr.io_segreadcnt * PAGE_SIZE;
1032    smbIOAttr.io_maxsegwritesize = smbIOAttr.io_segwritecnt * PAGE_SIZE;
1033
1034    smbIOAttr.io_maxreadcnt = smbIOAttr.io_maxsegreadsize;
1035    smbIOAttr.io_maxwritecnt = smbIOAttr.io_maxsegwritesize;
1036
1037	SMBWARNING("io_maxsegreadsize = %d io_maxsegwritesize = %d f_iosize = %ld vc_rxmax = %d vc_wxmax = %d\n",
1038			 smbIOAttr.io_maxsegreadsize, smbIOAttr.io_maxsegwritesize,
1039			 vfs_statfs(mp)->f_iosize,
1040			 SSTOVC(share)->vc_rxmax, SSTOVC(share)->vc_wxmax);
1041
1042	vfs_setioattr(mp, &smbIOAttr);
1043
1044
1045	/* smbfs_root did a vnode_get and a vnode_ref, so keep the ref but release the get */
1046	vnode_put(vp);
1047	/* We now have everyting we need to setup the dead/up/down routines */
1048	lck_mtx_lock(&share->ss_shlock);
1049	/* Use to tell the VC that the share is going away, so just timeout messages */
1050	share->ss_going_away = smbfs_is_going_away;
1051	/* Routines to call when the mount is having problems */
1052	share->ss_down = smbfs_down;
1053	share->ss_up = smbfs_up;
1054	share->ss_dead = smbfs_dead;
1055	if (smp->sm_args.altflags & SMBFS_MNT_SOFT) {
1056		if (smp->sm_args.altflags & SMBFS_MNT_DFS_SHARE) {
1057			/*
1058			 * Dfs Trigger node, set the dead timer to something smaller and
1059			 * never soft mount time out the operations
1060			 */
1061			share->ss_dead_timer = smbfs_trigger_deadtimer;
1062		} else {
1063			/* Timeout the operations */
1064			share->ss_soft_timer = SOFTMOUNT_TIMEOUT;
1065			/* Soft mounts use the default timer value */
1066			share->ss_dead_timer = smbfs_deadtimer;
1067		}
1068	} else {
1069		share->ss_dead_timer = smbfs_hard_deadtimer;
1070	}
1071	/* All done add the mount point to the share so we can access these routines */
1072	share->ss_mount = smp;
1073	lck_mtx_unlock(&share->ss_shlock);
1074	SMBDEBUG("%s dead timer = %d\n", share->ss_name, share->ss_dead_timer);
1075
1076	OSAddAtomic(1, &SSTOVC(share)->vc_volume_cnt);
1077	if (SSTOVC(share)->throttle_info) {
1078		throttle_info_mount_ref(mp, SSTOVC(share)->throttle_info);
1079	}
1080
1081    smbfs_notify_change_create_thread(smp);
1082    if (smp->sm_args.altflags & SMBFS_MNT_COMPOUND_ON) {
1083        vfs_setcompoundopen(mp);
1084    }
1085    else {
1086        SMBWARNING("compound off in preferences\n");
1087    }
1088
1089    if ((SSTOVC(share)->vc_flags & SMBV_SMB2) &&
1090        (SSTOVC(share)->vc_misc_flags & SMBV_OSX_SERVER)) {
1091
1092        /* Mac OS X SMB 2/3 server */
1093        share->ss_fstype = SMB_FS_MAC_OS_X;
1094
1095        /* Enable server message notification */
1096        smbfs_start_svrmsg_notify(smp);
1097    }
1098
1099	mount_cnt++;
1100
1101    SMB_LOG_KTRACE(SMB_DBG_MOUNT | DBG_FUNC_END, 0, 0, 0, 0, 0);
1102	return (0);
1103bad:
1104	if (share) {
1105		lck_mtx_lock(&share->ss_shlock);
1106		share->ss_mount = NULL;	/* share->ss_mount is smp which we free below  */
1107		lck_mtx_unlock(&share->ss_shlock);
1108		smb_share_rele(share, context);
1109	}
1110	if (smp) {
1111		vfs_setfsprivate(mp, (void *)0);
1112
1113		/* Was malloced by hashinit */
1114		if (smp->sm_hash)
1115			SMB_FREE(smp->sm_hash, M_SMBFSHASH);
1116		lck_mtx_free(smp->sm_hashlock, hash_lck_grp);
1117
1118		lck_mtx_destroy(&smp->sm_statfslock, smbfs_mutex_group);
1119		lck_mtx_destroy(&smp->sm_reclaim_lock, smbfs_mutex_group);
1120		lck_rw_destroy(&smp->sm_rw_sharelock, smbfs_rwlock_group);
1121        lck_mtx_destroy(&smp->sm_svrmsg_lock, smbfs_mutex_group);
1122		SMB_FREE(smp->sm_args.volume_name, M_SMBSTR);
1123		SMB_FREE(smp->sm_args.path, M_SMBFSDATA);
1124		SMB_FREE(smp->sm_args.unique_id, M_SMBFSDATA);
1125		SMB_FREE(smp->ntwrk_gids, M_TEMP);
1126		SMB_FREE(smp->ntwrk_sids, M_TEMP);
1127		SMB_FREE(smp, M_SMBFSDATA);
1128	}
1129	SMB_FREE(args, M_SMBFSDATA); /* Done with the args free them */
1130
1131    SMB_LOG_KTRACE(SMB_DBG_MOUNT | DBG_FUNC_END, error, 0, 0, 0, 0);
1132	return (error);
1133}
1134
1135/* Unmount the filesystem described by mp. */
1136static int
1137smbfs_unmount(struct mount *mp, int mntflags, vfs_context_t context)
1138{
1139	struct smbmount *smp = VFSTOSMBFS(mp);
1140    struct smb_share *share = smp->sm_share;
1141	vnode_t vp;
1142	int error = 0;
1143
1144    SMB_LOG_KTRACE(SMB_DBG_UNMOUNT | DBG_FUNC_START, mntflags, 0, 0, 0, 0);
1145
1146	SMBVDEBUG("smbfs_unmount: flags=%04x\n", mntflags);
1147
1148	/* Force unmount shutdown all outstanding I/O requests on this share. */
1149	if (mntflags & MNT_FORCE) {
1150		smb_iod_errorout_share_request(share, ENXIO);
1151	}
1152
1153	error = smbfs_root(mp, &vp, context);
1154	if (error) {
1155		goto done;
1156    }
1157
1158	error = vflush(mp, vp, (mntflags & MNT_FORCE) ? FORCECLOSE : 0);
1159	if (error) {
1160		vnode_put(vp);
1161		goto done;
1162	}
1163
1164	if (vnode_isinuse(vp, 1)  && !(mntflags & MNT_FORCE)) {
1165		SMBDEBUG("smbfs_unmount: usecnt\n");
1166		vnode_put(vp);
1167        error = EBUSY;
1168		goto done;
1169	}
1170
1171	smp->sm_rvp = NULL;	/* We no longer have a reference so clear it out */
1172	vnode_rele(vp);	/* to drop ref taken by smbfs_mount */
1173	vnode_put(vp);	/* to drop ref taken by VFS_ROOT above */
1174
1175	(void)vflush(mp, NULLVP, FORCECLOSE);
1176
1177    /* Cancel outstanding svrmsg notify request */
1178    if ((SSTOVC(share)->vc_flags & SMBV_SMB2) &&
1179        (SSTOVC(share)->vc_misc_flags & SMBV_OSX_SERVER)) {
1180        smbfs_stop_svrmsg_notify(smp);
1181    }
1182
1183	/* We are done with this share shutdown all outstanding I/O requests. */
1184	smb_iod_errorout_share_request(share, ENXIO);
1185
1186	OSAddAtomic(-1, &SSTOVC(share)->vc_volume_cnt);
1187	smbfs_notify_change_destroy_thread(smp);
1188
1189	if (SSTOVC(share)->throttle_info)
1190		throttle_info_mount_rel(mp);
1191
1192    /* Make sure SMB 2/3 fid table is empty */
1193    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
1194        smb_fid_delete_all(share);
1195    }
1196
1197	/* Remove the smb mount pointer from the share before freeing it */
1198	lck_mtx_lock(&share->ss_shlock);
1199	share->ss_mount = NULL;
1200	share->ss_dead = NULL;
1201	share->ss_up = NULL;
1202	share->ss_down = NULL;
1203	lck_mtx_unlock(&share->ss_shlock);
1204
1205	smb_share_rele(share, context);
1206	vfs_setfsprivate(mp, (void *)0);
1207
1208	if (smp->sm_hash) {
1209		SMB_FREE(smp->sm_hash, M_SMBFSHASH);
1210		smp->sm_hash = (void *)0xDEAD5AB0;
1211	}
1212	lck_mtx_free(smp->sm_hashlock, hash_lck_grp);
1213
1214	lck_mtx_destroy(&smp->sm_statfslock, smbfs_mutex_group);
1215	lck_mtx_destroy(&smp->sm_reclaim_lock, smbfs_mutex_group);
1216    lck_mtx_destroy(&smp->sm_svrmsg_lock, smbfs_mutex_group);
1217	lck_rw_destroy(&smp->sm_rw_sharelock, smbfs_rwlock_group);
1218
1219    if (smp->sm_args.volume_name) {
1220        SMB_FREE(smp->sm_args.volume_name, M_SMBSTR);
1221    }
1222    if (smp->sm_args.path) {
1223        SMB_FREE(smp->sm_args.path, M_SMBSTR);
1224    }
1225    if (smp->sm_args.unique_id) {
1226        SMB_FREE(smp->sm_args.unique_id, M_SMBSTR);
1227    }
1228    if (smp->ntwrk_gids) {
1229        SMB_FREE(smp->ntwrk_gids, M_SMBSTR);
1230    }
1231    if (smp->ntwrk_sids) {
1232        SMB_FREE(smp->ntwrk_sids, M_SMBSTR);
1233    }
1234    if (smp) {
1235        SMB_FREE(smp, M_SMBSTR);
1236    }
1237
1238	vfs_clearflags(mp, MNT_LOCAL);
1239	mount_cnt--;
1240
1241    error = 0;
1242
1243done:
1244    SMB_LOG_KTRACE(SMB_DBG_UNMOUNT | DBG_FUNC_END, error, 0, 0, 0, 0);
1245	return (error);
1246}
1247
1248/*
1249 * Return locked root vnode of a filesystem
1250 */
1251static int
1252smbfs_root(struct mount *mp, vnode_t *vpp, vfs_context_t context)
1253{
1254	struct smbmount *smp = VFSTOSMBFS(mp);
1255	struct smb_share *share = NULL;
1256	vnode_t vp;
1257	struct smbfattr fattr;
1258	int error = 0;
1259
1260    SMB_LOG_KTRACE(SMB_DBG_ROOT | DBG_FUNC_START, 0, 0, 0, 0, 0);
1261
1262	if (smp == NULL) {
1263		SMBERROR("smp == NULL (bug in umount)\n");
1264        error = EINVAL;
1265        goto done;
1266	}
1267
1268	if (smp->sm_rvp) {
1269		/* just get the saved root vnode as its much faster */
1270		*vpp = smp->sm_rvp;
1271		error = vnode_get(*vpp);
1272        goto done;
1273	}
1274
1275	/* Fill in the default values that we already know about the root vnode */
1276	bzero(&fattr, sizeof(fattr));
1277	nanouptime(&fattr.fa_reqtime);
1278	fattr.fa_valid_mask |= FA_VTYPE_VALID;
1279	fattr.fa_attr = SMB_EFA_DIRECTORY;
1280	fattr.fa_vtype = VDIR;
1281
1282    if (smp->sm_root_ino == 0) {
1283        /*
1284         * Must be at mount time and we dont know what the root File ID is.
1285         * Assume its 2 to start with
1286         */
1287        smp->sm_root_ino = SMBFS_ROOT_INO;
1288        fattr.fa_ino = SMBFS_ROOT_INO;
1289   }
1290    else {
1291        /* Recreating root vnode and we know what its ID was */
1292        fattr.fa_ino = smp->sm_root_ino;
1293    }
1294
1295	/*
1296	 * First time to get the root vnode, smbfs_nget will create it and check
1297	 * with the network to make sure all is well with the root node. Could get
1298	 * an error if the device is not ready are we have no access.
1299	 */
1300	share = smb_get_share_with_reference(smp);
1301	error = smbfs_nget(share, mp,
1302                       NULL, "TheRooT", 7,
1303                       &fattr, &vp,
1304                       0, SMBFS_NGET_CREATE_VNODE,
1305                       context);
1306	smb_share_rele(share, context);
1307	if (error) {
1308        goto done;
1309    }
1310
1311	/*
1312	 * Since root vnode has an exclusive lock, I know only one process can be
1313	 * here at this time.  Check once more while I still have the lock that
1314	 * sm_rvp is still NULL before taking a ref and saving it.
1315	 */
1316	if (smp->sm_rvp == NULL) {
1317		smp->sm_rvp = vp;	/* this will be released in the unmount code */
1318		smbnode_unlock(VTOSMB(vp));	/* Release the smbnode lock */
1319		/*
1320		 * Now save a ref to this vnode so that we can quickly retrieve in
1321		 * subsequent calls and make sure it doesn't go away until we unmount.
1322		 */
1323		error = vnode_ref(vp);
1324		/* It would be very rare for vnode_ref to fail, but be paranoid anyways */
1325		if (error) {
1326			SMBERROR("vnode_ref on rootvp failed error %d\n", error);
1327			smp->sm_rvp = NULL;
1328			vnode_put(vp);
1329            goto done;
1330		}
1331	} else {
1332		/*
1333		 * Must have had two or more processes running at same time, other process
1334		 * saved the root vnode, so just unlock this one and return
1335		 */
1336		smbnode_unlock(VTOSMB(vp));		/* Release the smbnode lock */
1337	}
1338
1339	*vpp = vp;
1340    error = 0;
1341
1342done:
1343    SMB_LOG_KTRACE(SMB_DBG_ROOT | DBG_FUNC_END, error, 0, 0, 0, 0);
1344    return (error);
1345}
1346
1347/*
1348 * Vfs start routine, a no-op.
1349 */
1350/* ARGSUSED */
1351static int
1352smbfs_start(struct mount *mp, int flags, vfs_context_t context)
1353{
1354#pragma unused(mp, flags, context)
1355	return 0;
1356}
1357
1358/*ARGSUSED*/
1359static int
1360smbfs_init(struct vfsconf *vfsp)
1361{
1362#pragma unused(vfsp)
1363	static int32_t done = 0;
1364
1365	if (done == 1)
1366		return (0);
1367	done = 1;
1368	smbfs_lock_init();
1369
1370	return 0;
1371}
1372
1373/*
1374 * smbfs_vfs_getattr call
1375 */
1376static int
1377smbfs_vfs_getattr(struct mount *mp, struct vfs_attr *fsap, vfs_context_t context)
1378{
1379	struct smbmount *smp = VFSTOSMBFS(mp);
1380	struct smb_share *share = NULL;
1381	struct vfsstatfs cachedstatfs;
1382	struct timespec ts;
1383	int error = 0;
1384    struct smb_vc *vcp = NULL;
1385
1386    SMB_LOG_KTRACE(SMB_DBG_VFS_GETATTR | DBG_FUNC_START, 0, 0, 0, 0, 0);
1387
1388	if ((smp->sm_rvp == NULL) || (VTOSMB(smp->sm_rvp) == NULL)) {
1389		error = EINVAL;
1390        goto done;
1391    }
1392
1393	share = smb_get_share_with_reference(smp);
1394    vcp = SSTOVC(share);
1395
1396	lck_mtx_lock(&smp->sm_statfslock);
1397	cachedstatfs = smp->sm_statfsbuf;
1398	if (smp->sm_status & SM_STATUS_STATFS)
1399		lck_mtx_unlock(&smp->sm_statfslock);
1400	else {
1401		smp->sm_status |= SM_STATUS_STATFS;
1402		lck_mtx_unlock(&smp->sm_statfslock);
1403		nanouptime(&ts);
1404		/* We always check the first time otherwise only if the cache is stale. */
1405		if ((smp->sm_statfstime == 0) ||
1406			(((ts.tv_sec - smp->sm_statfstime) > SM_MAX_STATFSTIME) &&
1407			(VFSATTR_IS_ACTIVE(fsap, f_bsize) || VFSATTR_IS_ACTIVE(fsap, f_blocks) ||
1408			 VFSATTR_IS_ACTIVE(fsap, f_bfree) || VFSATTR_IS_ACTIVE(fsap, f_bavail) ||
1409			 VFSATTR_IS_ACTIVE(fsap, f_files) || VFSATTR_IS_ACTIVE(fsap, f_ffree)))) {
1410			/* update cached from-the-server data */
1411			error = smbfs_smb_statfs(smp, &cachedstatfs, context);
1412			if (error == 0) {
1413				nanouptime(&ts);
1414				smp->sm_statfstime = ts.tv_sec;
1415				lck_mtx_lock(&smp->sm_statfslock);
1416				smp->sm_statfsbuf = cachedstatfs;
1417				lck_mtx_unlock(&smp->sm_statfslock);
1418			}
1419            else {
1420				error = 0;
1421			}
1422		}
1423		lck_mtx_lock(&smp->sm_statfslock);
1424		smp->sm_status &= ~SM_STATUS_STATFS;
1425		lck_mtx_unlock(&smp->sm_statfslock);
1426	}
1427
1428	/*
1429	 * Not sure what to do about these items, seems we get call for them and
1430	 * if they are not filled in an error gets return. We tell them in the
1431	 * capibilities that we do not support these items. Notice AFP fills them
1432	 * in and the values they using are the same as below. The AFP code does have
1433	 * these items but they never get updated and always end with these same
1434	 * values.
1435	 */
1436	VFSATTR_RETURN (fsap, f_objcount, (uint64_t) 0 + (uint64_t)0);
1437	/* We do not support setting filecount. */
1438	VFSATTR_RETURN (fsap, f_filecount, (uint64_t) 0);
1439	/* We do not support setting dircount. */
1440	VFSATTR_RETURN (fsap, f_dircount, (uint64_t) 0);
1441	/* We do not support setting maxobjcount. */
1442	VFSATTR_RETURN (fsap, f_maxobjcount, (uint64_t) 0xFFFFFFFF);
1443
1444	/* copy results from cached statfs */
1445	VFSATTR_RETURN(fsap, f_bsize, cachedstatfs.f_bsize);
1446	VFSATTR_RETURN(fsap, f_iosize, cachedstatfs.f_iosize);
1447	VFSATTR_RETURN(fsap, f_blocks, cachedstatfs.f_blocks);
1448	VFSATTR_RETURN(fsap, f_bfree, cachedstatfs.f_bfree);
1449	VFSATTR_RETURN(fsap, f_bavail, cachedstatfs.f_bavail);
1450	VFSATTR_RETURN (fsap, f_bused, cachedstatfs.f_blocks - cachedstatfs.f_bavail);
1451	VFSATTR_RETURN(fsap, f_files, cachedstatfs.f_files);
1452	VFSATTR_RETURN(fsap, f_ffree, cachedstatfs.f_ffree);
1453
1454	fsap->f_fsid.val[0] = vfs_statfs(mp)->f_fsid.val[0];
1455	fsap->f_fsid.val[1] = vfs_typenum(mp);
1456	VFSATTR_SET_SUPPORTED(fsap, f_fsid);
1457
1458	/* The VFS layer handles f_owner. */
1459
1460	/*
1461	 * NOTE:  the valid field indicates whether your VFS knows whether a
1462	 * capability is supported or not. So, if you know FOR SURE that a capability
1463	 * is support or not, then set that bit in the valid part.  Then, in the
1464	 * capabilities field, you either set it if supported or leave it clear if
1465	 * not supported
1466	 */
1467	if (VFSATTR_IS_ACTIVE(fsap, f_capabilities)) {
1468		vol_capabilities_attr_t *cap = &fsap->f_capabilities;
1469
1470		cap->capabilities[VOL_CAPABILITIES_FORMAT] =
1471			VOL_CAP_FMT_SYMBOLICLINKS |
1472			VOL_CAP_FMT_FAST_STATFS |
1473			VOL_CAP_FMT_OPENDENYMODES |
1474			VOL_CAP_FMT_HIDDEN_FILES |
1475            VOL_CAP_FMT_64BIT_OBJECT_IDS |
1476			0;
1477
1478		/*
1479         * Only say we support large files if the server supports it.
1480         * FAT shares can not handle large files either.
1481         */
1482		if ((VC_CAPS(vcp) & SMB_CAP_LARGE_FILES) &&
1483            (share->ss_fstype != SMB_FS_FAT)) {
1484			cap->capabilities[VOL_CAPABILITIES_FORMAT] |= VOL_CAP_FMT_2TB_FILESIZE;
1485        }
1486
1487        /* Must be FAT so don't trust the modify times */
1488		if (share->ss_fstype == SMB_FS_FAT)
1489			cap->capabilities[VOL_CAPABILITIES_FORMAT] |= VOL_CAP_FMT_NO_ROOT_TIMES;
1490
1491		if (share->ss_attributes & FILE_CASE_PRESERVED_NAMES)
1492			cap->capabilities[VOL_CAPABILITIES_FORMAT] |= VOL_CAP_FMT_CASE_PRESERVING;
1493
1494        if (vcp->vc_misc_flags & SMBV_OSX_SERVER) {
1495            /* Its OS X Server so we know for sure */
1496            if (vcp->vc_volume_caps & kAAPL_CASE_SENSITIVE) {
1497                cap->capabilities[VOL_CAPABILITIES_FORMAT] |= VOL_CAP_FMT_CASE_SENSITIVE;
1498            }
1499
1500            if ((vcp->vc_volume_caps & kAAPL_SUPPORT_RESOLVE_ID) &&
1501                (vcp->vc_misc_flags & SMBV_HAS_FILEIDS)) {
1502                /* Supports Resolve ID */
1503                cap->capabilities[VOL_CAPABILITIES_FORMAT] |= VOL_CAP_FMT_PATH_FROM_ID |
1504                                                              VOL_CAP_FMT_PERSISTENTOBJECTIDS;
1505            }
1506        }
1507        else {
1508            /*
1509             * Not a OS X Server, so we have to guess.
1510             *
1511             * This SMB file system is case INSENSITIVE and case preserving,
1512             * but servers vary, depending on the underlying volume.  In
1513             * pathconf we have to give a yes or no answer. We need to return a
1514             * consistent answer in both cases. We do not know the real answer
1515             * for case sensitive, but lets default to what 90% of the servers
1516             * have set. Also remember this fixes Radar 4057391 and 3530751.
1517             */
1518        }
1519
1520        if (share->ss_attributes & FILE_SUPPORTS_SPARSE_FILES)
1521			cap->capabilities[VOL_CAPABILITIES_FORMAT] |= VOL_CAP_FMT_SPARSE_FILES;
1522
1523		cap->capabilities[VOL_CAPABILITIES_INTERFACES] =
1524			VOL_CAP_INT_ATTRLIST |
1525			VOL_CAP_INT_FLOCK |
1526			VOL_CAP_INT_MANLOCK |
1527			0;
1528
1529        /*
1530         * If its a FAT filesystem, then named streams are not supported.
1531         * If named streams are not supported, then the attribute enumeration
1532         * calls wont work as we can not Max Access or Resource Fork info.
1533         * Thus named streams and non FAT is required for the attribute
1534         * enumeration calls.
1535         */
1536        if ((share->ss_fstype != SMB_FS_FAT) &&
1537            (share->ss_attributes & FILE_NAMED_STREAMS) &&
1538            !(smp->sm_args.altflags & SMBFS_MNT_READDIRATTR_OFF)) {
1539            /* vnop_readdirattr allowed */
1540            cap->capabilities[VOL_CAPABILITIES_INTERFACES] |= VOL_CAP_INT_READDIRATTR;
1541        }
1542        else {
1543            if (share->ss_fstype == SMB_FS_FAT) {
1544                SMBWARNING("FAT filesystem so smbfs_vnop_readdirattr is disabled for %s volume\n",
1545                           (smp->sm_args.volume_name) ? smp->sm_args.volume_name : "");
1546            }
1547
1548            if (!(share->ss_attributes & FILE_NAMED_STREAMS)) {
1549                SMBWARNING("No named streams so smbfs_vnop_readdirattr is disabled for %s volume\n",
1550                           (smp->sm_args.volume_name) ? smp->sm_args.volume_name : "");
1551            }
1552
1553            if (smp->sm_args.altflags & SMBFS_MNT_READDIRATTR_OFF) {
1554                SMBWARNING("smbfs_vnop_readdirattr has been turned off for %s volume\n",
1555                           (smp->sm_args.volume_name) ? smp->sm_args.volume_name : "");
1556            }
1557        }
1558
1559        if (UNIX_CAPS(share) & CIFS_UNIX_FCNTL_LOCKS_CAP)
1560			cap->capabilities[VOL_CAPABILITIES_INTERFACES] |= VOL_CAP_INT_ADVLOCK;
1561
1562		if (share->ss_attributes & FILE_NAMED_STREAMS)
1563			cap->capabilities[VOL_CAPABILITIES_INTERFACES] |= VOL_CAP_INT_NAMEDSTREAMS | VOL_CAP_INT_EXTENDED_ATTR;
1564
1565        if ((smp->sm_args.altflags & SMBFS_MNT_NOTIFY_OFF) == SMBFS_MNT_NOTIFY_OFF) {
1566            SMBWARNING("Notifications have been turned off for %s volume\n",
1567                       (smp->sm_args.volume_name) ? smp->sm_args.volume_name : "");
1568        }
1569        else {
1570            if (!(vcp->vc_flags & SMBV_SMB2) &&
1571                (vcp->vc_maxmux < SMB_NOTIFY_MIN_MUX)) {
1572                /* SMB 1 */
1573                SMBWARNING("Notifications are not support on %s volume\n",
1574                           (smp->sm_args.volume_name) ? smp->sm_args.volume_name : "");
1575            }
1576            else {
1577                cap->capabilities[VOL_CAPABILITIES_INTERFACES] |= VOL_CAP_INT_REMOTE_EVENT;
1578            }
1579        }
1580
1581        /*
1582         * We only turn on VOL_CAP_INT_COPYFILE if it's an SMB 2/3 connection
1583         * AND we know it supports FSCTL_SRV_COPY_CHUNK IOCTL.
1584         */
1585		if ((SSTOVC(share)->vc_flags & SMBV_SMB2) &&
1586            (SSTOVC(share)->vc_misc_flags & SMBV_HAS_COPYCHUNK)) {
1587            cap->capabilities[VOL_CAPABILITIES_INTERFACES] |= VOL_CAP_INT_COPYFILE;
1588        }
1589
1590		cap->capabilities[VOL_CAPABILITIES_RESERVED1] = 0;
1591		cap->capabilities[VOL_CAPABILITIES_RESERVED2] = 0;
1592
1593		cap->valid[VOL_CAPABILITIES_FORMAT] =
1594			VOL_CAP_FMT_PERSISTENTOBJECTIDS |
1595			VOL_CAP_FMT_NO_ROOT_TIMES |
1596			VOL_CAP_FMT_SYMBOLICLINKS |
1597			VOL_CAP_FMT_HARDLINKS |
1598			VOL_CAP_FMT_JOURNAL |
1599			VOL_CAP_FMT_JOURNAL_ACTIVE |
1600			VOL_CAP_FMT_SPARSE_FILES |
1601			VOL_CAP_FMT_ZERO_RUNS |
1602			VOL_CAP_FMT_2TB_FILESIZE |
1603			VOL_CAP_FMT_CASE_PRESERVING |
1604			VOL_CAP_FMT_CASE_SENSITIVE |
1605			VOL_CAP_FMT_FAST_STATFS |
1606			VOL_CAP_FMT_OPENDENYMODES |
1607			VOL_CAP_FMT_HIDDEN_FILES |
1608            VOL_CAP_FMT_64BIT_OBJECT_IDS |
1609			0;
1610
1611        if (vcp->vc_misc_flags & SMBV_OSX_SERVER) {
1612            /* Its OS X Server so we know for sure */
1613            if ((vcp->vc_volume_caps & kAAPL_SUPPORT_RESOLVE_ID) &&
1614                (vcp->vc_misc_flags & SMBV_HAS_FILEIDS)) {
1615                /* Supports Resolve ID */
1616                cap->valid[VOL_CAPABILITIES_FORMAT] |= VOL_CAP_FMT_PATH_FROM_ID;
1617            }
1618        }
1619
1620        cap->valid[VOL_CAPABILITIES_INTERFACES] =
1621			VOL_CAP_INT_SEARCHFS |
1622			VOL_CAP_INT_ATTRLIST |
1623			VOL_CAP_INT_NFSEXPORT |
1624			VOL_CAP_INT_READDIRATTR |
1625			VOL_CAP_INT_EXCHANGEDATA |
1626			VOL_CAP_INT_COPYFILE |
1627			VOL_CAP_INT_ALLOCATE |
1628			VOL_CAP_INT_VOL_RENAME |
1629			VOL_CAP_INT_ADVLOCK |
1630			VOL_CAP_INT_FLOCK |
1631			VOL_CAP_INT_MANLOCK |
1632			VOL_CAP_INT_NAMEDSTREAMS |
1633			VOL_CAP_INT_EXTENDED_ATTR |
1634			VOL_CAP_INT_REMOTE_EVENT |
1635			0;
1636
1637		cap->valid[VOL_CAPABILITIES_RESERVED1] = 0;
1638		cap->valid[VOL_CAPABILITIES_RESERVED2] = 0;
1639		VFSATTR_SET_SUPPORTED(fsap, f_capabilities);
1640	}
1641
1642	/*
1643	 * NOTE:  the valid field indicates whether your VFS knows whether a
1644	 * attribute is supported or not. So, if you know FOR SURE that a capability
1645	 * is support or not, then set that bit in the valid part.
1646	 */
1647	if (VFSATTR_IS_ACTIVE(fsap, f_attributes)) {
1648		fsap->f_attributes.validattr.commonattr =
1649												ATTR_CMN_NAME	|
1650												ATTR_CMN_DEVID	|
1651												ATTR_CMN_FSID	|
1652												ATTR_CMN_OBJTYPE |
1653												ATTR_CMN_OBJTAG	|
1654												ATTR_CMN_OBJID	|
1655												/* ATTR_CMN_OBJPERMANENTID | */
1656												ATTR_CMN_PAROBJID |
1657												/* ATTR_CMN_SCRIPT | */
1658												ATTR_CMN_CRTIME |
1659												ATTR_CMN_MODTIME |
1660												ATTR_CMN_CHGTIME |
1661												ATTR_CMN_ACCTIME |
1662												/* ATTR_CMN_BKUPTIME | */
1663												/* Just not sure about the following: */
1664												ATTR_CMN_FNDRINFO |
1665												ATTR_CMN_OWNERID |
1666												ATTR_CMN_GRPID	|
1667												ATTR_CMN_ACCESSMASK |
1668												ATTR_CMN_FLAGS	|
1669												ATTR_CMN_USERACCESS |
1670												ATTR_CMN_EXTENDED_SECURITY |
1671												ATTR_CMN_UUID |
1672												ATTR_CMN_GRPUUID |
1673												0;
1674		fsap->f_attributes.validattr.volattr =
1675												ATTR_VOL_FSTYPE	|
1676												/* ATTR_VOL_SIGNATURE */
1677												ATTR_VOL_SIZE	|
1678												ATTR_VOL_SPACEFREE |
1679												ATTR_VOL_SPACEAVAIL |
1680												ATTR_VOL_MINALLOCATION |
1681												ATTR_VOL_ALLOCATIONCLUMP |
1682												ATTR_VOL_IOBLOCKSIZE |
1683												/* ATTR_VOL_OBJCOUNT */
1684												/* ATTR_VOL_FILECOUNT */
1685												/* ATTR_VOL_DIRCOUNT */
1686												/* ATTR_VOL_MAXOBJCOUNT */
1687												ATTR_VOL_MOUNTPOINT |
1688												ATTR_VOL_NAME	|
1689												ATTR_VOL_MOUNTFLAGS |
1690												ATTR_VOL_MOUNTEDDEVICE |
1691												/* ATTR_VOL_ENCODINGSUSED */
1692												ATTR_VOL_CAPABILITIES |
1693												ATTR_VOL_ATTRIBUTES |
1694												0;
1695		fsap->f_attributes.validattr.dirattr =
1696												ATTR_DIR_LINKCOUNT |
1697												ATTR_DIR_MOUNTSTATUS |
1698												0;
1699		fsap->f_attributes.validattr.fileattr =
1700												ATTR_FILE_LINKCOUNT |
1701												ATTR_FILE_TOTALSIZE |
1702												ATTR_FILE_ALLOCSIZE |
1703												/* ATTR_FILE_IOBLOCKSIZE */
1704												ATTR_FILE_DEVTYPE |
1705												/* ATTR_FILE_FORKCOUNT */
1706												/* ATTR_FILE_FORKLIST */
1707												ATTR_FILE_DATALENGTH |
1708												ATTR_FILE_DATAALLOCSIZE |
1709												ATTR_FILE_RSRCLENGTH |
1710												ATTR_FILE_RSRCALLOCSIZE |
1711												0;
1712		fsap->f_attributes.validattr.forkattr = 0;
1713
1714		fsap->f_attributes.nativeattr.commonattr =
1715												ATTR_CMN_NAME	|
1716												ATTR_CMN_DEVID	|
1717												ATTR_CMN_FSID	|
1718												ATTR_CMN_OBJTYPE |
1719												ATTR_CMN_OBJTAG	|
1720												ATTR_CMN_OBJID	|
1721												/* ATTR_CMN_OBJPERMANENTID | */
1722												ATTR_CMN_PAROBJID |
1723												/* ATTR_CMN_SCRIPT | */
1724												ATTR_CMN_CRTIME |
1725												ATTR_CMN_MODTIME |
1726												ATTR_CMN_ACCTIME |
1727												/* ATTR_CMN_BKUPTIME | */
1728												/* ATTR_CMN_OWNERID | */	/* Supported but not native */
1729												/* ATTR_CMN_GRPID	| */	/* Supported but not native */
1730												/* ATTR_CMN_ACCESSMASK | */	/* Supported but not native */
1731												ATTR_CMN_FLAGS	|
1732												/* ATTR_CMN_USERACCESS | */	/* Supported but not native */
1733												0;
1734			/* FAT does not support change time */
1735		if (share->ss_fstype != SMB_FS_FAT) {
1736			fsap->f_attributes.nativeattr.commonattr |= ATTR_CMN_CHGTIME;
1737		}
1738		/* Named Streams knows about Finder Info */
1739		if (share->ss_attributes & FILE_NAMED_STREAMS) {
1740			fsap->f_attributes.nativeattr.commonattr |= ATTR_CMN_FNDRINFO;
1741		}
1742
1743		if (share->ss_attributes & FILE_PERSISTENT_ACLS) {
1744			fsap->f_attributes.nativeattr.commonattr |= ATTR_CMN_EXTENDED_SECURITY | ATTR_CMN_UUID | ATTR_CMN_GRPUUID;
1745		}
1746
1747		fsap->f_attributes.nativeattr.volattr =
1748												ATTR_VOL_FSTYPE	|
1749												/* ATTR_VOL_SIGNATURE */
1750												ATTR_VOL_SIZE	|
1751												ATTR_VOL_SPACEFREE |
1752												ATTR_VOL_SPACEAVAIL |
1753												ATTR_VOL_MINALLOCATION |
1754												ATTR_VOL_ALLOCATIONCLUMP |
1755												ATTR_VOL_IOBLOCKSIZE |
1756												/* ATTR_VOL_OBJCOUNT */
1757												/* ATTR_VOL_FILECOUNT */
1758												/* ATTR_VOL_DIRCOUNT */
1759												/* ATTR_VOL_MAXOBJCOUNT */
1760												ATTR_VOL_MOUNTPOINT |
1761												ATTR_VOL_NAME	|
1762												ATTR_VOL_MOUNTFLAGS |
1763												ATTR_VOL_MOUNTEDDEVICE |
1764												/* ATTR_VOL_ENCODINGSUSED */
1765												ATTR_VOL_CAPABILITIES |
1766												ATTR_VOL_ATTRIBUTES |
1767												0;
1768		fsap->f_attributes.nativeattr.dirattr = 0;
1769		fsap->f_attributes.nativeattr.fileattr =
1770												/* ATTR_FILE_LINKCOUNT | */	/* Supported but not native */
1771												/* ATTR_FILE_IOBLOCKSIZE */
1772												ATTR_FILE_DEVTYPE |
1773												/* ATTR_FILE_FORKCOUNT */
1774												/* ATTR_FILE_FORKLIST */
1775												ATTR_FILE_DATALENGTH |
1776												ATTR_FILE_DATAALLOCSIZE |
1777												0;
1778		/*
1779		 * Once we added streams support we should add this code. Radar 2899967
1780		 */
1781		if (share->ss_attributes & FILE_NAMED_STREAMS)
1782			fsap->f_attributes.nativeattr.fileattr |= ATTR_FILE_TOTALSIZE |
1783													ATTR_FILE_ALLOCSIZE |
1784													ATTR_FILE_RSRCLENGTH |
1785													ATTR_FILE_RSRCALLOCSIZE;
1786
1787		fsap->f_attributes.nativeattr.forkattr = 0;
1788		VFSATTR_SET_SUPPORTED(fsap, f_attributes);
1789	}
1790	/*
1791	 * Our filesystem doesn't support volume dates. Let the VFS layer handle
1792	 * these if requested.
1793	 */
1794
1795	 /*
1796	  * Could be one of the following:
1797	  *		SMB_FS_FAT, SMB_FS_CDFS, SMB_FS_UDF,
1798	  *		SMB_FS_NTFS_UNKNOWN, SMB_FS_NTFS, SMB_FS_NTFS_UNIX,
1799	  *		SMB_FS_MAC_OS_X
1800	  */
1801	VFSATTR_RETURN(fsap, f_fssubtype, share->ss_fstype);
1802
1803	if (VFSATTR_IS_ACTIVE(fsap, f_vol_name) && fsap->f_vol_name) {
1804		if (smp->sm_args.volume_name) {
1805			strlcpy(fsap->f_vol_name, smp->sm_args.volume_name, MAXPATHLEN);
1806		} else {
1807			/*
1808			 * ref 3984574.  Returning null here keeps vfs from returning
1809			 * f_mntonname, and causes CarbonCore (File Mgr) to use the
1810			 * f_mntfromname, as it did (& still does) when an error is returned.
1811			 */
1812			*fsap->f_vol_name = '\0';
1813		}
1814		VFSATTR_SET_SUPPORTED(fsap, f_vol_name);
1815	}
1816
1817	/* Let the vfs layer handle f_signature */
1818	/* We never set f_carbon_fsid, see <rdar://problem/4470282> depricated */
1819
1820	smb_share_rele(share, context);
1821
1822done:
1823    SMB_LOG_KTRACE(SMB_DBG_VFS_GETATTR | DBG_FUNC_END, error, 0, 0, 0, 0);
1824    return (error);
1825}
1826
1827struct smbfs_sync_cargs {
1828	vfs_context_t	context;
1829	int	waitfor;
1830	int	error;
1831};
1832
1833
1834static int
1835smbfs_sync_callback(vnode_t vp, void *args)
1836{
1837	int error;
1838	struct smbfs_sync_cargs *cargs;
1839	struct smbnode *np = NULL;
1840	struct smb_share *share = NULL;
1841	struct timespec	ts;
1842    struct timespec waittime;
1843    int dirty = 0;
1844
1845	cargs = (struct smbfs_sync_cargs *)args;
1846
1847	if (smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK) != 0) {
1848		return (VNODE_RETURNED);
1849	}
1850
1851	np = VTOSMB(vp);
1852	np->n_lastvop = smbfs_sync_callback;
1853
1854	share = smb_get_share_with_reference(VTOSMBFS(vp));
1855	/*
1856	 * Must have gone into reconnect mode while interating the vnodes. Nothing for
1857	 * us to do until reconnect is done. Just get out and wait for the next time.
1858	 */
1859	if (share->ss_flags & SMBS_RECONNECTING) {
1860		goto done;
1861	}
1862
1863	if (vnode_isreg(vp)) {
1864		/*
1865		 * See if the file needs to be reopened. Ignore the error if being
1866		 * revoke it will get caught below
1867		 */
1868		(void)smbfs_smb_reopen_file(share, np, cargs->context);
1869
1870		lck_mtx_lock(&np->f_openStateLock);
1871		if (np->f_openState & kNeedRevoke) {
1872			lck_mtx_unlock(&np->f_openStateLock);
1873
1874			SMBWARNING_LOCK(np, "revoking %s\n", np->n_name);
1875
1876			smbnode_unlock(np);
1877			np = NULL; /* Already unlocked */
1878			vn_revoke(vp, REVOKEALL, cargs->context);
1879			goto done;
1880		}
1881		lck_mtx_unlock(&np->f_openStateLock);
1882	}
1883	/*
1884	 * We have dirty data or we have a set eof pending in either case
1885	 * deal with it in smbfs_fsync.
1886	 */
1887    dirty = vnode_hasdirtyblks(vp);
1888	if (dirty ||
1889        (vnode_isreg(vp) && (np->n_flag & (NNEEDS_EOF_SET | NNEEDS_FLUSH)))) {
1890
1891        if (!(dirty) &&
1892            !(np->n_flag & NNEEDS_EOF_SET) &&
1893            (SSTOVC(share)->vc_server_caps & kAAPL_UNIX_BASED)) {
1894            /*
1895             * If its only needs a flush and the server is unix based, skip
1896             * doing this flush because the server OS is already doing a sync
1897             * with flush every 30 seconds or so.
1898             */
1899            np->n_flag &= ~NNEEDS_FLUSH;
1900        }
1901        else {
1902            /*
1903             * Only send flush to server if its been longer than 30 secs since when
1904             * the last write was done. A flush can take a while and thus it can
1905             * hammer performance if you are doing a flush in the middle of a long
1906             * set of writes.
1907             */
1908            nanouptime(&ts);
1909            waittime.tv_sec = SMB_FSYNC_TIMO;
1910            waittime.tv_nsec = 0;
1911            timespecsub(&ts, &waittime);
1912
1913            if (timespeccmp(&ts, &np->n_last_write_time, >)) {
1914                error = smbfs_fsync(share, vp, cargs->waitfor, 0, cargs->context);
1915                if (error)
1916                    cargs->error = error;
1917            }
1918        }
1919	}
1920
1921	/* Someone is monitoring this node see if we have any work */
1922	if (vnode_ismonitored(vp)) {
1923		int updateNotifyNode = FALSE;
1924
1925		if (vnode_isdir(vp) && !(np->n_flag & N_POLLNOTIFY)) {
1926			/*
1927			 * The smbfs_restart_change_notify will now handle not only reopening
1928			 * of notifcation, but also the closing of notifications. This is
1929			 * done to force items into polling when we have too many items.
1930			 */
1931			smbfs_restart_change_notify(share, np, cargs->context);
1932			updateNotifyNode = np->d_needsUpdate;
1933		} else
1934			updateNotifyNode = TRUE;
1935		/* Looks like something change udate the notify routines and our cache */
1936		if (updateNotifyNode)
1937			(void)smbfs_update_cache(share, vp, NULL, cargs->context);
1938	}
1939done:
1940	if (np) {
1941		smbnode_unlock(np);
1942	}
1943	/* We only have a share if we took a reference, release it */
1944	if (share) {
1945		smb_share_rele(share, cargs->context);
1946	}
1947
1948	return (VNODE_RETURNED);
1949}
1950
1951/*
1952 * Flush out the buffer cache
1953 */
1954static int
1955smbfs_sync(struct mount *mp, int waitfor, vfs_context_t context)
1956{
1957	struct smbfs_sync_cargs args;
1958
1959    SMB_LOG_KTRACE(SMB_DBG_SYNC | DBG_FUNC_START, 0, 0, 0, 0, 0);
1960
1961	args.context = context;
1962	args.waitfor = waitfor;
1963	args.error = 0;
1964	/*
1965	 * Force stale buffer cache information to be flushed.
1966	 *
1967	 * sbmfs_sync_callback will be called for each vnode
1968	 * hung off of this mount point... the vnode will be
1969	 * properly referenced and unreferenced around the callback
1970	 */
1971	vnode_iterate(mp, VNODE_ITERATE_ACTIVE, smbfs_sync_callback, (void *)&args);
1972
1973    SMB_LOG_KTRACE(SMB_DBG_SYNC | DBG_FUNC_END, args.error, 0, 0, 0, 0);
1974	return (args.error);
1975}
1976
1977/*
1978 * smbfs_vget - Equivalent of AFP Resolve ID
1979 * Returns an unlocked vnode
1980 */
1981static int
1982smbfs_vget(struct mount *mp, ino64_t ino, vnode_t *vpp, vfs_context_t context)
1983{
1984    int error;
1985    struct smbmount *smp = VFSTOSMBFS(mp);
1986    struct smb_share *share = NULL;
1987    struct smb_vc *vcp = NULL;
1988    char *path = NULL;
1989    size_t path_max = MAXPATHLEN;
1990    struct smbfattr *fap = NULL;
1991    uint32_t resolve_error = 0;
1992    char *server_path = NULL;
1993    vnode_t root_vp = NULL;
1994    struct smbnode *root_np = NULL;
1995
1996    SMB_LOG_KTRACE(SMB_DBG_VGET | DBG_FUNC_START, ino, 0, 0, 0, 0);
1997
1998    if (smp == NULL) {
1999        SMBERROR("smp == NULL\n");
2000        error = EINVAL;
2001        goto done;
2002    }
2003
2004    SMB_MALLOC(path,
2005               char *,
2006               MAXPATHLEN,
2007               M_SMBTEMP,
2008               M_WAITOK | M_ZERO);
2009    if (path == NULL) {
2010        SMBERROR("SMB_MALLOC failed\n");
2011        error = ENOMEM;
2012        goto done;
2013    }
2014
2015    SMB_MALLOC(fap,
2016               struct smbfattr *,
2017               sizeof(struct smbfattr),
2018               M_SMBTEMP,
2019               M_WAITOK | M_ZERO);
2020    if (fap == NULL) {
2021        SMBERROR("SMB_MALLOC failed\n");
2022        error = ENOMEM;
2023        goto done;
2024    }
2025
2026    share = smb_get_share_with_reference(smp);
2027    vcp = SSTOVC(share);
2028
2029    if ((vcp->vc_misc_flags & SMBV_OSX_SERVER) &&
2030        (vcp->vc_volume_caps & kAAPL_SUPPORT_RESOLVE_ID) &&
2031        (vcp->vc_misc_flags & SMBV_HAS_FILEIDS)) {
2032        /*
2033         * Supports Resolve ID.
2034         * First check to see if we already have the vnode
2035         */
2036        if ((ino == SMBFS_ROOT_INO) || (ino == SMBFS_ROOT_PAR_INO)) {
2037            /* Get the root vnode */
2038            error = smbfs_root(mp, vpp, context);
2039            goto done;
2040        }
2041        else {
2042            /*
2043             * Some other vnode
2044             */
2045            fap->fa_ino = ino;
2046
2047            /*
2048             * Since we only have the ino in the fap, if we do find an existing
2049             * vnode, dont update its meta data
2050             */
2051            if (smbfs_nget(share, mp,
2052                           NULL, NULL, 0,
2053                           fap, vpp,
2054                           0, (SMBFS_NGET_LOOKUP_ONLY | SMBFS_NGET_NO_CACHE_UPDATE),
2055                           context) == 0) {
2056                /*
2057                 * Found one in our hash table. Unlock it and return it
2058                 */
2059                error = 0;
2060                smbnode_unlock(VTOSMB(*vpp));
2061                goto done;
2062            }
2063        }
2064
2065        /*
2066         * Not already in our hash table.
2067         * Do Resolve ID to server to see if server can find the item.  If so
2068         * it will return the path from the share to the item.
2069         *
2070         * Need root vnode to do the Resolve ID call on
2071         */
2072        error = smbfs_root(mp, &root_vp, context);
2073        if (error) {
2074            SMBDEBUG("smbfs_root failed %d\n", error);
2075            goto done;
2076        }
2077        root_np = VTOSMB(root_vp);
2078
2079        error = smb2fs_smb_cmpd_resolve_id(share, root_np,
2080                                           ino, &resolve_error, &server_path,
2081                                           context);
2082        if (error) {
2083            goto done;
2084        }
2085
2086        if (resolve_error) {
2087            error = resolve_error;
2088            goto done;
2089        }
2090
2091        if (server_path == NULL) {
2092            error = ENOENT;
2093            goto done;
2094        }
2095
2096        /*
2097         * Build the local path to the item starting with mount point
2098         */
2099        if (strlcpy(path, vfs_statfs(mp)->f_mntonname, path_max) >= path_max) {
2100            /* Should not happen */
2101            SMBDEBUG("path too long <%s>\n", vfs_statfs(mp)->f_mntonname);
2102            error = ENAMETOOLONG;
2103            goto done;
2104        }
2105        path_max = MAXPATHLEN - strlen(path);
2106
2107        if (strlcat(path, "/", path_max) >= path_max) {
2108            /* Should not happen */
2109            SMBDEBUG("path too long <%s> + <%s>\n", path, "/");
2110            error = ENAMETOOLONG;
2111            goto done;
2112        }
2113        path_max = MAXPATHLEN - strlen(path);
2114
2115        if (strlcat(path, server_path, path_max) >= path_max) {
2116            SMBDEBUG("path too long <%s> + <%s>\n", path, server_path);
2117            error = ENAMETOOLONG;
2118            goto done;
2119        }
2120
2121        /*
2122         * Follow that path to find the vnode
2123         */
2124        error = vnode_lookup (path, 0, vpp, context);
2125        if (error) {
2126            SMBDEBUG("vnode_lookup failed %d\n", error);
2127            goto done;
2128        }
2129
2130        /* make sure it is one of my vnodes */
2131        if (vnode_tag(*vpp) != VT_CIFS) {
2132            SMBDEBUG("vnode_lookup found non SMB vnode???\n");
2133            error = ENOENT;
2134            goto done;
2135        }
2136    }
2137    else {
2138        error = ENOTSUP;
2139    }
2140
2141done:
2142    if (root_vp) {
2143        vnode_put(root_vp);
2144    }
2145
2146    if (server_path) {
2147        SMB_FREE(server_path, M_SMBTEMP);
2148    }
2149
2150    if (fap) {
2151        SMB_FREE(fap, M_SMBTEMP);
2152    }
2153
2154    if (path) {
2155        SMB_FREE(path, M_SMBTEMP);
2156    }
2157
2158    /* We only have a share if we took a reference, release it */
2159    if (share) {
2160        smb_share_rele(share, context);
2161    }
2162
2163    SMB_LOG_KTRACE(SMB_DBG_VGET | DBG_FUNC_END, error, 0, 0, 0, 0);
2164    return (error);
2165}
2166
2167static int
2168smbfs_fhtovp(struct mount *mp, int fhlen, unsigned char *fhp, vnode_t *vpp,
2169	     vfs_context_t context)
2170{
2171#pragma unused(mp, fhlen, fhp, vpp, context)
2172	return (EINVAL);
2173}
2174
2175/*
2176 * Vnode pointer to File handle, should never happen either
2177 */
2178static int
2179smbfs_vptofh(vnode_t vp, int *fhlen, unsigned char *fhp, vfs_context_t context)
2180{
2181#pragma unused(vp, fhlen, fhp, context)
2182	return (EINVAL);
2183}
2184
2185/*
2186 * smbfs_sysctl handles the VFS_CTL_QUERY request which tells interested
2187 * parties if the connection with the remote server is up or down.
2188 */
2189static int
2190smbfs_sysctl(int * name, unsigned namelen, user_addr_t oldp, size_t * oldlenp,
2191	     user_addr_t newp, size_t newlen, vfs_context_t context)
2192{
2193#pragma unused(oldlenp, newp, newlen)
2194	int error = 0;
2195	struct sysctl_req *req;
2196	struct mount *mp = NULL;
2197	struct smbmount *smp = NULL;
2198	struct vfsquery vq;
2199	int32_t dev = 0;
2200	struct smb_remount_info info;
2201	struct smb_share *share;
2202	struct vfs_server v_server;
2203	uint count;
2204	uint totlen;
2205	uint numThreads;
2206	struct netfs_status *nsp = NULL;
2207	struct smb_vc *vcp = NULL;
2208	struct smb_rq *rqp, *trqp;
2209
2210    SMB_LOG_KTRACE(SMB_DBG_SYSCTL | DBG_FUNC_START, name[0], 0, 0, 0, 0);
2211
2212	/*
2213	 * All names at this level are terminal.
2214	 */
2215	if (namelen > 1) {
2216		error = ENOTDIR;	/* overloaded */
2217        goto done;
2218    }
2219
2220	switch (name[0]) {
2221		case VFS_CTL_STATFS:
2222		case VFS_CTL_UMOUNT:
2223		case VFS_CTL_NEWADDR:
2224		case VFS_CTL_TIMEO:
2225		case VFS_CTL_NOLOCKS:
2226			/* Force the VFS layer to handle these */
2227			error = ENOTSUP;
2228            goto done;
2229			break;
2230		case SMBFS_SYSCTL_GET_SERVER_SHARE:
2231		case SMBFS_SYSCTL_REMOUNT_INFO:
2232		case SMBFS_SYSCTL_REMOUNT:
2233		case VFS_CTL_QUERY:
2234		case VFS_CTL_SADDR:
2235        case VFS_CTL_DISC:
2236        case VFS_CTL_SERVERINFO:
2237        case VFS_CTL_NSTATUS:
2238		{
2239			boolean_t is_64_bit = vfs_context_is64bit(context);
2240			union union_vfsidctl vc;
2241
2242			req = CAST_DOWN(struct sysctl_req *, oldp);
2243			error = SYSCTL_IN(req, &vc, is_64_bit ? sizeof(vc.vc64) : sizeof(vc.vc32));
2244			if (error) {
2245				break;
2246			}
2247			mp = vfs_getvfs(&vc.vc32.vc_fsid); /* works for 32 and 64 */
2248			/*
2249			 * The sysctl_vfs_ctlbyfsid grabs a reference on the mount before
2250			 * calling us, so we know the mount point can't go away while we
2251			 * are working on it here. Just to be safe we make sure it can be
2252			 * found by vfs_getvfs. Also if its being forced unmounted there
2253			 * is nothing for us to do here just get out.
2254			 */
2255			if (mp && !(vfs_isforce(mp))) {
2256				smp = VFSTOSMBFS(mp);
2257			}
2258			if (!smp) {
2259				error = ENOENT;
2260				break;
2261			}
2262			req->newidx = 0;
2263			if (is_64_bit) {
2264				req->newptr = vc.vc64.vc_ptr;
2265				req->newlen = (size_t)vc.vc64.vc_len;
2266			} else {
2267				req->newptr = CAST_USER_ADDR_T(vc.vc32.vc_ptr);
2268				req->newlen = vc.vc32.vc_len;
2269			}
2270			break;
2271		}
2272		default:
2273			error = ENOTSUP;
2274			break;
2275	}
2276	if (error) {
2277		goto done;
2278	}
2279
2280	/* We only support new style vfs sysctl. */
2281	switch (name[0]) {
2282		case SMBFS_SYSCTL_GET_SERVER_SHARE:
2283		{
2284			size_t len;
2285			char *serverShareStr;
2286
2287			share = smb_get_share_with_reference(smp);
2288			len = strnlen(SSTOVC(share)->vc_srvname, SMB_MAX_DNS_SRVNAMELEN);
2289			len += 1; /* Slash */
2290			len += strnlen(share->ss_name, SMB_MAXSHARENAMELEN);
2291			len += 1; /* null byte */
2292			SMB_MALLOC(serverShareStr, char *, len, M_TEMP, M_WAITOK | M_ZERO);
2293			strlcpy(serverShareStr, SSTOVC(share)->vc_srvname, len);
2294			strlcat(serverShareStr, "/", len);
2295			strlcat(serverShareStr, share->ss_name, len);
2296			smb_share_rele(share, context);
2297			error = SYSCTL_OUT(req, serverShareStr, len);
2298			SMB_FREE(serverShareStr, M_TEMP);
2299			break;
2300		}
2301		case SMBFS_SYSCTL_REMOUNT_INFO:
2302			share = smb_get_share_with_reference(smp);
2303			smbfs_remountInfo(mp, share, &info);
2304			smb_share_rele(share, context);
2305			error = SYSCTL_OUT(req, &info, sizeof(info));
2306			break;
2307		case SMBFS_SYSCTL_REMOUNT:
2308			error = SYSCTL_IN(req, &dev, sizeof(dev));
2309			if (!error) {
2310				error = smbfs_remount(dev, mp, smp, context);
2311			}
2312			break;
2313		case VFS_CTL_QUERY:
2314			bzero(&vq, sizeof(vq));
2315			if (smp && (smp->sm_status & SM_STATUS_DEAD)) {
2316				vq.vq_flags |= VQ_DEAD;
2317			} else if (smp) {
2318				int dontNotify = ((smp->sm_args.altflags & SMBFS_MNT_SOFT) &&
2319								(vfs_flags(smp->sm_mp) & MNT_DONTBROWSE));
2320
2321				if ((smp->sm_status & SM_STATUS_DOWN) && !dontNotify) {
2322						vq.vq_flags |= VQ_NOTRESP;
2323				}
2324				if (smp->sm_status & SM_STATUS_REMOUNT) {
2325					vq.vq_flags |= VQ_ASSIST;
2326				} else if (smp->sm_status & SM_STATUS_UPDATED) {
2327					vq.vq_flags |= VQ_UPDATE;
2328					/* report back only once */
2329					smp->sm_status &= ~SM_STATUS_UPDATED;
2330				}
2331
2332                /* Check if we have any pending svrmsg replies */
2333                if (smp->sm_svrmsg_pending) {
2334                    vq.vq_flags |= VQ_SERVEREVENT;
2335                }
2336			}
2337
2338            SMB_LOG_KTRACE(SMB_DBG_SYSCTL | DBG_FUNC_NONE,
2339                           0xabc001, vq.vq_flags, 0, 0, 0);
2340
2341			SMBDEBUG("vq.vq_flags = 0x%x\n", vq.vq_flags);
2342			error = SYSCTL_OUT(req, &vq, sizeof(vq));
2343			break;
2344
2345		case VFS_CTL_SADDR:
2346			if (smp->sm_args.altflags & SMBFS_MNT_DFS_SHARE) {
2347				/* Never let them unmount a dfs share */
2348				error = ENOTSUP;
2349			}
2350            else {
2351				struct sockaddr_storage storage;
2352				struct sockaddr *saddr;
2353				size_t len;
2354
2355				memset(&storage, 0, sizeof(storage));
2356
2357				/* Get a reference on the share */
2358				share = smb_get_share_with_reference(smp);
2359
2360				if (SSTOVC(share)->vc_saddr->sa_family == AF_NETBIOS) {
2361					/* NetBIOS sockaddr get the real IPv4 sockaddr */
2362					saddr = (struct sockaddr *)
2363                        &((struct sockaddr_nb *) SSTOVC(share)->vc_saddr)->snb_addrin;
2364				}
2365                else {
2366					/* IPv4 or IPv6 sockaddr */
2367					saddr = SSTOVC(share)->vc_saddr;
2368				}
2369
2370				/* Just to be safe, make sure we have a safe length */
2371				len = (saddr->sa_len > sizeof(storage)) ? sizeof(storage) : saddr->sa_len;
2372				memcpy(&storage, saddr, len);
2373				smb_share_rele(share, context);
2374				error = SYSCTL_OUT(req, &storage, len);
2375			}
2376			break;
2377
2378        case VFS_CTL_DISC:
2379			if (smp->sm_args.altflags & SMBFS_MNT_DFS_SHARE) {
2380				/* Never let them unmount a dfs share */
2381				error = ENOTSUP;
2382			}
2383            else {
2384                /*
2385                 * Server is not responding. KEA will now request an unmount.
2386                 * If there are no files opened for write AND there are no files
2387                 * sitting in UBC with dirty data, then return 0 and signal KEA
2388                 * to unmount us right now.  KEA will not display this share in
2389                 * the dialog since we should be unmounting immediately.
2390                 * Otherwise, return EBUSY and let the dialog be displayed so
2391                 * the user can decide what to do
2392                 */
2393                error = 0;  /* assume can be immediately unmounted */
2394
2395				/* Get a reference on the share */
2396				share = smb_get_share_with_reference(smp);
2397
2398                if (!vfs_isrdonly(mp)) {
2399                    /* only check for "busy" files if not read only */
2400                    lck_mtx_lock(&share->ss_shlock);
2401
2402                    error = smbfs_IObusy(smp);
2403                    SMBDEBUG("VFS_CTL_DISC - smbfs_IObusy returned %d\n", error);
2404
2405                    lck_mtx_unlock(&share->ss_shlock);
2406                }
2407
2408                SMB_LOG_KTRACE(SMB_DBG_SYSCTL | DBG_FUNC_NONE,
2409                               0xabc002, error, 0, 0, 0);
2410
2411                if (error != EBUSY) {
2412                    SMBDEBUG("VFS_CTL_DISC unmounting\n");
2413                    /* ok to immediately be unmounted */
2414					share->ss_dead(share);
2415                }
2416
2417				smb_share_rele(share, context);
2418            }
2419
2420            break;
2421
2422        case VFS_CTL_SERVERINFO:
2423        {
2424            /* Fill in the server name */
2425            size_t len;
2426            share = smb_get_share_with_reference(smp);
2427            len = strnlen(SSTOVC(share)->vc_srvname, SMB_MAX_DNS_SRVNAMELEN);
2428            strlcpy((char *)v_server.vs_server_name, SSTOVC(share)->vc_srvname, len + 1);
2429
2430            if (smp->sm_svrmsg_pending) {
2431                /* Fill in shutdown delay */
2432                if (smp->sm_svrmsg_pending & SVRMSG_RCVD_GOING_DOWN) {
2433                    /* Set the delay (in minutes) we received from the server */
2434                    v_server.vs_minutes = smp->sm_svrmsg_shutdown_delay / 60;
2435
2436                    smp->sm_svrmsg_pending &= ~SVRMSG_RCVD_GOING_DOWN;
2437                } else if (smp->sm_svrmsg_pending & SVRMSG_RCVD_SHUTDOWN_CANCEL) {
2438                    /* Delay = 0xfff means server is staying up */
2439                    v_server.vs_minutes = 0xfff;
2440                    smp->sm_svrmsg_pending &= ~SVRMSG_RCVD_SHUTDOWN_CANCEL;
2441                }
2442            } else {
2443                /*
2444                 * No server events to report.
2445                 * Don't return an error, otherwise nothing gets passed back.
2446                 * Use -1 for v_minutes to indicate an error.
2447                 */
2448                v_server.vs_minutes = -1;
2449            }
2450            smb_share_rele(share, context);
2451
2452            error = SYSCTL_OUT(req, &v_server, sizeof(v_server));
2453
2454            break;
2455        }
2456
2457        case VFS_CTL_NSTATUS:
2458            /* grab a reference until we're done with the share */
2459            share  = smb_get_share_with_reference(smp);
2460
2461            /* Get access to the vc underneath */
2462            vcp = SSTOVC(share);
2463
2464            /* Round up the threads */
2465            numThreads = 0;
2466            SMB_IOD_RQLOCK(vcp->vc_iod);
2467            TAILQ_FOREACH_SAFE(rqp, &(vcp->vc_iod)->iod_rqlist, sr_link, trqp) {
2468                /* Only count threads for this share and
2469                 * they're not internal or async threads */
2470                if  ((rqp->sr_share == share) &&
2471                     !(rqp->sr_flags & (SMBR_ASYNC | SMBR_INTERNAL))) {
2472                    numThreads++;
2473                }
2474            }
2475            SMB_IOD_RQUNLOCK(vcp->vc_iod);
2476
2477            /* Calculate total size of result buffer */
2478            totlen = sizeof(struct netfs_status) + (numThreads * sizeof(uint64_t));
2479
2480            if (req->oldptr == USER_ADDR_NULL) { // Caller is querying buffer size
2481                smb_share_rele(share, context);
2482                return SYSCTL_OUT(req, NULL, totlen);
2483            }
2484
2485            MALLOC(nsp, struct netfs_status *, totlen, M_TEMP, M_WAITOK|M_ZERO);
2486            if (nsp == NULL) {
2487                smb_share_rele(share, context);
2488                return ENOMEM;
2489            }
2490
2491            if (smp->sm_status & SM_STATUS_DOWN) {
2492                nsp->ns_status |= VQ_NOTRESP;
2493            }
2494            if (smp->sm_status & SM_STATUS_DEAD) {
2495                nsp->ns_status |= VQ_DEAD;
2496            }
2497
2498            /* Return some significant mount options as a string
2499             * e.g. "rw,soft,vers=0x0302,sec=kerberos,timeout=20 */
2500            snprintf(nsp->ns_mountopts, sizeof(nsp->ns_mountopts),
2501                     "%s,%s,vers=0x%X,sec=%s,timeout=%d",
2502                     (vfs_flags(mp) & MNT_RDONLY) ? "ro" : "rw",
2503                     (smp->sm_args.altflags & SMBFS_MNT_SOFT) ? "soft" : "hard",
2504                     vcp->vc_sopt.sv_dialect ? vcp->vc_sopt.sv_dialect : 0x01,
2505                     (vcp->vc_flags & SMBV_GUEST_ACCESS)        ? "guest" :
2506                     (vcp->vc_flags & SMBV_PRIV_GUEST_ACCESS)   ? "privguest" :
2507                     (vcp->vc_flags & SMBV_ANONYMOUS_ACCESS)    ? "anonymous" :
2508                     (vcp->vc_flags & SMBV_KERBEROS_ACCESS)     ? "kerberos" :
2509                     (vcp->vc_sopt.sv_caps & SMB_CAP_EXT_SECURITY)       ? "gss" : "unknown",
2510                     (smp->sm_args.altflags & SMBFS_MNT_SOFT) ? share->ss_soft_timer : (share->ss_dead_timer + vcp->vc_resp_wait_timeout));
2511
2512            nsp->ns_threadcount = numThreads;
2513
2514            /*
2515             * Get the thread ids of threads waiting for a reply
2516             * and find the longest wait time.
2517             */
2518            if (numThreads > 0) {
2519                struct timespec now;
2520                time_t sendtime;
2521
2522                nanouptime(&now);
2523                count = 0;
2524                sendtime = now.tv_sec;
2525                SMB_IOD_RQLOCK(vcp->vc_iod);
2526                TAILQ_FOREACH_SAFE(rqp, &(vcp->vc_iod)->iod_rqlist, sr_link, trqp) {
2527                    /* Only count threads for this share if they're not internal threads */
2528                    if  ((rqp->sr_share == share) &&
2529                         !(rqp->sr_flags & (SMBR_ASYNC | SMBR_INTERNAL))) {
2530                        if ((rqp->sr_state & ~SMBRQ_NOTSENT) && rqp->sr_timesent.tv_sec < sendtime) {
2531                            sendtime = rqp->sr_timesent.tv_sec;
2532                        }
2533                        nsp->ns_threadids[count] = rqp->sr_threadId;
2534                        if (++count >= numThreads)
2535                            break;
2536                    }
2537                }
2538                nsp->ns_waittime = (uint32_t)(now.tv_sec - sendtime);
2539                SMB_IOD_RQUNLOCK(vcp->vc_iod);
2540            }
2541
2542            smb_share_rele(share, context);
2543
2544            error = SYSCTL_OUT(req, nsp, totlen);
2545            break;
2546
2547	    default:
2548			error = ENOTSUP;
2549			break;
2550	}
2551
2552done:
2553	if (error) {
2554		SMBWARNING("name[0] = %d error = %d\n", name[0], error);
2555	}
2556
2557    SMB_LOG_KTRACE(SMB_DBG_SYSCTL | DBG_FUNC_END, error, 0, 0, 0, 0);
2558	return (error);
2559}
2560
2561static char smbfs_name[MFSNAMELEN] = "smbfs";
2562
2563kmod_info_t *smbfs_kmod_infop;
2564
2565typedef int (*PFI)();
2566
2567extern struct vnodeopv_desc smbfs_vnodeop_opv_desc;
2568static struct vnodeopv_desc *smbfs_vnodeop_opv_desc_list[1] =
2569{
2570	&smbfs_vnodeop_opv_desc
2571};
2572
2573
2574extern int version_major;
2575extern int version_minor;
2576
2577static vfstable_t  smbfs_vfsconf;
2578
2579static struct vfsops smbfs_vfsops = {
2580	smbfs_mount,
2581	smbfs_start,
2582	smbfs_unmount,
2583	smbfs_root,
2584	NULL,			/* quotactl */
2585	smbfs_vfs_getattr,
2586	smbfs_sync,
2587	smbfs_vget,
2588	smbfs_fhtovp,
2589	smbfs_vptofh,
2590	smbfs_init,
2591	smbfs_sysctl,
2592	NULL,
2593	{0}
2594};
2595
2596int smbfs_module_start(kmod_info_t *ki, void *data)
2597{
2598#pragma unused(data)
2599	struct vfs_fsentry vfe;
2600	int	error;
2601
2602	smbfs_kmod_infop = ki;
2603
2604	vfe.vfe_vfsops = &smbfs_vfsops;
2605	/* We just have vnode operations for regular files and directories */
2606	vfe.vfe_vopcnt = 1;
2607	vfe.vfe_opvdescs = smbfs_vnodeop_opv_desc_list;
2608	strlcpy(vfe.vfe_fsname, smbfs_name, sizeof(vfe.vfe_fsname));
2609	vfe.vfe_flags = VFS_TBLTHREADSAFE | VFS_TBLFSNODELOCK | VFS_TBLNOTYPENUM |
2610					VFS_TBL64BITREADY | VFS_TBLREADDIR_EXTENDED |
2611					VFS_TBLUNMOUNT_PREFLIGHT;
2612
2613	vfe.vfe_reserv[0] = 0;
2614	vfe.vfe_reserv[1] = 0;
2615
2616	error = vfs_fsadd(&vfe, &smbfs_vfsconf);
2617	if (error)
2618		goto out;
2619
2620	smbnet_lock_init();	/* Initialize the network locks */
2621
2622	/* This just calls nsmb_dev_load */
2623	SEND_EVENT(dev_netsmb, MOD_LOAD);
2624
2625	sysctl_register_oid(&sysctl__net_smb);
2626	sysctl_register_oid(&sysctl__net_smb_fs);
2627
2628	sysctl_register_oid(&sysctl__net_smb_fs_version);
2629	sysctl_register_oid(&sysctl__net_smb_fs_loglevel);
2630
2631	sysctl_register_oid(&sysctl__net_smb_fs_kern_deadtimer);
2632	sysctl_register_oid(&sysctl__net_smb_fs_kern_hard_deadtimer);
2633	sysctl_register_oid(&sysctl__net_smb_fs_kern_soft_deadtimer);
2634
2635	sysctl_register_oid(&sysctl__net_smb_fs_tcpsndbuf);
2636	sysctl_register_oid(&sysctl__net_smb_fs_tcprcvbuf);
2637
2638	sysctl_register_oid(&sysctl__net_smb_fs_maxwrite);
2639	sysctl_register_oid(&sysctl__net_smb_fs_maxread);
2640
2641	sysctl_register_oid(&sysctl__net_smb_fs_maxsegreadsize);
2642	sysctl_register_oid(&sysctl__net_smb_fs_maxsegwritesize);
2643
2644	smbfs_install_sleep_wake_notifier();
2645
2646out:
2647	return (error ? KERN_FAILURE : KERN_SUCCESS);
2648}
2649
2650
2651int smbfs_module_stop(kmod_info_t *ki, void *data)
2652{
2653#pragma unused(ki)
2654#pragma unused(data)
2655	int error;
2656
2657	/*
2658	 * The dev_rw_lck lock is global value and protects the dev_open_cnt,
2659	 * unloadInProgress flag, the device opens, closes, loads and unloads. All device
2660	 * opens and close are serialize, so we only have one happening at any time.
2661	 */
2662	lck_rw_lock_exclusive(dev_rw_lck);
2663	unloadInProgress = TRUE;
2664	/* We are still in use, don't unload. */
2665	if (mount_cnt || dev_open_cnt) {
2666		SMBWARNING("Still in use, we have %d volumes mounted and %d devices opened\n",
2667				   mount_cnt, dev_open_cnt);
2668		unloadInProgress = FALSE;
2669		lck_rw_unlock_exclusive(dev_rw_lck);
2670		return KERN_NO_ACCESS;
2671	}
2672	lck_rw_unlock_exclusive(dev_rw_lck);
2673	error = vfs_fsremove(smbfs_vfsconf);
2674	if (error) {
2675		/* Should never happen */
2676		SMBERROR("vfs_fsremove failed with %d, may want to reboot!\n", error);
2677		goto out;
2678	}
2679	sysctl_unregister_oid(&sysctl__net_smb_fs_maxsegreadsize);
2680	sysctl_unregister_oid(&sysctl__net_smb_fs_maxsegwritesize);
2681
2682	sysctl_unregister_oid(&sysctl__net_smb_fs_maxwrite);
2683	sysctl_unregister_oid(&sysctl__net_smb_fs_maxread);
2684
2685	sysctl_unregister_oid(&sysctl__net_smb_fs_tcpsndbuf);
2686	sysctl_unregister_oid(&sysctl__net_smb_fs_tcprcvbuf);
2687
2688	sysctl_unregister_oid(&sysctl__net_smb_fs_kern_deadtimer);
2689	sysctl_unregister_oid(&sysctl__net_smb_fs_kern_hard_deadtimer);
2690	sysctl_unregister_oid(&sysctl__net_smb_fs_kern_soft_deadtimer);
2691
2692	sysctl_unregister_oid(&sysctl__net_smb_fs_version);
2693	sysctl_unregister_oid(&sysctl__net_smb_fs_loglevel);
2694
2695	sysctl_unregister_oid(&sysctl__net_smb_fs);
2696	sysctl_unregister_oid(&sysctl__net_smb);
2697
2698	/* This just calls nsmb_dev_load */
2699	SEND_EVENT(dev_netsmb, MOD_UNLOAD);
2700
2701	smbfs_remove_sleep_wake_notifier();
2702
2703	lck_rw_free(dev_rw_lck, dev_lck_grp);
2704	smbfs_lock_uninit();	/* Free up the file system locks */
2705	smbnet_lock_uninit();	/* Free up the network locks */
2706
2707out:
2708	return (error ? KERN_FAILURE : KERN_SUCCESS);
2709}
2710