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 /* 23d3d50737SRafael 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> 44*5c5f1371SRichard Lowe #include <sys/sysmacros.h> 45911106dfSjm199354 46bfc848c6Sjm199354 #define VS_REQ_MAGIC 0x52515354 /* 'RQST' */ 47911106dfSjm199354 48bfc848c6Sjm199354 #define VS_REQS_DEFAULT 20000 /* pending scan requests - reql */ 49bfc848c6Sjm199354 #define VS_NODES_DEFAULT 128 /* concurrent file scans */ 50bfc848c6Sjm199354 #define VS_WORKERS_DEFAULT 32 /* worker threads */ 51bfc848c6Sjm199354 #define VS_SCANWAIT_DEFAULT 15*60 /* seconds to wait for scan result */ 52bfc848c6Sjm199354 #define VS_REQL_HANDLER_TIMEOUT 30 53bfc848c6Sjm199354 #define VS_EXT_RECURSE_DEPTH 8 54bfc848c6Sjm199354 55bfc848c6Sjm199354 /* access derived from scan result (VS_STATUS_XXX) and file attributes */ 56bfc848c6Sjm199354 #define VS_ACCESS_UNDEFINED 0 57bfc848c6Sjm199354 #define VS_ACCESS_ALLOW 1 /* return 0 */ 58bfc848c6Sjm199354 #define VS_ACCESS_DENY 2 /* return EACCES */ 59bfc848c6Sjm199354 60bfc848c6Sjm199354 #define tolower(C) (((C) >= 'A' && (C) <= 'Z') ? (C) - 'A' + 'a' : (C)) 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 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 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 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 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 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 * 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 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)) { 503d3d50737SRafael Vanoni timeout = time_left; 504d3d50737SRafael Vanoni time_left = cv_reltimedwait_sig(&(req->vsr_cv), 505d3d50737SRafael 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 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 590d3d50737SRafael Vanoni (void) cv_reltimedwait(&vscan_svc_reql_cv, &vscan_svc_mutex, 591d3d50737SRafael 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 * 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 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