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