Print this page
3373 gcc >= 4.5 concerns about offsetof()
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/vscan/vscan_svc.c
+++ new/usr/src/uts/common/io/vscan/vscan_svc.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
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 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 #include <sys/stat.h>
28 28 #include <sys/ddi.h>
29 29 #include <sys/sunddi.h>
30 30 #include <sys/time.h>
31 31 #include <sys/varargs.h>
32 32 #include <sys/conf.h>
33 33 #include <sys/modctl.h>
34 34 #include <sys/cmn_err.h>
35 35 #include <sys/vnode.h>
36 36 #include <fs/fs_subr.h>
37 37 #include <sys/types.h>
38 38 #include <sys/file.h>
39 39 #include <sys/disp.h>
40 40 #include <sys/sdt.h>
41 41 #include <sys/cred.h>
42 42 #include <sys/list.h>
43 43 #include <sys/vscan.h>
44 44
45 45 #define VS_REQ_MAGIC 0x52515354 /* 'RQST' */
46 46
47 47 #define VS_REQS_DEFAULT 20000 /* pending scan requests - reql */
48 48 #define VS_NODES_DEFAULT 128 /* concurrent file scans */
49 49 #define VS_WORKERS_DEFAULT 32 /* worker threads */
↓ open down ↓ |
49 lines elided |
↑ open up ↑ |
50 50 #define VS_SCANWAIT_DEFAULT 15*60 /* seconds to wait for scan result */
51 51 #define VS_REQL_HANDLER_TIMEOUT 30
52 52 #define VS_EXT_RECURSE_DEPTH 8
53 53
54 54 /* access derived from scan result (VS_STATUS_XXX) and file attributes */
55 55 #define VS_ACCESS_UNDEFINED 0
56 56 #define VS_ACCESS_ALLOW 1 /* return 0 */
57 57 #define VS_ACCESS_DENY 2 /* return EACCES */
58 58
59 59 #define tolower(C) (((C) >= 'A' && (C) <= 'Z') ? (C) - 'A' + 'a' : (C))
60 -#define offsetof(s, m) (size_t)(&(((s *)0)->m))
60 +#if defined(__GNUC__)
61 +#define offsetof(s, m) __builtin_offsetof(s, m)
62 +#else
63 +#define offsetof(s, m) ((size_t)(&(((s *)0)->m)))
64 +#endif
61 65
62 66 /* global variables - tunable via /etc/system */
63 67 uint32_t vs_reqs_max = VS_REQS_DEFAULT; /* max scan requests */
64 68 uint32_t vs_nodes_max = VS_NODES_DEFAULT; /* max in-progress scan requests */
65 69 uint32_t vs_workers = VS_WORKERS_DEFAULT; /* max workers send reqs to vscand */
66 70 uint32_t vs_scan_wait = VS_SCANWAIT_DEFAULT; /* secs to wait for scan result */
67 71
68 72
69 73 /*
70 74 * vscan_svc_state
71 75 *
72 76 * +-----------------+
73 77 * | VS_SVC_UNCONFIG |
74 78 * +-----------------+
75 79 * | ^
76 80 * | svc_init | svc_fini
77 81 * v |
78 82 * +-----------------+
79 83 * | VS_SVC_IDLE |<----|
80 84 * +-----------------+ |
81 85 * | |
82 86 * | svc_enable |
83 87 * |<----------------| |
84 88 * v | |
85 89 * +-----------------+ | |
86 90 * | VS_SVC_ENABLED |--| |
87 91 * +-----------------+ |
88 92 * | |
89 93 * | svc_disable | handler thread exit,
90 94 * v | all requests complete
91 95 * +-----------------+ |
92 96 * | VS_SVC_DISABLED |-----|
93 97 * +-----------------+
94 98 *
95 99 * svc_enable may occur when we are already in the ENABLED
96 100 * state if vscand has exited without clean shutdown and
97 101 * then reconnected within the delayed disable time period
98 102 * (vs_reconnect_timeout) - see vscan_drv
99 103 */
100 104
101 105 typedef enum {
102 106 VS_SVC_UNCONFIG,
103 107 VS_SVC_IDLE,
104 108 VS_SVC_ENABLED, /* service enabled and registered */
105 109 VS_SVC_DISABLED /* service disabled and nunregistered */
106 110 } vscan_svc_state_t;
107 111 static vscan_svc_state_t vscan_svc_state = VS_SVC_UNCONFIG;
108 112
109 113
110 114 /*
111 115 * vscan_svc_req_state
112 116 *
113 117 * When a scan request is received from the file system it is
114 118 * identified in or inserted into the vscan_svc_reql (INIT).
115 119 * If the request is asynchronous 0 is then returned to the caller.
116 120 * If the request is synchronous the req's refcnt is incremented
117 121 * and the caller waits for the request to complete.
118 122 * The refcnt is also incremented when the request is inserted
119 123 * in vscan_svc_nodes, and decremented on scan_complete.
120 124 *
121 125 * vscan_svc_handler processes requests from the request list,
122 126 * inserting them into vscan_svc_nodes and the task queue (QUEUED).
123 127 * When the task queue call back (vscan_svc_do_scan) is invoked
124 128 * the request transitions to IN_PROGRESS state. If the request
125 129 * is sucessfully sent to vscand (door_call) and the door response
126 130 * is SCANNING then the scan result will be received asynchronously.
127 131 * Although unusual, it is possible that the async response is
128 132 * received before the door call returns (hence the ASYNC_COMPLETE
129 133 * state).
130 134 * When the result has been determined / received,
131 135 * vscan_svc_scan_complete is invoked to transition the request to
132 136 * COMPLETE state, decrement refcnt and signal all waiting callers.
133 137 * When the last waiting caller has processed the result (refcnt == 0)
134 138 * the request is removed from vscan_svc_reql and vscan_svc_nodes
135 139 * and deleted.
136 140 *
137 141 * | ^
138 142 * | reql_insert | refcnt == 0
139 143 * v | (delete)
140 144 * +------------------------+ +---------------------+
141 145 * | VS_SVC_REQ_INIT | -----DISABLE----> | VS_SVC_REQ_COMPLETE |
142 146 * +------------------------+ +---------------------+
143 147 * | ^
144 148 * | insert_req, tq_dispatch |
145 149 * v |
146 150 * +------------------------+ |
147 151 * | VS_SVC_REQ_QUEUED | scan_complete
148 152 * +------------------------+ |
149 153 * | |
150 154 * | tq_callback (do_scan) |
151 155 * | |
152 156 * v scan not req'd, error, |
153 157 * +------------------------+ or door_result != SCANNING |
154 158 * | VS_SVC_REQ_IN_PROGRESS |----------------->-------------|
155 159 * +------------------------+ |
156 160 * | | |
157 161 * | | door_result == SCANNING |
158 162 * | v |
159 163 * | +---------------------------+ async result |
160 164 * | | VS_SVC_REQ_SCANNING |-------->---------|
161 165 * | +---------------------------+ |
162 166 * | |
163 167 * | async result |
164 168 * v |
165 169 * +---------------------------+ door_result = SCANNING |
166 170 * | VS_SVC_REQ_ASYNC_COMPLETE |-------->------------------|
167 171 * +---------------------------+
168 172 */
169 173 typedef enum {
170 174 VS_SVC_REQ_INIT,
171 175 VS_SVC_REQ_QUEUED,
172 176 VS_SVC_REQ_IN_PROGRESS,
173 177 VS_SVC_REQ_SCANNING,
174 178 VS_SVC_REQ_ASYNC_COMPLETE,
175 179 VS_SVC_REQ_COMPLETE
176 180 } vscan_svc_req_state_t;
177 181
178 182
179 183 /*
180 184 * vscan_svc_reql - the list of pending and in-progress scan requests
181 185 */
182 186 typedef struct vscan_req {
183 187 uint32_t vsr_magic; /* VS_REQ_MAGIC */
184 188 list_node_t vsr_lnode;
185 189 vnode_t *vsr_vp;
186 190 uint32_t vsr_idx; /* vscan_svc_nodes index */
187 191 uint32_t vsr_seqnum; /* unigue request id */
188 192 uint32_t vsr_refcnt;
189 193 kcondvar_t vsr_cv;
190 194 vscan_svc_req_state_t vsr_state;
191 195 } vscan_req_t;
192 196
193 197 static list_t vscan_svc_reql;
194 198
195 199
196 200 /*
197 201 * vscan_svc_nodes - table of files being scanned
198 202 *
199 203 * The index into this table is passed in the door call to
200 204 * vscand. vscand uses the idx to determine which minor node
201 205 * to open to read the file data. Within the kernel driver
202 206 * the minor device number can thus be used to identify the
203 207 * table index to get the appropriate vnode.
204 208 *
205 209 * Instance 0 is reserved for the daemon/driver control
206 210 * interface: enable/configure/disable
207 211 */
208 212 typedef struct vscan_svc_node {
209 213 vscan_req_t *vsn_req;
210 214 uint8_t vsn_quarantined;
211 215 uint8_t vsn_modified;
212 216 uint64_t vsn_size;
213 217 timestruc_t vsn_mtime;
214 218 vs_scanstamp_t vsn_scanstamp;
215 219 uint32_t vsn_result;
216 220 uint32_t vsn_access;
217 221 } vscan_svc_node_t;
218 222
219 223 static vscan_svc_node_t *vscan_svc_nodes;
220 224 static int vscan_svc_nodes_sz;
221 225
222 226
223 227 /* vscan_svc_taskq - queue of requests waiting to be sent to vscand */
224 228 static taskq_t *vscan_svc_taskq = NULL;
225 229
226 230 /* counts of entries in vscan_svc_reql, vscan_svc_nodes & vscan_svc_taskq */
227 231 typedef struct {
228 232 uint32_t vsc_reql;
229 233 uint32_t vsc_node;
230 234 uint32_t vsc_tq;
231 235 } vscan_svc_counts_t;
232 236 static vscan_svc_counts_t vscan_svc_counts;
233 237
234 238 /*
235 239 * vscan_svc_mutex protects the data pertaining to scan requests:
236 240 * request list - vscan_svc_reql
237 241 * node table - vscan_svc_nodes
238 242 */
239 243 static kmutex_t vscan_svc_mutex;
240 244
241 245 /* unique request id for vscand request/response correlation */
242 246 static uint32_t vscan_svc_seqnum = 0;
243 247
244 248 /*
245 249 * vscan_svc_cfg_mutex protects the configuration data:
246 250 * vscan_svc_config, vscan_svc_types
247 251 */
248 252 static kmutex_t vscan_svc_cfg_mutex;
249 253
250 254 /* configuration data - for virus scan exemption */
251 255 static vs_config_t vscan_svc_config;
252 256 static char *vscan_svc_types[VS_TYPES_MAX];
253 257
254 258 /* thread to insert reql entries into vscan_svc_nodes & vscan_svc_taskq */
255 259 static kthread_t *vscan_svc_reql_thread;
256 260 static kcondvar_t vscan_svc_reql_cv;
257 261 static vscan_req_t *vscan_svc_reql_next; /* next pending scan request */
258 262
259 263 /* local functions */
260 264 int vscan_svc_scan_file(vnode_t *, cred_t *, int);
261 265 static void vscan_svc_taskq_callback(void *);
262 266 static int vscan_svc_exempt_file(vnode_t *, boolean_t *);
263 267 static int vscan_svc_exempt_filetype(char *);
264 268 static int vscan_svc_match_ext(char *, char *, int);
265 269 static void vscan_svc_do_scan(vscan_req_t *);
266 270 static vs_scan_req_t *vscan_svc_populate_req(int);
267 271 static void vscan_svc_process_scan_result(int);
268 272 static void vscan_svc_scan_complete(vscan_req_t *);
269 273 static void vscan_svc_delete_req(vscan_req_t *);
270 274 static int vscan_svc_insert_req(vscan_req_t *);
271 275 static void vscan_svc_remove_req(int);
272 276 static vscan_req_t *vscan_svc_reql_find(vnode_t *);
273 277 static vscan_req_t *vscan_svc_reql_insert(vnode_t *);
274 278 static void vscan_svc_reql_remove(vscan_req_t *);
275 279
276 280 static int vscan_svc_getattr(int);
277 281 static int vscan_svc_setattr(int, int);
278 282
279 283 /* thread to insert reql entries into vscan_svc_nodes & vscan_svc_taskq */
280 284 static void vscan_svc_reql_handler(void);
281 285
282 286
283 287 /*
284 288 * vscan_svc_init
285 289 */
286 290 int
287 291 vscan_svc_init()
288 292 {
289 293 if (vscan_svc_state != VS_SVC_UNCONFIG) {
290 294 DTRACE_PROBE1(vscan__svc__state__violation,
291 295 int, vscan_svc_state);
292 296 return (-1);
293 297 }
294 298
295 299 mutex_init(&vscan_svc_mutex, NULL, MUTEX_DEFAULT, NULL);
296 300 mutex_init(&vscan_svc_cfg_mutex, NULL, MUTEX_DEFAULT, NULL);
297 301 cv_init(&vscan_svc_reql_cv, NULL, CV_DEFAULT, NULL);
298 302
299 303 vscan_svc_nodes_sz = sizeof (vscan_svc_node_t) * (vs_nodes_max + 1);
300 304 vscan_svc_nodes = kmem_zalloc(vscan_svc_nodes_sz, KM_SLEEP);
301 305
302 306 vscan_svc_counts.vsc_reql = 0;
303 307 vscan_svc_counts.vsc_node = 0;
304 308 vscan_svc_counts.vsc_tq = 0;
305 309
306 310 vscan_svc_state = VS_SVC_IDLE;
307 311
308 312 return (0);
309 313 }
310 314
311 315
312 316 /*
313 317 * vscan_svc_fini
314 318 */
315 319 void
316 320 vscan_svc_fini()
317 321 {
318 322 if (vscan_svc_state != VS_SVC_IDLE) {
319 323 DTRACE_PROBE1(vscan__svc__state__violation,
320 324 int, vscan_svc_state);
321 325 return;
322 326 }
323 327
324 328 kmem_free(vscan_svc_nodes, vscan_svc_nodes_sz);
325 329
326 330 cv_destroy(&vscan_svc_reql_cv);
327 331 mutex_destroy(&vscan_svc_mutex);
328 332 mutex_destroy(&vscan_svc_cfg_mutex);
329 333 vscan_svc_state = VS_SVC_UNCONFIG;
330 334 }
331 335
332 336
333 337 /*
334 338 * vscan_svc_enable
335 339 */
336 340 int
337 341 vscan_svc_enable(void)
338 342 {
339 343 mutex_enter(&vscan_svc_mutex);
340 344
341 345 switch (vscan_svc_state) {
342 346 case VS_SVC_ENABLED:
343 347 /*
344 348 * it's possible (and okay) for vscan_svc_enable to be
345 349 * called when already enabled if vscand reconnects
346 350 * during a delayed disable
347 351 */
348 352 break;
349 353 case VS_SVC_IDLE:
350 354 list_create(&vscan_svc_reql, sizeof (vscan_req_t),
351 355 offsetof(vscan_req_t, vsr_lnode));
352 356 vscan_svc_reql_next = list_head(&vscan_svc_reql);
353 357
354 358 vscan_svc_taskq = taskq_create("vscan_taskq", vs_workers,
355 359 MINCLSYSPRI, 1, INT_MAX, TASKQ_DYNAMIC);
356 360 ASSERT(vscan_svc_taskq != NULL);
357 361
358 362 vscan_svc_reql_thread = thread_create(NULL, 0,
359 363 vscan_svc_reql_handler, 0, 0, &p0, TS_RUN, MINCLSYSPRI);
360 364 ASSERT(vscan_svc_reql_thread != NULL);
361 365
362 366 /* ready to start processing requests */
363 367 vscan_svc_state = VS_SVC_ENABLED;
364 368 fs_vscan_register(vscan_svc_scan_file);
365 369 break;
366 370 default:
367 371 DTRACE_PROBE1(vscan__svc__state__violation,
368 372 int, vscan_svc_state);
369 373 return (-1);
370 374 }
371 375
372 376 mutex_exit(&vscan_svc_mutex);
373 377 return (0);
374 378 }
375 379
376 380
377 381 /*
378 382 * vscan_svc_disable
379 383 *
380 384 * Resources allocated during vscan_svc_enable are free'd by
381 385 * the handler thread immediately prior to exiting
382 386 */
383 387 void
384 388 vscan_svc_disable(void)
385 389 {
386 390 mutex_enter(&vscan_svc_mutex);
387 391
388 392 switch (vscan_svc_state) {
389 393 case VS_SVC_ENABLED:
390 394 fs_vscan_register(NULL);
391 395 vscan_svc_state = VS_SVC_DISABLED;
392 396 cv_signal(&vscan_svc_reql_cv); /* wake handler thread */
393 397 break;
394 398 default:
395 399 DTRACE_PROBE1(vscan__svc__state__violation, int,
396 400 vscan_svc_state);
397 401 }
398 402
399 403 mutex_exit(&vscan_svc_mutex);
400 404 }
401 405
402 406
403 407 /*
404 408 * vscan_svc_in_use
405 409 */
406 410 boolean_t
407 411 vscan_svc_in_use()
408 412 {
409 413 boolean_t in_use;
410 414
411 415 mutex_enter(&vscan_svc_mutex);
412 416
413 417 switch (vscan_svc_state) {
414 418 case VS_SVC_IDLE:
415 419 case VS_SVC_UNCONFIG:
416 420 in_use = B_FALSE;
417 421 break;
418 422 default:
419 423 in_use = B_TRUE;
420 424 break;
421 425 }
422 426
423 427 mutex_exit(&vscan_svc_mutex);
424 428 return (in_use);
425 429 }
426 430
427 431
428 432 /*
429 433 * vscan_svc_get_vnode
430 434 *
431 435 * Get the file vnode indexed by idx.
432 436 */
433 437 vnode_t *
434 438 vscan_svc_get_vnode(int idx)
435 439 {
436 440 vnode_t *vp = NULL;
437 441
438 442 ASSERT(idx > 0);
439 443 ASSERT(idx <= vs_nodes_max);
440 444
441 445 mutex_enter(&vscan_svc_mutex);
442 446 if (vscan_svc_nodes[idx].vsn_req)
443 447 vp = vscan_svc_nodes[idx].vsn_req->vsr_vp;
444 448 mutex_exit(&vscan_svc_mutex);
445 449
446 450 return (vp);
447 451 }
448 452
449 453
450 454 /*
451 455 * vscan_svc_scan_file
452 456 *
453 457 * This function is the entry point for the file system to
454 458 * request that a file be virus scanned.
455 459 */
456 460 int
457 461 vscan_svc_scan_file(vnode_t *vp, cred_t *cr, int async)
458 462 {
459 463 int access;
460 464 vscan_req_t *req;
461 465 boolean_t allow;
462 466 clock_t timeout, time_left;
463 467
464 468 if ((vp == NULL) || (vp->v_path == NULL) || cr == NULL)
465 469 return (0);
466 470
467 471 DTRACE_PROBE2(vscan__scan__file, char *, vp->v_path, int, async);
468 472
469 473 /* check if size or type exempts file from scanning */
470 474 if (vscan_svc_exempt_file(vp, &allow)) {
471 475 if ((allow == B_TRUE) || (async != 0))
472 476 return (0);
473 477
474 478 return (EACCES);
475 479 }
476 480
477 481 mutex_enter(&vscan_svc_mutex);
478 482
479 483 if (vscan_svc_state != VS_SVC_ENABLED) {
480 484 DTRACE_PROBE1(vscan__svc__state__violation,
481 485 int, vscan_svc_state);
482 486 mutex_exit(&vscan_svc_mutex);
483 487 return (0);
484 488 }
485 489
486 490 /* insert (or find) request in list */
487 491 if ((req = vscan_svc_reql_insert(vp)) == NULL) {
488 492 mutex_exit(&vscan_svc_mutex);
489 493 cmn_err(CE_WARN, "Virus scan request list full");
490 494 return ((async != 0) ? 0 : EACCES);
491 495 }
492 496
493 497 /* asynchronous request: return 0 */
494 498 if (async) {
495 499 mutex_exit(&vscan_svc_mutex);
496 500 return (0);
497 501 }
498 502
499 503 /* synchronous scan request: wait for result */
500 504 ++(req->vsr_refcnt);
501 505 time_left = SEC_TO_TICK(vs_scan_wait);
502 506 while ((time_left > 0) && (req->vsr_state != VS_SVC_REQ_COMPLETE)) {
503 507 timeout = time_left;
504 508 time_left = cv_reltimedwait_sig(&(req->vsr_cv),
505 509 &vscan_svc_mutex, timeout, TR_CLOCK_TICK);
506 510 }
507 511
508 512 if (time_left == -1) {
509 513 cmn_err(CE_WARN, "Virus scan request timeout %s (%d) \n",
510 514 vp->v_path, req->vsr_seqnum);
511 515 DTRACE_PROBE1(vscan__scan__timeout, vscan_req_t *, req);
512 516 }
513 517
514 518 ASSERT(req->vsr_magic == VS_REQ_MAGIC);
515 519 if (vscan_svc_state == VS_SVC_DISABLED)
516 520 access = VS_ACCESS_ALLOW;
517 521 else if (req->vsr_idx == 0)
518 522 access = VS_ACCESS_DENY;
519 523 else
520 524 access = vscan_svc_nodes[req->vsr_idx].vsn_access;
521 525
522 526 if ((--req->vsr_refcnt) == 0)
523 527 vscan_svc_delete_req(req);
524 528
525 529 mutex_exit(&vscan_svc_mutex);
526 530 return ((access == VS_ACCESS_ALLOW) ? 0 : EACCES);
527 531 }
528 532
529 533
530 534 /*
531 535 * vscan_svc_reql_handler
532 536 *
533 537 * inserts scan requests (from vscan_svc_reql) into
534 538 * vscan_svc_nodes and vscan_svc_taskq
535 539 */
536 540 static void
537 541 vscan_svc_reql_handler(void)
538 542 {
539 543 vscan_req_t *req, *next;
540 544
541 545 for (;;) {
542 546 mutex_enter(&vscan_svc_mutex);
543 547
544 548 if ((vscan_svc_state == VS_SVC_DISABLED) &&
545 549 (vscan_svc_counts.vsc_reql == 0)) {
546 550 /* free resources allocated durining enable */
547 551 taskq_destroy(vscan_svc_taskq);
548 552 vscan_svc_taskq = NULL;
549 553 list_destroy(&vscan_svc_reql);
550 554 vscan_svc_state = VS_SVC_IDLE;
551 555 mutex_exit(&vscan_svc_mutex);
552 556 return;
553 557 }
554 558
555 559 /*
556 560 * If disabled, scan_complete any pending requests.
557 561 * Otherwise insert pending requests into vscan_svc_nodes
558 562 * and vscan_svc_taskq. If no slots are available in
559 563 * vscan_svc_nodes break loop and wait for one
560 564 */
561 565 req = vscan_svc_reql_next;
562 566
563 567 while (req != NULL) {
564 568 ASSERT(req->vsr_magic == VS_REQ_MAGIC);
565 569 next = list_next(&vscan_svc_reql, req);
566 570
567 571 if (vscan_svc_state == VS_SVC_DISABLED) {
568 572 vscan_svc_scan_complete(req);
569 573 } else {
570 574 /* insert request into vscan_svc_nodes */
571 575 if (vscan_svc_insert_req(req) == -1)
572 576 break;
573 577
574 578 /* add the scan request into the taskq */
575 579 (void) taskq_dispatch(vscan_svc_taskq,
576 580 vscan_svc_taskq_callback,
577 581 (void *)req, TQ_SLEEP);
578 582 ++(vscan_svc_counts.vsc_tq);
579 583
580 584 req->vsr_state = VS_SVC_REQ_QUEUED;
581 585 }
582 586 req = next;
583 587 }
584 588
585 589 vscan_svc_reql_next = req;
586 590
587 591 DTRACE_PROBE2(vscan__req__counts, char *, "handler wait",
588 592 vscan_svc_counts_t *, &vscan_svc_counts);
589 593
590 594 (void) cv_reltimedwait(&vscan_svc_reql_cv, &vscan_svc_mutex,
591 595 SEC_TO_TICK(VS_REQL_HANDLER_TIMEOUT), TR_CLOCK_TICK);
592 596
593 597 DTRACE_PROBE2(vscan__req__counts, char *, "handler wake",
594 598 vscan_svc_counts_t *, &vscan_svc_counts);
595 599
596 600 mutex_exit(&vscan_svc_mutex);
597 601 }
598 602 }
599 603
600 604
601 605 static void
602 606 vscan_svc_taskq_callback(void *data)
603 607 {
604 608 vscan_req_t *req;
605 609
606 610 mutex_enter(&vscan_svc_mutex);
607 611
608 612 req = (vscan_req_t *)data;
609 613 ASSERT(req->vsr_magic == VS_REQ_MAGIC);
610 614 vscan_svc_do_scan(req);
611 615 if (req->vsr_state != VS_SVC_REQ_SCANNING)
612 616 vscan_svc_scan_complete(req);
613 617
614 618 --(vscan_svc_counts.vsc_tq);
615 619 mutex_exit(&vscan_svc_mutex);
616 620 }
617 621
618 622
619 623 /*
620 624 * vscan_svc_do_scan
621 625 *
622 626 * Note: To avoid potential deadlock it is important that
623 627 * vscan_svc_mutex is not held during the call to
624 628 * vscan_drv_create_note. vscan_drv_create_note enters
625 629 * the vscan_drv_mutex and it is possible that a thread
626 630 * holding that mutex could be waiting for vscan_svc_mutex.
627 631 */
628 632 static void
629 633 vscan_svc_do_scan(vscan_req_t *req)
630 634 {
631 635 int idx, result;
632 636 vscan_svc_node_t *node;
633 637 vs_scan_req_t *door_req;
634 638
635 639 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
636 640
637 641 idx = req->vsr_idx;
638 642 node = &vscan_svc_nodes[idx];
639 643
640 644 req->vsr_state = VS_SVC_REQ_IN_PROGRESS;
641 645
642 646 /* if vscan not enabled (shutting down), allow ACCESS */
643 647 if (vscan_svc_state != VS_SVC_ENABLED) {
644 648 node->vsn_access = VS_ACCESS_ALLOW;
645 649 return;
646 650 }
647 651
648 652 if (vscan_svc_getattr(idx) != 0) {
649 653 cmn_err(CE_WARN, "Can't access xattr for %s\n",
650 654 req->vsr_vp->v_path);
651 655 node->vsn_access = VS_ACCESS_DENY;
652 656 return;
653 657 }
654 658
655 659 /* valid scan_req ptr guaranteed */
656 660 door_req = vscan_svc_populate_req(idx);
657 661
658 662 /* free up mutex around create node and door call */
659 663 mutex_exit(&vscan_svc_mutex);
660 664 if (vscan_drv_create_node(idx) != B_TRUE)
661 665 result = VS_STATUS_ERROR;
662 666 else
663 667 result = vscan_door_scan_file(door_req);
664 668 kmem_free(door_req, sizeof (vs_scan_req_t));
665 669 mutex_enter(&vscan_svc_mutex);
666 670
667 671 if (result != VS_STATUS_SCANNING) {
668 672 vscan_svc_nodes[idx].vsn_result = result;
669 673 vscan_svc_process_scan_result(idx);
670 674 } else { /* async response */
671 675 if (req->vsr_state == VS_SVC_REQ_IN_PROGRESS)
672 676 req->vsr_state = VS_SVC_REQ_SCANNING;
673 677 }
674 678 }
675 679
676 680
677 681 /*
678 682 * vscan_svc_populate_req
679 683 *
680 684 * Allocate a scan request to be sent to vscand, populating it
681 685 * from the data in vscan_svc_nodes[idx].
682 686 *
683 687 * Returns: scan request object
684 688 */
685 689 static vs_scan_req_t *
686 690 vscan_svc_populate_req(int idx)
687 691 {
688 692 vs_scan_req_t *scan_req;
689 693 vscan_req_t *req;
690 694 vscan_svc_node_t *node;
691 695
692 696 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
693 697
694 698 node = &vscan_svc_nodes[idx];
695 699 req = node->vsn_req;
696 700 scan_req = kmem_zalloc(sizeof (vs_scan_req_t), KM_SLEEP);
697 701
698 702 scan_req->vsr_idx = idx;
699 703 scan_req->vsr_seqnum = req->vsr_seqnum;
700 704 (void) strncpy(scan_req->vsr_path, req->vsr_vp->v_path, MAXPATHLEN);
701 705 scan_req->vsr_size = node->vsn_size;
702 706 scan_req->vsr_modified = node->vsn_modified;
703 707 scan_req->vsr_quarantined = node->vsn_quarantined;
704 708 scan_req->vsr_flags = 0;
705 709 (void) strncpy(scan_req->vsr_scanstamp,
706 710 node->vsn_scanstamp, sizeof (vs_scanstamp_t));
707 711
708 712 return (scan_req);
709 713 }
710 714
711 715
712 716 /*
713 717 * vscan_svc_scan_complete
714 718 */
715 719 static void
716 720 vscan_svc_scan_complete(vscan_req_t *req)
717 721 {
718 722 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
719 723 ASSERT(req != NULL);
720 724
721 725 req->vsr_state = VS_SVC_REQ_COMPLETE;
722 726
723 727 if ((--req->vsr_refcnt) == 0)
724 728 vscan_svc_delete_req(req);
725 729 else
726 730 cv_broadcast(&(req->vsr_cv));
727 731 }
728 732
729 733
730 734 /*
731 735 * vscan_svc_delete_req
732 736 */
733 737 static void
734 738 vscan_svc_delete_req(vscan_req_t *req)
735 739 {
736 740 int idx;
737 741
738 742 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
739 743 ASSERT(req != NULL);
740 744 ASSERT(req->vsr_refcnt == 0);
741 745 ASSERT(req->vsr_state == VS_SVC_REQ_COMPLETE);
742 746
743 747 if ((idx = req->vsr_idx) != 0)
744 748 vscan_svc_remove_req(idx);
745 749
746 750 vscan_svc_reql_remove(req);
747 751
748 752 cv_signal(&vscan_svc_reql_cv);
749 753 }
750 754
751 755
752 756 /*
753 757 * vscan_svc_scan_result
754 758 *
755 759 * Invoked from vscan_drv.c on receipt of an ioctl containing
756 760 * an async scan result (VS_DRV_IOCTL_RESULT)
757 761 * If the vsr_seqnum in the response does not match that in the
758 762 * vscan_svc_nodes entry the result is discarded.
759 763 */
760 764 void
761 765 vscan_svc_scan_result(vs_scan_rsp_t *scan_rsp)
762 766 {
763 767 vscan_req_t *req;
764 768 vscan_svc_node_t *node;
765 769
766 770 mutex_enter(&vscan_svc_mutex);
767 771
768 772 node = &vscan_svc_nodes[scan_rsp->vsr_idx];
769 773
770 774 if ((req = node->vsn_req) == NULL) {
771 775 mutex_exit(&vscan_svc_mutex);
772 776 return;
773 777 }
774 778
775 779 ASSERT(req->vsr_magic == VS_REQ_MAGIC);
776 780
777 781 if (scan_rsp->vsr_seqnum != req->vsr_seqnum) {
778 782 mutex_exit(&vscan_svc_mutex);
779 783 return;
780 784 }
781 785
782 786 node->vsn_result = scan_rsp->vsr_result;
783 787 (void) strncpy(node->vsn_scanstamp,
784 788 scan_rsp->vsr_scanstamp, sizeof (vs_scanstamp_t));
785 789
786 790 vscan_svc_process_scan_result(scan_rsp->vsr_idx);
787 791
788 792 if (node->vsn_req->vsr_state == VS_SVC_REQ_SCANNING)
789 793 vscan_svc_scan_complete(node->vsn_req);
790 794 else
791 795 node->vsn_req->vsr_state = VS_SVC_REQ_ASYNC_COMPLETE;
792 796
793 797 mutex_exit(&vscan_svc_mutex);
794 798 }
795 799
796 800
797 801 /*
798 802 * vscan_svc_scan_abort
799 803 *
800 804 * Abort in-progress scan requests.
801 805 */
802 806 void
803 807 vscan_svc_scan_abort()
804 808 {
805 809 int idx;
806 810 vscan_req_t *req;
807 811
808 812 mutex_enter(&vscan_svc_mutex);
809 813
810 814 for (idx = 1; idx <= vs_nodes_max; idx++) {
811 815 if ((req = vscan_svc_nodes[idx].vsn_req) == NULL)
812 816 continue;
813 817
814 818 ASSERT(req->vsr_magic == VS_REQ_MAGIC);
815 819
816 820 if (req->vsr_state == VS_SVC_REQ_SCANNING) {
817 821 DTRACE_PROBE1(vscan__abort, vscan_req_t *, req);
818 822 vscan_svc_process_scan_result(idx);
819 823 vscan_svc_scan_complete(req);
820 824 }
821 825 }
822 826
823 827 mutex_exit(&vscan_svc_mutex);
824 828 }
825 829
826 830
827 831 /*
828 832 * vscan_svc_process_scan_result
829 833 *
830 834 * Sets vsn_access and updates file attributes based on vsn_result,
831 835 * as follows:
832 836 *
833 837 * VS_STATUS_INFECTED
834 838 * deny access, set quarantine attribute, clear scanstamp
835 839 * VS_STATUS_CLEAN
836 840 * allow access, set scanstamp,
837 841 * if file not modified since scan initiated, clear modified attribute
838 842 * VS_STATUS_NO_SCAN
839 843 * deny access if file quarantined, otherwise allow access
840 844 * VS_STATUS_UNDEFINED, VS_STATUS_ERROR
841 845 * deny access if file quarantined, modified or no scanstamp
842 846 * otherwise, allow access
843 847 */
844 848 static void
845 849 vscan_svc_process_scan_result(int idx)
846 850 {
847 851 struct vattr attr;
848 852 vnode_t *vp;
849 853 timestruc_t *mtime;
850 854 vscan_svc_node_t *node;
851 855
852 856 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
853 857
854 858 node = &vscan_svc_nodes[idx];
855 859
856 860 switch (node->vsn_result) {
857 861 case VS_STATUS_INFECTED:
858 862 node->vsn_access = VS_ACCESS_DENY;
859 863 node->vsn_quarantined = 1;
860 864 node->vsn_scanstamp[0] = '\0';
861 865 (void) vscan_svc_setattr(idx,
862 866 XAT_AV_QUARANTINED | XAT_AV_SCANSTAMP);
863 867 break;
864 868
865 869 case VS_STATUS_CLEAN:
866 870 node->vsn_access = VS_ACCESS_ALLOW;
867 871
868 872 /* if mtime has changed, don't clear the modified attribute */
869 873 vp = node->vsn_req->vsr_vp;
870 874 mtime = &(node->vsn_mtime);
871 875 attr.va_mask = AT_MTIME;
872 876 if ((VOP_GETATTR(vp, &attr, 0, kcred, NULL) != 0) ||
873 877 (mtime->tv_sec != attr.va_mtime.tv_sec) ||
874 878 (mtime->tv_nsec != attr.va_mtime.tv_nsec)) {
875 879 DTRACE_PROBE1(vscan__mtime__changed, vscan_svc_node_t *,
876 880 node);
877 881 (void) vscan_svc_setattr(idx, XAT_AV_SCANSTAMP);
878 882 break;
879 883 }
880 884
881 885 node->vsn_modified = 0;
882 886 (void) vscan_svc_setattr(idx,
883 887 XAT_AV_SCANSTAMP | XAT_AV_MODIFIED);
884 888 break;
885 889
886 890 case VS_STATUS_NO_SCAN:
887 891 if (node->vsn_quarantined)
888 892 node->vsn_access = VS_ACCESS_DENY;
889 893 else
890 894 node->vsn_access = VS_ACCESS_ALLOW;
891 895 break;
892 896
893 897 case VS_STATUS_ERROR:
894 898 case VS_STATUS_UNDEFINED:
895 899 default:
896 900 if ((node->vsn_quarantined) ||
897 901 (node->vsn_modified) ||
898 902 (node->vsn_scanstamp[0] == '\0'))
899 903 node->vsn_access = VS_ACCESS_DENY;
900 904 else
901 905 node->vsn_access = VS_ACCESS_ALLOW;
902 906 break;
903 907 }
904 908
905 909 DTRACE_PROBE4(vscan__result,
906 910 int, idx, int, node->vsn_req->vsr_seqnum,
907 911 int, node->vsn_result, int, node->vsn_access);
908 912 }
909 913
910 914
911 915 /*
912 916 * vscan_svc_getattr
913 917 *
914 918 * Get the vscan related system attributes, AT_SIZE & AT_MTIME.
915 919 */
916 920 static int
917 921 vscan_svc_getattr(int idx)
918 922 {
919 923 xvattr_t xvattr;
920 924 xoptattr_t *xoap = NULL;
921 925 vnode_t *vp;
922 926 vscan_svc_node_t *node;
923 927
924 928 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
925 929
926 930 node = &vscan_svc_nodes[idx];
927 931 if ((vp = node->vsn_req->vsr_vp) == NULL)
928 932 return (-1);
929 933
930 934 /* get the attributes */
931 935 xva_init(&xvattr); /* sets AT_XVATTR */
932 936
933 937 xvattr.xva_vattr.va_mask |= AT_SIZE;
934 938 xvattr.xva_vattr.va_mask |= AT_MTIME;
935 939 XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
936 940 XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
937 941 XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP);
938 942
939 943 if (VOP_GETATTR(vp, (vattr_t *)&xvattr, 0, kcred, NULL) != 0)
940 944 return (-1);
941 945
942 946 if ((xoap = xva_getxoptattr(&xvattr)) == NULL) {
943 947 cmn_err(CE_NOTE, "Virus scan request failed; "
944 948 "file system does not support virus scanning");
945 949 return (-1);
946 950 }
947 951
948 952 node->vsn_size = xvattr.xva_vattr.va_size;
949 953 node->vsn_mtime.tv_sec = xvattr.xva_vattr.va_mtime.tv_sec;
950 954 node->vsn_mtime.tv_nsec = xvattr.xva_vattr.va_mtime.tv_nsec;
951 955
952 956 if (XVA_ISSET_RTN(&xvattr, XAT_AV_MODIFIED) == 0)
953 957 return (-1);
954 958 node->vsn_modified = xoap->xoa_av_modified;
955 959
956 960 if (XVA_ISSET_RTN(&xvattr, XAT_AV_QUARANTINED) == 0)
957 961 return (-1);
958 962 node->vsn_quarantined = xoap->xoa_av_quarantined;
959 963
960 964 if (XVA_ISSET_RTN(&xvattr, XAT_AV_SCANSTAMP) != 0) {
961 965 (void) memcpy(node->vsn_scanstamp,
962 966 xoap->xoa_av_scanstamp, AV_SCANSTAMP_SZ);
963 967 }
964 968
965 969 DTRACE_PROBE1(vscan__getattr, vscan_svc_node_t *, node);
966 970 return (0);
967 971 }
968 972
969 973
970 974 /*
971 975 * vscan_svc_setattr
972 976 *
973 977 * Set the vscan related system attributes.
974 978 */
975 979 static int
976 980 vscan_svc_setattr(int idx, int which)
977 981 {
978 982 xvattr_t xvattr;
979 983 xoptattr_t *xoap = NULL;
980 984 vnode_t *vp;
981 985 int len;
982 986 vscan_svc_node_t *node;
983 987
984 988 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
985 989
986 990 node = &vscan_svc_nodes[idx];
987 991 if ((vp = node->vsn_req->vsr_vp) == NULL)
988 992 return (-1);
989 993
990 994 /* update the attributes */
991 995 xva_init(&xvattr); /* sets AT_XVATTR */
992 996 if ((xoap = xva_getxoptattr(&xvattr)) == NULL)
993 997 return (-1);
994 998
995 999 if (which & XAT_AV_MODIFIED) {
996 1000 XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
997 1001 xoap->xoa_av_modified = node->vsn_modified;
998 1002 }
999 1003
1000 1004 if (which & XAT_AV_QUARANTINED) {
1001 1005 XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
1002 1006 xoap->xoa_av_quarantined = node->vsn_quarantined;
1003 1007 }
1004 1008
1005 1009 if (which & XAT_AV_SCANSTAMP) {
1006 1010 XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP);
1007 1011 len = strlen(node->vsn_scanstamp);
1008 1012 (void) memcpy(xoap->xoa_av_scanstamp,
1009 1013 node->vsn_scanstamp, len);
1010 1014 }
1011 1015
1012 1016 /* if access is denied, set mtime to invalidate client cache */
1013 1017 if (node->vsn_access != VS_ACCESS_ALLOW) {
1014 1018 xvattr.xva_vattr.va_mask |= AT_MTIME;
1015 1019 gethrestime(&xvattr.xva_vattr.va_mtime);
1016 1020 }
1017 1021
1018 1022 if (VOP_SETATTR(vp, (vattr_t *)&xvattr, 0, kcred, NULL) != 0)
1019 1023 return (-1);
1020 1024
1021 1025 DTRACE_PROBE2(vscan__setattr,
1022 1026 vscan_svc_node_t *, node, int, which);
1023 1027
1024 1028 return (0);
1025 1029 }
1026 1030
1027 1031
1028 1032 /*
1029 1033 * vscan_svc_configure
1030 1034 *
1031 1035 * store configuration in vscan_svc_config
1032 1036 * set up vscan_svc_types array of pointers into
1033 1037 * vscan_svc_config.vsc_types for efficient searching
1034 1038 */
1035 1039 int
1036 1040 vscan_svc_configure(vs_config_t *conf)
1037 1041 {
1038 1042 int count = 0;
1039 1043 char *p, *beg, *end;
1040 1044
1041 1045 mutex_enter(&vscan_svc_cfg_mutex);
1042 1046
1043 1047 vscan_svc_config = *conf;
1044 1048
1045 1049 (void) memset(vscan_svc_types, 0, sizeof (vscan_svc_types));
1046 1050
1047 1051 beg = vscan_svc_config.vsc_types;
1048 1052 end = beg + vscan_svc_config.vsc_types_len;
1049 1053
1050 1054 for (p = beg; p < end; p += strlen(p) + 1) {
1051 1055 if (count >= VS_TYPES_MAX) {
1052 1056 mutex_exit(&vscan_svc_mutex);
1053 1057 return (-1);
1054 1058 }
1055 1059
1056 1060 vscan_svc_types[count] = p;
1057 1061 ++count;
1058 1062 }
1059 1063
1060 1064 mutex_exit(&vscan_svc_cfg_mutex);
1061 1065 return (0);
1062 1066 }
1063 1067
1064 1068
1065 1069 /*
1066 1070 * vscan_svc_exempt_file
1067 1071 *
1068 1072 * check if a file's size or type exempts it from virus scanning
1069 1073 *
1070 1074 * If the file is exempt from virus scanning, allow will be set
1071 1075 * to define whether files access should be allowed (B_TRUE) or
1072 1076 * denied (B_FALSE)
1073 1077 *
1074 1078 * Returns: 1 exempt
1075 1079 * 0 scan required
1076 1080 */
1077 1081 static int
1078 1082 vscan_svc_exempt_file(vnode_t *vp, boolean_t *allow)
1079 1083 {
1080 1084 struct vattr attr;
1081 1085
1082 1086 ASSERT(vp != NULL);
1083 1087 ASSERT(vp->v_path != NULL);
1084 1088
1085 1089 attr.va_mask = AT_SIZE;
1086 1090
1087 1091 if (VOP_GETATTR(vp, &attr, 0, kcred, NULL) != 0) {
1088 1092 *allow = B_FALSE;
1089 1093 return (0);
1090 1094 }
1091 1095
1092 1096 mutex_enter(&vscan_svc_cfg_mutex);
1093 1097
1094 1098 if (attr.va_size > vscan_svc_config.vsc_max_size) {
1095 1099 DTRACE_PROBE2(vscan__exempt__filesize, char *,
1096 1100 vp->v_path, int, *allow);
1097 1101
1098 1102 *allow = (vscan_svc_config.vsc_allow) ? B_TRUE : B_FALSE;
1099 1103 mutex_exit(&vscan_svc_cfg_mutex);
1100 1104 return (1);
1101 1105 }
1102 1106
1103 1107 if (vscan_svc_exempt_filetype(vp->v_path)) {
1104 1108 DTRACE_PROBE1(vscan__exempt__filetype, char *, vp->v_path);
1105 1109 *allow = B_TRUE;
1106 1110 mutex_exit(&vscan_svc_cfg_mutex);
1107 1111 return (1);
1108 1112 }
1109 1113
1110 1114 mutex_exit(&vscan_svc_cfg_mutex);
1111 1115 return (0);
1112 1116 }
1113 1117
1114 1118
1115 1119 /*
1116 1120 * vscan_svc_exempt_filetype
1117 1121 *
1118 1122 * Each entry in vscan_svc_types includes a rule indicator (+,-)
1119 1123 * followed by the match string for file types to which the rule
1120 1124 * applies. Look for first match of file type in vscan_svc_types
1121 1125 * and return 1 (exempt) if the indicator is '-', and 0 (not exempt)
1122 1126 * if the indicator is '+'.
1123 1127 * If vscan_svc_match_ext fails, or no match is found, return 0
1124 1128 * (not exempt)
1125 1129 *
1126 1130 * Returns 1: exempt, 0: not exempt
1127 1131 */
1128 1132 static int
1129 1133 vscan_svc_exempt_filetype(char *filepath)
1130 1134 {
1131 1135 int i, rc, exempt = 0;
1132 1136 char *filename, *ext;
1133 1137
1134 1138 ASSERT(MUTEX_HELD(&vscan_svc_cfg_mutex));
1135 1139
1136 1140 if ((filename = strrchr(filepath, '/')) == 0)
1137 1141 filename = filepath;
1138 1142 else
1139 1143 filename++;
1140 1144
1141 1145 if ((ext = strrchr(filename, '.')) == NULL)
1142 1146 ext = "";
1143 1147 else
1144 1148 ext++;
1145 1149
1146 1150 for (i = 0; i < VS_TYPES_MAX; i ++) {
1147 1151 if (vscan_svc_types[i] == 0)
1148 1152 break;
1149 1153
1150 1154 rc = vscan_svc_match_ext(vscan_svc_types[i] + 1, ext, 1);
1151 1155 if (rc == -1)
1152 1156 break;
1153 1157 if (rc > 0) {
1154 1158 DTRACE_PROBE2(vscan__type__match, char *, ext,
1155 1159 char *, vscan_svc_types[i]);
1156 1160 exempt = (vscan_svc_types[i][0] == '-');
1157 1161 break;
1158 1162 }
1159 1163 }
1160 1164
1161 1165 return (exempt);
1162 1166 }
1163 1167
1164 1168
1165 1169 /*
1166 1170 * vscan_svc_match_ext
1167 1171 *
1168 1172 * Performs a case-insensitive match for two strings. The first string
1169 1173 * argument can contain the wildcard characters '?' and '*'
1170 1174 *
1171 1175 * Returns: 0 no match
1172 1176 * 1 match
1173 1177 * -1 recursion error
1174 1178 */
1175 1179 static int
1176 1180 vscan_svc_match_ext(char *patn, char *str, int depth)
1177 1181 {
1178 1182 int c1, c2;
1179 1183 if (depth > VS_EXT_RECURSE_DEPTH)
1180 1184 return (-1);
1181 1185
1182 1186 for (;;) {
1183 1187 switch (*patn) {
1184 1188 case 0:
1185 1189 return (*str == 0);
1186 1190
1187 1191 case '?':
1188 1192 if (*str != 0) {
1189 1193 str++;
1190 1194 patn++;
1191 1195 continue;
1192 1196 }
1193 1197 return (0);
1194 1198
1195 1199 case '*':
1196 1200 patn++;
1197 1201 if (*patn == 0)
1198 1202 return (1);
1199 1203
1200 1204 while (*str) {
1201 1205 if (vscan_svc_match_ext(patn, str, depth + 1))
1202 1206 return (1);
1203 1207 str++;
1204 1208 }
1205 1209 return (0);
1206 1210
1207 1211 default:
1208 1212 if (*str != *patn) {
1209 1213 c1 = *str;
1210 1214 c2 = *patn;
1211 1215
1212 1216 c1 = tolower(c1);
1213 1217 c2 = tolower(c2);
1214 1218 if (c1 != c2)
1215 1219 return (0);
1216 1220 }
1217 1221 str++;
1218 1222 patn++;
1219 1223 continue;
1220 1224 }
1221 1225 }
1222 1226 /* NOT REACHED */
1223 1227 }
1224 1228
1225 1229
1226 1230 /*
1227 1231 * vscan_svc_insert_req
1228 1232 *
1229 1233 * Insert request in next available available slot in vscan_svc_nodes
1230 1234 *
1231 1235 * Returns: idx of slot, or -1 if no slot available
1232 1236 */
1233 1237 static int
1234 1238 vscan_svc_insert_req(vscan_req_t *req)
1235 1239 {
1236 1240 int idx;
1237 1241 vscan_svc_node_t *node;
1238 1242
1239 1243 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
1240 1244
1241 1245 if (vscan_svc_counts.vsc_node == vs_nodes_max)
1242 1246 return (-1);
1243 1247
1244 1248 for (idx = 1; idx <= vs_nodes_max; idx++) {
1245 1249 if (vscan_svc_nodes[idx].vsn_req == NULL) {
1246 1250 req->vsr_idx = idx;
1247 1251
1248 1252 node = &vscan_svc_nodes[idx];
1249 1253 (void) memset(node, 0, sizeof (vscan_svc_node_t));
1250 1254 node->vsn_req = req;
1251 1255 node->vsn_modified = 1;
1252 1256 node->vsn_result = VS_STATUS_UNDEFINED;
1253 1257 node->vsn_access = VS_ACCESS_UNDEFINED;
1254 1258
1255 1259 ++(vscan_svc_counts.vsc_node);
1256 1260 return (idx);
1257 1261 }
1258 1262 }
1259 1263
1260 1264 return (-1);
1261 1265 }
1262 1266
1263 1267
1264 1268 /*
1265 1269 * vscan_svc_remove_req
1266 1270 */
1267 1271 static void
1268 1272 vscan_svc_remove_req(int idx)
1269 1273 {
1270 1274 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
1271 1275
1272 1276 if (idx != 0) {
1273 1277 (void) memset(&vscan_svc_nodes[idx], 0,
1274 1278 sizeof (vscan_svc_node_t));
1275 1279 --(vscan_svc_counts.vsc_node);
1276 1280 }
1277 1281 }
1278 1282
1279 1283
1280 1284 /*
1281 1285 * vscan_svc_reql_find
1282 1286 */
1283 1287 static vscan_req_t *
1284 1288 vscan_svc_reql_find(vnode_t *vp)
1285 1289 {
1286 1290 vscan_req_t *req;
1287 1291 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
1288 1292
1289 1293 req = list_head(&vscan_svc_reql);
1290 1294
1291 1295 while (req != NULL) {
1292 1296 ASSERT(req->vsr_magic == VS_REQ_MAGIC);
1293 1297 if ((req->vsr_vp == vp) &&
1294 1298 (req->vsr_state != VS_SVC_REQ_COMPLETE))
1295 1299 break;
1296 1300
1297 1301 req = list_next(&vscan_svc_reql, req);
1298 1302 }
1299 1303
1300 1304 return (req);
1301 1305 }
1302 1306
1303 1307
1304 1308 /*
1305 1309 * vscan_svc_reql_insert
1306 1310 */
1307 1311 static vscan_req_t *
1308 1312 vscan_svc_reql_insert(vnode_t *vp)
1309 1313 {
1310 1314 vscan_req_t *req;
1311 1315
1312 1316 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
1313 1317
1314 1318 /* if request already in list then return it */
1315 1319 if ((req = vscan_svc_reql_find(vp)) != NULL)
1316 1320 return (req);
1317 1321
1318 1322 /* if list is full return NULL */
1319 1323 if (vscan_svc_counts.vsc_reql == vs_reqs_max)
1320 1324 return (NULL);
1321 1325
1322 1326 /* create a new request and insert into list */
1323 1327 VN_HOLD(vp);
1324 1328
1325 1329 req = kmem_zalloc(sizeof (vscan_req_t), KM_SLEEP);
1326 1330
1327 1331 req->vsr_magic = VS_REQ_MAGIC;
1328 1332 if (vscan_svc_seqnum == UINT32_MAX)
1329 1333 vscan_svc_seqnum = 0;
1330 1334 req->vsr_seqnum = ++vscan_svc_seqnum;
1331 1335 req->vsr_vp = vp;
1332 1336 req->vsr_refcnt = 1; /* decremented in vscan_svc_scan_complete */
1333 1337 req->vsr_state = VS_SVC_REQ_INIT;
1334 1338 cv_init(&(req->vsr_cv), NULL, CV_DEFAULT, NULL);
1335 1339
1336 1340 list_insert_tail(&vscan_svc_reql, req);
1337 1341 if (vscan_svc_reql_next == NULL)
1338 1342 vscan_svc_reql_next = req;
1339 1343
1340 1344 ++(vscan_svc_counts.vsc_reql);
1341 1345
1342 1346 /* wake reql handler thread */
1343 1347 cv_signal(&vscan_svc_reql_cv);
1344 1348
1345 1349 return (req);
1346 1350 }
1347 1351
1348 1352
1349 1353 /*
1350 1354 * vscan_svc_reql_remove
1351 1355 */
1352 1356 static void
1353 1357 vscan_svc_reql_remove(vscan_req_t *req)
1354 1358 {
1355 1359 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
1356 1360 ASSERT(req->vsr_magic == VS_REQ_MAGIC);
1357 1361
1358 1362 if (vscan_svc_reql_next == req)
1359 1363 vscan_svc_reql_next = list_next(&vscan_svc_reql, req);
1360 1364
1361 1365 list_remove(&vscan_svc_reql, req);
1362 1366 cv_destroy(&(req->vsr_cv));
1363 1367 VN_RELE(req->vsr_vp);
1364 1368
1365 1369 kmem_free(req, sizeof (vscan_req_t));
1366 1370 --(vscan_svc_counts.vsc_reql);
1367 1371 }
↓ open down ↓ |
1297 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX