vscan_svc.c revision bfc848c632c9eacb2a640246d96e198f1b185c03
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * CDDL HEADER START
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * The contents of this file are subject to the terms of the
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * Common Development and Distribution License (the "License").
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * You may not use this file except in compliance with the License.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * See the License for the specific language governing permissions
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * and limitations under the License.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * When distributing Covered Code, include this CDDL HEADER in each
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * If applicable, add the following below this CDDL HEADER, with the
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * fields enclosed by brackets "[]" replaced with your own identifying
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * information: Portions Copyright [yyyy] [name of copyright owner]
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * CDDL HEADER END
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * Use is subject to license terms.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#pragma ident "%Z%%M% %I% %E% SMI"
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#define VS_REQS_DEFAULT 20000 /* pending scan requests - reql */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#define VS_NODES_DEFAULT 128 /* concurrent file scans */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#define VS_SCANWAIT_DEFAULT 15*60 /* seconds to wait for scan result */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/* access derived from scan result (VS_STATUS_XXX) and file attributes */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#define tolower(C) (((C) >= 'A' && (C) <= 'Z') ? (C) - 'A' + 'a' : (C))
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/* global variables - tunable via /etc/system */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncuint32_t vs_reqs_max = VS_REQS_DEFAULT; /* max scan requests */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncuint32_t vs_nodes_max = VS_NODES_DEFAULT; /* max in-progress scan requests */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncuint32_t vs_workers = VS_WORKERS_DEFAULT; /* max workers send reqs to vscand */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncuint32_t vs_scan_wait = VS_SCANWAIT_DEFAULT; /* secs to wait for scan result */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * vscan_svc_state
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * +-----------------+
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * | VS_SVC_UNCONFIG |
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * +-----------------+
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * | svc_init | svc_fini
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * +-----------------+
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * | VS_SVC_IDLE |<----|
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * +-----------------+ |
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * | svc_enable |
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * |<----------------| |
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * +-----------------+ | |
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * | VS_SVC_ENABLED |--| |
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * +-----------------+ |
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * | svc_disable | handler thread exit,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * v | all requests complete
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * +-----------------+ |
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * | VS_SVC_DISABLED |-----|
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * +-----------------+
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * svc_enable may occur when we are already in the ENABLED
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * state if vscand has exited without clean shutdown and
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * then reconnected within the delayed disable time period
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * (vs_reconnect_timeout) - see vscan_drv
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsynctypedef enum {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync VS_SVC_ENABLED, /* service enabled and registered */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync VS_SVC_DISABLED /* service disabled and nunregistered */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncstatic vscan_svc_state_t vscan_svc_state = VS_SVC_UNCONFIG;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * vscan_svc_req_state
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * When a scan request is received from the file system it is
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * identified in or inserted into the vscan_svc_reql (INIT).
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * If the request is asynchronous 0 is then returned to the caller.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * If the request is synchronous the req's refcnt is incremented
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * and the caller waits for the request to complete.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * The refcnt is also incremented when the request is inserted
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * in vscan_svc_nodes, and decremented on scan_complete.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * vscan_svc_handler processes requests from the request list,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * inserting them into vscan_svc_nodes and the task queue (QUEUED).
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * When the task queue call back (vscan_svc_do_scan) is invoked
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * the request transitions to IN_PROGRESS state. If the request
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * is sucessfully sent to vscand (door_call) and the door response
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * is SCANNING then the scan result will be received asynchronously.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * Although unusual, it is possible that the async response is
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * received before the door call returns (hence the ASYNC_COMPLETE
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * When the result has been determined / received,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * vscan_svc_scan_complete is invoked to transition the request to
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * COMPLETE state, decrement refcnt and signal all waiting callers.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * When the last waiting caller has processed the result (refcnt == 0)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * the request is removed from vscan_svc_reql and vscan_svc_nodes
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * and deleted.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * | reql_insert | refcnt == 0
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * v | (delete)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * +------------------------+ +---------------------+
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * | VS_SVC_REQ_INIT | -----DISABLE----> | VS_SVC_REQ_COMPLETE |
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * +------------------------+ +---------------------+
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * | insert_req, tq_dispatch |
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * +------------------------+ |
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * | VS_SVC_REQ_QUEUED | scan_complete
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * +------------------------+ |
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * | tq_callback (do_scan) |
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * v scan not req'd, error, |
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * +------------------------+ or door_result != SCANNING |
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * | VS_SVC_REQ_IN_PROGRESS |----------------->-------------|
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * +------------------------+ |
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * | | door_result == SCANNING |
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * | +---------------------------+ async result |
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * | | VS_SVC_REQ_SCANNING |-------->---------|
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * | +---------------------------+ |
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * | async result |
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * +---------------------------+ door_result = SCANNING |
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * | VS_SVC_REQ_ASYNC_COMPLETE |-------->------------------|
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * +---------------------------+
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsynctypedef enum {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * vscan_svc_reql - the list of pending and in-progress scan requests
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsynctypedef struct vscan_req {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * vscan_svc_nodes - table of files being scanned
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * The index into this table is passed in the door call to
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * vscand. vscand uses the idx to determine which minor node
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * to open to read the file data. Within the kernel driver
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * the minor device number can thus be used to identify the
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * table index to get the appropriate vnode.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * Instance 0 is reserved for the daemon/driver control
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsynctypedef struct vscan_svc_node {
static int vscan_svc_nodes_sz;
static void vscan_svc_taskq_callback(void *);
static int vscan_svc_exempt_filetype(char *);
static int vscan_svc_match_ext(char *, char *, int);
static void vscan_svc_process_scan_result(int);
static void vscan_svc_remove_req(int);
static int vscan_svc_getattr(int);
static int vscan_svc_setattr(int, int);
static void vscan_svc_reql_handler(void);
int, vscan_svc_state);
int, vscan_svc_state);
vscan_svc_enable(void)
switch (vscan_svc_state) {
case VS_SVC_ENABLED:
case VS_SVC_IDLE:
int, vscan_svc_state);
vscan_svc_disable(void)
switch (vscan_svc_state) {
case VS_SVC_ENABLED:
switch (vscan_svc_state) {
case VS_SVC_IDLE:
case VS_SVC_UNCONFIG:
return (in_use);
vnode_t *
return (vp);
int access;
return (EACCES);
int, vscan_svc_state);
if (async) {
vscan_svc_reql_handler(void)
static vs_scan_req_t *
return (scan_req);
int idx;
* Invoked from vscan_drv.c on receipt of an ioctl containing
int idx;
case VS_STATUS_INFECTED:
case VS_STATUS_CLEAN:
node);
case VS_STATUS_NO_SCAN:
case VS_STATUS_ERROR:
case VS_STATUS_UNDEFINED:
int len;
int count = 0;
++count;
filename++;
ext++;
for (i = 0; i < VS_TYPES_MAX; i ++) {
if (vscan_svc_types[i] == 0)
if (rc > 0) {
char *, vscan_svc_types[i]);
return (exempt);
switch (*patn) {
return (*str == 0);
if (*str != 0) {
str++;
patn++;
patn++;
if (*patn == 0)
while (*str) {
str++;
str++;
patn++;
int idx;
return (idx);
if (idx != 0) {
sizeof (vscan_svc_node_t));
static vscan_req_t *
return (req);
static vscan_req_t *
return (req);
return (NULL);
vscan_svc_seqnum = 0;
return (req);