1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T. 27 * All rights reserved. 28 */ 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/thread.h> 33 #include <sys/t_lock.h> 34 #include <sys/time.h> 35 #include <sys/vnode.h> 36 #include <sys/vfs.h> 37 #include <sys/errno.h> 38 #include <sys/buf.h> 39 #include <sys/stat.h> 40 #include <sys/cred.h> 41 #include <sys/kmem.h> 42 #include <sys/debug.h> 43 #include <sys/dnlc.h> 44 #include <sys/vmsystm.h> 45 #include <sys/flock.h> 46 #include <sys/share.h> 47 #include <sys/cmn_err.h> 48 #include <sys/tiuser.h> 49 #include <sys/sysmacros.h> 50 #include <sys/callb.h> 51 #include <sys/acl.h> 52 #include <sys/kstat.h> 53 #include <sys/signal.h> 54 #include <sys/list.h> 55 #include <sys/zone.h> 56 57 #include <netsmb/smb_conn.h> 58 59 #include <smbfs/smbfs.h> 60 #include <smbfs/smbfs_node.h> 61 #include <smbfs/smbfs_subr.h> 62 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> 70 71 /* 72 * The following code provide zone support in order to perform an action 73 * for each smbfs mount in a zone. This is also where we would add 74 * per-zone globals and kernel threads for the smbfs module (since 75 * they must be terminated by the shutdown callback). 76 */ 77 78 struct smi_globals { 79 kmutex_t smg_lock; /* lock protecting smg_list */ 80 list_t smg_list; /* list of SMBFS mounts in zone */ 81 boolean_t smg_destructor_called; 82 }; 83 typedef struct smi_globals smi_globals_t; 84 85 static zone_key_t smi_list_key; 86 87 /* ARGSUSED */ 88 static void * 89 smbfs_zone_init(zoneid_t zoneid) 90 { 91 smi_globals_t *smg; 92 93 smg = kmem_alloc(sizeof (*smg), KM_SLEEP); 94 mutex_init(&smg->smg_lock, NULL, MUTEX_DEFAULT, NULL); 95 list_create(&smg->smg_list, sizeof (smbmntinfo_t), 96 offsetof(smbmntinfo_t, smi_zone_node)); 97 smg->smg_destructor_called = B_FALSE; 98 return (smg); 99 } 100 101 /* 102 * Callback routine to tell all SMBFS mounts in the zone to stop creating new 103 * threads. Existing threads should exit. 104 */ 105 /* ARGSUSED */ 106 static void 107 smbfs_zone_shutdown(zoneid_t zoneid, void *data) 108 { 109 smi_globals_t *smg = data; 110 smbmntinfo_t *smi; 111 112 ASSERT(smg != NULL); 113 again: 114 mutex_enter(&smg->smg_lock); 115 for (smi = list_head(&smg->smg_list); smi != NULL; 116 smi = list_next(&smg->smg_list, smi)) { 117 118 /* 119 * If we've done the shutdown work for this FS, skip. 120 * Once we go off the end of the list, we're done. 121 */ 122 if (smi->smi_flags & SMI_DEAD) 123 continue; 124 125 /* 126 * We will do work, so not done. Get a hold on the FS. 127 */ 128 VFS_HOLD(smi->smi_vfsp); 129 130 /* 131 * purge the DNLC for this filesystem 132 */ 133 (void) dnlc_purge_vfsp(smi->smi_vfsp, 0); 134 135 mutex_enter(&smi->smi_lock); 136 smi->smi_flags |= SMI_DEAD; 137 mutex_exit(&smi->smi_lock); 138 139 /* 140 * Drop lock and release FS, which may change list, then repeat. 141 * We're done when every mi has been done or the list is empty. 142 */ 143 mutex_exit(&smg->smg_lock); 144 VFS_RELE(smi->smi_vfsp); 145 goto again; 146 } 147 mutex_exit(&smg->smg_lock); 148 } 149 150 static void 151 smbfs_zone_free_globals(smi_globals_t *smg) 152 { 153 list_destroy(&smg->smg_list); /* makes sure the list is empty */ 154 mutex_destroy(&smg->smg_lock); 155 kmem_free(smg, sizeof (*smg)); 156 157 } 158 159 /* ARGSUSED */ 160 static void 161 smbfs_zone_destroy(zoneid_t zoneid, void *data) 162 { 163 smi_globals_t *smg = data; 164 165 ASSERT(smg != NULL); 166 mutex_enter(&smg->smg_lock); 167 if (list_head(&smg->smg_list) != NULL) { 168 /* Still waiting for VFS_FREEVFS() */ 169 smg->smg_destructor_called = B_TRUE; 170 mutex_exit(&smg->smg_lock); 171 return; 172 } 173 smbfs_zone_free_globals(smg); 174 } 175 176 /* 177 * Add an SMBFS mount to the per-zone list of SMBFS mounts. 178 */ 179 void 180 smbfs_zonelist_add(smbmntinfo_t *smi) 181 { 182 smi_globals_t *smg; 183 184 smg = zone_getspecific(smi_list_key, smi->smi_zone); 185 mutex_enter(&smg->smg_lock); 186 list_insert_head(&smg->smg_list, smi); 187 mutex_exit(&smg->smg_lock); 188 } 189 190 /* 191 * Remove an SMBFS mount from the per-zone list of SMBFS mounts. 192 */ 193 void 194 smbfs_zonelist_remove(smbmntinfo_t *smi) 195 { 196 smi_globals_t *smg; 197 198 smg = zone_getspecific(smi_list_key, smi->smi_zone); 199 mutex_enter(&smg->smg_lock); 200 list_remove(&smg->smg_list, smi); 201 /* 202 * We can be called asynchronously by VFS_FREEVFS() after the zone 203 * shutdown/destroy callbacks have executed; if so, clean up the zone's 204 * smi_globals. 205 */ 206 if (list_head(&smg->smg_list) == NULL && 207 smg->smg_destructor_called == B_TRUE) { 208 smbfs_zone_free_globals(smg); 209 return; 210 } 211 mutex_exit(&smg->smg_lock); 212 } 213 214 #ifdef lint 215 #define NEED_SMBFS_CALLBACKS 1 216 #endif 217 218 #ifdef NEED_SMBFS_CALLBACKS 219 /* 220 * Call-back hooks for netsmb, in case we want them. 221 * Apple's VFS wants them. We may not need them. 222 */ 223 /*ARGSUSED*/ 224 static void smbfs_dead(smb_share_t *ssp) 225 { 226 /* 227 * Walk the mount list, finding all mounts 228 * using this share... 229 */ 230 } 231 232 /*ARGSUSED*/ 233 static void smbfs_cb_nop(smb_share_t *ss) 234 { 235 /* no-op */ 236 } 237 238 smb_fscb_t smbfs_cb = { 239 .fscb_disconn = smbfs_dead, 240 .fscb_connect = smbfs_cb_nop, 241 .fscb_down = smbfs_cb_nop, 242 .fscb_up = smbfs_cb_nop }; 243 244 #endif /* NEED_SMBFS_CALLBACKS */ 245 246 /* 247 * SMBFS Client initialization routine. This routine should only be called 248 * once. It performs the following tasks: 249 * - Initalize all global locks 250 * - Call sub-initialization routines (localize access to variables) 251 */ 252 int 253 smbfs_clntinit(void) 254 { 255 int error; 256 257 error = smbfs_subrinit(); 258 if (error) 259 return (error); 260 zone_key_create(&smi_list_key, smbfs_zone_init, smbfs_zone_shutdown, 261 smbfs_zone_destroy); 262 #ifdef NEED_SMBFS_CALLBACKS 263 smb_fscb_set(&smbfs_cb); 264 #endif /* NEED_SMBFS_CALLBACKS */ 265 return (0); 266 } 267 268 /* 269 * This routine is called when the modunload is called. This will cleanup 270 * the previously allocated/initialized nodes. 271 */ 272 void 273 smbfs_clntfini(void) 274 { 275 #ifdef NEED_SMBFS_CALLBACKS 276 smb_fscb_set(NULL); 277 #endif /* NEED_SMBFS_CALLBACKS */ 278 (void) zone_key_delete(smi_list_key); 279 smbfs_subrfini(); 280 } 281