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