15440Sjm199354 /* 25440Sjm199354 * CDDL HEADER START 35440Sjm199354 * 45440Sjm199354 * The contents of this file are subject to the terms of the 55440Sjm199354 * Common Development and Distribution License (the "License"). 65440Sjm199354 * You may not use this file except in compliance with the License. 75440Sjm199354 * 85440Sjm199354 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95440Sjm199354 * or http://www.opensolaris.org/os/licensing. 105440Sjm199354 * See the License for the specific language governing permissions 115440Sjm199354 * and limitations under the License. 125440Sjm199354 * 135440Sjm199354 * When distributing Covered Code, include this CDDL HEADER in each 145440Sjm199354 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155440Sjm199354 * If applicable, add the following below this CDDL HEADER, with the 165440Sjm199354 * fields enclosed by brackets "[]" replaced with your own identifying 175440Sjm199354 * information: Portions Copyright [yyyy] [name of copyright owner] 185440Sjm199354 * 195440Sjm199354 * CDDL HEADER END 205440Sjm199354 */ 215440Sjm199354 225440Sjm199354 /* 235931Sjm199354 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 245440Sjm199354 * Use is subject to license terms. 255440Sjm199354 */ 265440Sjm199354 275440Sjm199354 #pragma ident "%Z%%M% %I% %E% SMI" 285440Sjm199354 295440Sjm199354 #include <sys/stat.h> 305440Sjm199354 #include <sys/ddi.h> 315440Sjm199354 #include <sys/sunddi.h> 325440Sjm199354 #include <sys/time.h> 335440Sjm199354 #include <sys/varargs.h> 345440Sjm199354 #include <sys/conf.h> 355440Sjm199354 #include <sys/modctl.h> 365440Sjm199354 #include <sys/cmn_err.h> 375440Sjm199354 #include <sys/vnode.h> 385440Sjm199354 #include <fs/fs_subr.h> 395440Sjm199354 #include <sys/types.h> 405440Sjm199354 #include <sys/file.h> 415440Sjm199354 #include <sys/disp.h> 425440Sjm199354 #include <sys/sdt.h> 435440Sjm199354 #include <sys/cred.h> 44*6407Sjm199354 #include <sys/list.h> 455440Sjm199354 #include <sys/vscan.h> 465440Sjm199354 47*6407Sjm199354 #define VS_REQ_MAGIC 0x52515354 /* 'RQST' */ 48*6407Sjm199354 49*6407Sjm199354 #define VS_REQS_DEFAULT 20000 /* pending scan requests - reql */ 50*6407Sjm199354 #define VS_NODES_DEFAULT 128 /* concurrent file scans */ 51*6407Sjm199354 #define VS_WORKERS_DEFAULT 32 /* worker threads */ 52*6407Sjm199354 #define VS_SCANWAIT_DEFAULT 15*60 /* seconds to wait for scan result */ 53*6407Sjm199354 #define VS_REQL_HANDLER_TIMEOUT 30 545440Sjm199354 #define VS_EXT_RECURSE_DEPTH 8 55*6407Sjm199354 56*6407Sjm199354 /* access derived from scan result (VS_STATUS_XXX) and file attributes */ 57*6407Sjm199354 #define VS_ACCESS_UNDEFINED 0 58*6407Sjm199354 #define VS_ACCESS_ALLOW 1 /* return 0 */ 59*6407Sjm199354 #define VS_ACCESS_DENY 2 /* return EACCES */ 60*6407Sjm199354 615440Sjm199354 #define tolower(C) (((C) >= 'A' && (C) <= 'Z') ? (C) - 'A' + 'a' : (C)) 62*6407Sjm199354 #define offsetof(s, m) (size_t)(&(((s *)0)->m)) 63*6407Sjm199354 64*6407Sjm199354 /* global variables - tunable via /etc/system */ 65*6407Sjm199354 uint32_t vs_reqs_max = VS_REQS_DEFAULT; /* max scan requests */ 66*6407Sjm199354 uint32_t vs_nodes_max = VS_NODES_DEFAULT; /* max in-progress scan requests */ 67*6407Sjm199354 uint32_t vs_workers = VS_WORKERS_DEFAULT; /* max workers send reqs to vscand */ 68*6407Sjm199354 uint32_t vs_scan_wait = VS_SCANWAIT_DEFAULT; /* secs to wait for scan result */ 69*6407Sjm199354 705440Sjm199354 71*6407Sjm199354 /* 72*6407Sjm199354 * vscan_svc_state 73*6407Sjm199354 * 74*6407Sjm199354 * +-----------------+ 75*6407Sjm199354 * | VS_SVC_UNCONFIG | 76*6407Sjm199354 * +-----------------+ 77*6407Sjm199354 * | ^ 78*6407Sjm199354 * | svc_init | svc_fini 79*6407Sjm199354 * v | 80*6407Sjm199354 * +-----------------+ 81*6407Sjm199354 * | VS_SVC_IDLE |<----| 82*6407Sjm199354 * +-----------------+ | 83*6407Sjm199354 * | | 84*6407Sjm199354 * | svc_enable | 85*6407Sjm199354 * |<----------------| | 86*6407Sjm199354 * v | | 87*6407Sjm199354 * +-----------------+ | | 88*6407Sjm199354 * | VS_SVC_ENABLED |--| | 89*6407Sjm199354 * +-----------------+ | 90*6407Sjm199354 * | | 91*6407Sjm199354 * | svc_disable | handler thread exit, 92*6407Sjm199354 * v | all requests complete 93*6407Sjm199354 * +-----------------+ | 94*6407Sjm199354 * | VS_SVC_DISABLED |-----| 95*6407Sjm199354 * +-----------------+ 96*6407Sjm199354 * 97*6407Sjm199354 * svc_enable may occur when we are already in the ENABLED 98*6407Sjm199354 * state if vscand has exited without clean shutdown and 99*6407Sjm199354 * then reconnected within the delayed disable time period 100*6407Sjm199354 * (vs_reconnect_timeout) - see vscan_drv 101*6407Sjm199354 */ 102*6407Sjm199354 103*6407Sjm199354 typedef enum { 104*6407Sjm199354 VS_SVC_UNCONFIG, 105*6407Sjm199354 VS_SVC_IDLE, 106*6407Sjm199354 VS_SVC_ENABLED, /* service enabled and registered */ 107*6407Sjm199354 VS_SVC_DISABLED /* service disabled and nunregistered */ 108*6407Sjm199354 } vscan_svc_state_t; 109*6407Sjm199354 static vscan_svc_state_t vscan_svc_state = VS_SVC_UNCONFIG; 110*6407Sjm199354 1115440Sjm199354 1125440Sjm199354 /* 113*6407Sjm199354 * vscan_svc_req_state 114*6407Sjm199354 * 115*6407Sjm199354 * When a scan request is received from the file system it is 116*6407Sjm199354 * identified in or inserted into the vscan_svc_reql (INIT). 117*6407Sjm199354 * If the request is asynchronous 0 is then returned to the caller. 118*6407Sjm199354 * If the request is synchronous the req's refcnt is incremented 119*6407Sjm199354 * and the caller waits for the request to complete. 120*6407Sjm199354 * The refcnt is also incremented when the request is inserted 121*6407Sjm199354 * in vscan_svc_nodes, and decremented on scan_complete. 122*6407Sjm199354 * 123*6407Sjm199354 * vscan_svc_handler processes requests from the request list, 124*6407Sjm199354 * inserting them into vscan_svc_nodes and the task queue (QUEUED). 125*6407Sjm199354 * When the task queue call back (vscan_svc_do_scan) is invoked 126*6407Sjm199354 * the request transitions to IN_PROGRESS state. If the request 127*6407Sjm199354 * is sucessfully sent to vscand (door_call) and the door response 128*6407Sjm199354 * is SCANNING then the scan result will be received asynchronously. 129*6407Sjm199354 * Although unusual, it is possible that the async response is 130*6407Sjm199354 * received before the door call returns (hence the ASYNC_COMPLETE 131*6407Sjm199354 * state). 132*6407Sjm199354 * When the result has been determined / received, 133*6407Sjm199354 * vscan_svc_scan_complete is invoked to transition the request to 134*6407Sjm199354 * COMPLETE state, decrement refcnt and signal all waiting callers. 135*6407Sjm199354 * When the last waiting caller has processed the result (refcnt == 0) 136*6407Sjm199354 * the request is removed from vscan_svc_reql and vscan_svc_nodes 137*6407Sjm199354 * and deleted. 138*6407Sjm199354 * 139*6407Sjm199354 * | ^ 140*6407Sjm199354 * | reql_insert | refcnt == 0 141*6407Sjm199354 * v | (delete) 142*6407Sjm199354 * +------------------------+ +---------------------+ 143*6407Sjm199354 * | VS_SVC_REQ_INIT | -----DISABLE----> | VS_SVC_REQ_COMPLETE | 144*6407Sjm199354 * +------------------------+ +---------------------+ 145*6407Sjm199354 * | ^ 146*6407Sjm199354 * | insert_req, tq_dispatch | 147*6407Sjm199354 * v | 148*6407Sjm199354 * +------------------------+ | 149*6407Sjm199354 * | VS_SVC_REQ_QUEUED | scan_complete 150*6407Sjm199354 * +------------------------+ | 151*6407Sjm199354 * | | 152*6407Sjm199354 * | tq_callback (do_scan) | 153*6407Sjm199354 * | | 154*6407Sjm199354 * v scan not req'd, error, | 155*6407Sjm199354 * +------------------------+ or door_result != SCANNING | 156*6407Sjm199354 * | VS_SVC_REQ_IN_PROGRESS |----------------->-------------| 157*6407Sjm199354 * +------------------------+ | 158*6407Sjm199354 * | | | 159*6407Sjm199354 * | | door_result == SCANNING | 160*6407Sjm199354 * | v | 161*6407Sjm199354 * | +---------------------------+ async result | 162*6407Sjm199354 * | | VS_SVC_REQ_SCANNING |-------->---------| 163*6407Sjm199354 * | +---------------------------+ | 164*6407Sjm199354 * | | 165*6407Sjm199354 * | async result | 166*6407Sjm199354 * v | 167*6407Sjm199354 * +---------------------------+ door_result = SCANNING | 168*6407Sjm199354 * | VS_SVC_REQ_ASYNC_COMPLETE |-------->------------------| 169*6407Sjm199354 * +---------------------------+ 170*6407Sjm199354 */ 171*6407Sjm199354 typedef enum { 172*6407Sjm199354 VS_SVC_REQ_INIT, 173*6407Sjm199354 VS_SVC_REQ_QUEUED, 174*6407Sjm199354 VS_SVC_REQ_IN_PROGRESS, 175*6407Sjm199354 VS_SVC_REQ_SCANNING, 176*6407Sjm199354 VS_SVC_REQ_ASYNC_COMPLETE, 177*6407Sjm199354 VS_SVC_REQ_COMPLETE 178*6407Sjm199354 } vscan_svc_req_state_t; 179*6407Sjm199354 180*6407Sjm199354 181*6407Sjm199354 /* 182*6407Sjm199354 * vscan_svc_reql - the list of pending and in-progress scan requests 183*6407Sjm199354 */ 184*6407Sjm199354 typedef struct vscan_req { 185*6407Sjm199354 uint32_t vsr_magic; /* VS_REQ_MAGIC */ 186*6407Sjm199354 list_node_t vsr_lnode; 187*6407Sjm199354 vnode_t *vsr_vp; 188*6407Sjm199354 uint32_t vsr_idx; /* vscan_svc_nodes index */ 189*6407Sjm199354 uint32_t vsr_seqnum; /* unigue request id */ 190*6407Sjm199354 uint32_t vsr_refcnt; 191*6407Sjm199354 kcondvar_t vsr_cv; 192*6407Sjm199354 vscan_svc_req_state_t vsr_state; 193*6407Sjm199354 } vscan_req_t; 194*6407Sjm199354 195*6407Sjm199354 static list_t vscan_svc_reql; 196*6407Sjm199354 197*6407Sjm199354 198*6407Sjm199354 /* 199*6407Sjm199354 * vscan_svc_nodes - table of files being scanned 2005440Sjm199354 * 2015440Sjm199354 * The index into this table is passed in the door call to 2025440Sjm199354 * vscand. vscand uses the idx to determine which minor node 2035440Sjm199354 * to open to read the file data. Within the kernel driver 2045440Sjm199354 * the minor device number can thus be used to identify the 2055440Sjm199354 * table index to get the appropriate vnode. 2065440Sjm199354 * 2075440Sjm199354 * Instance 0 is reserved for the daemon/driver control 2085440Sjm199354 * interface: enable/configure/disable 2095440Sjm199354 */ 210*6407Sjm199354 typedef struct vscan_svc_node { 211*6407Sjm199354 vscan_req_t *vsn_req; 212*6407Sjm199354 uint8_t vsn_quarantined; 213*6407Sjm199354 uint8_t vsn_modified; 214*6407Sjm199354 uint64_t vsn_size; 215*6407Sjm199354 timestruc_t vsn_mtime; 216*6407Sjm199354 vs_scanstamp_t vsn_scanstamp; 217*6407Sjm199354 uint32_t vsn_result; 218*6407Sjm199354 uint32_t vsn_access; 219*6407Sjm199354 } vscan_svc_node_t; 2205440Sjm199354 221*6407Sjm199354 static vscan_svc_node_t *vscan_svc_nodes; 222*6407Sjm199354 static int vscan_svc_nodes_sz; 223*6407Sjm199354 224*6407Sjm199354 225*6407Sjm199354 /* vscan_svc_taskq - queue of requests waiting to be sent to vscand */ 226*6407Sjm199354 static taskq_t *vscan_svc_taskq = NULL; 2275440Sjm199354 228*6407Sjm199354 /* counts of entries in vscan_svc_reql, vscan_svc_nodes & vscan_svc_taskq */ 229*6407Sjm199354 typedef struct { 230*6407Sjm199354 uint32_t vsc_reql; 231*6407Sjm199354 uint32_t vsc_node; 232*6407Sjm199354 uint32_t vsc_tq; 233*6407Sjm199354 } vscan_svc_counts_t; 234*6407Sjm199354 static vscan_svc_counts_t vscan_svc_counts; 2355440Sjm199354 2365440Sjm199354 /* 2375440Sjm199354 * vscan_svc_mutex protects the data pertaining to scan requests: 238*6407Sjm199354 * request list - vscan_svc_reql 239*6407Sjm199354 * node table - vscan_svc_nodes 2405440Sjm199354 */ 2415440Sjm199354 static kmutex_t vscan_svc_mutex; 2425440Sjm199354 243*6407Sjm199354 /* unique request id for vscand request/response correlation */ 244*6407Sjm199354 static uint32_t vscan_svc_seqnum = 0; 245*6407Sjm199354 2465440Sjm199354 /* 2475440Sjm199354 * vscan_svc_cfg_mutex protects the configuration data: 2485440Sjm199354 * vscan_svc_config, vscan_svc_types 2495440Sjm199354 */ 2505440Sjm199354 static kmutex_t vscan_svc_cfg_mutex; 2515440Sjm199354 2525440Sjm199354 /* configuration data - for virus scan exemption */ 2535440Sjm199354 static vs_config_t vscan_svc_config; 2545440Sjm199354 static char *vscan_svc_types[VS_TYPES_MAX]; 2555440Sjm199354 256*6407Sjm199354 /* thread to insert reql entries into vscan_svc_nodes & vscan_svc_taskq */ 257*6407Sjm199354 static kthread_t *vscan_svc_reql_thread; 258*6407Sjm199354 static kcondvar_t vscan_svc_reql_cv; 259*6407Sjm199354 static vscan_req_t *vscan_svc_reql_next; /* next pending scan request */ 260*6407Sjm199354 2615440Sjm199354 /* local functions */ 2625440Sjm199354 int vscan_svc_scan_file(vnode_t *, cred_t *, int); 263*6407Sjm199354 static void vscan_svc_taskq_callback(void *); 2645440Sjm199354 static int vscan_svc_exempt_file(vnode_t *, boolean_t *); 2655440Sjm199354 static int vscan_svc_exempt_filetype(char *); 2665440Sjm199354 static int vscan_svc_match_ext(char *, char *, int); 267*6407Sjm199354 static void vscan_svc_do_scan(vscan_req_t *); 268*6407Sjm199354 static vs_scan_req_t *vscan_svc_populate_req(int); 2695931Sjm199354 static void vscan_svc_process_scan_result(int); 270*6407Sjm199354 static void vscan_svc_scan_complete(vscan_req_t *); 271*6407Sjm199354 static void vscan_svc_delete_req(vscan_req_t *); 272*6407Sjm199354 static int vscan_svc_insert_req(vscan_req_t *); 273*6407Sjm199354 static void vscan_svc_remove_req(int); 274*6407Sjm199354 static vscan_req_t *vscan_svc_reql_find(vnode_t *); 275*6407Sjm199354 static vscan_req_t *vscan_svc_reql_insert(vnode_t *); 276*6407Sjm199354 static void vscan_svc_reql_remove(vscan_req_t *); 277*6407Sjm199354 2785440Sjm199354 static int vscan_svc_getattr(int); 2795931Sjm199354 static int vscan_svc_setattr(int, int); 2805440Sjm199354 281*6407Sjm199354 /* thread to insert reql entries into vscan_svc_nodes & vscan_svc_taskq */ 282*6407Sjm199354 static void vscan_svc_reql_handler(void); 2835440Sjm199354 2845440Sjm199354 2855440Sjm199354 /* 2865440Sjm199354 * vscan_svc_init 2875440Sjm199354 */ 2885440Sjm199354 int 2895440Sjm199354 vscan_svc_init() 2905440Sjm199354 { 291*6407Sjm199354 if (vscan_svc_state != VS_SVC_UNCONFIG) { 292*6407Sjm199354 DTRACE_PROBE1(vscan__svc__state__violation, 293*6407Sjm199354 int, vscan_svc_state); 294*6407Sjm199354 return (-1); 295*6407Sjm199354 } 296*6407Sjm199354 297*6407Sjm199354 mutex_init(&vscan_svc_mutex, NULL, MUTEX_DEFAULT, NULL); 298*6407Sjm199354 mutex_init(&vscan_svc_cfg_mutex, NULL, MUTEX_DEFAULT, NULL); 299*6407Sjm199354 cv_init(&vscan_svc_reql_cv, NULL, CV_DEFAULT, NULL); 300*6407Sjm199354 301*6407Sjm199354 vscan_svc_nodes_sz = sizeof (vscan_svc_node_t) * (vs_nodes_max + 1); 302*6407Sjm199354 vscan_svc_nodes = kmem_zalloc(vscan_svc_nodes_sz, KM_SLEEP); 303*6407Sjm199354 304*6407Sjm199354 vscan_svc_counts.vsc_reql = 0; 305*6407Sjm199354 vscan_svc_counts.vsc_node = 0; 306*6407Sjm199354 vscan_svc_counts.vsc_tq = 0; 307*6407Sjm199354 308*6407Sjm199354 vscan_svc_state = VS_SVC_IDLE; 3095440Sjm199354 3105440Sjm199354 return (0); 3115440Sjm199354 } 3125440Sjm199354 313*6407Sjm199354 3145440Sjm199354 /* 3155440Sjm199354 * vscan_svc_fini 3165440Sjm199354 */ 3175440Sjm199354 void 3185440Sjm199354 vscan_svc_fini() 3195440Sjm199354 { 320*6407Sjm199354 if (vscan_svc_state != VS_SVC_IDLE) { 321*6407Sjm199354 DTRACE_PROBE1(vscan__svc__state__violation, 322*6407Sjm199354 int, vscan_svc_state); 323*6407Sjm199354 return; 324*6407Sjm199354 } 3255440Sjm199354 326*6407Sjm199354 kmem_free(vscan_svc_nodes, vscan_svc_nodes_sz); 327*6407Sjm199354 328*6407Sjm199354 cv_destroy(&vscan_svc_reql_cv); 3295440Sjm199354 mutex_destroy(&vscan_svc_mutex); 3305440Sjm199354 mutex_destroy(&vscan_svc_cfg_mutex); 331*6407Sjm199354 vscan_svc_state = VS_SVC_UNCONFIG; 3325440Sjm199354 } 3335440Sjm199354 334*6407Sjm199354 3355440Sjm199354 /* 3365440Sjm199354 * vscan_svc_enable 3375440Sjm199354 */ 338*6407Sjm199354 int 3395931Sjm199354 vscan_svc_enable(void) 3405440Sjm199354 { 3415931Sjm199354 mutex_enter(&vscan_svc_mutex); 342*6407Sjm199354 343*6407Sjm199354 switch (vscan_svc_state) { 344*6407Sjm199354 case VS_SVC_ENABLED: 345*6407Sjm199354 /* 346*6407Sjm199354 * it's possible (and okay) for vscan_svc_enable to be 347*6407Sjm199354 * called when already enabled if vscand reconnects 348*6407Sjm199354 * during a delayed disable 349*6407Sjm199354 */ 350*6407Sjm199354 break; 351*6407Sjm199354 case VS_SVC_IDLE: 352*6407Sjm199354 list_create(&vscan_svc_reql, sizeof (vscan_req_t), 353*6407Sjm199354 offsetof(vscan_req_t, vsr_lnode)); 354*6407Sjm199354 vscan_svc_reql_next = list_head(&vscan_svc_reql); 3555931Sjm199354 356*6407Sjm199354 vscan_svc_taskq = taskq_create("vscan_taskq", vs_workers, 357*6407Sjm199354 MINCLSYSPRI, 1, INT_MAX, TASKQ_DYNAMIC); 358*6407Sjm199354 ASSERT(vscan_svc_taskq != NULL); 359*6407Sjm199354 360*6407Sjm199354 vscan_svc_reql_thread = thread_create(NULL, 0, 361*6407Sjm199354 vscan_svc_reql_handler, 0, 0, &p0, TS_RUN, MINCLSYSPRI); 362*6407Sjm199354 ASSERT(vscan_svc_reql_thread != NULL); 363*6407Sjm199354 364*6407Sjm199354 /* ready to start processing requests */ 365*6407Sjm199354 vscan_svc_state = VS_SVC_ENABLED; 366*6407Sjm199354 fs_vscan_register(vscan_svc_scan_file); 367*6407Sjm199354 break; 368*6407Sjm199354 default: 369*6407Sjm199354 DTRACE_PROBE1(vscan__svc__state__violation, 370*6407Sjm199354 int, vscan_svc_state); 371*6407Sjm199354 return (-1); 3725931Sjm199354 } 3735931Sjm199354 3745931Sjm199354 mutex_exit(&vscan_svc_mutex); 375*6407Sjm199354 return (0); 3765931Sjm199354 } 3775931Sjm199354 3785440Sjm199354 3795931Sjm199354 /* 3805931Sjm199354 * vscan_svc_disable 381*6407Sjm199354 * 382*6407Sjm199354 * Resources allocated during vscan_svc_enable are free'd by 383*6407Sjm199354 * the handler thread immediately prior to exiting 3845931Sjm199354 */ 3855931Sjm199354 void 3865931Sjm199354 vscan_svc_disable(void) 3875931Sjm199354 { 3885931Sjm199354 mutex_enter(&vscan_svc_mutex); 3895440Sjm199354 390*6407Sjm199354 switch (vscan_svc_state) { 391*6407Sjm199354 case VS_SVC_ENABLED: 392*6407Sjm199354 fs_vscan_register(NULL); 393*6407Sjm199354 vscan_svc_state = VS_SVC_DISABLED; 394*6407Sjm199354 cv_signal(&vscan_svc_reql_cv); /* wake handler thread */ 395*6407Sjm199354 break; 396*6407Sjm199354 default: 397*6407Sjm199354 DTRACE_PROBE1(vscan__svc__state__violation, int, 398*6407Sjm199354 vscan_svc_state); 399*6407Sjm199354 } 4005931Sjm199354 401*6407Sjm199354 mutex_exit(&vscan_svc_mutex); 4025931Sjm199354 } 4035931Sjm199354 4045931Sjm199354 4055440Sjm199354 /* 4065440Sjm199354 * vscan_svc_in_use 4075440Sjm199354 */ 4085440Sjm199354 boolean_t 4095440Sjm199354 vscan_svc_in_use() 4105440Sjm199354 { 411*6407Sjm199354 boolean_t in_use; 4125440Sjm199354 4135440Sjm199354 mutex_enter(&vscan_svc_mutex); 4145440Sjm199354 415*6407Sjm199354 switch (vscan_svc_state) { 416*6407Sjm199354 case VS_SVC_IDLE: 417*6407Sjm199354 case VS_SVC_UNCONFIG: 418*6407Sjm199354 in_use = B_FALSE; 419*6407Sjm199354 break; 420*6407Sjm199354 default: 421*6407Sjm199354 in_use = B_TRUE; 422*6407Sjm199354 break; 423*6407Sjm199354 } 424*6407Sjm199354 425*6407Sjm199354 mutex_exit(&vscan_svc_mutex); 426*6407Sjm199354 return (in_use); 4275440Sjm199354 } 4285440Sjm199354 429*6407Sjm199354 4305440Sjm199354 /* 4315440Sjm199354 * vscan_svc_get_vnode 4325440Sjm199354 * 4335440Sjm199354 * Get the file vnode indexed by idx. 4345440Sjm199354 */ 4355440Sjm199354 vnode_t * 4365440Sjm199354 vscan_svc_get_vnode(int idx) 4375440Sjm199354 { 438*6407Sjm199354 vnode_t *vp = NULL; 439*6407Sjm199354 4405440Sjm199354 ASSERT(idx > 0); 441*6407Sjm199354 ASSERT(idx <= vs_nodes_max); 4425440Sjm199354 443*6407Sjm199354 mutex_enter(&vscan_svc_mutex); 444*6407Sjm199354 if (vscan_svc_nodes[idx].vsn_req) 445*6407Sjm199354 vp = vscan_svc_nodes[idx].vsn_req->vsr_vp; 446*6407Sjm199354 mutex_exit(&vscan_svc_mutex); 447*6407Sjm199354 448*6407Sjm199354 return (vp); 4495440Sjm199354 } 4505440Sjm199354 4515440Sjm199354 4525440Sjm199354 /* 4535440Sjm199354 * vscan_svc_scan_file 4545440Sjm199354 * 4555440Sjm199354 * This function is the entry point for the file system to 4565440Sjm199354 * request that a file be virus scanned. 4575440Sjm199354 */ 4585440Sjm199354 int 4595440Sjm199354 vscan_svc_scan_file(vnode_t *vp, cred_t *cr, int async) 4605440Sjm199354 { 461*6407Sjm199354 int access; 462*6407Sjm199354 vscan_req_t *req; 4635440Sjm199354 boolean_t allow; 464*6407Sjm199354 clock_t timeout, time_left; 4655440Sjm199354 466*6407Sjm199354 if ((vp == NULL) || (vp->v_path == NULL) || cr == NULL) 4675440Sjm199354 return (0); 4685440Sjm199354 4695440Sjm199354 DTRACE_PROBE2(vscan__scan__file, char *, vp->v_path, int, async); 4705440Sjm199354 4715440Sjm199354 /* check if size or type exempts file from scanning */ 4725440Sjm199354 if (vscan_svc_exempt_file(vp, &allow)) { 4735440Sjm199354 if ((allow == B_TRUE) || (async != 0)) 4745440Sjm199354 return (0); 4755440Sjm199354 4765440Sjm199354 return (EACCES); 4775440Sjm199354 } 4785440Sjm199354 479*6407Sjm199354 mutex_enter(&vscan_svc_mutex); 480*6407Sjm199354 481*6407Sjm199354 if (vscan_svc_state != VS_SVC_ENABLED) { 482*6407Sjm199354 DTRACE_PROBE1(vscan__svc__state__violation, 483*6407Sjm199354 int, vscan_svc_state); 484*6407Sjm199354 mutex_exit(&vscan_svc_mutex); 485*6407Sjm199354 return (0); 486*6407Sjm199354 } 4875440Sjm199354 488*6407Sjm199354 /* insert (or find) request in list */ 489*6407Sjm199354 if ((req = vscan_svc_reql_insert(vp)) == NULL) { 490*6407Sjm199354 mutex_exit(&vscan_svc_mutex); 491*6407Sjm199354 cmn_err(CE_WARN, "Virus scan request list full"); 492*6407Sjm199354 return ((async != 0) ? 0 : EACCES); 493*6407Sjm199354 } 4945440Sjm199354 495*6407Sjm199354 /* asynchronous request: return 0 */ 4965440Sjm199354 if (async) { 497*6407Sjm199354 mutex_exit(&vscan_svc_mutex); 498*6407Sjm199354 return (0); 4995440Sjm199354 } 5005440Sjm199354 501*6407Sjm199354 /* synchronous scan request: wait for result */ 502*6407Sjm199354 ++(req->vsr_refcnt); 503*6407Sjm199354 time_left = SEC_TO_TICK(vs_scan_wait); 504*6407Sjm199354 while ((time_left > 0) && (req->vsr_state != VS_SVC_REQ_COMPLETE)) { 505*6407Sjm199354 timeout = lbolt + time_left; 506*6407Sjm199354 time_left = cv_timedwait_sig(&(req->vsr_cv), 507*6407Sjm199354 &vscan_svc_mutex, timeout); 508*6407Sjm199354 } 509*6407Sjm199354 510*6407Sjm199354 if (time_left == -1) { 511*6407Sjm199354 cmn_err(CE_WARN, "Virus scan request timeout %s (%d) \n", 512*6407Sjm199354 vp->v_path, req->vsr_seqnum); 513*6407Sjm199354 DTRACE_PROBE1(vscan__scan__timeout, vscan_req_t *, req); 514*6407Sjm199354 } 515*6407Sjm199354 516*6407Sjm199354 ASSERT(req->vsr_magic == VS_REQ_MAGIC); 517*6407Sjm199354 if (vscan_svc_state == VS_SVC_DISABLED) 518*6407Sjm199354 access = VS_ACCESS_ALLOW; 519*6407Sjm199354 else if (req->vsr_idx == 0) 520*6407Sjm199354 access = VS_ACCESS_DENY; 521*6407Sjm199354 else 522*6407Sjm199354 access = vscan_svc_nodes[req->vsr_idx].vsn_access; 523*6407Sjm199354 524*6407Sjm199354 if ((--req->vsr_refcnt) == 0) 525*6407Sjm199354 vscan_svc_delete_req(req); 526*6407Sjm199354 5275440Sjm199354 mutex_exit(&vscan_svc_mutex); 528*6407Sjm199354 return ((access == VS_ACCESS_ALLOW) ? 0 : EACCES); 5295440Sjm199354 } 5305440Sjm199354 5315440Sjm199354 5325440Sjm199354 /* 533*6407Sjm199354 * vscan_svc_reql_handler 5345440Sjm199354 * 535*6407Sjm199354 * inserts scan requests (from vscan_svc_reql) into 536*6407Sjm199354 * vscan_svc_nodes and vscan_svc_taskq 5375440Sjm199354 */ 538*6407Sjm199354 static void 539*6407Sjm199354 vscan_svc_reql_handler(void) 540*6407Sjm199354 { 541*6407Sjm199354 vscan_req_t *req, *next; 542*6407Sjm199354 543*6407Sjm199354 for (;;) { 544*6407Sjm199354 mutex_enter(&vscan_svc_mutex); 545*6407Sjm199354 546*6407Sjm199354 if ((vscan_svc_state == VS_SVC_DISABLED) && 547*6407Sjm199354 (vscan_svc_counts.vsc_reql == 0)) { 548*6407Sjm199354 /* free resources allocated durining enable */ 549*6407Sjm199354 taskq_destroy(vscan_svc_taskq); 550*6407Sjm199354 vscan_svc_taskq = NULL; 551*6407Sjm199354 list_destroy(&vscan_svc_reql); 552*6407Sjm199354 vscan_svc_state = VS_SVC_IDLE; 553*6407Sjm199354 mutex_exit(&vscan_svc_mutex); 554*6407Sjm199354 return; 555*6407Sjm199354 } 556*6407Sjm199354 557*6407Sjm199354 /* 558*6407Sjm199354 * If disabled, scan_complete any pending requests. 559*6407Sjm199354 * Otherwise insert pending requests into vscan_svc_nodes 560*6407Sjm199354 * and vscan_svc_taskq. If no slots are available in 561*6407Sjm199354 * vscan_svc_nodes break loop and wait for one 562*6407Sjm199354 */ 563*6407Sjm199354 req = vscan_svc_reql_next; 564*6407Sjm199354 565*6407Sjm199354 while (req != NULL) { 566*6407Sjm199354 ASSERT(req->vsr_magic == VS_REQ_MAGIC); 567*6407Sjm199354 next = list_next(&vscan_svc_reql, req); 568*6407Sjm199354 569*6407Sjm199354 if (vscan_svc_state == VS_SVC_DISABLED) { 570*6407Sjm199354 vscan_svc_scan_complete(req); 571*6407Sjm199354 } else { 572*6407Sjm199354 /* insert request into vscan_svc_nodes */ 573*6407Sjm199354 if (vscan_svc_insert_req(req) == -1) 574*6407Sjm199354 break; 575*6407Sjm199354 576*6407Sjm199354 /* add the scan request into the taskq */ 577*6407Sjm199354 (void) taskq_dispatch(vscan_svc_taskq, 578*6407Sjm199354 vscan_svc_taskq_callback, 579*6407Sjm199354 (void *)req, TQ_SLEEP); 580*6407Sjm199354 ++(vscan_svc_counts.vsc_tq); 581*6407Sjm199354 582*6407Sjm199354 req->vsr_state = VS_SVC_REQ_QUEUED; 583*6407Sjm199354 } 584*6407Sjm199354 req = next; 585*6407Sjm199354 } 586*6407Sjm199354 587*6407Sjm199354 vscan_svc_reql_next = req; 588*6407Sjm199354 589*6407Sjm199354 DTRACE_PROBE2(vscan__req__counts, char *, "handler wait", 590*6407Sjm199354 vscan_svc_counts_t *, &vscan_svc_counts); 591*6407Sjm199354 592*6407Sjm199354 (void) cv_timedwait(&vscan_svc_reql_cv, &vscan_svc_mutex, 593*6407Sjm199354 lbolt + SEC_TO_TICK(VS_REQL_HANDLER_TIMEOUT)); 594*6407Sjm199354 595*6407Sjm199354 DTRACE_PROBE2(vscan__req__counts, char *, "handler wake", 596*6407Sjm199354 vscan_svc_counts_t *, &vscan_svc_counts); 597*6407Sjm199354 598*6407Sjm199354 mutex_exit(&vscan_svc_mutex); 599*6407Sjm199354 } 600*6407Sjm199354 } 601*6407Sjm199354 602*6407Sjm199354 603*6407Sjm199354 static void 6045440Sjm199354 vscan_svc_taskq_callback(void *data) 6055440Sjm199354 { 606*6407Sjm199354 vscan_req_t *req; 6075440Sjm199354 6085440Sjm199354 mutex_enter(&vscan_svc_mutex); 609*6407Sjm199354 610*6407Sjm199354 req = (vscan_req_t *)data; 611*6407Sjm199354 ASSERT(req->vsr_magic == VS_REQ_MAGIC); 612*6407Sjm199354 vscan_svc_do_scan(req); 613*6407Sjm199354 if (req->vsr_state != VS_SVC_REQ_SCANNING) 614*6407Sjm199354 vscan_svc_scan_complete(req); 615*6407Sjm199354 616*6407Sjm199354 --(vscan_svc_counts.vsc_tq); 6175440Sjm199354 mutex_exit(&vscan_svc_mutex); 6185440Sjm199354 } 6195440Sjm199354 6205440Sjm199354 6215440Sjm199354 /* 6225440Sjm199354 * vscan_svc_do_scan 6235440Sjm199354 * 624*6407Sjm199354 * Note: To avoid potential deadlock it is important that 625*6407Sjm199354 * vscan_svc_mutex is not held during the call to 626*6407Sjm199354 * vscan_drv_create_note. vscan_drv_create_note enters 627*6407Sjm199354 * the vscan_drv_mutex and it is possible that a thread 628*6407Sjm199354 * holding that mutex could be waiting for vscan_svc_mutex. 629*6407Sjm199354 */ 630*6407Sjm199354 static void 631*6407Sjm199354 vscan_svc_do_scan(vscan_req_t *req) 632*6407Sjm199354 { 633*6407Sjm199354 int idx, result; 634*6407Sjm199354 vscan_svc_node_t *node; 635*6407Sjm199354 vs_scan_req_t *door_req; 636*6407Sjm199354 637*6407Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 638*6407Sjm199354 639*6407Sjm199354 idx = req->vsr_idx; 640*6407Sjm199354 node = &vscan_svc_nodes[idx]; 641*6407Sjm199354 642*6407Sjm199354 req->vsr_state = VS_SVC_REQ_IN_PROGRESS; 643*6407Sjm199354 644*6407Sjm199354 /* if vscan not enabled (shutting down), allow ACCESS */ 645*6407Sjm199354 if (vscan_svc_state != VS_SVC_ENABLED) { 646*6407Sjm199354 node->vsn_access = VS_ACCESS_ALLOW; 647*6407Sjm199354 return; 648*6407Sjm199354 } 649*6407Sjm199354 650*6407Sjm199354 if (vscan_svc_getattr(idx) != 0) { 651*6407Sjm199354 cmn_err(CE_WARN, "Can't access xattr for %s\n", 652*6407Sjm199354 req->vsr_vp->v_path); 653*6407Sjm199354 node->vsn_access = VS_ACCESS_DENY; 654*6407Sjm199354 return; 655*6407Sjm199354 } 656*6407Sjm199354 657*6407Sjm199354 /* valid scan_req ptr guaranteed */ 658*6407Sjm199354 door_req = vscan_svc_populate_req(idx); 659*6407Sjm199354 660*6407Sjm199354 /* free up mutex around create node and door call */ 661*6407Sjm199354 mutex_exit(&vscan_svc_mutex); 662*6407Sjm199354 if (vscan_drv_create_node(idx) != B_TRUE) 663*6407Sjm199354 result = VS_STATUS_ERROR; 664*6407Sjm199354 else 665*6407Sjm199354 result = vscan_door_scan_file(door_req); 666*6407Sjm199354 kmem_free(door_req, sizeof (vs_scan_req_t)); 667*6407Sjm199354 mutex_enter(&vscan_svc_mutex); 668*6407Sjm199354 669*6407Sjm199354 if (result != VS_STATUS_SCANNING) { 670*6407Sjm199354 vscan_svc_nodes[idx].vsn_result = result; 671*6407Sjm199354 vscan_svc_process_scan_result(idx); 672*6407Sjm199354 } else { /* async response */ 673*6407Sjm199354 if (req->vsr_state == VS_SVC_REQ_IN_PROGRESS) 674*6407Sjm199354 req->vsr_state = VS_SVC_REQ_SCANNING; 675*6407Sjm199354 } 676*6407Sjm199354 } 677*6407Sjm199354 678*6407Sjm199354 679*6407Sjm199354 /* 680*6407Sjm199354 * vscan_svc_populate_req 681*6407Sjm199354 * 682*6407Sjm199354 * Allocate a scan request to be sent to vscand, populating it 683*6407Sjm199354 * from the data in vscan_svc_nodes[idx]. 684*6407Sjm199354 * 685*6407Sjm199354 * Returns: scan request object 6865440Sjm199354 */ 687*6407Sjm199354 static vs_scan_req_t * 688*6407Sjm199354 vscan_svc_populate_req(int idx) 689*6407Sjm199354 { 690*6407Sjm199354 vs_scan_req_t *scan_req; 691*6407Sjm199354 vscan_req_t *req; 692*6407Sjm199354 vscan_svc_node_t *node; 693*6407Sjm199354 694*6407Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 695*6407Sjm199354 696*6407Sjm199354 node = &vscan_svc_nodes[idx]; 697*6407Sjm199354 req = node->vsn_req; 698*6407Sjm199354 scan_req = kmem_zalloc(sizeof (vs_scan_req_t), KM_SLEEP); 699*6407Sjm199354 700*6407Sjm199354 scan_req->vsr_idx = idx; 701*6407Sjm199354 scan_req->vsr_seqnum = req->vsr_seqnum; 702*6407Sjm199354 (void) strncpy(scan_req->vsr_path, req->vsr_vp->v_path, MAXPATHLEN); 703*6407Sjm199354 scan_req->vsr_size = node->vsn_size; 704*6407Sjm199354 scan_req->vsr_modified = node->vsn_modified; 705*6407Sjm199354 scan_req->vsr_quarantined = node->vsn_quarantined; 706*6407Sjm199354 scan_req->vsr_flags = 0; 707*6407Sjm199354 (void) strncpy(scan_req->vsr_scanstamp, 708*6407Sjm199354 node->vsn_scanstamp, sizeof (vs_scanstamp_t)); 709*6407Sjm199354 710*6407Sjm199354 return (scan_req); 711*6407Sjm199354 } 712*6407Sjm199354 713*6407Sjm199354 714*6407Sjm199354 /* 715*6407Sjm199354 * vscan_svc_scan_complete 716*6407Sjm199354 */ 717*6407Sjm199354 static void 718*6407Sjm199354 vscan_svc_scan_complete(vscan_req_t *req) 7195440Sjm199354 { 720*6407Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 721*6407Sjm199354 ASSERT(req != NULL); 722*6407Sjm199354 723*6407Sjm199354 req->vsr_state = VS_SVC_REQ_COMPLETE; 724*6407Sjm199354 725*6407Sjm199354 if ((--req->vsr_refcnt) == 0) 726*6407Sjm199354 vscan_svc_delete_req(req); 727*6407Sjm199354 else 728*6407Sjm199354 cv_broadcast(&(req->vsr_cv)); 729*6407Sjm199354 } 730*6407Sjm199354 731*6407Sjm199354 732*6407Sjm199354 /* 733*6407Sjm199354 * vscan_svc_delete_req 734*6407Sjm199354 */ 735*6407Sjm199354 static void 736*6407Sjm199354 vscan_svc_delete_req(vscan_req_t *req) 737*6407Sjm199354 { 738*6407Sjm199354 int idx; 739*6407Sjm199354 740*6407Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 741*6407Sjm199354 ASSERT(req != NULL); 742*6407Sjm199354 ASSERT(req->vsr_refcnt == 0); 743*6407Sjm199354 ASSERT(req->vsr_state == VS_SVC_REQ_COMPLETE); 744*6407Sjm199354 745*6407Sjm199354 if ((idx = req->vsr_idx) != 0) 746*6407Sjm199354 vscan_svc_remove_req(idx); 747*6407Sjm199354 748*6407Sjm199354 vscan_svc_reql_remove(req); 749*6407Sjm199354 750*6407Sjm199354 cv_signal(&vscan_svc_reql_cv); 751*6407Sjm199354 } 752*6407Sjm199354 753*6407Sjm199354 754*6407Sjm199354 /* 755*6407Sjm199354 * vscan_svc_scan_result 756*6407Sjm199354 * 757*6407Sjm199354 * Invoked from vscan_drv.c on receipt of an ioctl containing 758*6407Sjm199354 * an async scan result (VS_DRV_IOCTL_RESULT) 759*6407Sjm199354 * If the vsr_seqnum in the response does not match that in the 760*6407Sjm199354 * vscan_svc_nodes entry the result is discarded. 761*6407Sjm199354 */ 762*6407Sjm199354 void 763*6407Sjm199354 vscan_svc_scan_result(vs_scan_rsp_t *scan_rsp) 764*6407Sjm199354 { 765*6407Sjm199354 vscan_req_t *req; 766*6407Sjm199354 vscan_svc_node_t *node; 7675440Sjm199354 7685440Sjm199354 mutex_enter(&vscan_svc_mutex); 7695440Sjm199354 770*6407Sjm199354 node = &vscan_svc_nodes[scan_rsp->vsr_idx]; 771*6407Sjm199354 772*6407Sjm199354 if ((req = node->vsn_req) == NULL) { 773*6407Sjm199354 mutex_exit(&vscan_svc_mutex); 774*6407Sjm199354 return; 775*6407Sjm199354 } 776*6407Sjm199354 777*6407Sjm199354 ASSERT(req->vsr_magic == VS_REQ_MAGIC); 778*6407Sjm199354 779*6407Sjm199354 if (scan_rsp->vsr_seqnum != req->vsr_seqnum) { 780*6407Sjm199354 mutex_exit(&vscan_svc_mutex); 781*6407Sjm199354 return; 782*6407Sjm199354 } 783*6407Sjm199354 784*6407Sjm199354 node->vsn_result = scan_rsp->vsr_result; 785*6407Sjm199354 (void) strncpy(node->vsn_scanstamp, 786*6407Sjm199354 scan_rsp->vsr_scanstamp, sizeof (vs_scanstamp_t)); 787*6407Sjm199354 788*6407Sjm199354 vscan_svc_process_scan_result(scan_rsp->vsr_idx); 789*6407Sjm199354 790*6407Sjm199354 if (node->vsn_req->vsr_state == VS_SVC_REQ_SCANNING) 791*6407Sjm199354 vscan_svc_scan_complete(node->vsn_req); 792*6407Sjm199354 else 793*6407Sjm199354 node->vsn_req->vsr_state = VS_SVC_REQ_ASYNC_COMPLETE; 7945440Sjm199354 795*6407Sjm199354 mutex_exit(&vscan_svc_mutex); 796*6407Sjm199354 } 797*6407Sjm199354 7985931Sjm199354 799*6407Sjm199354 /* 800*6407Sjm199354 * vscan_svc_scan_abort 801*6407Sjm199354 * 802*6407Sjm199354 * Abort in-progress scan requests. 803*6407Sjm199354 */ 804*6407Sjm199354 void 805*6407Sjm199354 vscan_svc_scan_abort() 806*6407Sjm199354 { 807*6407Sjm199354 int idx; 808*6407Sjm199354 vscan_req_t *req; 809*6407Sjm199354 810*6407Sjm199354 mutex_enter(&vscan_svc_mutex); 811*6407Sjm199354 812*6407Sjm199354 for (idx = 1; idx <= vs_nodes_max; idx++) { 813*6407Sjm199354 if ((req = vscan_svc_nodes[idx].vsn_req) == NULL) 814*6407Sjm199354 continue; 815*6407Sjm199354 816*6407Sjm199354 ASSERT(req->vsr_magic == VS_REQ_MAGIC); 817*6407Sjm199354 818*6407Sjm199354 if (req->vsr_state == VS_SVC_REQ_SCANNING) { 819*6407Sjm199354 DTRACE_PROBE1(vscan__abort, vscan_req_t *, req); 820*6407Sjm199354 vscan_svc_process_scan_result(idx); 821*6407Sjm199354 vscan_svc_scan_complete(req); 8225440Sjm199354 } 8235440Sjm199354 } 8245440Sjm199354 8255440Sjm199354 mutex_exit(&vscan_svc_mutex); 8265440Sjm199354 } 8275440Sjm199354 8285931Sjm199354 8295931Sjm199354 /* 8305931Sjm199354 * vscan_svc_process_scan_result 8315931Sjm199354 * 832*6407Sjm199354 * Sets vsn_access and updates file attributes based on vsn_result, 8335931Sjm199354 * as follows: 8345931Sjm199354 * 8355931Sjm199354 * VS_STATUS_INFECTED 8365931Sjm199354 * deny access, set quarantine attribute, clear scanstamp 8375931Sjm199354 * VS_STATUS_CLEAN 8385931Sjm199354 * allow access, set scanstamp, 8395931Sjm199354 * if file not modified since scan initiated, clear modified attribute 8405931Sjm199354 * VS_STATUS_NO_SCAN 8415931Sjm199354 * deny access if file quarantined, otherwise allow access 8425931Sjm199354 * VS_STATUS_UNDEFINED, VS_STATUS_ERROR 8435931Sjm199354 * deny access if file quarantined, modified or no scanstamp 8445931Sjm199354 * otherwise, allow access 8455931Sjm199354 */ 8465931Sjm199354 static void 8475931Sjm199354 vscan_svc_process_scan_result(int idx) 8485931Sjm199354 { 8495931Sjm199354 struct vattr attr; 8505931Sjm199354 vnode_t *vp; 8515931Sjm199354 timestruc_t *mtime; 852*6407Sjm199354 vscan_svc_node_t *node; 8535931Sjm199354 8545931Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 8555931Sjm199354 856*6407Sjm199354 node = &vscan_svc_nodes[idx]; 8575931Sjm199354 858*6407Sjm199354 switch (node->vsn_result) { 8595931Sjm199354 case VS_STATUS_INFECTED: 860*6407Sjm199354 node->vsn_access = VS_ACCESS_DENY; 861*6407Sjm199354 node->vsn_quarantined = 1; 862*6407Sjm199354 node->vsn_scanstamp[0] = '\0'; 8635931Sjm199354 (void) vscan_svc_setattr(idx, 8645931Sjm199354 XAT_AV_QUARANTINED | XAT_AV_SCANSTAMP); 865*6407Sjm199354 break; 8665931Sjm199354 8675931Sjm199354 case VS_STATUS_CLEAN: 868*6407Sjm199354 node->vsn_access = VS_ACCESS_ALLOW; 8695931Sjm199354 8705931Sjm199354 /* if mtime has changed, don't clear the modified attribute */ 871*6407Sjm199354 vp = node->vsn_req->vsr_vp; 872*6407Sjm199354 mtime = &(node->vsn_mtime); 8735931Sjm199354 attr.va_mask = AT_MTIME; 8745931Sjm199354 if ((VOP_GETATTR(vp, &attr, 0, kcred, NULL) != 0) || 8755931Sjm199354 (mtime->tv_sec != attr.va_mtime.tv_sec) || 8765931Sjm199354 (mtime->tv_nsec != attr.va_mtime.tv_nsec)) { 877*6407Sjm199354 DTRACE_PROBE1(vscan__mtime__changed, vscan_svc_node_t *, 878*6407Sjm199354 node); 8795931Sjm199354 (void) vscan_svc_setattr(idx, XAT_AV_SCANSTAMP); 880*6407Sjm199354 break; 8815931Sjm199354 } 8825931Sjm199354 883*6407Sjm199354 node->vsn_modified = 0; 8845931Sjm199354 (void) vscan_svc_setattr(idx, 8855931Sjm199354 XAT_AV_SCANSTAMP | XAT_AV_MODIFIED); 886*6407Sjm199354 break; 8875931Sjm199354 8885931Sjm199354 case VS_STATUS_NO_SCAN: 889*6407Sjm199354 if (node->vsn_quarantined) 890*6407Sjm199354 node->vsn_access = VS_ACCESS_DENY; 8915931Sjm199354 else 892*6407Sjm199354 node->vsn_access = VS_ACCESS_ALLOW; 893*6407Sjm199354 break; 8945931Sjm199354 8955931Sjm199354 case VS_STATUS_ERROR: 8965931Sjm199354 case VS_STATUS_UNDEFINED: 8975931Sjm199354 default: 898*6407Sjm199354 if ((node->vsn_quarantined) || 899*6407Sjm199354 (node->vsn_modified) || 900*6407Sjm199354 (node->vsn_scanstamp[0] == '\0')) 901*6407Sjm199354 node->vsn_access = VS_ACCESS_DENY; 9025931Sjm199354 else 903*6407Sjm199354 node->vsn_access = VS_ACCESS_ALLOW; 904*6407Sjm199354 break; 9055440Sjm199354 } 9065440Sjm199354 907*6407Sjm199354 DTRACE_PROBE4(vscan__result, 908*6407Sjm199354 int, idx, int, node->vsn_req->vsr_seqnum, 909*6407Sjm199354 int, node->vsn_result, int, node->vsn_access); 9105440Sjm199354 } 9115440Sjm199354 9125440Sjm199354 9135440Sjm199354 /* 9145440Sjm199354 * vscan_svc_getattr 9155440Sjm199354 * 9165931Sjm199354 * Get the vscan related system attributes, AT_SIZE & AT_MTIME. 9175440Sjm199354 */ 9185440Sjm199354 static int 9195440Sjm199354 vscan_svc_getattr(int idx) 9205440Sjm199354 { 9215440Sjm199354 xvattr_t xvattr; 9225440Sjm199354 xoptattr_t *xoap = NULL; 9235440Sjm199354 vnode_t *vp; 924*6407Sjm199354 vscan_svc_node_t *node; 9255440Sjm199354 9265440Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 9275440Sjm199354 928*6407Sjm199354 node = &vscan_svc_nodes[idx]; 929*6407Sjm199354 if ((vp = node->vsn_req->vsr_vp) == NULL) 9305440Sjm199354 return (-1); 9315440Sjm199354 9325440Sjm199354 /* get the attributes */ 9335440Sjm199354 xva_init(&xvattr); /* sets AT_XVATTR */ 9345440Sjm199354 9355440Sjm199354 xvattr.xva_vattr.va_mask |= AT_SIZE; 9365931Sjm199354 xvattr.xva_vattr.va_mask |= AT_MTIME; 9375440Sjm199354 XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED); 9385440Sjm199354 XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED); 9395440Sjm199354 XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP); 9405440Sjm199354 9415440Sjm199354 if (VOP_GETATTR(vp, (vattr_t *)&xvattr, 0, kcred, NULL) != 0) 9425440Sjm199354 return (-1); 9435440Sjm199354 9445440Sjm199354 if ((xoap = xva_getxoptattr(&xvattr)) == NULL) { 9455440Sjm199354 cmn_err(CE_NOTE, "Virus scan request failed; " 9465440Sjm199354 "file system does not support virus scanning"); 9475440Sjm199354 return (-1); 9485440Sjm199354 } 9495440Sjm199354 950*6407Sjm199354 node->vsn_size = xvattr.xva_vattr.va_size; 951*6407Sjm199354 node->vsn_mtime.tv_sec = xvattr.xva_vattr.va_mtime.tv_sec; 952*6407Sjm199354 node->vsn_mtime.tv_nsec = xvattr.xva_vattr.va_mtime.tv_nsec; 9535440Sjm199354 9545440Sjm199354 if (XVA_ISSET_RTN(&xvattr, XAT_AV_MODIFIED) == 0) 9555440Sjm199354 return (-1); 956*6407Sjm199354 node->vsn_modified = xoap->xoa_av_modified; 9575440Sjm199354 9585440Sjm199354 if (XVA_ISSET_RTN(&xvattr, XAT_AV_QUARANTINED) == 0) 9595440Sjm199354 return (-1); 960*6407Sjm199354 node->vsn_quarantined = xoap->xoa_av_quarantined; 9615440Sjm199354 9625440Sjm199354 if (XVA_ISSET_RTN(&xvattr, XAT_AV_SCANSTAMP) != 0) { 963*6407Sjm199354 (void) memcpy(node->vsn_scanstamp, 9645440Sjm199354 xoap->xoa_av_scanstamp, AV_SCANSTAMP_SZ); 9655440Sjm199354 } 9665440Sjm199354 967*6407Sjm199354 DTRACE_PROBE1(vscan__getattr, vscan_svc_node_t *, node); 9685440Sjm199354 return (0); 9695440Sjm199354 } 9705440Sjm199354 9715440Sjm199354 9725440Sjm199354 /* 9735440Sjm199354 * vscan_svc_setattr 9745440Sjm199354 * 9755440Sjm199354 * Set the vscan related system attributes. 9765440Sjm199354 */ 9775440Sjm199354 static int 9785931Sjm199354 vscan_svc_setattr(int idx, int which) 9795440Sjm199354 { 9805440Sjm199354 xvattr_t xvattr; 9815440Sjm199354 xoptattr_t *xoap = NULL; 9825440Sjm199354 vnode_t *vp; 9835440Sjm199354 int len; 984*6407Sjm199354 vscan_svc_node_t *node; 9855440Sjm199354 9865440Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 9875440Sjm199354 988*6407Sjm199354 node = &vscan_svc_nodes[idx]; 989*6407Sjm199354 if ((vp = node->vsn_req->vsr_vp) == NULL) 9905440Sjm199354 return (-1); 9915440Sjm199354 9925440Sjm199354 /* update the attributes */ 9935440Sjm199354 xva_init(&xvattr); /* sets AT_XVATTR */ 9945440Sjm199354 if ((xoap = xva_getxoptattr(&xvattr)) == NULL) 9955440Sjm199354 return (-1); 9965440Sjm199354 9975931Sjm199354 if (which & XAT_AV_MODIFIED) { 9985931Sjm199354 XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED); 999*6407Sjm199354 xoap->xoa_av_modified = node->vsn_modified; 10005931Sjm199354 } 10015440Sjm199354 10025931Sjm199354 if (which & XAT_AV_QUARANTINED) { 10035931Sjm199354 XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED); 1004*6407Sjm199354 xoap->xoa_av_quarantined = node->vsn_quarantined; 10055931Sjm199354 } 10065440Sjm199354 10075931Sjm199354 if (which & XAT_AV_SCANSTAMP) { 10085931Sjm199354 XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP); 1009*6407Sjm199354 len = strlen(node->vsn_scanstamp); 10105931Sjm199354 (void) memcpy(xoap->xoa_av_scanstamp, 1011*6407Sjm199354 node->vsn_scanstamp, len); 10125931Sjm199354 } 10135440Sjm199354 10145440Sjm199354 /* if access is denied, set mtime to invalidate client cache */ 1015*6407Sjm199354 if (node->vsn_access != VS_ACCESS_ALLOW) { 10165440Sjm199354 xvattr.xva_vattr.va_mask |= AT_MTIME; 10175440Sjm199354 gethrestime(&xvattr.xva_vattr.va_mtime); 10185440Sjm199354 } 10195440Sjm199354 10205440Sjm199354 if (VOP_SETATTR(vp, (vattr_t *)&xvattr, 0, kcred, NULL) != 0) 10215440Sjm199354 return (-1); 10225440Sjm199354 10235931Sjm199354 DTRACE_PROBE2(vscan__setattr, 1024*6407Sjm199354 vscan_svc_node_t *, node, int, which); 10255931Sjm199354 10265440Sjm199354 return (0); 10275440Sjm199354 } 10285440Sjm199354 10295440Sjm199354 10305440Sjm199354 /* 10315440Sjm199354 * vscan_svc_configure 10325440Sjm199354 * 10335440Sjm199354 * store configuration in vscan_svc_config 10345440Sjm199354 * set up vscan_svc_types array of pointers into 10355440Sjm199354 * vscan_svc_config.vsc_types for efficient searching 10365440Sjm199354 */ 10375440Sjm199354 int 10385440Sjm199354 vscan_svc_configure(vs_config_t *conf) 10395440Sjm199354 { 10405440Sjm199354 int count = 0; 10415440Sjm199354 char *p, *beg, *end; 10425440Sjm199354 10435440Sjm199354 mutex_enter(&vscan_svc_cfg_mutex); 10445440Sjm199354 10455440Sjm199354 vscan_svc_config = *conf; 10465440Sjm199354 10475440Sjm199354 (void) memset(vscan_svc_types, 0, sizeof (vscan_svc_types)); 10485440Sjm199354 10495440Sjm199354 beg = vscan_svc_config.vsc_types; 10505440Sjm199354 end = beg + vscan_svc_config.vsc_types_len; 10515440Sjm199354 10525440Sjm199354 for (p = beg; p < end; p += strlen(p) + 1) { 10535440Sjm199354 if (count >= VS_TYPES_MAX) { 10545440Sjm199354 mutex_exit(&vscan_svc_mutex); 10555440Sjm199354 return (-1); 10565440Sjm199354 } 10575440Sjm199354 10585440Sjm199354 vscan_svc_types[count] = p; 10595440Sjm199354 ++count; 10605440Sjm199354 } 10615440Sjm199354 10625440Sjm199354 mutex_exit(&vscan_svc_cfg_mutex); 10635440Sjm199354 return (0); 10645440Sjm199354 } 10655440Sjm199354 10665440Sjm199354 10675440Sjm199354 /* 10685440Sjm199354 * vscan_svc_exempt_file 10695440Sjm199354 * 10705440Sjm199354 * check if a file's size or type exempts it from virus scanning 10715440Sjm199354 * 10725440Sjm199354 * If the file is exempt from virus scanning, allow will be set 10735440Sjm199354 * to define whether files access should be allowed (B_TRUE) or 10745440Sjm199354 * denied (B_FALSE) 10755440Sjm199354 * 10765440Sjm199354 * Returns: 1 exempt 10775440Sjm199354 * 0 scan required 10785440Sjm199354 */ 10795440Sjm199354 static int 10805440Sjm199354 vscan_svc_exempt_file(vnode_t *vp, boolean_t *allow) 10815440Sjm199354 { 10825440Sjm199354 struct vattr attr; 10835440Sjm199354 10845440Sjm199354 ASSERT(vp != NULL); 10855440Sjm199354 ASSERT(vp->v_path != NULL); 10865440Sjm199354 10875440Sjm199354 attr.va_mask = AT_SIZE; 10885440Sjm199354 10895440Sjm199354 if (VOP_GETATTR(vp, &attr, 0, kcred, NULL) != 0) { 10905440Sjm199354 *allow = B_FALSE; 10915440Sjm199354 return (0); 10925440Sjm199354 } 10935440Sjm199354 10945440Sjm199354 mutex_enter(&vscan_svc_cfg_mutex); 10955440Sjm199354 10965440Sjm199354 if (attr.va_size > vscan_svc_config.vsc_max_size) { 10975440Sjm199354 DTRACE_PROBE2(vscan__exempt__filesize, char *, 10985440Sjm199354 vp->v_path, int, *allow); 10995440Sjm199354 11005440Sjm199354 *allow = (vscan_svc_config.vsc_allow) ? B_TRUE : B_FALSE; 11015440Sjm199354 mutex_exit(&vscan_svc_cfg_mutex); 11025440Sjm199354 return (1); 11035440Sjm199354 } 11045440Sjm199354 11055440Sjm199354 if (vscan_svc_exempt_filetype(vp->v_path)) { 11065440Sjm199354 DTRACE_PROBE1(vscan__exempt__filetype, char *, vp->v_path); 11075440Sjm199354 *allow = B_TRUE; 11085440Sjm199354 mutex_exit(&vscan_svc_cfg_mutex); 11095440Sjm199354 return (1); 11105440Sjm199354 } 11115440Sjm199354 11125440Sjm199354 mutex_exit(&vscan_svc_cfg_mutex); 11135440Sjm199354 return (0); 11145440Sjm199354 } 11155440Sjm199354 11165440Sjm199354 11175440Sjm199354 /* 11185440Sjm199354 * vscan_svc_exempt_filetype 11195440Sjm199354 * 11205440Sjm199354 * Each entry in vscan_svc_types includes a rule indicator (+,-) 11215440Sjm199354 * followed by the match string for file types to which the rule 11225440Sjm199354 * applies. Look for first match of file type in vscan_svc_types 11235440Sjm199354 * and return 1 (exempt) if the indicator is '-', and 0 (not exempt) 11245440Sjm199354 * if the indicator is '+'. 11255440Sjm199354 * If vscan_svc_match_ext fails, or no match is found, return 0 11265440Sjm199354 * (not exempt) 11275440Sjm199354 * 11285440Sjm199354 * Returns 1: exempt, 0: not exempt 11295440Sjm199354 */ 11305440Sjm199354 static int 11315440Sjm199354 vscan_svc_exempt_filetype(char *filepath) 11325440Sjm199354 { 11335440Sjm199354 int i, rc, exempt = 0; 11345440Sjm199354 char *filename, *ext; 11355440Sjm199354 11365440Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_cfg_mutex)); 11375440Sjm199354 11385440Sjm199354 if ((filename = strrchr(filepath, '/')) == 0) 11395440Sjm199354 filename = filepath; 11405440Sjm199354 else 11415440Sjm199354 filename++; 11425440Sjm199354 11435440Sjm199354 if ((ext = strrchr(filename, '.')) == NULL) 11445440Sjm199354 ext = ""; 11455440Sjm199354 else 11465440Sjm199354 ext++; 11475440Sjm199354 11485440Sjm199354 for (i = 0; i < VS_TYPES_MAX; i ++) { 11495440Sjm199354 if (vscan_svc_types[i] == 0) 11505440Sjm199354 break; 11515440Sjm199354 11525440Sjm199354 rc = vscan_svc_match_ext(vscan_svc_types[i] + 1, ext, 1); 11535440Sjm199354 if (rc == -1) 11545440Sjm199354 break; 11555440Sjm199354 if (rc > 0) { 11565440Sjm199354 DTRACE_PROBE2(vscan__type__match, char *, ext, 11575440Sjm199354 char *, vscan_svc_types[i]); 11585440Sjm199354 exempt = (vscan_svc_types[i][0] == '-'); 11595440Sjm199354 break; 11605440Sjm199354 } 11615440Sjm199354 } 11625440Sjm199354 11635440Sjm199354 return (exempt); 11645440Sjm199354 } 11655440Sjm199354 11665440Sjm199354 11675440Sjm199354 /* 11685440Sjm199354 * vscan_svc_match_ext 11695440Sjm199354 * 11705440Sjm199354 * Performs a case-insensitive match for two strings. The first string 11715440Sjm199354 * argument can contain the wildcard characters '?' and '*' 11725440Sjm199354 * 11735440Sjm199354 * Returns: 0 no match 11745440Sjm199354 * 1 match 11755440Sjm199354 * -1 recursion error 11765440Sjm199354 */ 11775440Sjm199354 static int 11785440Sjm199354 vscan_svc_match_ext(char *patn, char *str, int depth) 11795440Sjm199354 { 11805440Sjm199354 int c1, c2; 11815440Sjm199354 if (depth > VS_EXT_RECURSE_DEPTH) 11825440Sjm199354 return (-1); 11835440Sjm199354 11845440Sjm199354 for (;;) { 11855440Sjm199354 switch (*patn) { 11865440Sjm199354 case 0: 11875440Sjm199354 return (*str == 0); 11885440Sjm199354 11895440Sjm199354 case '?': 11905440Sjm199354 if (*str != 0) { 11915440Sjm199354 str++; 11925440Sjm199354 patn++; 11935440Sjm199354 continue; 11945440Sjm199354 } 11955440Sjm199354 return (0); 11965440Sjm199354 11975440Sjm199354 case '*': 11985440Sjm199354 patn++; 11995440Sjm199354 if (*patn == 0) 12005440Sjm199354 return (1); 12015440Sjm199354 12025440Sjm199354 while (*str) { 12035440Sjm199354 if (vscan_svc_match_ext(patn, str, depth + 1)) 12045440Sjm199354 return (1); 12055440Sjm199354 str++; 12065440Sjm199354 } 12075440Sjm199354 return (0); 12085440Sjm199354 12095440Sjm199354 default: 12105440Sjm199354 if (*str != *patn) { 12115440Sjm199354 c1 = *str; 12125440Sjm199354 c2 = *patn; 12135440Sjm199354 12145440Sjm199354 c1 = tolower(c1); 12155440Sjm199354 c2 = tolower(c2); 12165440Sjm199354 if (c1 != c2) 12175440Sjm199354 return (0); 12185440Sjm199354 } 12195440Sjm199354 str++; 12205440Sjm199354 patn++; 12215440Sjm199354 continue; 12225440Sjm199354 } 12235440Sjm199354 } 12245440Sjm199354 /* NOT REACHED */ 12255440Sjm199354 } 1226*6407Sjm199354 1227*6407Sjm199354 1228*6407Sjm199354 /* 1229*6407Sjm199354 * vscan_svc_insert_req 1230*6407Sjm199354 * 1231*6407Sjm199354 * Insert request in next available available slot in vscan_svc_nodes 1232*6407Sjm199354 * 1233*6407Sjm199354 * Returns: idx of slot, or -1 if no slot available 1234*6407Sjm199354 */ 1235*6407Sjm199354 static int 1236*6407Sjm199354 vscan_svc_insert_req(vscan_req_t *req) 1237*6407Sjm199354 { 1238*6407Sjm199354 int idx; 1239*6407Sjm199354 vscan_svc_node_t *node; 1240*6407Sjm199354 1241*6407Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 1242*6407Sjm199354 1243*6407Sjm199354 if (vscan_svc_counts.vsc_node == vs_nodes_max) 1244*6407Sjm199354 return (-1); 1245*6407Sjm199354 1246*6407Sjm199354 for (idx = 1; idx <= vs_nodes_max; idx++) { 1247*6407Sjm199354 if (vscan_svc_nodes[idx].vsn_req == NULL) { 1248*6407Sjm199354 req->vsr_idx = idx; 1249*6407Sjm199354 1250*6407Sjm199354 node = &vscan_svc_nodes[idx]; 1251*6407Sjm199354 (void) memset(node, 0, sizeof (vscan_svc_node_t)); 1252*6407Sjm199354 node->vsn_req = req; 1253*6407Sjm199354 node->vsn_modified = 1; 1254*6407Sjm199354 node->vsn_result = VS_STATUS_UNDEFINED; 1255*6407Sjm199354 node->vsn_access = VS_ACCESS_UNDEFINED; 1256*6407Sjm199354 1257*6407Sjm199354 ++(vscan_svc_counts.vsc_node); 1258*6407Sjm199354 return (idx); 1259*6407Sjm199354 } 1260*6407Sjm199354 } 1261*6407Sjm199354 1262*6407Sjm199354 return (-1); 1263*6407Sjm199354 } 1264*6407Sjm199354 1265*6407Sjm199354 1266*6407Sjm199354 /* 1267*6407Sjm199354 * vscan_svc_remove_req 1268*6407Sjm199354 */ 1269*6407Sjm199354 static void 1270*6407Sjm199354 vscan_svc_remove_req(int idx) 1271*6407Sjm199354 { 1272*6407Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 1273*6407Sjm199354 1274*6407Sjm199354 if (idx != 0) { 1275*6407Sjm199354 (void) memset(&vscan_svc_nodes[idx], 0, 1276*6407Sjm199354 sizeof (vscan_svc_node_t)); 1277*6407Sjm199354 --(vscan_svc_counts.vsc_node); 1278*6407Sjm199354 } 1279*6407Sjm199354 } 1280*6407Sjm199354 1281*6407Sjm199354 1282*6407Sjm199354 /* 1283*6407Sjm199354 * vscan_svc_reql_find 1284*6407Sjm199354 */ 1285*6407Sjm199354 static vscan_req_t * 1286*6407Sjm199354 vscan_svc_reql_find(vnode_t *vp) 1287*6407Sjm199354 { 1288*6407Sjm199354 vscan_req_t *req; 1289*6407Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 1290*6407Sjm199354 1291*6407Sjm199354 req = list_head(&vscan_svc_reql); 1292*6407Sjm199354 1293*6407Sjm199354 while (req != NULL) { 1294*6407Sjm199354 ASSERT(req->vsr_magic == VS_REQ_MAGIC); 1295*6407Sjm199354 if ((req->vsr_vp == vp) && 1296*6407Sjm199354 (req->vsr_state != VS_SVC_REQ_COMPLETE)) 1297*6407Sjm199354 break; 1298*6407Sjm199354 1299*6407Sjm199354 req = list_next(&vscan_svc_reql, req); 1300*6407Sjm199354 } 1301*6407Sjm199354 1302*6407Sjm199354 return (req); 1303*6407Sjm199354 } 1304*6407Sjm199354 1305*6407Sjm199354 1306*6407Sjm199354 /* 1307*6407Sjm199354 * vscan_svc_reql_insert 1308*6407Sjm199354 */ 1309*6407Sjm199354 static vscan_req_t * 1310*6407Sjm199354 vscan_svc_reql_insert(vnode_t *vp) 1311*6407Sjm199354 { 1312*6407Sjm199354 vscan_req_t *req; 1313*6407Sjm199354 1314*6407Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 1315*6407Sjm199354 1316*6407Sjm199354 /* if request already in list then return it */ 1317*6407Sjm199354 if ((req = vscan_svc_reql_find(vp)) != NULL) 1318*6407Sjm199354 return (req); 1319*6407Sjm199354 1320*6407Sjm199354 /* if list is full return NULL */ 1321*6407Sjm199354 if (vscan_svc_counts.vsc_reql == vs_reqs_max) 1322*6407Sjm199354 return (NULL); 1323*6407Sjm199354 1324*6407Sjm199354 /* create a new request and insert into list */ 1325*6407Sjm199354 VN_HOLD(vp); 1326*6407Sjm199354 1327*6407Sjm199354 req = kmem_zalloc(sizeof (vscan_req_t), KM_SLEEP); 1328*6407Sjm199354 1329*6407Sjm199354 req->vsr_magic = VS_REQ_MAGIC; 1330*6407Sjm199354 if (vscan_svc_seqnum == UINT32_MAX) 1331*6407Sjm199354 vscan_svc_seqnum = 0; 1332*6407Sjm199354 req->vsr_seqnum = ++vscan_svc_seqnum; 1333*6407Sjm199354 req->vsr_vp = vp; 1334*6407Sjm199354 req->vsr_refcnt = 1; /* decremented in vscan_svc_scan_complete */ 1335*6407Sjm199354 req->vsr_state = VS_SVC_REQ_INIT; 1336*6407Sjm199354 cv_init(&(req->vsr_cv), NULL, CV_DEFAULT, NULL); 1337*6407Sjm199354 1338*6407Sjm199354 list_insert_tail(&vscan_svc_reql, req); 1339*6407Sjm199354 if (vscan_svc_reql_next == NULL) 1340*6407Sjm199354 vscan_svc_reql_next = req; 1341*6407Sjm199354 1342*6407Sjm199354 ++(vscan_svc_counts.vsc_reql); 1343*6407Sjm199354 1344*6407Sjm199354 /* wake reql handler thread */ 1345*6407Sjm199354 cv_signal(&vscan_svc_reql_cv); 1346*6407Sjm199354 1347*6407Sjm199354 return (req); 1348*6407Sjm199354 } 1349*6407Sjm199354 1350*6407Sjm199354 1351*6407Sjm199354 /* 1352*6407Sjm199354 * vscan_svc_reql_remove 1353*6407Sjm199354 */ 1354*6407Sjm199354 static void 1355*6407Sjm199354 vscan_svc_reql_remove(vscan_req_t *req) 1356*6407Sjm199354 { 1357*6407Sjm199354 ASSERT(MUTEX_HELD(&vscan_svc_mutex)); 1358*6407Sjm199354 ASSERT(req->vsr_magic == VS_REQ_MAGIC); 1359*6407Sjm199354 1360*6407Sjm199354 if (vscan_svc_reql_next == req) 1361*6407Sjm199354 vscan_svc_reql_next = list_next(&vscan_svc_reql, req); 1362*6407Sjm199354 1363*6407Sjm199354 list_remove(&vscan_svc_reql, req); 1364*6407Sjm199354 cv_destroy(&(req->vsr_cv)); 1365*6407Sjm199354 VN_RELE(req->vsr_vp); 1366*6407Sjm199354 1367*6407Sjm199354 kmem_free(req, sizeof (vscan_req_t)); 1368*6407Sjm199354 --(vscan_svc_counts.vsc_reql); 1369*6407Sjm199354 } 1370