Print this page
NEX-17095 illumos 8935 SMB ioctl fixes incomplete
8935 SMB ioctl fixes incomplete
Reviewed by: Alex Wilson <alex.wilson@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Rui Loura <rui.loura@joyent.com>
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Dominik Hassler <hasslerd@gmx.li>
Approved by: Garrett D'Amore <garrett@damore.org>
NEX-15958 panic importing CA share after failover
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Include in backports of:
NEX-9808 SMB3 persistent handles
NEX-15958 panic importing CA share after failover
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Include in backports of:
NEX-9808 SMB3 persistent handles
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-5273 SMB 3 Encryption
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-7490 read_kstat_data panic in smb_named_kstat_update
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexent.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-6308 namespace collision for per-share kstats when changing sharesmb property
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-6266 SMB kstats namespace collision for share names longer than 28 characters (follow-up)
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-6266 SMB kstats namespace collision for share names longer than 28 characters
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-5175 want SMB statistics separately for reads, writes, other
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-4844 assertion failed: kshare->shr_magic == SMB_SHARE_MAGIC
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-4313 want iops, bandwidth, and latency kstats for smb
Portions contributed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-3863 Would like an SMB share property to enable/disable quotas
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
SMB-74 Process oplock breaks as session requests
SMB-50 User-mode SMB server
Includes work by these authors:
Thomas Keiser <thomas.keiser@nexenta.com>
Albert Lee <trisk@nexenta.com>
SMB-65 SMB server in non-global zones (data structure changes)
Many things move to the smb_server_t object, and
many functions gain an sv arg (which server).
SMB-65 SMB server in non-global zones (kmem_caches)
common kmem_cache instances across zones
separate GZ-only init from NGZ init
SMB-64 smbsrv workers run at excessively high priority
re #9812 rb3153 System panic'd with assertion failed: sl->sl_count == 0 in smb_slist_destructor after hostname change, smbd restart and attempts to rejoin active directory domain
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/smbsrv/smb_kshare.c
+++ new/usr/src/uts/common/fs/smbsrv/smb_kshare.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
|
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 - * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
24 + * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
25 25 * Copyright 2017 Joyent, Inc.
26 26 */
27 27
28 28 #include <smbsrv/smb_door.h>
29 -#include <smbsrv/smb_kproto.h>
30 29 #include <smbsrv/smb_ktypes.h>
30 +#include <smbsrv/smb2_kproto.h>
31 +#include <smbsrv/smb_kstat.h>
31 32
32 33 typedef struct smb_unshare {
33 34 list_node_t us_lnd;
34 35 char us_sharename[MAXNAMELEN];
35 36 } smb_unshare_t;
36 37
37 38 static kmem_cache_t *smb_kshare_cache_share;
38 39 static kmem_cache_t *smb_kshare_cache_unexport;
39 -kmem_cache_t *smb_kshare_cache_vfs;
40 40
41 41 static int smb_kshare_cmp(const void *, const void *);
42 42 static void smb_kshare_hold(const void *);
43 43 static boolean_t smb_kshare_rele(const void *);
44 44 static void smb_kshare_destroy(void *);
45 45 static char *smb_kshare_oemname(const char *);
46 46 static int smb_kshare_is_special(const char *);
47 47 static boolean_t smb_kshare_is_admin(const char *);
48 48 static smb_kshare_t *smb_kshare_decode(nvlist_t *);
49 49 static uint32_t smb_kshare_decode_bool(nvlist_t *, const char *, uint32_t);
50 50 static void smb_kshare_unexport_thread(smb_thread_t *, void *);
51 51 static int smb_kshare_export(smb_server_t *, smb_kshare_t *);
52 52 static int smb_kshare_unexport(smb_server_t *, const char *);
53 53 static int smb_kshare_export_trans(smb_server_t *, char *, char *, char *);
54 54 static void smb_kshare_csc_flags(smb_kshare_t *, const char *);
55 +static int smb_named_kstat_update(kstat_t *ks, int rw);
56 +static int smb_kshare_kstat_update(kstat_t *, int);
57 +void kshare_stats_init(smb_server_t *, smb_kshare_t *);
58 +void kshare_stats_fini(smb_kshare_t *);
55 59
56 60 static boolean_t smb_export_isready(smb_server_t *);
57 61
58 62 #ifdef _KERNEL
59 63 static int smb_kshare_chk_dsrv_status(int, smb_dr_ctx_t *);
60 64 #endif /* _KERNEL */
61 65
62 66 static const smb_avl_nops_t smb_kshare_avlops = {
63 67 smb_kshare_cmp,
64 68 smb_kshare_hold,
65 69 smb_kshare_rele,
66 70 smb_kshare_destroy
67 71 };
68 72
69 73 #ifdef _KERNEL
70 74 /*
71 75 * This function is not MultiThread safe. The caller has to make sure only one
72 76 * thread calls this function.
73 77 */
74 78 door_handle_t
75 79 smb_kshare_door_init(int door_id)
76 80 {
77 81 return (door_ki_lookup(door_id));
78 82 }
79 83
80 84 /*
81 85 * This function is not MultiThread safe. The caller has to make sure only one
82 86 * thread calls this function.
83 87 */
84 88 void
85 89 smb_kshare_door_fini(door_handle_t dhdl)
86 90 {
87 91 if (dhdl)
88 92 door_ki_rele(dhdl);
89 93 }
90 94
91 95 /*
92 96 * This is a special interface that will be utilized by ZFS to cause
93 97 * a share to be added/removed
94 98 *
95 99 * arg is either a smb_share_t or share_name from userspace.
96 100 * It will need to be copied into the kernel. It is smb_share_t
97 101 * for add operations and share_name for delete operations.
98 102 */
99 103 int
100 104 smb_kshare_upcall(door_handle_t dhdl, void *arg, boolean_t add_share)
101 105 {
102 106 door_arg_t doorarg = { 0 };
103 107 char *buf = NULL;
104 108 char *str = NULL;
105 109 int error;
106 110 int rc;
107 111 unsigned int used;
108 112 smb_dr_ctx_t *dec_ctx;
109 113 smb_dr_ctx_t *enc_ctx;
110 114 smb_share_t *lmshare = NULL;
111 115 int opcode;
112 116
113 117 opcode = (add_share) ? SMB_SHROP_ADD : SMB_SHROP_DELETE;
114 118
115 119 buf = kmem_alloc(SMB_SHARE_DSIZE, KM_SLEEP);
116 120 enc_ctx = smb_dr_encode_start(buf, SMB_SHARE_DSIZE);
117 121 smb_dr_put_uint32(enc_ctx, opcode);
118 122
119 123 switch (opcode) {
120 124 case SMB_SHROP_ADD:
121 125 lmshare = kmem_alloc(sizeof (smb_share_t), KM_SLEEP);
122 126 error = xcopyin(arg, lmshare, sizeof (smb_share_t));
123 127 if (error != 0) {
124 128 kmem_free(lmshare, sizeof (smb_share_t));
125 129 kmem_free(buf, SMB_SHARE_DSIZE);
126 130 return (error);
127 131 }
128 132 smb_dr_put_share(enc_ctx, lmshare);
129 133 break;
130 134
131 135 case SMB_SHROP_DELETE:
132 136 str = kmem_alloc(MAXPATHLEN, KM_SLEEP);
133 137 error = copyinstr(arg, str, MAXPATHLEN, NULL);
134 138 if (error != 0) {
135 139 kmem_free(str, MAXPATHLEN);
136 140 kmem_free(buf, SMB_SHARE_DSIZE);
137 141 return (error);
138 142 }
139 143 smb_dr_put_string(enc_ctx, str);
140 144 kmem_free(str, MAXPATHLEN);
141 145 break;
142 146 }
143 147
144 148 if ((error = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
145 149 kmem_free(buf, SMB_SHARE_DSIZE);
146 150 if (lmshare)
147 151 kmem_free(lmshare, sizeof (smb_share_t));
148 152 return (NERR_InternalError);
149 153 }
150 154
151 155 doorarg.data_ptr = buf;
152 156 doorarg.data_size = used;
153 157 doorarg.rbuf = buf;
154 158 doorarg.rsize = SMB_SHARE_DSIZE;
155 159
156 160 error = door_ki_upcall_limited(dhdl, &doorarg, NULL, SIZE_MAX, 0);
157 161
158 162 if (error) {
159 163 kmem_free(buf, SMB_SHARE_DSIZE);
160 164 if (lmshare)
161 165 kmem_free(lmshare, sizeof (smb_share_t));
162 166 return (error);
163 167 }
164 168
165 169 dec_ctx = smb_dr_decode_start(doorarg.data_ptr, doorarg.data_size);
166 170 if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
167 171 kmem_free(buf, SMB_SHARE_DSIZE);
168 172 if (lmshare)
169 173 kmem_free(lmshare, sizeof (smb_share_t));
170 174 return (NERR_InternalError);
171 175 }
172 176
173 177 rc = smb_dr_get_uint32(dec_ctx);
174 178 if (opcode == SMB_SHROP_ADD)
175 179 smb_dr_get_share(dec_ctx, lmshare);
176 180
177 181 if (smb_dr_decode_finish(dec_ctx))
178 182 rc = NERR_InternalError;
179 183
180 184 kmem_free(buf, SMB_SHARE_DSIZE);
181 185 if (lmshare)
182 186 kmem_free(lmshare, sizeof (smb_share_t));
183 187
184 188 return ((rc == NERR_DuplicateShare && add_share) ? 0 : rc);
185 189 }
186 190 #endif /* _KERNEL */
187 191
188 192 /*
189 193 * Executes map and unmap command for shares.
190 194 */
191 195 int
192 196 smb_kshare_exec(smb_server_t *sv, smb_shr_execinfo_t *execinfo)
193 197 {
194 198 int exec_rc = 0;
195 199
196 200 (void) smb_kdoor_upcall(sv, SMB_DR_SHR_EXEC,
197 201 execinfo, smb_shr_execinfo_xdr, &exec_rc, xdr_int);
198 202
199 203 return (exec_rc);
200 204 }
201 205
202 206 /*
203 207 * Obtains any host access restriction on the specified
204 208 * share for the given host (ipaddr) by calling smbd
205 209 */
206 210 uint32_t
207 211 smb_kshare_hostaccess(smb_kshare_t *shr, smb_session_t *session)
208 212 {
209 213 smb_shr_hostaccess_query_t req;
210 214 smb_inaddr_t *ipaddr = &session->ipaddr;
211 215 uint32_t host_access = SMB_SHRF_ACC_OPEN;
212 216 uint32_t flag = SMB_SHRF_ACC_OPEN;
213 217 uint32_t access;
214 218
215 219 if (smb_inet_iszero(ipaddr))
216 220 return (ACE_ALL_PERMS);
217 221
218 222 if ((shr->shr_access_none == NULL || *shr->shr_access_none == '\0') &&
219 223 (shr->shr_access_ro == NULL || *shr->shr_access_ro == '\0') &&
220 224 (shr->shr_access_rw == NULL || *shr->shr_access_rw == '\0'))
221 225 return (ACE_ALL_PERMS);
222 226
223 227 if (shr->shr_access_none != NULL)
224 228 flag |= SMB_SHRF_ACC_NONE;
225 229 if (shr->shr_access_ro != NULL)
226 230 flag |= SMB_SHRF_ACC_RO;
227 231 if (shr->shr_access_rw != NULL)
228 232 flag |= SMB_SHRF_ACC_RW;
229 233
230 234 req.shq_none = shr->shr_access_none;
231 235 req.shq_ro = shr->shr_access_ro;
232 236 req.shq_rw = shr->shr_access_rw;
233 237 req.shq_flag = flag;
234 238 req.shq_ipaddr = *ipaddr;
235 239
236 240 (void) smb_kdoor_upcall(session->s_server, SMB_DR_SHR_HOSTACCESS,
237 241 &req, smb_shr_hostaccess_query_xdr, &host_access, xdr_uint32_t);
238 242
239 243 switch (host_access) {
240 244 case SMB_SHRF_ACC_RO:
241 245 access = ACE_ALL_PERMS & ~ACE_ALL_WRITE_PERMS;
242 246 break;
243 247 case SMB_SHRF_ACC_OPEN:
244 248 case SMB_SHRF_ACC_RW:
245 249 access = ACE_ALL_PERMS;
246 250 break;
247 251 case SMB_SHRF_ACC_NONE:
248 252 default:
249 253 access = 0;
250 254 }
251 255
252 256 return (access);
253 257 }
254 258
255 259 /*
256 260 * This function is called when smb_server_t is
257 261 * created which means smb/service is ready for
258 262 * exporting SMB shares
259 263 */
260 264 void
261 265 smb_export_start(smb_server_t *sv)
262 266 {
263 267 mutex_enter(&sv->sv_export.e_mutex);
264 268 if (sv->sv_export.e_ready) {
265 269 mutex_exit(&sv->sv_export.e_mutex);
266 270 return;
267 271 }
268 272
269 273 sv->sv_export.e_ready = B_TRUE;
270 274 mutex_exit(&sv->sv_export.e_mutex);
271 275
272 276 smb_avl_create(&sv->sv_export.e_share_avl, sizeof (smb_kshare_t),
273 277 offsetof(smb_kshare_t, shr_link), &smb_kshare_avlops);
274 278
275 279 (void) smb_kshare_export_trans(sv, "IPC$", "IPC$", "Remote IPC");
276 280 (void) smb_kshare_export_trans(sv, "c$", SMB_CVOL, "Default Share");
277 281 (void) smb_kshare_export_trans(sv, "vss$", SMB_VSS, "VSS");
278 282 }
279 283
280 284 /*
281 285 * This function is called when smb_server_t goes
282 286 * away which means SMB shares should not be made
283 287 * available to clients
284 288 */
285 289 void
286 290 smb_export_stop(smb_server_t *sv)
|
↓ open down ↓ |
222 lines elided |
↑ open up ↑ |
287 291 {
288 292 mutex_enter(&sv->sv_export.e_mutex);
289 293 if (!sv->sv_export.e_ready) {
290 294 mutex_exit(&sv->sv_export.e_mutex);
291 295 return;
292 296 }
293 297 sv->sv_export.e_ready = B_FALSE;
294 298 mutex_exit(&sv->sv_export.e_mutex);
295 299
296 300 smb_avl_destroy(&sv->sv_export.e_share_avl);
297 - smb_vfs_rele_all(&sv->sv_export);
298 301 }
299 302
300 303 void
301 304 smb_kshare_g_init(void)
302 305 {
303 306 smb_kshare_cache_share = kmem_cache_create("smb_share_cache",
304 307 sizeof (smb_kshare_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
305 308
306 309 smb_kshare_cache_unexport = kmem_cache_create("smb_unexport_cache",
307 310 sizeof (smb_unshare_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
308 -
309 - smb_kshare_cache_vfs = kmem_cache_create("smb_vfs_cache",
310 - sizeof (smb_vfs_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
311 311 }
312 312
313 313 void
314 314 smb_kshare_init(smb_server_t *sv)
315 315 {
316 316
317 - smb_llist_constructor(&sv->sv_export.e_vfs_list, sizeof (smb_vfs_t),
318 - offsetof(smb_vfs_t, sv_lnd));
319 -
320 317 smb_slist_constructor(&sv->sv_export.e_unexport_list,
321 318 sizeof (smb_unshare_t), offsetof(smb_unshare_t, us_lnd));
322 319 }
323 320
324 321 int
325 322 smb_kshare_start(smb_server_t *sv)
326 323 {
327 324 smb_thread_init(&sv->sv_export.e_unexport_thread, "smb_kshare_unexport",
328 325 smb_kshare_unexport_thread, sv, smbsrv_base_pri);
329 326
330 327 return (smb_thread_start(&sv->sv_export.e_unexport_thread));
331 328 }
332 329
333 330 void
334 331 smb_kshare_stop(smb_server_t *sv)
335 332 {
336 333 smb_thread_stop(&sv->sv_export.e_unexport_thread);
337 334 smb_thread_destroy(&sv->sv_export.e_unexport_thread);
338 335 }
339 336
340 337 void
|
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
341 338 smb_kshare_fini(smb_server_t *sv)
342 339 {
343 340 smb_unshare_t *ux;
344 341
345 342 while ((ux = list_head(&sv->sv_export.e_unexport_list.sl_list))
346 343 != NULL) {
347 344 smb_slist_remove(&sv->sv_export.e_unexport_list, ux);
348 345 kmem_cache_free(smb_kshare_cache_unexport, ux);
349 346 }
350 347 smb_slist_destructor(&sv->sv_export.e_unexport_list);
351 -
352 - smb_vfs_rele_all(&sv->sv_export);
353 -
354 - smb_llist_destructor(&sv->sv_export.e_vfs_list);
355 348 }
356 349
357 350 void
358 351 smb_kshare_g_fini(void)
359 352 {
360 353 kmem_cache_destroy(smb_kshare_cache_unexport);
361 354 kmem_cache_destroy(smb_kshare_cache_share);
362 - kmem_cache_destroy(smb_kshare_cache_vfs);
363 355 }
364 356
365 357 /*
366 358 * A list of shares in nvlist format can be sent down
367 359 * from userspace thourgh the IOCTL interface. The nvlist
368 360 * is unpacked here and all the shares in the list will
369 361 * be exported.
370 362 */
371 363 int
372 364 smb_kshare_export_list(smb_ioc_share_t *ioc)
373 365 {
374 366 smb_server_t *sv = NULL;
375 367 nvlist_t *shrlist = NULL;
376 368 nvlist_t *share;
377 369 nvpair_t *nvp;
378 370 smb_kshare_t *shr;
379 371 char *shrname;
380 372 int rc;
381 373
382 374 if ((rc = smb_server_lookup(&sv)) != 0)
383 375 return (rc);
384 376
385 377 if (!smb_export_isready(sv)) {
386 378 rc = ENOTACTIVE;
387 379 goto out;
388 380 }
389 381
390 382 /*
391 383 * Reality check that the nvlist's reported length doesn't exceed the
392 384 * ioctl's total length. We then assume the nvlist_unpack() will
393 385 * sanity check the nvlist itself.
394 386 */
395 387 if ((ioc->shrlen + offsetof(smb_ioc_share_t, shr)) > ioc->hdr.len) {
396 388 rc = EINVAL;
397 389 goto out;
398 390 }
399 391 rc = nvlist_unpack(ioc->shr, ioc->shrlen, &shrlist, KM_SLEEP);
400 392 if (rc != 0)
401 393 goto out;
402 394
403 395 for (nvp = nvlist_next_nvpair(shrlist, NULL); nvp != NULL;
404 396 nvp = nvlist_next_nvpair(shrlist, nvp)) {
405 397
406 398 /*
407 399 * Since this loop can run for a while we want to exit
408 400 * as soon as the server state is anything but RUNNING
409 401 * to allow shutdown to proceed.
410 402 */
411 403 if (sv->sv_state != SMB_SERVER_STATE_RUNNING)
412 404 goto out;
413 405
414 406 if (nvpair_type(nvp) != DATA_TYPE_NVLIST)
415 407 continue;
416 408
417 409 shrname = nvpair_name(nvp);
418 410 ASSERT(shrname);
419 411
420 412 if ((rc = nvpair_value_nvlist(nvp, &share)) != 0) {
421 413 cmn_err(CE_WARN, "export[%s]: failed accessing",
422 414 shrname);
423 415 continue;
424 416 }
425 417
426 418 if ((shr = smb_kshare_decode(share)) == NULL) {
427 419 cmn_err(CE_WARN, "export[%s]: failed decoding",
428 420 shrname);
429 421 continue;
430 422 }
431 423
432 424 /* smb_kshare_export consumes shr so it's not leaked */
433 425 if ((rc = smb_kshare_export(sv, shr)) != 0) {
434 426 smb_kshare_destroy(shr);
435 427 continue;
436 428 }
437 429 }
438 430 rc = 0;
439 431
440 432 out:
441 433 nvlist_free(shrlist);
442 434 smb_server_release(sv);
443 435 return (rc);
444 436 }
445 437
446 438 /*
447 439 * This function is invoked when a share is disabled to disconnect trees
448 440 * and close files. Cleaning up may involve VOP and/or VFS calls, which
449 441 * may conflict/deadlock with stuck threads if something is amiss with the
450 442 * file system. Queueing the request for asynchronous processing allows the
451 443 * call to return immediately so that, if the unshare is being done in the
452 444 * context of a forced unmount, the forced unmount will always be able to
453 445 * proceed (unblocking stuck I/O and eventually allowing all blocked unshare
454 446 * processes to complete).
455 447 *
456 448 * The path lookup to find the root vnode of the VFS in question and the
457 449 * release of this vnode are done synchronously prior to any associated
458 450 * unmount. Doing these asynchronous to an associated unmount could run
459 451 * the risk of a spurious EBUSY for a standard unmount or an EIO during
460 452 * the path lookup due to a forced unmount finishing first.
461 453 */
462 454 int
463 455 smb_kshare_unexport_list(smb_ioc_share_t *ioc)
464 456 {
465 457 smb_server_t *sv = NULL;
466 458 smb_unshare_t *ux;
467 459 nvlist_t *shrlist = NULL;
468 460 nvpair_t *nvp;
469 461 boolean_t unexport = B_FALSE;
470 462 char *shrname;
471 463 int rc;
472 464
473 465 if ((rc = smb_server_lookup(&sv)) != 0)
474 466 return (rc);
475 467
476 468 /*
477 469 * Reality check that the nvlist's reported length doesn't exceed the
478 470 * ioctl's total length. We then assume the nvlist_unpack() will
479 471 * sanity check the nvlist itself.
480 472 */
481 473 if ((ioc->shrlen + offsetof(smb_ioc_share_t, shr)) > ioc->hdr.len) {
482 474 rc = EINVAL;
483 475 goto out;
484 476 }
485 477 if ((rc = nvlist_unpack(ioc->shr, ioc->shrlen, &shrlist, 0)) != 0)
486 478 goto out;
487 479
488 480 for (nvp = nvlist_next_nvpair(shrlist, NULL); nvp != NULL;
489 481 nvp = nvlist_next_nvpair(shrlist, nvp)) {
490 482 if (nvpair_type(nvp) != DATA_TYPE_NVLIST)
491 483 continue;
492 484
493 485 shrname = nvpair_name(nvp);
494 486 ASSERT(shrname);
495 487
496 488 if ((rc = smb_kshare_unexport(sv, shrname)) != 0)
497 489 continue;
498 490
499 491 ux = kmem_cache_alloc(smb_kshare_cache_unexport, KM_SLEEP);
500 492 (void) strlcpy(ux->us_sharename, shrname, MAXNAMELEN);
501 493
502 494 smb_slist_insert_tail(&sv->sv_export.e_unexport_list, ux);
503 495 unexport = B_TRUE;
504 496 }
505 497
506 498 if (unexport)
507 499 smb_thread_signal(&sv->sv_export.e_unexport_thread);
508 500 rc = 0;
509 501
510 502 out:
511 503 nvlist_free(shrlist);
512 504 smb_server_release(sv);
513 505 return (rc);
514 506 }
515 507
516 508 /*
517 509 * Get properties (currently only shortname enablement)
518 510 * of specified share.
519 511 */
520 512 int
521 513 smb_kshare_info(smb_ioc_shareinfo_t *ioc)
522 514 {
523 515 ioc->shortnames = smb_shortnames;
524 516 return (0);
525 517 }
526 518
527 519 /*
528 520 * This function builds a response for a NetShareEnum RAP request.
529 521 * List of shares is scanned twice. In the first round the total number
530 522 * of shares which their OEM name is shorter than 13 chars (esi->es_ntotal)
531 523 * and also the number of shares that fit in the given buffer are calculated.
532 524 * In the second round the shares data are encoded in the buffer.
533 525 *
534 526 * The data associated with each share has two parts, a fixed size part and
535 527 * a variable size part which is share's comment. The outline of the response
536 528 * buffer is so that fixed part for all the shares will appear first and follows
537 529 * with the comments for all those shares and that's why the data cannot be
538 530 * encoded in one round without unnecessarily complicating the code.
539 531 */
540 532 void
541 533 smb_kshare_enum(smb_server_t *sv, smb_enumshare_info_t *esi)
542 534 {
543 535 smb_avl_t *share_avl;
544 536 smb_avl_cursor_t cursor;
545 537 smb_kshare_t *shr;
546 538 int remained;
547 539 uint16_t infolen = 0;
548 540 uint16_t cmntlen = 0;
549 541 uint16_t sharelen;
550 542 uint16_t clen;
551 543 uint32_t cmnt_offs;
552 544 smb_msgbuf_t info_mb;
553 545 smb_msgbuf_t cmnt_mb;
554 546 boolean_t autohome_added = B_FALSE;
555 547
556 548 if (!smb_export_isready(sv)) {
557 549 esi->es_ntotal = esi->es_nsent = 0;
558 550 esi->es_datasize = 0;
559 551 return;
560 552 }
561 553
562 554 esi->es_ntotal = esi->es_nsent = 0;
563 555 remained = esi->es_bufsize;
564 556 share_avl = &sv->sv_export.e_share_avl;
565 557
566 558 /* Do the necessary calculations in the first round */
567 559 smb_avl_iterinit(share_avl, &cursor);
568 560
569 561 while ((shr = smb_avl_iterate(share_avl, &cursor)) != NULL) {
570 562 if (shr->shr_oemname == NULL) {
571 563 smb_avl_release(share_avl, shr);
572 564 continue;
573 565 }
574 566
575 567 if ((shr->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) {
576 568 if (esi->es_posix_uid == shr->shr_uid) {
577 569 autohome_added = B_TRUE;
578 570 } else {
579 571 smb_avl_release(share_avl, shr);
580 572 continue;
581 573 }
582 574 }
583 575
584 576 esi->es_ntotal++;
585 577
586 578 if (remained <= 0) {
587 579 smb_avl_release(share_avl, shr);
588 580 continue;
589 581 }
590 582
591 583 clen = strlen(shr->shr_cmnt) + 1;
592 584 sharelen = SHARE_INFO_1_SIZE + clen;
593 585
594 586 if (sharelen <= remained) {
595 587 infolen += SHARE_INFO_1_SIZE;
596 588 cmntlen += clen;
597 589 }
598 590
599 591 remained -= sharelen;
600 592 smb_avl_release(share_avl, shr);
601 593 }
602 594
603 595 esi->es_datasize = infolen + cmntlen;
604 596
605 597 smb_msgbuf_init(&info_mb, (uint8_t *)esi->es_buf, infolen, 0);
606 598 smb_msgbuf_init(&cmnt_mb, (uint8_t *)esi->es_buf + infolen, cmntlen, 0);
607 599 cmnt_offs = infolen;
608 600
609 601 /* Encode the data in the second round */
610 602 smb_avl_iterinit(share_avl, &cursor);
611 603 autohome_added = B_FALSE;
612 604
613 605 while ((shr = smb_avl_iterate(share_avl, &cursor)) != NULL) {
614 606 if (shr->shr_oemname == NULL) {
615 607 smb_avl_release(share_avl, shr);
616 608 continue;
617 609 }
618 610
619 611 if ((shr->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) {
620 612 if (esi->es_posix_uid == shr->shr_uid) {
621 613 autohome_added = B_TRUE;
622 614 } else {
623 615 smb_avl_release(share_avl, shr);
624 616 continue;
625 617 }
626 618 }
627 619
628 620 if (smb_msgbuf_encode(&info_mb, "13c.wl",
629 621 shr->shr_oemname, shr->shr_type, cmnt_offs) < 0) {
630 622 smb_avl_release(share_avl, shr);
631 623 break;
632 624 }
633 625
634 626 if (smb_msgbuf_encode(&cmnt_mb, "s", shr->shr_cmnt) < 0) {
635 627 smb_avl_release(share_avl, shr);
636 628 break;
637 629 }
638 630
639 631 cmnt_offs += strlen(shr->shr_cmnt) + 1;
640 632 esi->es_nsent++;
641 633
642 634 smb_avl_release(share_avl, shr);
643 635 }
644 636
645 637 smb_msgbuf_term(&info_mb);
646 638 smb_msgbuf_term(&cmnt_mb);
647 639 }
648 640
649 641 /*
650 642 * Looks up the given share and returns a pointer
651 643 * to its definition if it's found. A hold on the
652 644 * object is taken before the pointer is returned
653 645 * in which case the caller MUST always call
654 646 * smb_kshare_release().
655 647 */
656 648 smb_kshare_t *
657 649 smb_kshare_lookup(smb_server_t *sv, const char *shrname)
658 650 {
659 651 smb_kshare_t key;
660 652 smb_kshare_t *shr;
661 653
662 654 ASSERT(shrname);
663 655
664 656 if (!smb_export_isready(sv))
665 657 return (NULL);
666 658
667 659 key.shr_name = (char *)shrname;
668 660 shr = smb_avl_lookup(&sv->sv_export.e_share_avl, &key);
669 661 return (shr);
670 662 }
671 663
672 664 /*
673 665 * Releases the hold taken on the specified share object
674 666 */
675 667 void
|
↓ open down ↓ |
303 lines elided |
↑ open up ↑ |
676 668 smb_kshare_release(smb_server_t *sv, smb_kshare_t *shr)
677 669 {
678 670 ASSERT(shr);
679 671 ASSERT(shr->shr_magic == SMB_SHARE_MAGIC);
680 672
681 673 smb_avl_release(&sv->sv_export.e_share_avl, shr);
682 674 }
683 675
684 676 /*
685 677 * Add the given share in the specified server.
686 - * If the share is a disk share, smb_vfs_hold() is
687 - * invoked to ensure that there is a hold on the
688 - * corresponding file system before the share is
689 - * added to shares AVL.
678 + * If the share is a disk share, lookup the share path
679 + * and hold the smb_node_t for the share root.
690 680 *
691 681 * If the share is an Autohome share and it is
692 682 * already in the AVL only a reference count for
693 683 * that share is incremented.
694 684 */
695 685 static int
696 686 smb_kshare_export(smb_server_t *sv, smb_kshare_t *shr)
697 687 {
698 688 smb_avl_t *share_avl;
699 689 smb_kshare_t *auto_shr;
700 - vnode_t *vp;
690 + smb_node_t *snode = NULL;
701 691 int rc = 0;
702 692
703 693 share_avl = &sv->sv_export.e_share_avl;
704 694
705 695 if (!STYPE_ISDSK(shr->shr_type)) {
706 696 if ((rc = smb_avl_add(share_avl, shr)) != 0) {
707 697 cmn_err(CE_WARN, "export[%s]: failed caching (%d)",
708 698 shr->shr_name, rc);
709 699 }
710 700
711 701 return (rc);
712 702 }
713 703
714 704 if ((auto_shr = smb_avl_lookup(share_avl, shr)) != NULL) {
715 - if ((auto_shr->shr_flags & SMB_SHRF_AUTOHOME) == 0) {
716 - smb_avl_release(share_avl, auto_shr);
717 - return (EEXIST);
705 + rc = EEXIST;
706 + if ((auto_shr->shr_flags & SMB_SHRF_AUTOHOME) != 0) {
707 + mutex_enter(&auto_shr->shr_mutex);
708 + auto_shr->shr_autocnt++;
709 + mutex_exit(&auto_shr->shr_mutex);
710 + rc = 0;
718 711 }
719 -
720 - mutex_enter(&auto_shr->shr_mutex);
721 - auto_shr->shr_autocnt++;
722 - mutex_exit(&auto_shr->shr_mutex);
723 712 smb_avl_release(share_avl, auto_shr);
724 - return (0);
713 + return (rc);
725 714 }
726 715
727 - if ((rc = smb_server_sharevp(sv, shr->shr_path, &vp)) != 0) {
728 - cmn_err(CE_WARN, "export[%s(%s)]: failed obtaining vnode (%d)",
716 + /*
717 + * Get the root smb_node_t for this share, held.
718 + * This hold is normally released during AVL destroy,
719 + * via the element destructor: smb_kshare_destroy
720 + */
721 + rc = smb_server_share_lookup(sv, shr->shr_path, &snode);
722 + if (rc != 0) {
723 + cmn_err(CE_WARN, "export[%s(%s)]: lookup failed (%d)",
729 724 shr->shr_name, shr->shr_path, rc);
730 725 return (rc);
731 726 }
732 727
733 - if ((rc = smb_vfs_hold(&sv->sv_export, vp->v_vfsp)) == 0) {
734 - if ((rc = smb_avl_add(share_avl, shr)) != 0) {
735 - cmn_err(CE_WARN, "export[%s]: failed caching (%d)",
736 - shr->shr_name, rc);
737 - smb_vfs_rele(&sv->sv_export, vp->v_vfsp);
728 + shr->shr_root_node = snode;
729 + if ((rc = smb_avl_add(share_avl, shr)) != 0) {
730 + cmn_err(CE_WARN, "export[%s]: failed caching (%d)",
731 + shr->shr_name, rc);
732 + shr->shr_root_node = NULL;
733 + smb_node_release(snode);
734 + return (rc);
735 + }
736 +
737 + kshare_stats_init(sv, shr);
738 +
739 + /*
740 + * For CA shares, find or create the CA handle dir,
741 + * and (if restarted) import persistent handles.
742 + */
743 + if ((shr->shr_flags & SMB_SHRF_CA) != 0) {
744 + rc = smb2_dh_new_ca_share(sv, shr);
745 + if (rc != 0) {
746 + /* Just make it a non-CA share. */
747 + mutex_enter(&shr->shr_mutex);
748 + shr->shr_flags &= ~SMB_SHRF_CA;
749 + mutex_exit(&shr->shr_mutex);
750 + rc = 0;
738 751 }
739 - } else {
740 - cmn_err(CE_WARN, "export[%s(%s)]: failed holding VFS (%d)",
741 - shr->shr_name, shr->shr_path, rc);
742 752 }
743 753
744 - VN_RELE(vp);
745 754 return (rc);
746 755 }
747 756
757 +
748 758 /*
759 + * Following a pattern somewhat similar to smb_server_kstat_init,
760 + * but organized a little differently.
761 + */
762 +void
763 +kshare_stats_init(smb_server_t *sv, smb_kshare_t *ks)
764 +{
765 + static const char *kr_names[] = SMBSRV_CLSH__NAMES;
766 + char ks_name[KSTAT_STRLEN];
767 + smbsrv_clsh_kstats_t *ksr;
768 + int idx;
769 + smb_named_stats_t *smbnsp;
770 + kstat_t *kstat = NULL;
771 + int namelen;
772 +
773 + /*
774 + * Most share names are short, and we'd like to allow consumers like
775 + * the smbstat command to compose the kstat names for short share names
776 + * directly. In the (rare) case where we have longer share names, we
777 + * need an indirection scheme to get around the limited (31 chars) size
778 + * of kstat names. So for share names 24 chars or shorter, we compose
779 + * the kstat name directly as "smbsrv:0:sh/sharename" and when the share
780 + * name is longer, compose the kstat name using an arbitrary
781 + * (but unique) identifier like: "smbsrv:0:sh/:ffffff0009560a98". To
782 + * find the unique identifier given a (long) share name, the consumer
783 + * has to enumerate the (fake) "smbsrvshr" kstat module, looking for the
784 + * kstat with the sharename element matching the one they want. Both
785 + * direct and indirect names are instantiated under the "smbsrvshr"
786 + * module, so a consumer that wants all the share kstats could always
787 + * lookup the kstat names using the indirection scheme if that's easier.
788 + * (Nothing forces the consumer to directly compose kstat names when the
789 + * share name happens to be short -- they can always enumerate to find
790 + * it.)
791 + *
792 + * SMB share names are not allowed to contain a colon. The naming
793 + * scheme here uses a colon at the beginning of what would otherwise be
794 + * the share name part of the kstat name to indicate that this name uses
795 + * the "indirection" scheme. With indirection, the part after the colon
796 + * is an arbitrary (but unique per share) identifier of some other
797 + * kstat, and a consumer needs to fetch that kstat to get the real share
798 + * name.
799 + */
800 + namelen = strlen(ks->shr_name);
801 + if (namelen <= 24) {
802 + (void) snprintf(ks_name, sizeof (ks_name), "sh/%s",
803 + ks->shr_name);
804 +
805 + kstat = kstat_hold_byname("smbsrvshr", 0, ks_name, sv->sv_zid);
806 + }
807 +
808 + if (namelen > 24 || kstat != NULL) {
809 + (void) snprintf(ks_name, sizeof (ks_name), "sh/:%p",
810 + (void *)ks);
811 +
812 + if (kstat != NULL)
813 + kstat_rele(kstat);
814 + }
815 +
816 + ks->shr_ksp = kstat_create_zone(SMBSRV_KSTAT_MODULE, 0,
817 + ks_name, SMBSRV_KSTAT_CLASS, KSTAT_TYPE_RAW,
818 + sizeof (smbsrv_clsh_kstats_t), 0, sv->sv_zid);
819 +
820 + if (ks->shr_ksp == NULL)
821 + return;
822 +
823 + ks->stats.ksns = kstat_create_zone("smbsrvshr", 0,
824 + ks_name, SMBSRV_KSTAT_CLASS, KSTAT_TYPE_NAMED,
825 + 0, KSTAT_FLAG_VIRTUAL, sv->sv_zid);
826 +
827 + if (ks->stats.ksns == NULL) {
828 + kstat_delete(ks->shr_ksp);
829 + ks->shr_ksp = NULL;
830 + return;
831 + }
832 +
833 + ks->shr_ksp->ks_update = smb_kshare_kstat_update;
834 + ks->shr_ksp->ks_private = ks;
835 +
836 + /*
837 + * In-line equivalent of smb_dispatch_stats_init
838 + */
839 + ksr = (smbsrv_clsh_kstats_t *)ks->shr_ksp->ks_data;
840 + for (idx = 0; idx < SMBSRV_CLSH__NREQ; idx++) {
841 + smb_latency_init(&ks->shr_stats[idx].sdt_lat);
842 + (void) strlcpy(ksr->ks_clsh[idx].kr_name, kr_names[idx],
843 + KSTAT_STRLEN);
844 + }
845 +
846 + /*
847 + * SMB named kstats setup for > KSTAT_STRLEN name to short name mapping.
848 + */
849 + smbnsp = &ks->stats.ks_data;
850 + ks->stats.ksns->ks_data = &ks->stats.ks_data;
851 + ks->stats.ksns->ks_data_size = sizeof (ks->stats.ks_data);
852 + ks->stats.ksns->ks_ndata = 1;
853 + kstat_named_init(smbnsp->kn, "share name",
854 + KSTAT_DATA_STRING);
855 + ks->stats.ksns->ks_update = smb_named_kstat_update;
856 + ks->stats.ksns->ks_private = (void *)ks;
857 +
858 + kstat_install(ks->shr_ksp);
859 + kstat_install(ks->stats.ksns);
860 +}
861 +
862 +void
863 +kshare_stats_fini(smb_kshare_t *ks)
864 +{
865 + int idx;
866 +
867 + for (idx = 0; idx < SMBSRV_CLSH__NREQ; idx++)
868 + smb_latency_destroy(&ks->shr_stats[idx].sdt_lat);
869 +}
870 +
871 +static int
872 +smb_named_kstat_update(kstat_t *ks, int rw)
873 +{
874 + smb_kshare_t *smbksp = (smb_kshare_t *)ks->ks_private;
875 + smb_named_stats_t *smbnsp = &smbksp->stats.ks_data;
876 +
877 + if (rw == KSTAT_READ) {
878 + (void) strlcpy(smbnsp->name, smbksp->shr_name,
879 + sizeof (smbnsp->name));
880 +
881 + kstat_named_setstr(&smbnsp->kn[0],
882 + (const char *)smbksp->shr_name);
883 + }
884 + return (0);
885 +}
886 +
887 +/*
888 + * Update the kstat data from our private stats.
889 + */
890 +static int
891 +smb_kshare_kstat_update(kstat_t *ksp, int rw)
892 +{
893 + smb_kshare_t *kshare;
894 + smb_disp_stats_t *sds;
895 + smbsrv_clsh_kstats_t *clsh;
896 + smb_kstat_req_t *ksr;
897 + int i;
898 +
899 + if (rw == KSTAT_WRITE)
900 + return (EACCES);
901 +
902 + kshare = ksp->ks_private;
903 + ASSERT(kshare->shr_magic == SMB_SHARE_MAGIC);
904 + sds = kshare->shr_stats;
905 +
906 + clsh = (smbsrv_clsh_kstats_t *)ksp->ks_data;
907 + ksr = clsh->ks_clsh;
908 +
909 + for (i = 0; i < SMBSRV_CLSH__NREQ; i++, ksr++, sds++) {
910 + ksr->kr_rxb = sds->sdt_rxb;
911 + ksr->kr_txb = sds->sdt_txb;
912 + mutex_enter(&sds->sdt_lat.ly_mutex);
913 + ksr->kr_nreq = sds->sdt_lat.ly_a_nreq;
914 + ksr->kr_sum = sds->sdt_lat.ly_a_sum;
915 + ksr->kr_a_mean = sds->sdt_lat.ly_a_mean;
916 + ksr->kr_a_stddev = sds->sdt_lat.ly_a_stddev;
917 + ksr->kr_d_mean = sds->sdt_lat.ly_d_mean;
918 + ksr->kr_d_stddev = sds->sdt_lat.ly_d_stddev;
919 + sds->sdt_lat.ly_d_mean = 0;
920 + sds->sdt_lat.ly_d_nreq = 0;
921 + sds->sdt_lat.ly_d_stddev = 0;
922 + sds->sdt_lat.ly_d_sum = 0;
923 + mutex_exit(&sds->sdt_lat.ly_mutex);
924 + }
925 +
926 + return (0);
927 +}
928 +
929 +/*
749 930 * Removes the share specified by 'shrname' from the AVL
750 931 * tree of the given server if it's there.
751 932 *
752 933 * If the share is an Autohome share, the autohome count
753 934 * is decremented and the share is only removed if the
754 935 * count goes to zero.
755 936 *
756 937 * If the share is a disk share, the hold on the corresponding
757 938 * file system is released before removing the share from
758 939 * the AVL tree.
759 940 */
760 941 static int
761 942 smb_kshare_unexport(smb_server_t *sv, const char *shrname)
762 943 {
763 944 smb_avl_t *share_avl;
764 945 smb_kshare_t key;
765 946 smb_kshare_t *shr;
766 - vnode_t *vp;
767 - int rc;
768 947 boolean_t auto_unexport;
769 948
770 949 share_avl = &sv->sv_export.e_share_avl;
771 950
772 951 key.shr_name = (char *)shrname;
773 952 if ((shr = smb_avl_lookup(share_avl, &key)) == NULL)
774 953 return (ENOENT);
775 954
776 955 if ((shr->shr_flags & SMB_SHRF_AUTOHOME) != 0) {
777 956 mutex_enter(&shr->shr_mutex);
778 957 shr->shr_autocnt--;
779 958 auto_unexport = (shr->shr_autocnt == 0);
780 959 mutex_exit(&shr->shr_mutex);
781 960 if (!auto_unexport) {
782 961 smb_avl_release(share_avl, shr);
783 962 return (0);
784 963 }
785 964 }
786 965
787 - if (STYPE_ISDSK(shr->shr_type)) {
788 - if ((rc = smb_server_sharevp(sv, shr->shr_path, &vp)) != 0) {
789 - smb_avl_release(share_avl, shr);
790 - cmn_err(CE_WARN, "unexport[%s]: failed obtaining vnode"
791 - " (%d)", shrname, rc);
792 - return (rc);
793 - }
966 + smb_avl_remove(share_avl, shr);
794 967
795 - smb_vfs_rele(&sv->sv_export, vp->v_vfsp);
796 - VN_RELE(vp);
797 - }
968 + mutex_enter(&shr->shr_mutex);
969 + shr->shr_flags |= SMB_SHRF_REMOVED;
970 + mutex_exit(&shr->shr_mutex);
798 971
799 - smb_avl_remove(share_avl, shr);
800 972 smb_avl_release(share_avl, shr);
801 973
802 974 return (0);
803 975 }
804 976
805 977 /*
806 978 * Exports IPC$ or Admin shares
807 979 */
808 980 static int
809 981 smb_kshare_export_trans(smb_server_t *sv, char *name, char *path, char *cmnt)
810 982 {
811 983 smb_kshare_t *shr;
812 984
813 985 ASSERT(name);
814 986 ASSERT(path);
815 987
816 988 shr = kmem_cache_alloc(smb_kshare_cache_share, KM_SLEEP);
817 989 bzero(shr, sizeof (smb_kshare_t));
818 990
819 991 shr->shr_magic = SMB_SHARE_MAGIC;
820 992 shr->shr_refcnt = 1;
821 993 shr->shr_flags = SMB_SHRF_TRANS | smb_kshare_is_admin(shr->shr_name);
822 994 if (strcasecmp(name, "IPC$") == 0)
823 995 shr->shr_type = STYPE_IPC;
824 996 else
825 997 shr->shr_type = STYPE_DISKTREE;
826 998
827 999 shr->shr_type |= smb_kshare_is_special(shr->shr_name);
828 1000
829 1001 shr->shr_name = smb_mem_strdup(name);
830 1002 if (path)
831 1003 shr->shr_path = smb_mem_strdup(path);
832 1004 if (cmnt)
833 1005 shr->shr_cmnt = smb_mem_strdup(cmnt);
834 1006 shr->shr_oemname = smb_kshare_oemname(name);
835 1007
836 1008 return (smb_kshare_export(sv, shr));
837 1009 }
838 1010
839 1011 /*
840 1012 * Decodes share information in an nvlist format into a smb_kshare_t
841 1013 * structure.
|
↓ open down ↓ |
32 lines elided |
↑ open up ↑ |
842 1014 *
843 1015 * This is a temporary function and will be replaced by functions
844 1016 * provided by libsharev2 code after it's available.
845 1017 */
846 1018 static smb_kshare_t *
847 1019 smb_kshare_decode(nvlist_t *share)
848 1020 {
849 1021 smb_kshare_t tmp;
850 1022 smb_kshare_t *shr;
851 1023 nvlist_t *smb;
852 - char *csc_name = NULL;
1024 + char *csc_name = NULL, *strbuf = NULL;
853 1025 int rc;
854 1026
855 1027 ASSERT(share);
856 1028
857 1029 bzero(&tmp, sizeof (smb_kshare_t));
858 1030
859 1031 rc = nvlist_lookup_string(share, "name", &tmp.shr_name);
860 1032 rc |= nvlist_lookup_string(share, "path", &tmp.shr_path);
861 1033 (void) nvlist_lookup_string(share, "desc", &tmp.shr_cmnt);
862 1034
863 1035 ASSERT(tmp.shr_name && tmp.shr_path);
864 1036
865 1037 rc |= nvlist_lookup_nvlist(share, "smb", &smb);
866 1038 if (rc != 0) {
867 1039 cmn_err(CE_WARN, "kshare: failed looking up SMB properties"
868 1040 " (%d)", rc);
869 1041 return (NULL);
870 1042 }
871 1043
872 1044 rc = nvlist_lookup_uint32(smb, "type", &tmp.shr_type);
873 1045 if (rc != 0) {
874 1046 cmn_err(CE_WARN, "kshare[%s]: failed getting the share type"
875 1047 " (%d)", tmp.shr_name, rc);
876 1048 return (NULL);
877 1049 }
878 1050
879 1051 (void) nvlist_lookup_string(smb, SHOPT_AD_CONTAINER,
880 1052 &tmp.shr_container);
881 1053 (void) nvlist_lookup_string(smb, SHOPT_NONE, &tmp.shr_access_none);
|
↓ open down ↓ |
19 lines elided |
↑ open up ↑ |
882 1054 (void) nvlist_lookup_string(smb, SHOPT_RO, &tmp.shr_access_ro);
883 1055 (void) nvlist_lookup_string(smb, SHOPT_RW, &tmp.shr_access_rw);
884 1056
885 1057 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_ABE, SMB_SHRF_ABE);
886 1058 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_CATIA,
887 1059 SMB_SHRF_CATIA);
888 1060 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_GUEST,
889 1061 SMB_SHRF_GUEST_OK);
890 1062 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_DFSROOT,
891 1063 SMB_SHRF_DFSROOT);
892 - tmp.shr_flags |= smb_kshare_decode_bool(smb, "Autohome",
1064 + tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_QUOTAS,
1065 + SMB_SHRF_QUOTAS);
1066 + tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_CA, SMB_SHRF_CA);
1067 + tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_FSO, SMB_SHRF_FSO);
1068 + tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_AUTOHOME,
893 1069 SMB_SHRF_AUTOHOME);
894 1070
895 1071 if ((tmp.shr_flags & SMB_SHRF_AUTOHOME) == SMB_SHRF_AUTOHOME) {
896 1072 rc = nvlist_lookup_uint32(smb, "uid", &tmp.shr_uid);
897 1073 rc |= nvlist_lookup_uint32(smb, "gid", &tmp.shr_gid);
898 1074 if (rc != 0) {
899 1075 cmn_err(CE_WARN, "kshare: failed looking up uid/gid"
900 1076 " (%d)", rc);
901 1077 return (NULL);
902 1078 }
903 1079 }
904 1080
1081 + (void) nvlist_lookup_string(smb, SHOPT_ENCRYPT, &strbuf);
1082 + smb_cfg_set_require(strbuf, &tmp.shr_encrypt);
1083 +
905 1084 (void) nvlist_lookup_string(smb, SHOPT_CSC, &csc_name);
906 1085 smb_kshare_csc_flags(&tmp, csc_name);
907 1086
908 1087 shr = kmem_cache_alloc(smb_kshare_cache_share, KM_SLEEP);
909 1088 bzero(shr, sizeof (smb_kshare_t));
910 1089
911 1090 shr->shr_magic = SMB_SHARE_MAGIC;
912 1091 shr->shr_refcnt = 1;
913 1092
914 1093 shr->shr_name = smb_mem_strdup(tmp.shr_name);
915 1094 shr->shr_path = smb_mem_strdup(tmp.shr_path);
916 1095 if (tmp.shr_cmnt)
917 1096 shr->shr_cmnt = smb_mem_strdup(tmp.shr_cmnt);
918 1097 if (tmp.shr_container)
919 1098 shr->shr_container = smb_mem_strdup(tmp.shr_container);
|
↓ open down ↓ |
5 lines elided |
↑ open up ↑ |
920 1099 if (tmp.shr_access_none)
921 1100 shr->shr_access_none = smb_mem_strdup(tmp.shr_access_none);
922 1101 if (tmp.shr_access_ro)
923 1102 shr->shr_access_ro = smb_mem_strdup(tmp.shr_access_ro);
924 1103 if (tmp.shr_access_rw)
925 1104 shr->shr_access_rw = smb_mem_strdup(tmp.shr_access_rw);
926 1105
927 1106 shr->shr_oemname = smb_kshare_oemname(shr->shr_name);
928 1107 shr->shr_flags = tmp.shr_flags | smb_kshare_is_admin(shr->shr_name);
929 1108 shr->shr_type = tmp.shr_type | smb_kshare_is_special(shr->shr_name);
1109 + shr->shr_encrypt = tmp.shr_encrypt;
930 1110
931 1111 shr->shr_uid = tmp.shr_uid;
932 1112 shr->shr_gid = tmp.shr_gid;
933 1113
934 1114 if ((shr->shr_flags & SMB_SHRF_AUTOHOME) == SMB_SHRF_AUTOHOME)
935 1115 shr->shr_autocnt = 1;
936 -
937 1116 return (shr);
938 1117 }
939 1118
940 1119 #if 0
941 1120 static void
942 1121 smb_kshare_log(smb_kshare_t *shr)
943 1122 {
944 1123 cmn_err(CE_NOTE, "Share info:");
945 1124 cmn_err(CE_NOTE, "\tname: %s", (shr->shr_name) ? shr->shr_name : "");
946 1125 cmn_err(CE_NOTE, "\tpath: %s", (shr->shr_path) ? shr->shr_path : "");
947 1126 cmn_err(CE_NOTE, "\tcmnt: (%s)",
948 1127 (shr->shr_cmnt) ? shr->shr_cmnt : "NULL");
949 1128 cmn_err(CE_NOTE, "\toemname: (%s)",
950 1129 (shr->shr_oemname) ? shr->shr_oemname : "NULL");
951 1130 cmn_err(CE_NOTE, "\tflags: %X", shr->shr_flags);
952 1131 cmn_err(CE_NOTE, "\ttype: %d", shr->shr_type);
953 1132 }
954 1133 #endif
955 1134
956 1135 /*
957 1136 * Compare function used by shares AVL
958 1137 */
959 1138 static int
960 1139 smb_kshare_cmp(const void *p1, const void *p2)
961 1140 {
962 1141 smb_kshare_t *shr1 = (smb_kshare_t *)p1;
963 1142 smb_kshare_t *shr2 = (smb_kshare_t *)p2;
964 1143 int rc;
965 1144
966 1145 ASSERT(shr1);
967 1146 ASSERT(shr1->shr_name);
968 1147
969 1148 ASSERT(shr2);
970 1149 ASSERT(shr2->shr_name);
971 1150
972 1151 rc = smb_strcasecmp(shr1->shr_name, shr2->shr_name, 0);
973 1152
974 1153 if (rc < 0)
975 1154 return (-1);
976 1155
977 1156 if (rc > 0)
978 1157 return (1);
979 1158
980 1159 return (0);
981 1160 }
982 1161
983 1162 /*
984 1163 * This function is called by smb_avl routines whenever
985 1164 * there is a need to take a hold on a share structure
986 1165 * inside AVL
987 1166 */
988 1167 static void
989 1168 smb_kshare_hold(const void *p)
990 1169 {
991 1170 smb_kshare_t *shr = (smb_kshare_t *)p;
992 1171
993 1172 ASSERT(shr);
994 1173 ASSERT(shr->shr_magic == SMB_SHARE_MAGIC);
995 1174
996 1175 mutex_enter(&shr->shr_mutex);
997 1176 shr->shr_refcnt++;
998 1177 mutex_exit(&shr->shr_mutex);
999 1178 }
1000 1179
1001 1180 /*
1002 1181 * This function must be called by smb_avl routines whenever
1003 1182 * smb_kshare_hold is called and the hold needs to be released.
1004 1183 */
1005 1184 static boolean_t
1006 1185 smb_kshare_rele(const void *p)
1007 1186 {
1008 1187 smb_kshare_t *shr = (smb_kshare_t *)p;
1009 1188 boolean_t destroy;
1010 1189
1011 1190 ASSERT(shr);
1012 1191 ASSERT(shr->shr_magic == SMB_SHARE_MAGIC);
1013 1192
1014 1193 mutex_enter(&shr->shr_mutex);
1015 1194 ASSERT(shr->shr_refcnt > 0);
1016 1195 shr->shr_refcnt--;
1017 1196 destroy = (shr->shr_refcnt == 0);
1018 1197 mutex_exit(&shr->shr_mutex);
1019 1198
1020 1199 return (destroy);
1021 1200 }
1022 1201
1023 1202 /*
1024 1203 * Frees all the memory allocated for the given
1025 1204 * share structure. It also removes the structure
|
↓ open down ↓ |
79 lines elided |
↑ open up ↑ |
1026 1205 * from the share cache.
1027 1206 */
1028 1207 static void
1029 1208 smb_kshare_destroy(void *p)
1030 1209 {
1031 1210 smb_kshare_t *shr = (smb_kshare_t *)p;
1032 1211
1033 1212 ASSERT(shr);
1034 1213 ASSERT(shr->shr_magic == SMB_SHARE_MAGIC);
1035 1214
1215 + if (shr->shr_ksp != NULL) {
1216 + kstat_delete(shr->shr_ksp);
1217 + shr->shr_ksp = NULL;
1218 + kshare_stats_fini(shr);
1219 + }
1220 +
1221 + if (shr->stats.ksns != NULL) {
1222 + kstat_delete(shr->stats.ksns);
1223 + }
1224 +
1225 + if (shr->shr_ca_dir != NULL)
1226 + smb_node_release(shr->shr_ca_dir);
1227 + if (shr->shr_root_node)
1228 + smb_node_release(shr->shr_root_node);
1229 +
1036 1230 smb_mem_free(shr->shr_name);
1037 1231 smb_mem_free(shr->shr_path);
1038 1232 smb_mem_free(shr->shr_cmnt);
1039 1233 smb_mem_free(shr->shr_container);
1040 1234 smb_mem_free(shr->shr_oemname);
1041 1235 smb_mem_free(shr->shr_access_none);
1042 1236 smb_mem_free(shr->shr_access_ro);
1043 1237 smb_mem_free(shr->shr_access_rw);
1044 1238
1045 1239 kmem_cache_free(smb_kshare_cache_share, shr);
1046 1240 }
1047 1241
1048 1242
1049 1243 /*
1050 1244 * Generate an OEM name for the given share name. If the name is
1051 1245 * shorter than 13 bytes the oemname will be returned; otherwise NULL
1052 1246 * is returned.
1053 1247 */
1054 1248 static char *
1055 1249 smb_kshare_oemname(const char *shrname)
1056 1250 {
1057 1251 smb_wchar_t *unibuf;
1058 1252 char *oem_name;
1059 1253 int length;
1060 1254
1061 1255 length = strlen(shrname) + 1;
1062 1256
1063 1257 oem_name = smb_mem_alloc(length);
1064 1258 unibuf = smb_mem_alloc(length * sizeof (smb_wchar_t));
1065 1259
1066 1260 (void) smb_mbstowcs(unibuf, shrname, length);
1067 1261
1068 1262 if (ucstooem(oem_name, unibuf, length, OEM_CPG_850) == 0)
1069 1263 (void) strcpy(oem_name, shrname);
1070 1264
1071 1265 smb_mem_free(unibuf);
1072 1266
1073 1267 if (strlen(oem_name) + 1 > SMB_SHARE_OEMNAME_MAX) {
1074 1268 smb_mem_free(oem_name);
1075 1269 return (NULL);
1076 1270 }
1077 1271
1078 1272 return (oem_name);
1079 1273 }
1080 1274
1081 1275 /*
1082 1276 * Special share reserved for interprocess communication (IPC$) or
1083 1277 * remote administration of the server (ADMIN$). Can also refer to
1084 1278 * administrative shares such as C$, D$, E$, and so forth.
1085 1279 */
1086 1280 static int
1087 1281 smb_kshare_is_special(const char *sharename)
1088 1282 {
1089 1283 int len;
1090 1284
1091 1285 if (sharename == NULL)
1092 1286 return (0);
1093 1287
1094 1288 if ((len = strlen(sharename)) == 0)
1095 1289 return (0);
1096 1290
1097 1291 if (sharename[len - 1] == '$')
1098 1292 return (STYPE_SPECIAL);
1099 1293
1100 1294 return (0);
1101 1295 }
1102 1296
1103 1297 /*
1104 1298 * Check whether or not this is a default admin share: C$, D$ etc.
1105 1299 */
1106 1300 static boolean_t
1107 1301 smb_kshare_is_admin(const char *sharename)
1108 1302 {
1109 1303 if (sharename == NULL)
1110 1304 return (B_FALSE);
1111 1305
1112 1306 if (strlen(sharename) == 2 &&
1113 1307 smb_isalpha(sharename[0]) && sharename[1] == '$') {
1114 1308 return (B_TRUE);
1115 1309 }
1116 1310
1117 1311 return (B_FALSE);
1118 1312 }
1119 1313
1120 1314 /*
1121 1315 * Decodes the given boolean share option.
1122 1316 * If the option is present in the nvlist and it's value is true
1123 1317 * returns the corresponding flag value, otherwise returns 0.
1124 1318 */
1125 1319 static uint32_t
1126 1320 smb_kshare_decode_bool(nvlist_t *nvl, const char *propname, uint32_t flag)
1127 1321 {
1128 1322 char *boolp;
1129 1323
1130 1324 if (nvlist_lookup_string(nvl, propname, &boolp) == 0)
1131 1325 if (strcasecmp(boolp, "true") == 0)
1132 1326 return (flag);
1133 1327
1134 1328 return (0);
1135 1329 }
1136 1330
1137 1331 /*
1138 1332 * Map a client-side caching (CSC) option to the appropriate share
1139 1333 * flag. Only one option is allowed; an error will be logged if
1140 1334 * multiple options have been specified. We don't need to do anything
1141 1335 * about multiple values here because the SRVSVC will not recognize
1142 1336 * a value containing multiple flags and will return the default value.
1143 1337 *
1144 1338 * If the option value is not recognized, it will be ignored: invalid
1145 1339 * values will typically be caught and rejected by sharemgr.
1146 1340 */
1147 1341 static void
1148 1342 smb_kshare_csc_flags(smb_kshare_t *shr, const char *value)
1149 1343 {
1150 1344 int i;
1151 1345 static struct {
1152 1346 char *value;
1153 1347 uint32_t flag;
1154 1348 } cscopt[] = {
1155 1349 { "disabled", SMB_SHRF_CSC_DISABLED },
1156 1350 { "manual", SMB_SHRF_CSC_MANUAL },
1157 1351 { "auto", SMB_SHRF_CSC_AUTO },
1158 1352 { "vdo", SMB_SHRF_CSC_VDO }
1159 1353 };
1160 1354
1161 1355 if (value == NULL)
1162 1356 return;
1163 1357
1164 1358 for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
1165 1359 if (strcasecmp(value, cscopt[i].value) == 0) {
1166 1360 shr->shr_flags |= cscopt[i].flag;
1167 1361 break;
1168 1362 }
1169 1363 }
1170 1364
1171 1365 switch (shr->shr_flags & SMB_SHRF_CSC_MASK) {
1172 1366 case 0:
1173 1367 case SMB_SHRF_CSC_DISABLED:
1174 1368 case SMB_SHRF_CSC_MANUAL:
1175 1369 case SMB_SHRF_CSC_AUTO:
1176 1370 case SMB_SHRF_CSC_VDO:
1177 1371 break;
1178 1372
1179 1373 default:
1180 1374 cmn_err(CE_NOTE, "csc option conflict: 0x%08x",
1181 1375 shr->shr_flags & SMB_SHRF_CSC_MASK);
1182 1376 break;
1183 1377 }
1184 1378 }
1185 1379
1186 1380 /*
1187 1381 * This function processes the unexport event list and disconnects shares
1188 1382 * asynchronously. The function executes as a zone-specific thread.
1189 1383 *
1190 1384 * The server arg passed in is safe to use without a reference count, because
1191 1385 * the server cannot be deleted until smb_thread_stop()/destroy() return,
1192 1386 * which is also when the thread exits.
1193 1387 */
1194 1388 /*ARGSUSED*/
1195 1389 static void
1196 1390 smb_kshare_unexport_thread(smb_thread_t *thread, void *arg)
1197 1391 {
1198 1392 smb_server_t *sv = arg;
1199 1393 smb_unshare_t *ux;
1200 1394
1201 1395 while (smb_thread_continue(thread)) {
1202 1396 while ((ux = list_head(&sv->sv_export.e_unexport_list.sl_list))
1203 1397 != NULL) {
1204 1398 smb_slist_remove(&sv->sv_export.e_unexport_list, ux);
1205 1399 (void) smb_server_unshare(ux->us_sharename);
1206 1400 kmem_cache_free(smb_kshare_cache_unexport, ux);
1207 1401 }
1208 1402 }
1209 1403 }
1210 1404
1211 1405 static boolean_t
1212 1406 smb_export_isready(smb_server_t *sv)
1213 1407 {
1214 1408 boolean_t ready;
1215 1409
1216 1410 mutex_enter(&sv->sv_export.e_mutex);
1217 1411 ready = sv->sv_export.e_ready;
1218 1412 mutex_exit(&sv->sv_export.e_mutex);
1219 1413
1220 1414 return (ready);
1221 1415 }
1222 1416
1223 1417 #ifdef _KERNEL
1224 1418 /*
1225 1419 * Return 0 upon success. Otherwise > 0
1226 1420 */
1227 1421 static int
1228 1422 smb_kshare_chk_dsrv_status(int opcode, smb_dr_ctx_t *dec_ctx)
1229 1423 {
1230 1424 int status = smb_dr_get_int32(dec_ctx);
1231 1425 int err;
1232 1426
1233 1427 switch (status) {
1234 1428 case SMB_SHARE_DSUCCESS:
1235 1429 return (0);
1236 1430
1237 1431 case SMB_SHARE_DERROR:
1238 1432 err = smb_dr_get_uint32(dec_ctx);
1239 1433 cmn_err(CE_WARN, "%d: Encountered door server error %d",
1240 1434 opcode, err);
1241 1435 (void) smb_dr_decode_finish(dec_ctx);
1242 1436 return (err);
1243 1437 }
1244 1438
1245 1439 ASSERT(0);
1246 1440 return (EINVAL);
1247 1441 }
1248 1442 #endif /* _KERNEL */
|
↓ open down ↓ |
203 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX