1911106dfSjm199354 /*
2911106dfSjm199354 * CDDL HEADER START
3911106dfSjm199354 *
4911106dfSjm199354 * The contents of this file are subject to the terms of the
5911106dfSjm199354 * Common Development and Distribution License (the "License").
6911106dfSjm199354 * You may not use this file except in compliance with the License.
7911106dfSjm199354 *
8911106dfSjm199354 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9911106dfSjm199354 * or http://www.opensolaris.org/os/licensing.
10911106dfSjm199354 * See the License for the specific language governing permissions
11911106dfSjm199354 * and limitations under the License.
12911106dfSjm199354 *
13911106dfSjm199354 * When distributing Covered Code, include this CDDL HEADER in each
14911106dfSjm199354 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15911106dfSjm199354 * If applicable, add the following below this CDDL HEADER, with the
16911106dfSjm199354 * fields enclosed by brackets "[]" replaced with your own identifying
17911106dfSjm199354 * information: Portions Copyright [yyyy] [name of copyright owner]
18911106dfSjm199354 *
19911106dfSjm199354 * CDDL HEADER END
20911106dfSjm199354 */
21911106dfSjm199354
22911106dfSjm199354 /*
23*d3d50737SRafael Vanoni * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24911106dfSjm199354 * Use is subject to license terms.
25911106dfSjm199354 */
26911106dfSjm199354
27911106dfSjm199354 #include <sys/stat.h>
28911106dfSjm199354 #include <sys/ddi.h>
29911106dfSjm199354 #include <sys/sunddi.h>
30911106dfSjm199354 #include <sys/time.h>
31911106dfSjm199354 #include <sys/varargs.h>
32911106dfSjm199354 #include <sys/conf.h>
33911106dfSjm199354 #include <sys/modctl.h>
34911106dfSjm199354 #include <sys/cmn_err.h>
35911106dfSjm199354 #include <sys/vnode.h>
36911106dfSjm199354 #include <fs/fs_subr.h>
37911106dfSjm199354 #include <sys/types.h>
38911106dfSjm199354 #include <sys/file.h>
39911106dfSjm199354 #include <sys/disp.h>
40911106dfSjm199354 #include <sys/sdt.h>
41911106dfSjm199354 #include <sys/cred.h>
42bfc848c6Sjm199354 #include <sys/list.h>
43911106dfSjm199354 #include <sys/vscan.h>
44911106dfSjm199354
45bfc848c6Sjm199354 #define VS_REQ_MAGIC 0x52515354 /* 'RQST' */
46911106dfSjm199354
47bfc848c6Sjm199354 #define VS_REQS_DEFAULT 20000 /* pending scan requests - reql */
48bfc848c6Sjm199354 #define VS_NODES_DEFAULT 128 /* concurrent file scans */
49bfc848c6Sjm199354 #define VS_WORKERS_DEFAULT 32 /* worker threads */
50bfc848c6Sjm199354 #define VS_SCANWAIT_DEFAULT 15*60 /* seconds to wait for scan result */
51bfc848c6Sjm199354 #define VS_REQL_HANDLER_TIMEOUT 30
52bfc848c6Sjm199354 #define VS_EXT_RECURSE_DEPTH 8
53bfc848c6Sjm199354
54bfc848c6Sjm199354 /* access derived from scan result (VS_STATUS_XXX) and file attributes */
55bfc848c6Sjm199354 #define VS_ACCESS_UNDEFINED 0
56bfc848c6Sjm199354 #define VS_ACCESS_ALLOW 1 /* return 0 */
57bfc848c6Sjm199354 #define VS_ACCESS_DENY 2 /* return EACCES */
58bfc848c6Sjm199354
59bfc848c6Sjm199354 #define tolower(C) (((C) >= 'A' && (C) <= 'Z') ? (C) - 'A' + 'a' : (C))
60bfc848c6Sjm199354 #define offsetof(s, m) (size_t)(&(((s *)0)->m))
61bfc848c6Sjm199354
62bfc848c6Sjm199354 /* global variables - tunable via /etc/system */
63bfc848c6Sjm199354 uint32_t vs_reqs_max = VS_REQS_DEFAULT; /* max scan requests */
64bfc848c6Sjm199354 uint32_t vs_nodes_max = VS_NODES_DEFAULT; /* max in-progress scan requests */
65bfc848c6Sjm199354 uint32_t vs_workers = VS_WORKERS_DEFAULT; /* max workers send reqs to vscand */
66bfc848c6Sjm199354 uint32_t vs_scan_wait = VS_SCANWAIT_DEFAULT; /* secs to wait for scan result */
67bfc848c6Sjm199354
68911106dfSjm199354
69911106dfSjm199354 /*
70bfc848c6Sjm199354 * vscan_svc_state
71bfc848c6Sjm199354 *
72bfc848c6Sjm199354 * +-----------------+
73bfc848c6Sjm199354 * | VS_SVC_UNCONFIG |
74bfc848c6Sjm199354 * +-----------------+
75bfc848c6Sjm199354 * | ^
76bfc848c6Sjm199354 * | svc_init | svc_fini
77bfc848c6Sjm199354 * v |
78bfc848c6Sjm199354 * +-----------------+
79bfc848c6Sjm199354 * | VS_SVC_IDLE |<----|
80bfc848c6Sjm199354 * +-----------------+ |
81bfc848c6Sjm199354 * | |
82bfc848c6Sjm199354 * | svc_enable |
83bfc848c6Sjm199354 * |<----------------| |
84bfc848c6Sjm199354 * v | |
85bfc848c6Sjm199354 * +-----------------+ | |
86bfc848c6Sjm199354 * | VS_SVC_ENABLED |--| |
87bfc848c6Sjm199354 * +-----------------+ |
88bfc848c6Sjm199354 * | |
89bfc848c6Sjm199354 * | svc_disable | handler thread exit,
90bfc848c6Sjm199354 * v | all requests complete
91bfc848c6Sjm199354 * +-----------------+ |
92bfc848c6Sjm199354 * | VS_SVC_DISABLED |-----|
93bfc848c6Sjm199354 * +-----------------+
94bfc848c6Sjm199354 *
95bfc848c6Sjm199354 * svc_enable may occur when we are already in the ENABLED
96bfc848c6Sjm199354 * state if vscand has exited without clean shutdown and
97bfc848c6Sjm199354 * then reconnected within the delayed disable time period
98bfc848c6Sjm199354 * (vs_reconnect_timeout) - see vscan_drv
99bfc848c6Sjm199354 */
100bfc848c6Sjm199354
101bfc848c6Sjm199354 typedef enum {
102bfc848c6Sjm199354 VS_SVC_UNCONFIG,
103bfc848c6Sjm199354 VS_SVC_IDLE,
104bfc848c6Sjm199354 VS_SVC_ENABLED, /* service enabled and registered */
105bfc848c6Sjm199354 VS_SVC_DISABLED /* service disabled and nunregistered */
106bfc848c6Sjm199354 } vscan_svc_state_t;
107bfc848c6Sjm199354 static vscan_svc_state_t vscan_svc_state = VS_SVC_UNCONFIG;
108bfc848c6Sjm199354
109bfc848c6Sjm199354
110bfc848c6Sjm199354 /*
111bfc848c6Sjm199354 * vscan_svc_req_state
112bfc848c6Sjm199354 *
113bfc848c6Sjm199354 * When a scan request is received from the file system it is
114bfc848c6Sjm199354 * identified in or inserted into the vscan_svc_reql (INIT).
115bfc848c6Sjm199354 * If the request is asynchronous 0 is then returned to the caller.
116bfc848c6Sjm199354 * If the request is synchronous the req's refcnt is incremented
117bfc848c6Sjm199354 * and the caller waits for the request to complete.
118bfc848c6Sjm199354 * The refcnt is also incremented when the request is inserted
119bfc848c6Sjm199354 * in vscan_svc_nodes, and decremented on scan_complete.
120bfc848c6Sjm199354 *
121bfc848c6Sjm199354 * vscan_svc_handler processes requests from the request list,
122bfc848c6Sjm199354 * inserting them into vscan_svc_nodes and the task queue (QUEUED).
123bfc848c6Sjm199354 * When the task queue call back (vscan_svc_do_scan) is invoked
124bfc848c6Sjm199354 * the request transitions to IN_PROGRESS state. If the request
125bfc848c6Sjm199354 * is sucessfully sent to vscand (door_call) and the door response
126bfc848c6Sjm199354 * is SCANNING then the scan result will be received asynchronously.
127bfc848c6Sjm199354 * Although unusual, it is possible that the async response is
128bfc848c6Sjm199354 * received before the door call returns (hence the ASYNC_COMPLETE
129bfc848c6Sjm199354 * state).
130bfc848c6Sjm199354 * When the result has been determined / received,
131bfc848c6Sjm199354 * vscan_svc_scan_complete is invoked to transition the request to
132bfc848c6Sjm199354 * COMPLETE state, decrement refcnt and signal all waiting callers.
133bfc848c6Sjm199354 * When the last waiting caller has processed the result (refcnt == 0)
134bfc848c6Sjm199354 * the request is removed from vscan_svc_reql and vscan_svc_nodes
135bfc848c6Sjm199354 * and deleted.
136bfc848c6Sjm199354 *
137bfc848c6Sjm199354 * | ^
138bfc848c6Sjm199354 * | reql_insert | refcnt == 0
139bfc848c6Sjm199354 * v | (delete)
140bfc848c6Sjm199354 * +------------------------+ +---------------------+
141bfc848c6Sjm199354 * | VS_SVC_REQ_INIT | -----DISABLE----> | VS_SVC_REQ_COMPLETE |
142bfc848c6Sjm199354 * +------------------------+ +---------------------+
143bfc848c6Sjm199354 * | ^
144bfc848c6Sjm199354 * | insert_req, tq_dispatch |
145bfc848c6Sjm199354 * v |
146bfc848c6Sjm199354 * +------------------------+ |
147bfc848c6Sjm199354 * | VS_SVC_REQ_QUEUED | scan_complete
148bfc848c6Sjm199354 * +------------------------+ |
149bfc848c6Sjm199354 * | |
150bfc848c6Sjm199354 * | tq_callback (do_scan) |
151bfc848c6Sjm199354 * | |
152bfc848c6Sjm199354 * v scan not req'd, error, |
153bfc848c6Sjm199354 * +------------------------+ or door_result != SCANNING |
154bfc848c6Sjm199354 * | VS_SVC_REQ_IN_PROGRESS |----------------->-------------|
155bfc848c6Sjm199354 * +------------------------+ |
156bfc848c6Sjm199354 * | | |
157bfc848c6Sjm199354 * | | door_result == SCANNING |
158bfc848c6Sjm199354 * | v |
159bfc848c6Sjm199354 * | +---------------------------+ async result |
160bfc848c6Sjm199354 * | | VS_SVC_REQ_SCANNING |-------->---------|
161bfc848c6Sjm199354 * | +---------------------------+ |
162bfc848c6Sjm199354 * | |
163bfc848c6Sjm199354 * | async result |
164bfc848c6Sjm199354 * v |
165bfc848c6Sjm199354 * +---------------------------+ door_result = SCANNING |
166bfc848c6Sjm199354 * | VS_SVC_REQ_ASYNC_COMPLETE |-------->------------------|
167bfc848c6Sjm199354 * +---------------------------+
168bfc848c6Sjm199354 */
169bfc848c6Sjm199354 typedef enum {
170bfc848c6Sjm199354 VS_SVC_REQ_INIT,
171bfc848c6Sjm199354 VS_SVC_REQ_QUEUED,
172bfc848c6Sjm199354 VS_SVC_REQ_IN_PROGRESS,
173bfc848c6Sjm199354 VS_SVC_REQ_SCANNING,
174bfc848c6Sjm199354 VS_SVC_REQ_ASYNC_COMPLETE,
175bfc848c6Sjm199354 VS_SVC_REQ_COMPLETE
176bfc848c6Sjm199354 } vscan_svc_req_state_t;
177bfc848c6Sjm199354
178bfc848c6Sjm199354
179bfc848c6Sjm199354 /*
180bfc848c6Sjm199354 * vscan_svc_reql - the list of pending and in-progress scan requests
181bfc848c6Sjm199354 */
182bfc848c6Sjm199354 typedef struct vscan_req {
183bfc848c6Sjm199354 uint32_t vsr_magic; /* VS_REQ_MAGIC */
184bfc848c6Sjm199354 list_node_t vsr_lnode;
185bfc848c6Sjm199354 vnode_t *vsr_vp;
186bfc848c6Sjm199354 uint32_t vsr_idx; /* vscan_svc_nodes index */
187bfc848c6Sjm199354 uint32_t vsr_seqnum; /* unigue request id */
188bfc848c6Sjm199354 uint32_t vsr_refcnt;
189bfc848c6Sjm199354 kcondvar_t vsr_cv;
190bfc848c6Sjm199354 vscan_svc_req_state_t vsr_state;
191bfc848c6Sjm199354 } vscan_req_t;
192bfc848c6Sjm199354
193bfc848c6Sjm199354 static list_t vscan_svc_reql;
194bfc848c6Sjm199354
195bfc848c6Sjm199354
196bfc848c6Sjm199354 /*
197bfc848c6Sjm199354 * vscan_svc_nodes - table of files being scanned
198911106dfSjm199354 *
199911106dfSjm199354 * The index into this table is passed in the door call to
200911106dfSjm199354 * vscand. vscand uses the idx to determine which minor node
201911106dfSjm199354 * to open to read the file data. Within the kernel driver
202911106dfSjm199354 * the minor device number can thus be used to identify the
203911106dfSjm199354 * table index to get the appropriate vnode.
204911106dfSjm199354 *
205911106dfSjm199354 * Instance 0 is reserved for the daemon/driver control
206911106dfSjm199354 * interface: enable/configure/disable
207911106dfSjm199354 */
208bfc848c6Sjm199354 typedef struct vscan_svc_node {
209bfc848c6Sjm199354 vscan_req_t *vsn_req;
210bfc848c6Sjm199354 uint8_t vsn_quarantined;
211bfc848c6Sjm199354 uint8_t vsn_modified;
212bfc848c6Sjm199354 uint64_t vsn_size;
213bfc848c6Sjm199354 timestruc_t vsn_mtime;
214bfc848c6Sjm199354 vs_scanstamp_t vsn_scanstamp;
215bfc848c6Sjm199354 uint32_t vsn_result;
216bfc848c6Sjm199354 uint32_t vsn_access;
217bfc848c6Sjm199354 } vscan_svc_node_t;
218911106dfSjm199354
219bfc848c6Sjm199354 static vscan_svc_node_t *vscan_svc_nodes;
220bfc848c6Sjm199354 static int vscan_svc_nodes_sz;
221911106dfSjm199354
222bfc848c6Sjm199354
223bfc848c6Sjm199354 /* vscan_svc_taskq - queue of requests waiting to be sent to vscand */
224911106dfSjm199354 static taskq_t *vscan_svc_taskq = NULL;
225bfc848c6Sjm199354
226bfc848c6Sjm199354 /* counts of entries in vscan_svc_reql, vscan_svc_nodes & vscan_svc_taskq */
227bfc848c6Sjm199354 typedef struct {
228bfc848c6Sjm199354 uint32_t vsc_reql;
229bfc848c6Sjm199354 uint32_t vsc_node;
230bfc848c6Sjm199354 uint32_t vsc_tq;
231bfc848c6Sjm199354 } vscan_svc_counts_t;
232bfc848c6Sjm199354 static vscan_svc_counts_t vscan_svc_counts;
233911106dfSjm199354
234911106dfSjm199354 /*
235911106dfSjm199354 * vscan_svc_mutex protects the data pertaining to scan requests:
236bfc848c6Sjm199354 * request list - vscan_svc_reql
237bfc848c6Sjm199354 * node table - vscan_svc_nodes
238911106dfSjm199354 */
239911106dfSjm199354 static kmutex_t vscan_svc_mutex;
240911106dfSjm199354
241bfc848c6Sjm199354 /* unique request id for vscand request/response correlation */
242bfc848c6Sjm199354 static uint32_t vscan_svc_seqnum = 0;
243bfc848c6Sjm199354
244911106dfSjm199354 /*
245911106dfSjm199354 * vscan_svc_cfg_mutex protects the configuration data:
246911106dfSjm199354 * vscan_svc_config, vscan_svc_types
247911106dfSjm199354 */
248911106dfSjm199354 static kmutex_t vscan_svc_cfg_mutex;
249911106dfSjm199354
250911106dfSjm199354 /* configuration data - for virus scan exemption */
251911106dfSjm199354 static vs_config_t vscan_svc_config;
252911106dfSjm199354 static char *vscan_svc_types[VS_TYPES_MAX];
253911106dfSjm199354
254bfc848c6Sjm199354 /* thread to insert reql entries into vscan_svc_nodes & vscan_svc_taskq */
255bfc848c6Sjm199354 static kthread_t *vscan_svc_reql_thread;
256bfc848c6Sjm199354 static kcondvar_t vscan_svc_reql_cv;
257bfc848c6Sjm199354 static vscan_req_t *vscan_svc_reql_next; /* next pending scan request */
258bfc848c6Sjm199354
259911106dfSjm199354 /* local functions */
260911106dfSjm199354 int vscan_svc_scan_file(vnode_t *, cred_t *, int);
261bfc848c6Sjm199354 static void vscan_svc_taskq_callback(void *);
262911106dfSjm199354 static int vscan_svc_exempt_file(vnode_t *, boolean_t *);
263911106dfSjm199354 static int vscan_svc_exempt_filetype(char *);
264911106dfSjm199354 static int vscan_svc_match_ext(char *, char *, int);
265bfc848c6Sjm199354 static void vscan_svc_do_scan(vscan_req_t *);
266bfc848c6Sjm199354 static vs_scan_req_t *vscan_svc_populate_req(int);
26753c11029Sjm199354 static void vscan_svc_process_scan_result(int);
268bfc848c6Sjm199354 static void vscan_svc_scan_complete(vscan_req_t *);
269bfc848c6Sjm199354 static void vscan_svc_delete_req(vscan_req_t *);
270bfc848c6Sjm199354 static int vscan_svc_insert_req(vscan_req_t *);
271bfc848c6Sjm199354 static void vscan_svc_remove_req(int);
272bfc848c6Sjm199354 static vscan_req_t *vscan_svc_reql_find(vnode_t *);
273bfc848c6Sjm199354 static vscan_req_t *vscan_svc_reql_insert(vnode_t *);
274bfc848c6Sjm199354 static void vscan_svc_reql_remove(vscan_req_t *);
275bfc848c6Sjm199354
276911106dfSjm199354 static int vscan_svc_getattr(int);
27753c11029Sjm199354 static int vscan_svc_setattr(int, int);
278911106dfSjm199354
279bfc848c6Sjm199354 /* thread to insert reql entries into vscan_svc_nodes & vscan_svc_taskq */
280bfc848c6Sjm199354 static void vscan_svc_reql_handler(void);
281911106dfSjm199354
282911106dfSjm199354
283911106dfSjm199354 /*
284911106dfSjm199354 * vscan_svc_init
285911106dfSjm199354 */
286911106dfSjm199354 int
vscan_svc_init()287911106dfSjm199354 vscan_svc_init()
288911106dfSjm199354 {
289bfc848c6Sjm199354 if (vscan_svc_state != VS_SVC_UNCONFIG) {
290bfc848c6Sjm199354 DTRACE_PROBE1(vscan__svc__state__violation,
291bfc848c6Sjm199354 int, vscan_svc_state);
292bfc848c6Sjm199354 return (-1);
293bfc848c6Sjm199354 }
294bfc848c6Sjm199354
295bfc848c6Sjm199354 mutex_init(&vscan_svc_mutex, NULL, MUTEX_DEFAULT, NULL);
296bfc848c6Sjm199354 mutex_init(&vscan_svc_cfg_mutex, NULL, MUTEX_DEFAULT, NULL);
297bfc848c6Sjm199354 cv_init(&vscan_svc_reql_cv, NULL, CV_DEFAULT, NULL);
298bfc848c6Sjm199354
299bfc848c6Sjm199354 vscan_svc_nodes_sz = sizeof (vscan_svc_node_t) * (vs_nodes_max + 1);
300bfc848c6Sjm199354 vscan_svc_nodes = kmem_zalloc(vscan_svc_nodes_sz, KM_SLEEP);
301bfc848c6Sjm199354
302bfc848c6Sjm199354 vscan_svc_counts.vsc_reql = 0;
303bfc848c6Sjm199354 vscan_svc_counts.vsc_node = 0;
304bfc848c6Sjm199354 vscan_svc_counts.vsc_tq = 0;
305bfc848c6Sjm199354
306bfc848c6Sjm199354 vscan_svc_state = VS_SVC_IDLE;
307911106dfSjm199354
308911106dfSjm199354 return (0);
309911106dfSjm199354 }
310911106dfSjm199354
311bfc848c6Sjm199354
312911106dfSjm199354 /*
313911106dfSjm199354 * vscan_svc_fini
314911106dfSjm199354 */
315911106dfSjm199354 void
vscan_svc_fini()316911106dfSjm199354 vscan_svc_fini()
317911106dfSjm199354 {
318bfc848c6Sjm199354 if (vscan_svc_state != VS_SVC_IDLE) {
319bfc848c6Sjm199354 DTRACE_PROBE1(vscan__svc__state__violation,
320bfc848c6Sjm199354 int, vscan_svc_state);
321bfc848c6Sjm199354 return;
322bfc848c6Sjm199354 }
323911106dfSjm199354
324bfc848c6Sjm199354 kmem_free(vscan_svc_nodes, vscan_svc_nodes_sz);
325bfc848c6Sjm199354
326bfc848c6Sjm199354 cv_destroy(&vscan_svc_reql_cv);
327911106dfSjm199354 mutex_destroy(&vscan_svc_mutex);
328911106dfSjm199354 mutex_destroy(&vscan_svc_cfg_mutex);
329bfc848c6Sjm199354 vscan_svc_state = VS_SVC_UNCONFIG;
330911106dfSjm199354 }
331911106dfSjm199354
332bfc848c6Sjm199354
333911106dfSjm199354 /*
334911106dfSjm199354 * vscan_svc_enable
335911106dfSjm199354 */
336bfc848c6Sjm199354 int
vscan_svc_enable(void)33753c11029Sjm199354 vscan_svc_enable(void)
338911106dfSjm199354 {
33953c11029Sjm199354 mutex_enter(&vscan_svc_mutex);
340911106dfSjm199354
341bfc848c6Sjm199354 switch (vscan_svc_state) {
342bfc848c6Sjm199354 case VS_SVC_ENABLED:
343bfc848c6Sjm199354 /*
344bfc848c6Sjm199354 * it's possible (and okay) for vscan_svc_enable to be
345bfc848c6Sjm199354 * called when already enabled if vscand reconnects
346bfc848c6Sjm199354 * during a delayed disable
347bfc848c6Sjm199354 */
348bfc848c6Sjm199354 break;
349bfc848c6Sjm199354 case VS_SVC_IDLE:
350bfc848c6Sjm199354 list_create(&vscan_svc_reql, sizeof (vscan_req_t),
351bfc848c6Sjm199354 offsetof(vscan_req_t, vsr_lnode));
352bfc848c6Sjm199354 vscan_svc_reql_next = list_head(&vscan_svc_reql);
35353c11029Sjm199354
354bfc848c6Sjm199354 vscan_svc_taskq = taskq_create("vscan_taskq", vs_workers,
355bfc848c6Sjm199354 MINCLSYSPRI, 1, INT_MAX, TASKQ_DYNAMIC);
356bfc848c6Sjm199354 ASSERT(vscan_svc_taskq != NULL);
357bfc848c6Sjm199354
358bfc848c6Sjm199354 vscan_svc_reql_thread = thread_create(NULL, 0,
359bfc848c6Sjm199354 vscan_svc_reql_handler, 0, 0, &p0, TS_RUN, MINCLSYSPRI);
360bfc848c6Sjm199354 ASSERT(vscan_svc_reql_thread != NULL);
361bfc848c6Sjm199354
362bfc848c6Sjm199354 /* ready to start processing requests */
363bfc848c6Sjm199354 vscan_svc_state = VS_SVC_ENABLED;
36453c11029Sjm199354 fs_vscan_register(vscan_svc_scan_file);
365bfc848c6Sjm199354 break;
366bfc848c6Sjm199354 default:
367bfc848c6Sjm199354 DTRACE_PROBE1(vscan__svc__state__violation,
368bfc848c6Sjm199354 int, vscan_svc_state);
369bfc848c6Sjm199354 return (-1);
370bfc848c6Sjm199354 }
371bfc848c6Sjm199354
37253c11029Sjm199354 mutex_exit(&vscan_svc_mutex);
373bfc848c6Sjm199354 return (0);
37453c11029Sjm199354 }
37553c11029Sjm199354
37653c11029Sjm199354
37753c11029Sjm199354 /*
37853c11029Sjm199354 * vscan_svc_disable
379bfc848c6Sjm199354 *
380bfc848c6Sjm199354 * Resources allocated during vscan_svc_enable are free'd by
381bfc848c6Sjm199354 * the handler thread immediately prior to exiting
38253c11029Sjm199354 */
38353c11029Sjm199354 void
vscan_svc_disable(void)38453c11029Sjm199354 vscan_svc_disable(void)
38553c11029Sjm199354 {
38653c11029Sjm199354 mutex_enter(&vscan_svc_mutex);
387bfc848c6Sjm199354
388bfc848c6Sjm199354 switch (vscan_svc_state) {
389bfc848c6Sjm199354 case VS_SVC_ENABLED:
39053c11029Sjm199354 fs_vscan_register(NULL);
391bfc848c6Sjm199354 vscan_svc_state = VS_SVC_DISABLED;
392bfc848c6Sjm199354 cv_signal(&vscan_svc_reql_cv); /* wake handler thread */
393bfc848c6Sjm199354 break;
394bfc848c6Sjm199354 default:
395bfc848c6Sjm199354 DTRACE_PROBE1(vscan__svc__state__violation, int,
396bfc848c6Sjm199354 vscan_svc_state);
39753c11029Sjm199354 }
398bfc848c6Sjm199354
39953c11029Sjm199354 mutex_exit(&vscan_svc_mutex);
40053c11029Sjm199354 }
40153c11029Sjm199354
40253c11029Sjm199354
403911106dfSjm199354 /*
404911106dfSjm199354 * vscan_svc_in_use
405911106dfSjm199354 */
406911106dfSjm199354 boolean_t
vscan_svc_in_use()407911106dfSjm199354 vscan_svc_in_use()
408911106dfSjm199354 {
409bfc848c6Sjm199354 boolean_t in_use;
410911106dfSjm199354
411911106dfSjm199354 mutex_enter(&vscan_svc_mutex);
412911106dfSjm199354
413bfc848c6Sjm199354 switch (vscan_svc_state) {
414bfc848c6Sjm199354 case VS_SVC_IDLE:
415bfc848c6Sjm199354 case VS_SVC_UNCONFIG:
416bfc848c6Sjm199354 in_use = B_FALSE;
417bfc848c6Sjm199354 break;
418bfc848c6Sjm199354 default:
419bfc848c6Sjm199354 in_use = B_TRUE;
420bfc848c6Sjm199354 break;
421911106dfSjm199354 }
422911106dfSjm199354
423bfc848c6Sjm199354 mutex_exit(&vscan_svc_mutex);
424bfc848c6Sjm199354 return (in_use);
425bfc848c6Sjm199354 }
426bfc848c6Sjm199354
427bfc848c6Sjm199354
428911106dfSjm199354 /*
429911106dfSjm199354 * vscan_svc_get_vnode
430911106dfSjm199354 *
431911106dfSjm199354 * Get the file vnode indexed by idx.
432911106dfSjm199354 */
433911106dfSjm199354 vnode_t *
vscan_svc_get_vnode(int idx)434911106dfSjm199354 vscan_svc_get_vnode(int idx)
435911106dfSjm199354 {
436bfc848c6Sjm199354 vnode_t *vp = NULL;
437911106dfSjm199354
438bfc848c6Sjm199354 ASSERT(idx > 0);
439bfc848c6Sjm199354 ASSERT(idx <= vs_nodes_max);
440bfc848c6Sjm199354
441bfc848c6Sjm199354 mutex_enter(&vscan_svc_mutex);
442bfc848c6Sjm199354 if (vscan_svc_nodes[idx].vsn_req)
443bfc848c6Sjm199354 vp = vscan_svc_nodes[idx].vsn_req->vsr_vp;
444bfc848c6Sjm199354 mutex_exit(&vscan_svc_mutex);
445bfc848c6Sjm199354
446bfc848c6Sjm199354 return (vp);
447911106dfSjm199354 }
448911106dfSjm199354
449911106dfSjm199354
450911106dfSjm199354 /*
451911106dfSjm199354 * vscan_svc_scan_file
452911106dfSjm199354 *
453911106dfSjm199354 * This function is the entry point for the file system to
454911106dfSjm199354 * request that a file be virus scanned.
455911106dfSjm199354 */
456911106dfSjm199354 int
vscan_svc_scan_file(vnode_t * vp,cred_t * cr,int async)457911106dfSjm199354 vscan_svc_scan_file(vnode_t *vp, cred_t *cr, int async)
458911106dfSjm199354 {
459bfc848c6Sjm199354 int access;
460bfc848c6Sjm199354 vscan_req_t *req;
461911106dfSjm199354 boolean_t allow;
462bfc848c6Sjm199354 clock_t timeout, time_left;
463911106dfSjm199354
464bfc848c6Sjm199354 if ((vp == NULL) || (vp->v_path == NULL) || cr == NULL)
465911106dfSjm199354 return (0);
466911106dfSjm199354
467911106dfSjm199354 DTRACE_PROBE2(vscan__scan__file, char *, vp->v_path, int, async);
468911106dfSjm199354
469911106dfSjm199354 /* check if size or type exempts file from scanning */
470911106dfSjm199354 if (vscan_svc_exempt_file(vp, &allow)) {
471911106dfSjm199354 if ((allow == B_TRUE) || (async != 0))
472911106dfSjm199354 return (0);
473911106dfSjm199354
474911106dfSjm199354 return (EACCES);
475911106dfSjm199354 }
476911106dfSjm199354
477911106dfSjm199354 mutex_enter(&vscan_svc_mutex);
478911106dfSjm199354
479bfc848c6Sjm199354 if (vscan_svc_state != VS_SVC_ENABLED) {
480bfc848c6Sjm199354 DTRACE_PROBE1(vscan__svc__state__violation,
481bfc848c6Sjm199354 int, vscan_svc_state);
482bfc848c6Sjm199354 mutex_exit(&vscan_svc_mutex);
483bfc848c6Sjm199354 return (0);
484bfc848c6Sjm199354 }
485bfc848c6Sjm199354
486bfc848c6Sjm199354 /* insert (or find) request in list */
487bfc848c6Sjm199354 if ((req = vscan_svc_reql_insert(vp)) == NULL) {
488bfc848c6Sjm199354 mutex_exit(&vscan_svc_mutex);
489bfc848c6Sjm199354 cmn_err(CE_WARN, "Virus scan request list full");
490bfc848c6Sjm199354 return ((async != 0) ? 0 : EACCES);
491bfc848c6Sjm199354 }
492bfc848c6Sjm199354
493bfc848c6Sjm199354 /* asynchronous request: return 0 */
494bfc848c6Sjm199354 if (async) {
495bfc848c6Sjm199354 mutex_exit(&vscan_svc_mutex);
496bfc848c6Sjm199354 return (0);
497bfc848c6Sjm199354 }
498bfc848c6Sjm199354
499bfc848c6Sjm199354 /* synchronous scan request: wait for result */
500bfc848c6Sjm199354 ++(req->vsr_refcnt);
501bfc848c6Sjm199354 time_left = SEC_TO_TICK(vs_scan_wait);
502bfc848c6Sjm199354 while ((time_left > 0) && (req->vsr_state != VS_SVC_REQ_COMPLETE)) {
503*d3d50737SRafael Vanoni timeout = time_left;
504*d3d50737SRafael Vanoni time_left = cv_reltimedwait_sig(&(req->vsr_cv),
505*d3d50737SRafael Vanoni &vscan_svc_mutex, timeout, TR_CLOCK_TICK);
506bfc848c6Sjm199354 }
507bfc848c6Sjm199354
508bfc848c6Sjm199354 if (time_left == -1) {
509bfc848c6Sjm199354 cmn_err(CE_WARN, "Virus scan request timeout %s (%d) \n",
510bfc848c6Sjm199354 vp->v_path, req->vsr_seqnum);
511bfc848c6Sjm199354 DTRACE_PROBE1(vscan__scan__timeout, vscan_req_t *, req);
512bfc848c6Sjm199354 }
513bfc848c6Sjm199354
514bfc848c6Sjm199354 ASSERT(req->vsr_magic == VS_REQ_MAGIC);
515bfc848c6Sjm199354 if (vscan_svc_state == VS_SVC_DISABLED)
516bfc848c6Sjm199354 access = VS_ACCESS_ALLOW;
517bfc848c6Sjm199354 else if (req->vsr_idx == 0)
518bfc848c6Sjm199354 access = VS_ACCESS_DENY;
519bfc848c6Sjm199354 else
520bfc848c6Sjm199354 access = vscan_svc_nodes[req->vsr_idx].vsn_access;
521bfc848c6Sjm199354
522bfc848c6Sjm199354 if ((--req->vsr_refcnt) == 0)
523bfc848c6Sjm199354 vscan_svc_delete_req(req);
524bfc848c6Sjm199354
525bfc848c6Sjm199354 mutex_exit(&vscan_svc_mutex);
526bfc848c6Sjm199354 return ((access == VS_ACCESS_ALLOW) ? 0 : EACCES);
527911106dfSjm199354 }
528911106dfSjm199354
529911106dfSjm199354
530911106dfSjm199354 /*
531bfc848c6Sjm199354 * vscan_svc_reql_handler
532911106dfSjm199354 *
533bfc848c6Sjm199354 * inserts scan requests (from vscan_svc_reql) into
534bfc848c6Sjm199354 * vscan_svc_nodes and vscan_svc_taskq
535911106dfSjm199354 */
536bfc848c6Sjm199354 static void
vscan_svc_reql_handler(void)537bfc848c6Sjm199354 vscan_svc_reql_handler(void)
538bfc848c6Sjm199354 {
539bfc848c6Sjm199354 vscan_req_t *req, *next;
540bfc848c6Sjm199354
541bfc848c6Sjm199354 for (;;) {
542bfc848c6Sjm199354 mutex_enter(&vscan_svc_mutex);
543bfc848c6Sjm199354
544bfc848c6Sjm199354 if ((vscan_svc_state == VS_SVC_DISABLED) &&
545bfc848c6Sjm199354 (vscan_svc_counts.vsc_reql == 0)) {
546bfc848c6Sjm199354 /* free resources allocated durining enable */
547bfc848c6Sjm199354 taskq_destroy(vscan_svc_taskq);
548bfc848c6Sjm199354 vscan_svc_taskq = NULL;
549bfc848c6Sjm199354 list_destroy(&vscan_svc_reql);
550bfc848c6Sjm199354 vscan_svc_state = VS_SVC_IDLE;
551bfc848c6Sjm199354 mutex_exit(&vscan_svc_mutex);
552bfc848c6Sjm199354 return;
553bfc848c6Sjm199354 }
554bfc848c6Sjm199354
555bfc848c6Sjm199354 /*
556bfc848c6Sjm199354 * If disabled, scan_complete any pending requests.
557bfc848c6Sjm199354 * Otherwise insert pending requests into vscan_svc_nodes
558bfc848c6Sjm199354 * and vscan_svc_taskq. If no slots are available in
559bfc848c6Sjm199354 * vscan_svc_nodes break loop and wait for one
560bfc848c6Sjm199354 */
561bfc848c6Sjm199354 req = vscan_svc_reql_next;
562bfc848c6Sjm199354
563bfc848c6Sjm199354 while (req != NULL) {
564bfc848c6Sjm199354 ASSERT(req->vsr_magic == VS_REQ_MAGIC);
565bfc848c6Sjm199354 next = list_next(&vscan_svc_reql, req);
566bfc848c6Sjm199354
567bfc848c6Sjm199354 if (vscan_svc_state == VS_SVC_DISABLED) {
568bfc848c6Sjm199354 vscan_svc_scan_complete(req);
569bfc848c6Sjm199354 } else {
570bfc848c6Sjm199354 /* insert request into vscan_svc_nodes */
571bfc848c6Sjm199354 if (vscan_svc_insert_req(req) == -1)
572bfc848c6Sjm199354 break;
573bfc848c6Sjm199354
574bfc848c6Sjm199354 /* add the scan request into the taskq */
575bfc848c6Sjm199354 (void) taskq_dispatch(vscan_svc_taskq,
576bfc848c6Sjm199354 vscan_svc_taskq_callback,
577bfc848c6Sjm199354 (void *)req, TQ_SLEEP);
578bfc848c6Sjm199354 ++(vscan_svc_counts.vsc_tq);
579bfc848c6Sjm199354
580bfc848c6Sjm199354 req->vsr_state = VS_SVC_REQ_QUEUED;
581bfc848c6Sjm199354 }
582bfc848c6Sjm199354 req = next;
583bfc848c6Sjm199354 }
584bfc848c6Sjm199354
585bfc848c6Sjm199354 vscan_svc_reql_next = req;
586bfc848c6Sjm199354
587bfc848c6Sjm199354 DTRACE_PROBE2(vscan__req__counts, char *, "handler wait",
588bfc848c6Sjm199354 vscan_svc_counts_t *, &vscan_svc_counts);
589bfc848c6Sjm199354
590*d3d50737SRafael Vanoni (void) cv_reltimedwait(&vscan_svc_reql_cv, &vscan_svc_mutex,
591*d3d50737SRafael Vanoni SEC_TO_TICK(VS_REQL_HANDLER_TIMEOUT), TR_CLOCK_TICK);
592bfc848c6Sjm199354
593bfc848c6Sjm199354 DTRACE_PROBE2(vscan__req__counts, char *, "handler wake",
594bfc848c6Sjm199354 vscan_svc_counts_t *, &vscan_svc_counts);
595bfc848c6Sjm199354
596bfc848c6Sjm199354 mutex_exit(&vscan_svc_mutex);
597bfc848c6Sjm199354 }
598bfc848c6Sjm199354 }
599bfc848c6Sjm199354
600bfc848c6Sjm199354
601bfc848c6Sjm199354 static void
vscan_svc_taskq_callback(void * data)602911106dfSjm199354 vscan_svc_taskq_callback(void *data)
603911106dfSjm199354 {
604bfc848c6Sjm199354 vscan_req_t *req;
605911106dfSjm199354
606911106dfSjm199354 mutex_enter(&vscan_svc_mutex);
607bfc848c6Sjm199354
608bfc848c6Sjm199354 req = (vscan_req_t *)data;
609bfc848c6Sjm199354 ASSERT(req->vsr_magic == VS_REQ_MAGIC);
610bfc848c6Sjm199354 vscan_svc_do_scan(req);
611bfc848c6Sjm199354 if (req->vsr_state != VS_SVC_REQ_SCANNING)
612bfc848c6Sjm199354 vscan_svc_scan_complete(req);
613bfc848c6Sjm199354
614bfc848c6Sjm199354 --(vscan_svc_counts.vsc_tq);
615911106dfSjm199354 mutex_exit(&vscan_svc_mutex);
616911106dfSjm199354 }
617911106dfSjm199354
618911106dfSjm199354
619911106dfSjm199354 /*
620911106dfSjm199354 * vscan_svc_do_scan
621911106dfSjm199354 *
622bfc848c6Sjm199354 * Note: To avoid potential deadlock it is important that
623bfc848c6Sjm199354 * vscan_svc_mutex is not held during the call to
624bfc848c6Sjm199354 * vscan_drv_create_note. vscan_drv_create_note enters
625bfc848c6Sjm199354 * the vscan_drv_mutex and it is possible that a thread
626bfc848c6Sjm199354 * holding that mutex could be waiting for vscan_svc_mutex.
627911106dfSjm199354 */
628bfc848c6Sjm199354 static void
vscan_svc_do_scan(vscan_req_t * req)629bfc848c6Sjm199354 vscan_svc_do_scan(vscan_req_t *req)
630911106dfSjm199354 {
631bfc848c6Sjm199354 int idx, result;
632bfc848c6Sjm199354 vscan_svc_node_t *node;
633bfc848c6Sjm199354 vs_scan_req_t *door_req;
634911106dfSjm199354
635bfc848c6Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
636bfc848c6Sjm199354
637bfc848c6Sjm199354 idx = req->vsr_idx;
638bfc848c6Sjm199354 node = &vscan_svc_nodes[idx];
639bfc848c6Sjm199354
640bfc848c6Sjm199354 req->vsr_state = VS_SVC_REQ_IN_PROGRESS;
641bfc848c6Sjm199354
642bfc848c6Sjm199354 /* if vscan not enabled (shutting down), allow ACCESS */
643bfc848c6Sjm199354 if (vscan_svc_state != VS_SVC_ENABLED) {
644bfc848c6Sjm199354 node->vsn_access = VS_ACCESS_ALLOW;
645bfc848c6Sjm199354 return;
646bfc848c6Sjm199354 }
647bfc848c6Sjm199354
648bfc848c6Sjm199354 if (vscan_svc_getattr(idx) != 0) {
649bfc848c6Sjm199354 cmn_err(CE_WARN, "Can't access xattr for %s\n",
650bfc848c6Sjm199354 req->vsr_vp->v_path);
651bfc848c6Sjm199354 node->vsn_access = VS_ACCESS_DENY;
652bfc848c6Sjm199354 return;
653bfc848c6Sjm199354 }
654bfc848c6Sjm199354
655bfc848c6Sjm199354 /* valid scan_req ptr guaranteed */
656bfc848c6Sjm199354 door_req = vscan_svc_populate_req(idx);
657bfc848c6Sjm199354
658bfc848c6Sjm199354 /* free up mutex around create node and door call */
659bfc848c6Sjm199354 mutex_exit(&vscan_svc_mutex);
660bfc848c6Sjm199354 if (vscan_drv_create_node(idx) != B_TRUE)
661bfc848c6Sjm199354 result = VS_STATUS_ERROR;
662bfc848c6Sjm199354 else
663bfc848c6Sjm199354 result = vscan_door_scan_file(door_req);
664bfc848c6Sjm199354 kmem_free(door_req, sizeof (vs_scan_req_t));
665911106dfSjm199354 mutex_enter(&vscan_svc_mutex);
666911106dfSjm199354
667bfc848c6Sjm199354 if (result != VS_STATUS_SCANNING) {
668bfc848c6Sjm199354 vscan_svc_nodes[idx].vsn_result = result;
669bfc848c6Sjm199354 vscan_svc_process_scan_result(idx);
670bfc848c6Sjm199354 } else { /* async response */
671bfc848c6Sjm199354 if (req->vsr_state == VS_SVC_REQ_IN_PROGRESS)
672bfc848c6Sjm199354 req->vsr_state = VS_SVC_REQ_SCANNING;
673bfc848c6Sjm199354 }
674bfc848c6Sjm199354 }
675bfc848c6Sjm199354
676bfc848c6Sjm199354
677911106dfSjm199354 /*
678bfc848c6Sjm199354 * vscan_svc_populate_req
679bfc848c6Sjm199354 *
680bfc848c6Sjm199354 * Allocate a scan request to be sent to vscand, populating it
681bfc848c6Sjm199354 * from the data in vscan_svc_nodes[idx].
682bfc848c6Sjm199354 *
683bfc848c6Sjm199354 * Returns: scan request object
684911106dfSjm199354 */
685bfc848c6Sjm199354 static vs_scan_req_t *
vscan_svc_populate_req(int idx)686bfc848c6Sjm199354 vscan_svc_populate_req(int idx)
687bfc848c6Sjm199354 {
688bfc848c6Sjm199354 vs_scan_req_t *scan_req;
689bfc848c6Sjm199354 vscan_req_t *req;
690bfc848c6Sjm199354 vscan_svc_node_t *node;
691911106dfSjm199354
692bfc848c6Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
693bfc848c6Sjm199354
694bfc848c6Sjm199354 node = &vscan_svc_nodes[idx];
695bfc848c6Sjm199354 req = node->vsn_req;
696bfc848c6Sjm199354 scan_req = kmem_zalloc(sizeof (vs_scan_req_t), KM_SLEEP);
697bfc848c6Sjm199354
698bfc848c6Sjm199354 scan_req->vsr_idx = idx;
699bfc848c6Sjm199354 scan_req->vsr_seqnum = req->vsr_seqnum;
700bfc848c6Sjm199354 (void) strncpy(scan_req->vsr_path, req->vsr_vp->v_path, MAXPATHLEN);
701bfc848c6Sjm199354 scan_req->vsr_size = node->vsn_size;
702bfc848c6Sjm199354 scan_req->vsr_modified = node->vsn_modified;
703bfc848c6Sjm199354 scan_req->vsr_quarantined = node->vsn_quarantined;
704bfc848c6Sjm199354 scan_req->vsr_flags = 0;
705bfc848c6Sjm199354 (void) strncpy(scan_req->vsr_scanstamp,
706bfc848c6Sjm199354 node->vsn_scanstamp, sizeof (vs_scanstamp_t));
707bfc848c6Sjm199354
708bfc848c6Sjm199354 return (scan_req);
709bfc848c6Sjm199354 }
710bfc848c6Sjm199354
711bfc848c6Sjm199354
712bfc848c6Sjm199354 /*
713bfc848c6Sjm199354 * vscan_svc_scan_complete
714bfc848c6Sjm199354 */
715bfc848c6Sjm199354 static void
vscan_svc_scan_complete(vscan_req_t * req)716bfc848c6Sjm199354 vscan_svc_scan_complete(vscan_req_t *req)
717bfc848c6Sjm199354 {
718bfc848c6Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
719bfc848c6Sjm199354 ASSERT(req != NULL);
720bfc848c6Sjm199354
721bfc848c6Sjm199354 req->vsr_state = VS_SVC_REQ_COMPLETE;
722bfc848c6Sjm199354
723bfc848c6Sjm199354 if ((--req->vsr_refcnt) == 0)
724bfc848c6Sjm199354 vscan_svc_delete_req(req);
725bfc848c6Sjm199354 else
726bfc848c6Sjm199354 cv_broadcast(&(req->vsr_cv));
727bfc848c6Sjm199354 }
728bfc848c6Sjm199354
729bfc848c6Sjm199354
730bfc848c6Sjm199354 /*
731bfc848c6Sjm199354 * vscan_svc_delete_req
732bfc848c6Sjm199354 */
733bfc848c6Sjm199354 static void
vscan_svc_delete_req(vscan_req_t * req)734bfc848c6Sjm199354 vscan_svc_delete_req(vscan_req_t *req)
735bfc848c6Sjm199354 {
736bfc848c6Sjm199354 int idx;
737bfc848c6Sjm199354
738bfc848c6Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
739bfc848c6Sjm199354 ASSERT(req != NULL);
740bfc848c6Sjm199354 ASSERT(req->vsr_refcnt == 0);
741bfc848c6Sjm199354 ASSERT(req->vsr_state == VS_SVC_REQ_COMPLETE);
742bfc848c6Sjm199354
743bfc848c6Sjm199354 if ((idx = req->vsr_idx) != 0)
744bfc848c6Sjm199354 vscan_svc_remove_req(idx);
745bfc848c6Sjm199354
746bfc848c6Sjm199354 vscan_svc_reql_remove(req);
747bfc848c6Sjm199354
748bfc848c6Sjm199354 cv_signal(&vscan_svc_reql_cv);
749bfc848c6Sjm199354 }
750bfc848c6Sjm199354
751bfc848c6Sjm199354
752bfc848c6Sjm199354 /*
753bfc848c6Sjm199354 * vscan_svc_scan_result
754bfc848c6Sjm199354 *
755bfc848c6Sjm199354 * Invoked from vscan_drv.c on receipt of an ioctl containing
756bfc848c6Sjm199354 * an async scan result (VS_DRV_IOCTL_RESULT)
757bfc848c6Sjm199354 * If the vsr_seqnum in the response does not match that in the
758bfc848c6Sjm199354 * vscan_svc_nodes entry the result is discarded.
759bfc848c6Sjm199354 */
760bfc848c6Sjm199354 void
vscan_svc_scan_result(vs_scan_rsp_t * scan_rsp)761bfc848c6Sjm199354 vscan_svc_scan_result(vs_scan_rsp_t *scan_rsp)
762bfc848c6Sjm199354 {
763bfc848c6Sjm199354 vscan_req_t *req;
764bfc848c6Sjm199354 vscan_svc_node_t *node;
765bfc848c6Sjm199354
766911106dfSjm199354 mutex_enter(&vscan_svc_mutex);
76753c11029Sjm199354
768bfc848c6Sjm199354 node = &vscan_svc_nodes[scan_rsp->vsr_idx];
769bfc848c6Sjm199354
770bfc848c6Sjm199354 if ((req = node->vsn_req) == NULL) {
771bfc848c6Sjm199354 mutex_exit(&vscan_svc_mutex);
772bfc848c6Sjm199354 return;
773911106dfSjm199354 }
774911106dfSjm199354
775bfc848c6Sjm199354 ASSERT(req->vsr_magic == VS_REQ_MAGIC);
776911106dfSjm199354
777bfc848c6Sjm199354 if (scan_rsp->vsr_seqnum != req->vsr_seqnum) {
778bfc848c6Sjm199354 mutex_exit(&vscan_svc_mutex);
779bfc848c6Sjm199354 return;
780bfc848c6Sjm199354 }
781911106dfSjm199354
782bfc848c6Sjm199354 node->vsn_result = scan_rsp->vsr_result;
783bfc848c6Sjm199354 (void) strncpy(node->vsn_scanstamp,
784bfc848c6Sjm199354 scan_rsp->vsr_scanstamp, sizeof (vs_scanstamp_t));
785bfc848c6Sjm199354
786bfc848c6Sjm199354 vscan_svc_process_scan_result(scan_rsp->vsr_idx);
787bfc848c6Sjm199354
788bfc848c6Sjm199354 if (node->vsn_req->vsr_state == VS_SVC_REQ_SCANNING)
789bfc848c6Sjm199354 vscan_svc_scan_complete(node->vsn_req);
790bfc848c6Sjm199354 else
791bfc848c6Sjm199354 node->vsn_req->vsr_state = VS_SVC_REQ_ASYNC_COMPLETE;
792911106dfSjm199354
793911106dfSjm199354 mutex_exit(&vscan_svc_mutex);
794bfc848c6Sjm199354 }
795911106dfSjm199354
796bfc848c6Sjm199354
797bfc848c6Sjm199354 /*
798bfc848c6Sjm199354 * vscan_svc_scan_abort
799bfc848c6Sjm199354 *
800bfc848c6Sjm199354 * Abort in-progress scan requests.
801bfc848c6Sjm199354 */
802bfc848c6Sjm199354 void
vscan_svc_scan_abort()803bfc848c6Sjm199354 vscan_svc_scan_abort()
804bfc848c6Sjm199354 {
805bfc848c6Sjm199354 int idx;
806bfc848c6Sjm199354 vscan_req_t *req;
807bfc848c6Sjm199354
808bfc848c6Sjm199354 mutex_enter(&vscan_svc_mutex);
809bfc848c6Sjm199354
810bfc848c6Sjm199354 for (idx = 1; idx <= vs_nodes_max; idx++) {
811bfc848c6Sjm199354 if ((req = vscan_svc_nodes[idx].vsn_req) == NULL)
812bfc848c6Sjm199354 continue;
813bfc848c6Sjm199354
814bfc848c6Sjm199354 ASSERT(req->vsr_magic == VS_REQ_MAGIC);
815bfc848c6Sjm199354
816bfc848c6Sjm199354 if (req->vsr_state == VS_SVC_REQ_SCANNING) {
817bfc848c6Sjm199354 DTRACE_PROBE1(vscan__abort, vscan_req_t *, req);
818bfc848c6Sjm199354 vscan_svc_process_scan_result(idx);
819bfc848c6Sjm199354 vscan_svc_scan_complete(req);
820bfc848c6Sjm199354 }
821bfc848c6Sjm199354 }
822bfc848c6Sjm199354
823bfc848c6Sjm199354 mutex_exit(&vscan_svc_mutex);
824911106dfSjm199354 }
825911106dfSjm199354
82653c11029Sjm199354
82753c11029Sjm199354 /*
82853c11029Sjm199354 * vscan_svc_process_scan_result
82953c11029Sjm199354 *
830bfc848c6Sjm199354 * Sets vsn_access and updates file attributes based on vsn_result,
83153c11029Sjm199354 * as follows:
83253c11029Sjm199354 *
83353c11029Sjm199354 * VS_STATUS_INFECTED
83453c11029Sjm199354 * deny access, set quarantine attribute, clear scanstamp
83553c11029Sjm199354 * VS_STATUS_CLEAN
83653c11029Sjm199354 * allow access, set scanstamp,
83753c11029Sjm199354 * if file not modified since scan initiated, clear modified attribute
83853c11029Sjm199354 * VS_STATUS_NO_SCAN
83953c11029Sjm199354 * deny access if file quarantined, otherwise allow access
84053c11029Sjm199354 * VS_STATUS_UNDEFINED, VS_STATUS_ERROR
84153c11029Sjm199354 * deny access if file quarantined, modified or no scanstamp
84253c11029Sjm199354 * otherwise, allow access
84353c11029Sjm199354 */
84453c11029Sjm199354 static void
vscan_svc_process_scan_result(int idx)84553c11029Sjm199354 vscan_svc_process_scan_result(int idx)
84653c11029Sjm199354 {
84753c11029Sjm199354 struct vattr attr;
84853c11029Sjm199354 vnode_t *vp;
84953c11029Sjm199354 timestruc_t *mtime;
850bfc848c6Sjm199354 vscan_svc_node_t *node;
85153c11029Sjm199354
85253c11029Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
85353c11029Sjm199354
854bfc848c6Sjm199354 node = &vscan_svc_nodes[idx];
85553c11029Sjm199354
856bfc848c6Sjm199354 switch (node->vsn_result) {
85753c11029Sjm199354 case VS_STATUS_INFECTED:
858bfc848c6Sjm199354 node->vsn_access = VS_ACCESS_DENY;
859bfc848c6Sjm199354 node->vsn_quarantined = 1;
860bfc848c6Sjm199354 node->vsn_scanstamp[0] = '\0';
86153c11029Sjm199354 (void) vscan_svc_setattr(idx,
86253c11029Sjm199354 XAT_AV_QUARANTINED | XAT_AV_SCANSTAMP);
863bfc848c6Sjm199354 break;
86453c11029Sjm199354
86553c11029Sjm199354 case VS_STATUS_CLEAN:
866bfc848c6Sjm199354 node->vsn_access = VS_ACCESS_ALLOW;
86753c11029Sjm199354
86853c11029Sjm199354 /* if mtime has changed, don't clear the modified attribute */
869bfc848c6Sjm199354 vp = node->vsn_req->vsr_vp;
870bfc848c6Sjm199354 mtime = &(node->vsn_mtime);
87153c11029Sjm199354 attr.va_mask = AT_MTIME;
87253c11029Sjm199354 if ((VOP_GETATTR(vp, &attr, 0, kcred, NULL) != 0) ||
87353c11029Sjm199354 (mtime->tv_sec != attr.va_mtime.tv_sec) ||
87453c11029Sjm199354 (mtime->tv_nsec != attr.va_mtime.tv_nsec)) {
875bfc848c6Sjm199354 DTRACE_PROBE1(vscan__mtime__changed, vscan_svc_node_t *,
876bfc848c6Sjm199354 node);
87753c11029Sjm199354 (void) vscan_svc_setattr(idx, XAT_AV_SCANSTAMP);
878bfc848c6Sjm199354 break;
87953c11029Sjm199354 }
88053c11029Sjm199354
881bfc848c6Sjm199354 node->vsn_modified = 0;
88253c11029Sjm199354 (void) vscan_svc_setattr(idx,
88353c11029Sjm199354 XAT_AV_SCANSTAMP | XAT_AV_MODIFIED);
884bfc848c6Sjm199354 break;
88553c11029Sjm199354
88653c11029Sjm199354 case VS_STATUS_NO_SCAN:
887bfc848c6Sjm199354 if (node->vsn_quarantined)
888bfc848c6Sjm199354 node->vsn_access = VS_ACCESS_DENY;
88953c11029Sjm199354 else
890bfc848c6Sjm199354 node->vsn_access = VS_ACCESS_ALLOW;
891bfc848c6Sjm199354 break;
89253c11029Sjm199354
89353c11029Sjm199354 case VS_STATUS_ERROR:
89453c11029Sjm199354 case VS_STATUS_UNDEFINED:
89553c11029Sjm199354 default:
896bfc848c6Sjm199354 if ((node->vsn_quarantined) ||
897bfc848c6Sjm199354 (node->vsn_modified) ||
898bfc848c6Sjm199354 (node->vsn_scanstamp[0] == '\0'))
899bfc848c6Sjm199354 node->vsn_access = VS_ACCESS_DENY;
90053c11029Sjm199354 else
901bfc848c6Sjm199354 node->vsn_access = VS_ACCESS_ALLOW;
902911106dfSjm199354 break;
903911106dfSjm199354 }
904911106dfSjm199354
905bfc848c6Sjm199354 DTRACE_PROBE4(vscan__result,
906bfc848c6Sjm199354 int, idx, int, node->vsn_req->vsr_seqnum,
907bfc848c6Sjm199354 int, node->vsn_result, int, node->vsn_access);
908911106dfSjm199354 }
909911106dfSjm199354
910911106dfSjm199354
911911106dfSjm199354 /*
912911106dfSjm199354 * vscan_svc_getattr
913911106dfSjm199354 *
91453c11029Sjm199354 * Get the vscan related system attributes, AT_SIZE & AT_MTIME.
915911106dfSjm199354 */
916911106dfSjm199354 static int
vscan_svc_getattr(int idx)917911106dfSjm199354 vscan_svc_getattr(int idx)
918911106dfSjm199354 {
919911106dfSjm199354 xvattr_t xvattr;
920911106dfSjm199354 xoptattr_t *xoap = NULL;
921911106dfSjm199354 vnode_t *vp;
922bfc848c6Sjm199354 vscan_svc_node_t *node;
923911106dfSjm199354
924911106dfSjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
925911106dfSjm199354
926bfc848c6Sjm199354 node = &vscan_svc_nodes[idx];
927bfc848c6Sjm199354 if ((vp = node->vsn_req->vsr_vp) == NULL)
928911106dfSjm199354 return (-1);
929911106dfSjm199354
930911106dfSjm199354 /* get the attributes */
931911106dfSjm199354 xva_init(&xvattr); /* sets AT_XVATTR */
932911106dfSjm199354
933911106dfSjm199354 xvattr.xva_vattr.va_mask |= AT_SIZE;
93453c11029Sjm199354 xvattr.xva_vattr.va_mask |= AT_MTIME;
935911106dfSjm199354 XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
936911106dfSjm199354 XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
937911106dfSjm199354 XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP);
938911106dfSjm199354
939911106dfSjm199354 if (VOP_GETATTR(vp, (vattr_t *)&xvattr, 0, kcred, NULL) != 0)
940911106dfSjm199354 return (-1);
941911106dfSjm199354
942911106dfSjm199354 if ((xoap = xva_getxoptattr(&xvattr)) == NULL) {
943911106dfSjm199354 cmn_err(CE_NOTE, "Virus scan request failed; "
944911106dfSjm199354 "file system does not support virus scanning");
945911106dfSjm199354 return (-1);
946911106dfSjm199354 }
947911106dfSjm199354
948bfc848c6Sjm199354 node->vsn_size = xvattr.xva_vattr.va_size;
949bfc848c6Sjm199354 node->vsn_mtime.tv_sec = xvattr.xva_vattr.va_mtime.tv_sec;
950bfc848c6Sjm199354 node->vsn_mtime.tv_nsec = xvattr.xva_vattr.va_mtime.tv_nsec;
951911106dfSjm199354
952911106dfSjm199354 if (XVA_ISSET_RTN(&xvattr, XAT_AV_MODIFIED) == 0)
953911106dfSjm199354 return (-1);
954bfc848c6Sjm199354 node->vsn_modified = xoap->xoa_av_modified;
955911106dfSjm199354
956911106dfSjm199354 if (XVA_ISSET_RTN(&xvattr, XAT_AV_QUARANTINED) == 0)
957911106dfSjm199354 return (-1);
958bfc848c6Sjm199354 node->vsn_quarantined = xoap->xoa_av_quarantined;
959911106dfSjm199354
960911106dfSjm199354 if (XVA_ISSET_RTN(&xvattr, XAT_AV_SCANSTAMP) != 0) {
961bfc848c6Sjm199354 (void) memcpy(node->vsn_scanstamp,
962911106dfSjm199354 xoap->xoa_av_scanstamp, AV_SCANSTAMP_SZ);
963911106dfSjm199354 }
964911106dfSjm199354
965bfc848c6Sjm199354 DTRACE_PROBE1(vscan__getattr, vscan_svc_node_t *, node);
966911106dfSjm199354 return (0);
967911106dfSjm199354 }
968911106dfSjm199354
969911106dfSjm199354
970911106dfSjm199354 /*
971911106dfSjm199354 * vscan_svc_setattr
972911106dfSjm199354 *
973911106dfSjm199354 * Set the vscan related system attributes.
974911106dfSjm199354 */
975911106dfSjm199354 static int
vscan_svc_setattr(int idx,int which)97653c11029Sjm199354 vscan_svc_setattr(int idx, int which)
977911106dfSjm199354 {
978911106dfSjm199354 xvattr_t xvattr;
979911106dfSjm199354 xoptattr_t *xoap = NULL;
980911106dfSjm199354 vnode_t *vp;
981911106dfSjm199354 int len;
982bfc848c6Sjm199354 vscan_svc_node_t *node;
983911106dfSjm199354
984911106dfSjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
985911106dfSjm199354
986bfc848c6Sjm199354 node = &vscan_svc_nodes[idx];
987bfc848c6Sjm199354 if ((vp = node->vsn_req->vsr_vp) == NULL)
988911106dfSjm199354 return (-1);
989911106dfSjm199354
990911106dfSjm199354 /* update the attributes */
991911106dfSjm199354 xva_init(&xvattr); /* sets AT_XVATTR */
992911106dfSjm199354 if ((xoap = xva_getxoptattr(&xvattr)) == NULL)
993911106dfSjm199354 return (-1);
994911106dfSjm199354
99553c11029Sjm199354 if (which & XAT_AV_MODIFIED) {
996911106dfSjm199354 XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
997bfc848c6Sjm199354 xoap->xoa_av_modified = node->vsn_modified;
99853c11029Sjm199354 }
999911106dfSjm199354
100053c11029Sjm199354 if (which & XAT_AV_QUARANTINED) {
1001911106dfSjm199354 XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
1002bfc848c6Sjm199354 xoap->xoa_av_quarantined = node->vsn_quarantined;
100353c11029Sjm199354 }
1004911106dfSjm199354
100553c11029Sjm199354 if (which & XAT_AV_SCANSTAMP) {
1006911106dfSjm199354 XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP);
1007bfc848c6Sjm199354 len = strlen(node->vsn_scanstamp);
1008911106dfSjm199354 (void) memcpy(xoap->xoa_av_scanstamp,
1009bfc848c6Sjm199354 node->vsn_scanstamp, len);
101053c11029Sjm199354 }
1011911106dfSjm199354
1012911106dfSjm199354 /* if access is denied, set mtime to invalidate client cache */
1013bfc848c6Sjm199354 if (node->vsn_access != VS_ACCESS_ALLOW) {
1014911106dfSjm199354 xvattr.xva_vattr.va_mask |= AT_MTIME;
1015911106dfSjm199354 gethrestime(&xvattr.xva_vattr.va_mtime);
1016911106dfSjm199354 }
1017911106dfSjm199354
1018911106dfSjm199354 if (VOP_SETATTR(vp, (vattr_t *)&xvattr, 0, kcred, NULL) != 0)
1019911106dfSjm199354 return (-1);
1020911106dfSjm199354
102153c11029Sjm199354 DTRACE_PROBE2(vscan__setattr,
1022bfc848c6Sjm199354 vscan_svc_node_t *, node, int, which);
102353c11029Sjm199354
1024911106dfSjm199354 return (0);
1025911106dfSjm199354 }
1026911106dfSjm199354
1027911106dfSjm199354
1028911106dfSjm199354 /*
1029911106dfSjm199354 * vscan_svc_configure
1030911106dfSjm199354 *
1031911106dfSjm199354 * store configuration in vscan_svc_config
1032911106dfSjm199354 * set up vscan_svc_types array of pointers into
1033911106dfSjm199354 * vscan_svc_config.vsc_types for efficient searching
1034911106dfSjm199354 */
1035911106dfSjm199354 int
vscan_svc_configure(vs_config_t * conf)1036911106dfSjm199354 vscan_svc_configure(vs_config_t *conf)
1037911106dfSjm199354 {
1038911106dfSjm199354 int count = 0;
1039911106dfSjm199354 char *p, *beg, *end;
1040911106dfSjm199354
1041911106dfSjm199354 mutex_enter(&vscan_svc_cfg_mutex);
1042911106dfSjm199354
1043911106dfSjm199354 vscan_svc_config = *conf;
1044911106dfSjm199354
1045911106dfSjm199354 (void) memset(vscan_svc_types, 0, sizeof (vscan_svc_types));
1046911106dfSjm199354
1047911106dfSjm199354 beg = vscan_svc_config.vsc_types;
1048911106dfSjm199354 end = beg + vscan_svc_config.vsc_types_len;
1049911106dfSjm199354
1050911106dfSjm199354 for (p = beg; p < end; p += strlen(p) + 1) {
1051911106dfSjm199354 if (count >= VS_TYPES_MAX) {
1052911106dfSjm199354 mutex_exit(&vscan_svc_mutex);
1053911106dfSjm199354 return (-1);
1054911106dfSjm199354 }
1055911106dfSjm199354
1056911106dfSjm199354 vscan_svc_types[count] = p;
1057911106dfSjm199354 ++count;
1058911106dfSjm199354 }
1059911106dfSjm199354
1060911106dfSjm199354 mutex_exit(&vscan_svc_cfg_mutex);
1061911106dfSjm199354 return (0);
1062911106dfSjm199354 }
1063911106dfSjm199354
1064911106dfSjm199354
1065911106dfSjm199354 /*
1066911106dfSjm199354 * vscan_svc_exempt_file
1067911106dfSjm199354 *
1068911106dfSjm199354 * check if a file's size or type exempts it from virus scanning
1069911106dfSjm199354 *
1070911106dfSjm199354 * If the file is exempt from virus scanning, allow will be set
1071911106dfSjm199354 * to define whether files access should be allowed (B_TRUE) or
1072911106dfSjm199354 * denied (B_FALSE)
1073911106dfSjm199354 *
1074911106dfSjm199354 * Returns: 1 exempt
1075911106dfSjm199354 * 0 scan required
1076911106dfSjm199354 */
1077911106dfSjm199354 static int
vscan_svc_exempt_file(vnode_t * vp,boolean_t * allow)1078911106dfSjm199354 vscan_svc_exempt_file(vnode_t *vp, boolean_t *allow)
1079911106dfSjm199354 {
1080911106dfSjm199354 struct vattr attr;
1081911106dfSjm199354
1082911106dfSjm199354 ASSERT(vp != NULL);
1083911106dfSjm199354 ASSERT(vp->v_path != NULL);
1084911106dfSjm199354
1085911106dfSjm199354 attr.va_mask = AT_SIZE;
1086911106dfSjm199354
1087911106dfSjm199354 if (VOP_GETATTR(vp, &attr, 0, kcred, NULL) != 0) {
1088911106dfSjm199354 *allow = B_FALSE;
1089911106dfSjm199354 return (0);
1090911106dfSjm199354 }
1091911106dfSjm199354
1092911106dfSjm199354 mutex_enter(&vscan_svc_cfg_mutex);
1093911106dfSjm199354
1094911106dfSjm199354 if (attr.va_size > vscan_svc_config.vsc_max_size) {
1095911106dfSjm199354 DTRACE_PROBE2(vscan__exempt__filesize, char *,
1096911106dfSjm199354 vp->v_path, int, *allow);
1097911106dfSjm199354
1098911106dfSjm199354 *allow = (vscan_svc_config.vsc_allow) ? B_TRUE : B_FALSE;
1099911106dfSjm199354 mutex_exit(&vscan_svc_cfg_mutex);
1100911106dfSjm199354 return (1);
1101911106dfSjm199354 }
1102911106dfSjm199354
1103911106dfSjm199354 if (vscan_svc_exempt_filetype(vp->v_path)) {
1104911106dfSjm199354 DTRACE_PROBE1(vscan__exempt__filetype, char *, vp->v_path);
1105911106dfSjm199354 *allow = B_TRUE;
1106911106dfSjm199354 mutex_exit(&vscan_svc_cfg_mutex);
1107911106dfSjm199354 return (1);
1108911106dfSjm199354 }
1109911106dfSjm199354
1110911106dfSjm199354 mutex_exit(&vscan_svc_cfg_mutex);
1111911106dfSjm199354 return (0);
1112911106dfSjm199354 }
1113911106dfSjm199354
1114911106dfSjm199354
1115911106dfSjm199354 /*
1116911106dfSjm199354 * vscan_svc_exempt_filetype
1117911106dfSjm199354 *
1118911106dfSjm199354 * Each entry in vscan_svc_types includes a rule indicator (+,-)
1119911106dfSjm199354 * followed by the match string for file types to which the rule
1120911106dfSjm199354 * applies. Look for first match of file type in vscan_svc_types
1121911106dfSjm199354 * and return 1 (exempt) if the indicator is '-', and 0 (not exempt)
1122911106dfSjm199354 * if the indicator is '+'.
1123911106dfSjm199354 * If vscan_svc_match_ext fails, or no match is found, return 0
1124911106dfSjm199354 * (not exempt)
1125911106dfSjm199354 *
1126911106dfSjm199354 * Returns 1: exempt, 0: not exempt
1127911106dfSjm199354 */
1128911106dfSjm199354 static int
vscan_svc_exempt_filetype(char * filepath)1129911106dfSjm199354 vscan_svc_exempt_filetype(char *filepath)
1130911106dfSjm199354 {
1131911106dfSjm199354 int i, rc, exempt = 0;
1132911106dfSjm199354 char *filename, *ext;
1133911106dfSjm199354
1134911106dfSjm199354 ASSERT(MUTEX_HELD(&vscan_svc_cfg_mutex));
1135911106dfSjm199354
1136911106dfSjm199354 if ((filename = strrchr(filepath, '/')) == 0)
1137911106dfSjm199354 filename = filepath;
1138911106dfSjm199354 else
1139911106dfSjm199354 filename++;
1140911106dfSjm199354
1141911106dfSjm199354 if ((ext = strrchr(filename, '.')) == NULL)
1142911106dfSjm199354 ext = "";
1143911106dfSjm199354 else
1144911106dfSjm199354 ext++;
1145911106dfSjm199354
1146911106dfSjm199354 for (i = 0; i < VS_TYPES_MAX; i ++) {
1147911106dfSjm199354 if (vscan_svc_types[i] == 0)
1148911106dfSjm199354 break;
1149911106dfSjm199354
1150911106dfSjm199354 rc = vscan_svc_match_ext(vscan_svc_types[i] + 1, ext, 1);
1151911106dfSjm199354 if (rc == -1)
1152911106dfSjm199354 break;
1153911106dfSjm199354 if (rc > 0) {
1154911106dfSjm199354 DTRACE_PROBE2(vscan__type__match, char *, ext,
1155911106dfSjm199354 char *, vscan_svc_types[i]);
1156911106dfSjm199354 exempt = (vscan_svc_types[i][0] == '-');
1157911106dfSjm199354 break;
1158911106dfSjm199354 }
1159911106dfSjm199354 }
1160911106dfSjm199354
1161911106dfSjm199354 return (exempt);
1162911106dfSjm199354 }
1163911106dfSjm199354
1164911106dfSjm199354
1165911106dfSjm199354 /*
1166911106dfSjm199354 * vscan_svc_match_ext
1167911106dfSjm199354 *
1168911106dfSjm199354 * Performs a case-insensitive match for two strings. The first string
1169911106dfSjm199354 * argument can contain the wildcard characters '?' and '*'
1170911106dfSjm199354 *
1171911106dfSjm199354 * Returns: 0 no match
1172911106dfSjm199354 * 1 match
1173911106dfSjm199354 * -1 recursion error
1174911106dfSjm199354 */
1175911106dfSjm199354 static int
vscan_svc_match_ext(char * patn,char * str,int depth)1176911106dfSjm199354 vscan_svc_match_ext(char *patn, char *str, int depth)
1177911106dfSjm199354 {
1178911106dfSjm199354 int c1, c2;
1179911106dfSjm199354 if (depth > VS_EXT_RECURSE_DEPTH)
1180911106dfSjm199354 return (-1);
1181911106dfSjm199354
1182911106dfSjm199354 for (;;) {
1183911106dfSjm199354 switch (*patn) {
1184911106dfSjm199354 case 0:
1185911106dfSjm199354 return (*str == 0);
1186911106dfSjm199354
1187911106dfSjm199354 case '?':
1188911106dfSjm199354 if (*str != 0) {
1189911106dfSjm199354 str++;
1190911106dfSjm199354 patn++;
1191911106dfSjm199354 continue;
1192911106dfSjm199354 }
1193911106dfSjm199354 return (0);
1194911106dfSjm199354
1195911106dfSjm199354 case '*':
1196911106dfSjm199354 patn++;
1197911106dfSjm199354 if (*patn == 0)
1198911106dfSjm199354 return (1);
1199911106dfSjm199354
1200911106dfSjm199354 while (*str) {
1201911106dfSjm199354 if (vscan_svc_match_ext(patn, str, depth + 1))
1202911106dfSjm199354 return (1);
1203911106dfSjm199354 str++;
1204911106dfSjm199354 }
1205911106dfSjm199354 return (0);
1206911106dfSjm199354
1207911106dfSjm199354 default:
1208911106dfSjm199354 if (*str != *patn) {
1209911106dfSjm199354 c1 = *str;
1210911106dfSjm199354 c2 = *patn;
1211911106dfSjm199354
1212911106dfSjm199354 c1 = tolower(c1);
1213911106dfSjm199354 c2 = tolower(c2);
1214911106dfSjm199354 if (c1 != c2)
1215911106dfSjm199354 return (0);
1216911106dfSjm199354 }
1217911106dfSjm199354 str++;
1218911106dfSjm199354 patn++;
1219911106dfSjm199354 continue;
1220911106dfSjm199354 }
1221911106dfSjm199354 }
1222911106dfSjm199354 /* NOT REACHED */
1223911106dfSjm199354 }
1224bfc848c6Sjm199354
1225bfc848c6Sjm199354
1226bfc848c6Sjm199354 /*
1227bfc848c6Sjm199354 * vscan_svc_insert_req
1228bfc848c6Sjm199354 *
1229bfc848c6Sjm199354 * Insert request in next available available slot in vscan_svc_nodes
1230bfc848c6Sjm199354 *
1231bfc848c6Sjm199354 * Returns: idx of slot, or -1 if no slot available
1232bfc848c6Sjm199354 */
1233bfc848c6Sjm199354 static int
vscan_svc_insert_req(vscan_req_t * req)1234bfc848c6Sjm199354 vscan_svc_insert_req(vscan_req_t *req)
1235bfc848c6Sjm199354 {
1236bfc848c6Sjm199354 int idx;
1237bfc848c6Sjm199354 vscan_svc_node_t *node;
1238bfc848c6Sjm199354
1239bfc848c6Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
1240bfc848c6Sjm199354
1241bfc848c6Sjm199354 if (vscan_svc_counts.vsc_node == vs_nodes_max)
1242bfc848c6Sjm199354 return (-1);
1243bfc848c6Sjm199354
1244bfc848c6Sjm199354 for (idx = 1; idx <= vs_nodes_max; idx++) {
1245bfc848c6Sjm199354 if (vscan_svc_nodes[idx].vsn_req == NULL) {
1246bfc848c6Sjm199354 req->vsr_idx = idx;
1247bfc848c6Sjm199354
1248bfc848c6Sjm199354 node = &vscan_svc_nodes[idx];
1249bfc848c6Sjm199354 (void) memset(node, 0, sizeof (vscan_svc_node_t));
1250bfc848c6Sjm199354 node->vsn_req = req;
1251bfc848c6Sjm199354 node->vsn_modified = 1;
1252bfc848c6Sjm199354 node->vsn_result = VS_STATUS_UNDEFINED;
1253bfc848c6Sjm199354 node->vsn_access = VS_ACCESS_UNDEFINED;
1254bfc848c6Sjm199354
1255bfc848c6Sjm199354 ++(vscan_svc_counts.vsc_node);
1256bfc848c6Sjm199354 return (idx);
1257bfc848c6Sjm199354 }
1258bfc848c6Sjm199354 }
1259bfc848c6Sjm199354
1260bfc848c6Sjm199354 return (-1);
1261bfc848c6Sjm199354 }
1262bfc848c6Sjm199354
1263bfc848c6Sjm199354
1264bfc848c6Sjm199354 /*
1265bfc848c6Sjm199354 * vscan_svc_remove_req
1266bfc848c6Sjm199354 */
1267bfc848c6Sjm199354 static void
vscan_svc_remove_req(int idx)1268bfc848c6Sjm199354 vscan_svc_remove_req(int idx)
1269bfc848c6Sjm199354 {
1270bfc848c6Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
1271bfc848c6Sjm199354
1272bfc848c6Sjm199354 if (idx != 0) {
1273bfc848c6Sjm199354 (void) memset(&vscan_svc_nodes[idx], 0,
1274bfc848c6Sjm199354 sizeof (vscan_svc_node_t));
1275bfc848c6Sjm199354 --(vscan_svc_counts.vsc_node);
1276bfc848c6Sjm199354 }
1277bfc848c6Sjm199354 }
1278bfc848c6Sjm199354
1279bfc848c6Sjm199354
1280bfc848c6Sjm199354 /*
1281bfc848c6Sjm199354 * vscan_svc_reql_find
1282bfc848c6Sjm199354 */
1283bfc848c6Sjm199354 static vscan_req_t *
vscan_svc_reql_find(vnode_t * vp)1284bfc848c6Sjm199354 vscan_svc_reql_find(vnode_t *vp)
1285bfc848c6Sjm199354 {
1286bfc848c6Sjm199354 vscan_req_t *req;
1287bfc848c6Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
1288bfc848c6Sjm199354
1289bfc848c6Sjm199354 req = list_head(&vscan_svc_reql);
1290bfc848c6Sjm199354
1291bfc848c6Sjm199354 while (req != NULL) {
1292bfc848c6Sjm199354 ASSERT(req->vsr_magic == VS_REQ_MAGIC);
1293bfc848c6Sjm199354 if ((req->vsr_vp == vp) &&
1294bfc848c6Sjm199354 (req->vsr_state != VS_SVC_REQ_COMPLETE))
1295bfc848c6Sjm199354 break;
1296bfc848c6Sjm199354
1297bfc848c6Sjm199354 req = list_next(&vscan_svc_reql, req);
1298bfc848c6Sjm199354 }
1299bfc848c6Sjm199354
1300bfc848c6Sjm199354 return (req);
1301bfc848c6Sjm199354 }
1302bfc848c6Sjm199354
1303bfc848c6Sjm199354
1304bfc848c6Sjm199354 /*
1305bfc848c6Sjm199354 * vscan_svc_reql_insert
1306bfc848c6Sjm199354 */
1307bfc848c6Sjm199354 static vscan_req_t *
vscan_svc_reql_insert(vnode_t * vp)1308bfc848c6Sjm199354 vscan_svc_reql_insert(vnode_t *vp)
1309bfc848c6Sjm199354 {
1310bfc848c6Sjm199354 vscan_req_t *req;
1311bfc848c6Sjm199354
1312bfc848c6Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
1313bfc848c6Sjm199354
1314bfc848c6Sjm199354 /* if request already in list then return it */
1315bfc848c6Sjm199354 if ((req = vscan_svc_reql_find(vp)) != NULL)
1316bfc848c6Sjm199354 return (req);
1317bfc848c6Sjm199354
1318bfc848c6Sjm199354 /* if list is full return NULL */
1319bfc848c6Sjm199354 if (vscan_svc_counts.vsc_reql == vs_reqs_max)
1320bfc848c6Sjm199354 return (NULL);
1321bfc848c6Sjm199354
1322bfc848c6Sjm199354 /* create a new request and insert into list */
1323bfc848c6Sjm199354 VN_HOLD(vp);
1324bfc848c6Sjm199354
1325bfc848c6Sjm199354 req = kmem_zalloc(sizeof (vscan_req_t), KM_SLEEP);
1326bfc848c6Sjm199354
1327bfc848c6Sjm199354 req->vsr_magic = VS_REQ_MAGIC;
1328bfc848c6Sjm199354 if (vscan_svc_seqnum == UINT32_MAX)
1329bfc848c6Sjm199354 vscan_svc_seqnum = 0;
1330bfc848c6Sjm199354 req->vsr_seqnum = ++vscan_svc_seqnum;
1331bfc848c6Sjm199354 req->vsr_vp = vp;
1332bfc848c6Sjm199354 req->vsr_refcnt = 1; /* decremented in vscan_svc_scan_complete */
1333bfc848c6Sjm199354 req->vsr_state = VS_SVC_REQ_INIT;
1334bfc848c6Sjm199354 cv_init(&(req->vsr_cv), NULL, CV_DEFAULT, NULL);
1335bfc848c6Sjm199354
1336bfc848c6Sjm199354 list_insert_tail(&vscan_svc_reql, req);
1337bfc848c6Sjm199354 if (vscan_svc_reql_next == NULL)
1338bfc848c6Sjm199354 vscan_svc_reql_next = req;
1339bfc848c6Sjm199354
1340bfc848c6Sjm199354 ++(vscan_svc_counts.vsc_reql);
1341bfc848c6Sjm199354
1342bfc848c6Sjm199354 /* wake reql handler thread */
1343bfc848c6Sjm199354 cv_signal(&vscan_svc_reql_cv);
1344bfc848c6Sjm199354
1345bfc848c6Sjm199354 return (req);
1346bfc848c6Sjm199354 }
1347bfc848c6Sjm199354
1348bfc848c6Sjm199354
1349bfc848c6Sjm199354 /*
1350bfc848c6Sjm199354 * vscan_svc_reql_remove
1351bfc848c6Sjm199354 */
1352bfc848c6Sjm199354 static void
vscan_svc_reql_remove(vscan_req_t * req)1353bfc848c6Sjm199354 vscan_svc_reql_remove(vscan_req_t *req)
1354bfc848c6Sjm199354 {
1355bfc848c6Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex));
1356bfc848c6Sjm199354 ASSERT(req->vsr_magic == VS_REQ_MAGIC);
1357bfc848c6Sjm199354
1358bfc848c6Sjm199354 if (vscan_svc_reql_next == req)
1359bfc848c6Sjm199354 vscan_svc_reql_next = list_next(&vscan_svc_reql, req);
1360bfc848c6Sjm199354
1361bfc848c6Sjm199354 list_remove(&vscan_svc_reql, req);
1362bfc848c6Sjm199354 cv_destroy(&(req->vsr_cv));
1363bfc848c6Sjm199354 VN_RELE(req->vsr_vp);
1364bfc848c6Sjm199354
1365bfc848c6Sjm199354 kmem_free(req, sizeof (vscan_req_t));
1366bfc848c6Sjm199354 --(vscan_svc_counts.vsc_reql);
1367bfc848c6Sjm199354 }
1368