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