Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / fs / smbclnt / smbfs / smbfs_client.c
blobe02d84942aaba48f623fc312fb9cb5d8614b1bf1
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
25 * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
26 * All rights reserved.
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/thread.h>
32 #include <sys/t_lock.h>
33 #include <sys/time.h>
34 #include <sys/vnode.h>
35 #include <sys/vfs.h>
36 #include <sys/errno.h>
37 #include <sys/buf.h>
38 #include <sys/stat.h>
39 #include <sys/cred.h>
40 #include <sys/kmem.h>
41 #include <sys/debug.h>
42 #include <sys/vmsystm.h>
43 #include <sys/flock.h>
44 #include <sys/share.h>
45 #include <sys/cmn_err.h>
46 #include <sys/tiuser.h>
47 #include <sys/sysmacros.h>
48 #include <sys/callb.h>
49 #include <sys/acl.h>
50 #include <sys/kstat.h>
51 #include <sys/signal.h>
52 #include <sys/list.h>
53 #include <sys/zone.h>
55 #include <netsmb/smb.h>
56 #include <netsmb/smb_conn.h>
57 #include <netsmb/smb_subr.h>
59 #include <smbfs/smbfs.h>
60 #include <smbfs/smbfs_node.h>
61 #include <smbfs/smbfs_subr.h>
63 #include <vm/hat.h>
64 #include <vm/as.h>
65 #include <vm/page.h>
66 #include <vm/pvn.h>
67 #include <vm/seg.h>
68 #include <vm/seg_map.h>
69 #include <vm/seg_vn.h>
71 #define ATTRCACHE_VALID(vp) (gethrtime() < VTOSMB(vp)->r_attrtime)
73 static int smbfs_getattr_cache(vnode_t *, smbfattr_t *);
74 static void smbfattr_to_vattr(vnode_t *, smbfattr_t *, vattr_t *);
75 static void smbfattr_to_xvattr(smbfattr_t *, vattr_t *);
76 static int smbfs_getattr_otw(vnode_t *, struct smbfattr *, cred_t *);
80 * The following code provide zone support in order to perform an action
81 * for each smbfs mount in a zone. This is also where we would add
82 * per-zone globals and kernel threads for the smbfs module (since
83 * they must be terminated by the shutdown callback).
86 struct smi_globals {
87 kmutex_t smg_lock; /* lock protecting smg_list */
88 list_t smg_list; /* list of SMBFS mounts in zone */
89 boolean_t smg_destructor_called;
91 typedef struct smi_globals smi_globals_t;
93 static zone_key_t smi_list_key;
96 * Attributes caching:
98 * Attributes are cached in the smbnode in struct vattr form.
99 * There is a time associated with the cached attributes (r_attrtime)
100 * which tells whether the attributes are valid. The time is initialized
101 * to the difference between current time and the modify time of the vnode
102 * when new attributes are cached. This allows the attributes for
103 * files that have changed recently to be timed out sooner than for files
104 * that have not changed for a long time. There are minimum and maximum
105 * timeout values that can be set per mount point.
109 * Helper for _validate_caches
112 smbfs_waitfor_purge_complete(vnode_t *vp)
114 smbnode_t *np;
115 k_sigset_t smask;
117 np = VTOSMB(vp);
118 if (np->r_serial != NULL && np->r_serial != curthread) {
119 mutex_enter(&np->r_statelock);
120 sigintr(&smask, VTOSMI(vp)->smi_flags & SMI_INT);
121 while (np->r_serial != NULL) {
122 if (!cv_wait_sig(&np->r_cv, &np->r_statelock)) {
123 sigunintr(&smask);
124 mutex_exit(&np->r_statelock);
125 return (EINTR);
128 sigunintr(&smask);
129 mutex_exit(&np->r_statelock);
131 return (0);
135 * Validate caches by checking cached attributes. If the cached
136 * attributes have timed out, then get new attributes from the server.
137 * As a side affect, this will do cache invalidation if the attributes
138 * have changed.
140 * If the attributes have not timed out and if there is a cache
141 * invalidation being done by some other thread, then wait until that
142 * thread has completed the cache invalidation.
145 smbfs_validate_caches(
146 struct vnode *vp,
147 cred_t *cr)
149 struct smbfattr fa;
150 int error;
152 if (ATTRCACHE_VALID(vp)) {
153 error = smbfs_waitfor_purge_complete(vp);
154 if (error)
155 return (error);
156 return (0);
159 return (smbfs_getattr_otw(vp, &fa, cr));
163 * Purge all of the various data caches.
165 * Here NFS also had a flags arg to control what gets flushed.
166 * We only have the page cache, so no flags arg.
168 /* ARGSUSED */
169 void
170 smbfs_purge_caches(struct vnode *vp, cred_t *cr)
174 * Here NFS has: Purge the DNLC for this vp,
175 * Clear any readdir state bits,
176 * the readlink response cache, ...
180 * Flush the page cache.
182 if (vn_has_cached_data(vp)) {
183 (void) fop_putpage(vp, 0, 0, B_INVAL, cr, NULL);
187 * Here NFS has: Flush the readdir response cache.
188 * No readdir cache in smbfs.
193 * Here NFS has:
194 * nfs_purge_rddir_cache()
195 * nfs3_cache_post_op_attr()
196 * nfs3_cache_post_op_vattr()
197 * nfs3_cache_wcc_data()
201 * Check the attribute cache to see if the new attributes match
202 * those cached. If they do, the various `data' caches are
203 * considered to be good. Otherwise, purge the cached data.
205 static void
206 smbfs_cache_check(
207 struct vnode *vp,
208 struct smbfattr *fap,
209 cred_t *cr)
211 smbnode_t *np;
212 int purge_data = 0;
213 int purge_acl = 0;
215 np = VTOSMB(vp);
216 mutex_enter(&np->r_statelock);
219 * Compare with NFS macro: CACHE_VALID
220 * If the mtime or size has changed,
221 * purge cached data.
223 if (np->r_attr.fa_mtime.tv_sec != fap->fa_mtime.tv_sec ||
224 np->r_attr.fa_mtime.tv_nsec != fap->fa_mtime.tv_nsec)
225 purge_data = 1;
226 if (np->r_attr.fa_size != fap->fa_size)
227 purge_data = 1;
229 if (np->r_attr.fa_ctime.tv_sec != fap->fa_ctime.tv_sec ||
230 np->r_attr.fa_ctime.tv_nsec != fap->fa_ctime.tv_nsec)
231 purge_acl = 1;
233 if (purge_acl) {
234 np->r_sectime = gethrtime();
237 mutex_exit(&np->r_statelock);
239 if (purge_data)
240 smbfs_purge_caches(vp, cr);
244 * Set attributes cache for given vnode using SMB fattr
245 * and update the attribute cache timeout.
247 * Based on NFS: nfs_attrcache, nfs_attrcache_va
249 void
250 smbfs_attrcache_fa(vnode_t *vp, struct smbfattr *fap)
252 smbnode_t *np;
253 smbmntinfo_t *smi;
254 hrtime_t delta, now;
255 uoff_t newsize;
256 vtype_t vtype, oldvt;
257 mode_t mode;
259 np = VTOSMB(vp);
260 smi = VTOSMI(vp);
263 * We allow v_type to change, so set that here
264 * (and the mode, which depends on the type).
266 if (fap->fa_attr & SMB_FA_DIR) {
267 vtype = VDIR;
268 mode = smi->smi_dmode;
269 } else {
270 vtype = VREG;
271 mode = smi->smi_fmode;
274 mutex_enter(&np->r_statelock);
275 now = gethrtime();
278 * Delta is the number of nanoseconds that we will
279 * cache the attributes of the file. It is based on
280 * the number of nanoseconds since the last time that
281 * we detected a change. The assumption is that files
282 * that changed recently are likely to change again.
283 * There is a minimum and a maximum for regular files
284 * and for directories which is enforced though.
286 * Using the time since last change was detected
287 * eliminates direct comparison or calculation
288 * using mixed client and server times. SMBFS
289 * does not make any assumptions regarding the
290 * client and server clocks being synchronized.
292 if (fap->fa_mtime.tv_sec != np->r_attr.fa_mtime.tv_sec ||
293 fap->fa_mtime.tv_nsec != np->r_attr.fa_mtime.tv_nsec ||
294 fap->fa_size != np->r_attr.fa_size)
295 np->r_mtime = now;
297 if ((smi->smi_flags & SMI_NOAC) || (vp->v_flag & VNOCACHE))
298 delta = 0;
299 else {
300 delta = now - np->r_mtime;
301 if (vtype == VDIR) {
302 if (delta < smi->smi_acdirmin)
303 delta = smi->smi_acdirmin;
304 else if (delta > smi->smi_acdirmax)
305 delta = smi->smi_acdirmax;
306 } else {
307 if (delta < smi->smi_acregmin)
308 delta = smi->smi_acregmin;
309 else if (delta > smi->smi_acregmax)
310 delta = smi->smi_acregmax;
314 np->r_attrtime = now + delta;
315 np->r_attr = *fap;
316 np->n_mode = mode;
317 oldvt = vp->v_type;
318 vp->v_type = vtype;
321 * Shall we update r_size? (local notion of size)
323 * The real criteria for updating r_size should be:
324 * if the file has grown on the server, or if
325 * the client has not modified the file.
327 * Also deal with the fact that SMB presents
328 * directories as having size=0. Doing that
329 * here and leaving fa_size as returned OtW
330 * avoids fixing the size lots of places.
332 newsize = fap->fa_size;
333 if (vtype == VDIR && newsize < DEV_BSIZE)
334 newsize = DEV_BSIZE;
336 if (np->r_size != newsize &&
337 (!vn_has_cached_data(vp) ||
338 (!(np->r_flags & RDIRTY) && np->r_count == 0))) {
339 /* OK to set the size. */
340 np->r_size = newsize;
344 * Here NFS has:
345 * nfs_setswaplike(vp, va);
346 * np->r_flags &= ~RWRITEATTR;
347 * (not needed here)
350 np->n_flag &= ~NATTRCHANGED;
351 mutex_exit(&np->r_statelock);
353 if (oldvt != vtype) {
354 SMBVDEBUG("vtype change %d to %d\n", oldvt, vtype);
359 * Fill in attribute from the cache.
361 * If valid, copy to *fap and return zero,
362 * otherwise return an error.
364 * From NFS: nfs_getattr_cache()
367 smbfs_getattr_cache(vnode_t *vp, struct smbfattr *fap)
369 smbnode_t *np;
370 int error;
372 np = VTOSMB(vp);
374 mutex_enter(&np->r_statelock);
375 if (gethrtime() >= np->r_attrtime) {
376 /* cache expired */
377 error = ENOENT;
378 } else {
379 /* cache is valid */
380 *fap = np->r_attr;
381 error = 0;
383 mutex_exit(&np->r_statelock);
385 return (error);
389 * Get attributes over-the-wire and update attributes cache
390 * if no error occurred in the over-the-wire operation.
391 * Return 0 if successful, otherwise error.
392 * From NFS: nfs_getattr_otw
394 static int
395 smbfs_getattr_otw(vnode_t *vp, struct smbfattr *fap, cred_t *cr)
397 struct smbnode *np;
398 struct smb_cred scred;
399 int error;
401 np = VTOSMB(vp);
404 * Here NFS uses the ACL RPC (if smi_flags & SMI_ACL)
405 * With SMB, getting the ACL is a significantly more
406 * expensive operation, so we do that only when asked
407 * for the uid/gid. See smbfsgetattr().
410 /* Shared lock for (possible) n_fid use. */
411 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
412 return (EINTR);
413 smb_credinit(&scred, cr);
415 bzero(fap, sizeof (*fap));
416 error = smbfs_smb_getfattr(np, fap, &scred);
418 smb_credrele(&scred);
419 smbfs_rw_exit(&np->r_lkserlock);
421 if (error) {
422 /* Here NFS has: PURGE_STALE_FH(error, vp, cr) */
423 smbfs_attrcache_remove(np);
424 if (error == ENOENT || error == ENOTDIR) {
426 * Getattr failed because the object was
427 * removed or renamed by another client.
428 * Remove any cached attributes under it.
430 smbfs_attrcache_prune(np);
432 return (error);
436 * Here NFS has: nfs_cache_fattr(vap, fa, vap, t, cr);
437 * which did: fattr_to_vattr, nfs_attr_cache.
438 * We cache the fattr form, so just do the
439 * cache check and store the attributes.
441 smbfs_cache_check(vp, fap, cr);
442 smbfs_attrcache_fa(vp, fap);
444 return (0);
448 * Return either cached or remote attributes. If we get remote attrs,
449 * use them to check and invalidate caches, then cache the new attributes.
451 * From NFS: nfsgetattr()
454 smbfsgetattr(vnode_t *vp, struct vattr *vap, cred_t *cr)
456 struct smbfattr fa;
457 smbmntinfo_t *smi;
458 uint_t mask;
459 int error;
461 smi = VTOSMI(vp);
463 ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone);
466 * If asked for UID or GID, update n_uid, n_gid.
468 mask = VATTR_ALL;
469 if (vap->va_mask & (VATTR_UID | VATTR_GID)) {
470 if (smi->smi_flags & SMI_ACL)
471 (void) smbfs_acl_getids(vp, cr);
472 /* else leave as set in make_smbnode */
473 } else {
474 mask &= ~(VATTR_UID | VATTR_GID);
478 * If we've got cached attributes, just use them;
479 * otherwise go to the server to get attributes,
480 * which will update the cache in the process.
482 error = smbfs_getattr_cache(vp, &fa);
483 if (error)
484 error = smbfs_getattr_otw(vp, &fa, cr);
485 if (error)
486 return (error);
487 vap->va_mask |= mask;
490 * Re. client's view of the file size, see:
491 * smbfs_attrcache_fa, smbfs_getattr_otw
493 smbfattr_to_vattr(vp, &fa, vap);
494 if (vap->va_mask & VATTR_XVATTR)
495 smbfattr_to_xvattr(&fa, vap);
497 return (0);
502 * Convert SMB over the wire attributes to vnode form.
503 * Returns 0 for success, error if failed (overflow, etc).
504 * From NFS: nattr_to_vattr()
506 void
507 smbfattr_to_vattr(vnode_t *vp, struct smbfattr *fa, struct vattr *vap)
509 struct smbnode *np = VTOSMB(vp);
512 * Take type, mode, uid, gid from the smbfs node,
513 * which has have been updated by _getattr_otw.
515 vap->va_type = vp->v_type;
516 vap->va_mode = np->n_mode;
518 vap->va_uid = np->n_uid;
519 vap->va_gid = np->n_gid;
521 vap->va_fsid = vp->v_vfsp->vfs_dev;
522 vap->va_nodeid = np->n_ino;
523 vap->va_nlink = 1;
526 * Difference from NFS here: We cache attributes as
527 * reported by the server, so r_attr.fa_size is the
528 * server's idea of the file size. This is called
529 * for getattr, so we want to return the client's
530 * idea of the file size. NFS deals with that in
531 * nfsgetattr(), the equivalent of our caller.
533 vap->va_size = np->r_size;
536 * Times. Note, already converted from NT to
537 * Unix form (in the unmarshalling code).
539 vap->va_atime = fa->fa_atime;
540 vap->va_mtime = fa->fa_mtime;
541 vap->va_ctime = fa->fa_ctime;
544 * rdev, blksize, seq are made up.
545 * va_nblocks is 512 byte blocks.
547 vap->va_rdev = vp->v_rdev;
548 vap->va_blksize = MAXBSIZE;
549 vap->va_nblocks = (fsblkcnt64_t)btod(np->r_attr.fa_allocsz);
550 vap->va_seq = 0;
554 * smbfattr_to_xvattr: like smbfattr_to_vattr but for
555 * Extensible system attributes (PSARC 2007/315)
557 static void
558 smbfattr_to_xvattr(struct smbfattr *fa, struct vattr *vap)
560 xvattr_t *xvap = (xvattr_t *)vap; /* *vap may be xvattr_t */
561 xoptattr_t *xoap = NULL;
563 if ((xoap = xva_getxoptattr(xvap)) == NULL)
564 return;
566 if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) {
567 xoap->xoa_createtime = fa->fa_createtime;
568 XVA_SET_RTN(xvap, XAT_CREATETIME);
571 if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) {
572 xoap->xoa_archive =
573 ((fa->fa_attr & SMB_FA_ARCHIVE) != 0);
574 XVA_SET_RTN(xvap, XAT_ARCHIVE);
577 if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) {
578 xoap->xoa_system =
579 ((fa->fa_attr & SMB_FA_SYSTEM) != 0);
580 XVA_SET_RTN(xvap, XAT_SYSTEM);
583 if (XVA_ISSET_REQ(xvap, XAT_READONLY)) {
584 xoap->xoa_readonly =
585 ((fa->fa_attr & SMB_FA_RDONLY) != 0);
586 XVA_SET_RTN(xvap, XAT_READONLY);
589 if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) {
590 xoap->xoa_hidden =
591 ((fa->fa_attr & SMB_FA_HIDDEN) != 0);
592 XVA_SET_RTN(xvap, XAT_HIDDEN);
597 * Here NFS has:
598 * nfs_async_... stuff
599 * which we're not using (no async I/O), and:
600 * writerp(),
601 * nfs_putpages()
602 * nfs_invalidate_pages()
603 * which we have in smbfs_vnops.c, and
604 * nfs_printfhandle()
605 * nfs_write_error()
606 * not needed here.
610 * Helper function for smbfs_sync
612 * Walk the per-zone list of smbfs mounts, calling smbfs_rflush
613 * on each one. This is a little tricky because we need to exit
614 * the list mutex before each _rflush call and then try to resume
615 * where we were in the list after re-entering the mutex.
617 void
618 smbfs_flushall(cred_t *cr)
620 smi_globals_t *smg;
621 smbmntinfo_t *tmp_smi, *cur_smi, *next_smi;
623 smg = zone_getspecific(smi_list_key, crgetzone(cr));
624 ASSERT(smg != NULL);
626 mutex_enter(&smg->smg_lock);
627 cur_smi = list_head(&smg->smg_list);
628 if (cur_smi == NULL) {
629 mutex_exit(&smg->smg_lock);
630 return;
632 VFS_HOLD(cur_smi->smi_vfsp);
633 mutex_exit(&smg->smg_lock);
635 flush:
636 smbfs_rflush(cur_smi->smi_vfsp, cr);
638 mutex_enter(&smg->smg_lock);
640 * Resume after cur_smi if that's still on the list,
641 * otherwise restart at the head.
643 for (tmp_smi = list_head(&smg->smg_list);
644 tmp_smi != NULL;
645 tmp_smi = list_next(&smg->smg_list, tmp_smi))
646 if (tmp_smi == cur_smi)
647 break;
648 if (tmp_smi != NULL)
649 next_smi = list_next(&smg->smg_list, tmp_smi);
650 else
651 next_smi = list_head(&smg->smg_list);
653 if (next_smi != NULL)
654 VFS_HOLD(next_smi->smi_vfsp);
655 VFS_RELE(cur_smi->smi_vfsp);
657 mutex_exit(&smg->smg_lock);
659 if (next_smi != NULL) {
660 cur_smi = next_smi;
661 goto flush;
666 * SMB Client initialization and cleanup.
667 * Much of it is per-zone now.
671 /* ARGSUSED */
672 static void *
673 smbfs_zone_init(zoneid_t zoneid)
675 smi_globals_t *smg;
677 smg = kmem_alloc(sizeof (*smg), KM_SLEEP);
678 mutex_init(&smg->smg_lock, NULL, MUTEX_DEFAULT, NULL);
679 list_create(&smg->smg_list, sizeof (smbmntinfo_t),
680 offsetof(smbmntinfo_t, smi_zone_node));
681 smg->smg_destructor_called = B_FALSE;
682 return (smg);
686 * Callback routine to tell all SMBFS mounts in the zone to stop creating new
687 * threads. Existing threads should exit.
689 /* ARGSUSED */
690 static void
691 smbfs_zone_shutdown(zoneid_t zoneid, void *data)
693 smi_globals_t *smg = data;
694 smbmntinfo_t *smi;
696 ASSERT(smg != NULL);
697 again:
698 mutex_enter(&smg->smg_lock);
699 for (smi = list_head(&smg->smg_list); smi != NULL;
700 smi = list_next(&smg->smg_list, smi)) {
703 * If we've done the shutdown work for this FS, skip.
704 * Once we go off the end of the list, we're done.
706 if (smi->smi_flags & SMI_DEAD)
707 continue;
710 * We will do work, so not done. Get a hold on the FS.
712 VFS_HOLD(smi->smi_vfsp);
714 mutex_enter(&smi->smi_lock);
715 smi->smi_flags |= SMI_DEAD;
716 mutex_exit(&smi->smi_lock);
719 * Drop lock and release FS, which may change list, then repeat.
720 * We're done when every mi has been done or the list is empty.
722 mutex_exit(&smg->smg_lock);
723 VFS_RELE(smi->smi_vfsp);
724 goto again;
726 mutex_exit(&smg->smg_lock);
729 static void
730 smbfs_zone_free_globals(smi_globals_t *smg)
732 list_destroy(&smg->smg_list); /* makes sure the list is empty */
733 mutex_destroy(&smg->smg_lock);
734 kmem_free(smg, sizeof (*smg));
738 /* ARGSUSED */
739 static void
740 smbfs_zone_destroy(zoneid_t zoneid, void *data)
742 smi_globals_t *smg = data;
744 ASSERT(smg != NULL);
745 mutex_enter(&smg->smg_lock);
746 if (list_head(&smg->smg_list) != NULL) {
747 /* Still waiting for VFS_FREEVFS() */
748 smg->smg_destructor_called = B_TRUE;
749 mutex_exit(&smg->smg_lock);
750 return;
752 smbfs_zone_free_globals(smg);
756 * Add an SMBFS mount to the per-zone list of SMBFS mounts.
758 void
759 smbfs_zonelist_add(smbmntinfo_t *smi)
761 smi_globals_t *smg;
763 smg = zone_getspecific(smi_list_key, smi->smi_zone_ref.zref_zone);
764 mutex_enter(&smg->smg_lock);
765 list_insert_head(&smg->smg_list, smi);
766 mutex_exit(&smg->smg_lock);
770 * Remove an SMBFS mount from the per-zone list of SMBFS mounts.
772 void
773 smbfs_zonelist_remove(smbmntinfo_t *smi)
775 smi_globals_t *smg;
777 smg = zone_getspecific(smi_list_key, smi->smi_zone_ref.zref_zone);
778 mutex_enter(&smg->smg_lock);
779 list_remove(&smg->smg_list, smi);
781 * We can be called asynchronously by VFS_FREEVFS() after the zone
782 * shutdown/destroy callbacks have executed; if so, clean up the zone's
783 * smi_globals.
785 if (list_head(&smg->smg_list) == NULL &&
786 smg->smg_destructor_called == B_TRUE) {
787 smbfs_zone_free_globals(smg);
788 return;
790 mutex_exit(&smg->smg_lock);
794 #ifdef NEED_SMBFS_CALLBACKS
796 * Call-back hooks for netsmb, in case we want them.
797 * Apple's VFS wants them. We may not need them.
799 /*ARGSUSED*/
800 static void smbfs_dead(smb_share_t *ssp)
803 * Walk the mount list, finding all mounts
804 * using this share...
808 /*ARGSUSED*/
809 static void smbfs_cb_nop(smb_share_t *ss)
811 /* no-op */
814 smb_fscb_t smbfs_cb = {
815 .fscb_disconn = smbfs_dead,
816 .fscb_connect = smbfs_cb_nop,
817 .fscb_down = smbfs_cb_nop,
818 .fscb_up = smbfs_cb_nop };
820 #endif /* NEED_SMBFS_CALLBACKS */
823 * SMBFS Client initialization routine. This routine should only be called
824 * once. It performs the following tasks:
825 * - Initalize all global locks
826 * - Call sub-initialization routines (localize access to variables)
829 smbfs_clntinit(void)
832 zone_key_create(&smi_list_key, smbfs_zone_init, smbfs_zone_shutdown,
833 smbfs_zone_destroy);
834 #ifdef NEED_SMBFS_CALLBACKS
835 (void) smb_fscb_set(&smbfs_cb);
836 #endif /* NEED_SMBFS_CALLBACKS */
837 return (0);
841 * This routine is called when the modunload is called. This will cleanup
842 * the previously allocated/initialized nodes.
844 void
845 smbfs_clntfini(void)
847 #ifdef NEED_SMBFS_CALLBACKS
848 (void) smb_fscb_set(NULL);
849 #endif /* NEED_SMBFS_CALLBACKS */
850 (void) zone_key_delete(smi_list_key);