From 7cb8e9bdb64be9776e68ed4f238209f0d3ea73d7 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sat, 2 Mar 2019 20:07:49 +0000 Subject: [PATCH] scst/src/scst_proc.c: Remove this file git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@8001 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/scst_proc.c | 2445 ------------------------------------------ 1 file changed, 2445 deletions(-) delete mode 100644 scst/src/scst_proc.c diff --git a/scst/src/scst_proc.c b/scst/src/scst_proc.c deleted file mode 100644 index 0da66b59a..000000000 --- a/scst/src/scst_proc.c +++ /dev/null @@ -1,2445 +0,0 @@ -/* - * scst_proc.c - * - * Copyright (C) 2004 - 2018 Vladislav Bolkhovitin - * Copyright (C) 2004 - 2005 Leonid Stoljar - * Copyright (C) 2007 - 2018 Western Digital Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2 - * of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef INSIDE_KERNEL_TREE -#include -#else -#include "scst.h" -#endif -#include "scst_priv.h" -#include "scst_mem.h" -#include "scst_pres.h" - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) -#include <../fs/proc/internal.h> /* PDE() */ -#elif !defined(RHEL_MAJOR) || RHEL_MAJOR -0 < 6 || RHEL_MINOR -0 < 5 -/* - * See also commits "procfs: new helper - PDE_DATA(inode)" - * (d9dda78bad879595d8c4220a067fc029d6484a16) and "proc: Make the PROC_I() and - * PDE() macros internal to procfs" - * (c30480b92cf497aa3b463367a82f1c2fdc5c46e9). - */ -static inline void *PDE_DATA(const struct inode *inode) -{ - return PROC_I(inode)->pde->data; -} -#endif - -static int scst_proc_init_groups(void); -static void scst_proc_cleanup_groups(void); -static int scst_proc_assign_handler(char *buf); -static int scst_proc_group_add(const char *p, unsigned int addr_method); -static int scst_proc_del_free_acg(struct scst_acg *acg, int remove_proc); - -static struct scst_proc_data scst_version_proc_data; -static struct scst_proc_data scst_help_proc_data; -static struct scst_proc_data scst_sgv_proc_data; -static struct scst_proc_data scst_groups_names_proc_data; -static struct scst_proc_data scst_groups_devices_proc_data; -static struct scst_proc_data scst_groups_addr_method_proc_data; -static struct scst_proc_data scst_sessions_proc_data; -static struct scst_proc_data scst_dev_handler_type_proc_data; -static struct scst_proc_data scst_tgt_proc_data; -static struct scst_proc_data scst_threads_proc_data; -static struct scst_proc_data scst_scsi_tgt_proc_data; -static struct scst_proc_data scst_dev_handler_proc_data; - -/* - * Must be less than 4K page size, since our output routines - * use some slack for overruns - */ -#define SCST_PROC_BLOCK_SIZE (PAGE_SIZE - 512) - -#define SCST_PROC_LOG_ENTRY_NAME "trace_level" -#define SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME "type" -#define SCST_PROC_VERSION_NAME "version" -#define SCST_PROC_SESSIONS_NAME "sessions" -#define SCST_PROC_HELP_NAME "help" -#define SCST_PROC_THREADS_NAME "threads" -#define SCST_PROC_GROUPS_ENTRY_NAME "groups" -#define SCST_PROC_GROUPS_DEVICES_ENTRY_NAME "devices" -#define SCST_PROC_GROUPS_USERS_ENTRY_NAME "names" -#define SCST_PROC_GROUPS_ADDR_METHOD_ENTRY_NAME "addr_method" - -#define SCST_PROC_ACTION_ALL 1 -#define SCST_PROC_ACTION_NONE 2 -#define SCST_PROC_ACTION_DEFAULT 3 -#define SCST_PROC_ACTION_ADD 4 -#define SCST_PROC_ACTION_CLEAR 5 -#define SCST_PROC_ACTION_MOVE 6 -#define SCST_PROC_ACTION_DEL 7 -#define SCST_PROC_ACTION_REPLACE 8 -#define SCST_PROC_ACTION_VALUE 9 -#define SCST_PROC_ACTION_ASSIGN 10 -#define SCST_PROC_ACTION_ADD_GROUP 11 -#define SCST_PROC_ACTION_DEL_GROUP 12 -#define SCST_PROC_ACTION_RENAME_GROUP 13 -#define SCST_PROC_ACTION_DUMP_PRS 14 - -static struct proc_dir_entry *scst_proc_scsi_tgt; -static struct proc_dir_entry *scst_proc_groups_root; - -#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) -static struct scst_proc_data scst_log_proc_data; - -static struct scst_trace_log scst_proc_trace_tbl[] = { - { TRACE_OUT_OF_MEM, "out_of_mem" }, - { TRACE_MINOR, "minor" }, - { TRACE_SG_OP, "sg" }, - { TRACE_MEMORY, "mem" }, - { TRACE_BUFF, "buff" }, -#ifndef GENERATING_UPSTREAM_PATCH - { TRACE_ENTRYEXIT, "entryexit" }, -#endif - { TRACE_PID, "pid" }, - { TRACE_LINE, "line" }, - { TRACE_FUNCTION, "function" }, - { TRACE_DEBUG, "debug" }, - { TRACE_SPECIAL, "special" }, - { TRACE_SCSI, "scsi" }, - { TRACE_MGMT, "mgmt" }, - { TRACE_MGMT_DEBUG, "mgmt_dbg" }, - { TRACE_FLOW_CONTROL, "flow_control" }, - { TRACE_PRES, "pr" }, - { 0, NULL } -}; - -static struct scst_trace_log scst_proc_local_trace_tbl[] = { - { TRACE_RTRY, "retry" }, - { TRACE_SCSI_SERIALIZING, "scsi_serializing" }, - { TRACE_DATA_SEND, "data_send" }, - { TRACE_DATA_RECEIVED, "data_received" }, - { TRACE_BLOCKING, "block" }, - { 0, NULL } -}; -#endif - -static char *scst_proc_help_string = -" echo \"assign H:C:I:L HANDLER_NAME\" >/proc/scsi_tgt/scsi_tgt\n" -"\n" -" echo \"add_group GROUP_NAME [FLAT]\" >/proc/scsi_tgt/scsi_tgt\n" -" echo \"add_group GROUP_NAME [LUN]\" >/proc/scsi_tgt/scsi_tgt\n" -" echo \"del_group GROUP_NAME\" >/proc/scsi_tgt/scsi_tgt\n" -" echo \"rename_group OLD_NAME NEW_NAME\" >/proc/scsi_tgt/scsi_tgt\n" -"\n" -" echo \"add|del H:C:I:L lun [READ_ONLY]\"" -" >/proc/scsi_tgt/groups/GROUP_NAME/devices\n" -" echo \"replace H:C:I:L lun [READ_ONLY]\"" -" >/proc/scsi_tgt/groups/GROUP_NAME/devices\n" -" echo \"add|del V_NAME lun [READ_ONLY]\"" -" >/proc/scsi_tgt/groups/GROUP_NAME/devices\n" -" echo \"replace V_NAME lun [READ_ONLY]\"" -" >/proc/scsi_tgt/groups/GROUP_NAME/devices\n" -" echo \"clear\" >/proc/scsi_tgt/groups/GROUP_NAME/devices\n" -"\n" -" echo \"add|del NAME\" >/proc/scsi_tgt/groups/GROUP_NAME/names\n" -" echo \"move NAME NEW_GROUP_NAME\" >/proc/scsi_tgt/groups/OLD_GROUP_NAME/names\n" -" echo \"clear\" >/proc/scsi_tgt/groups/GROUP_NAME/names\n" -"\n" -" echo \"DEC|0xHEX|0OCT\" >/proc/scsi_tgt/threads\n" -#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) -"\n" -" echo \"all|none|default\" >/proc/scsi_tgt/[DEV_HANDLER_NAME/]trace_level\n" -" echo \"value DEC|0xHEX|0OCT\"" -" >/proc/scsi_tgt/[DEV_HANDLER_NAME/]trace_level\n" -" echo \"set|add|del TOKEN\"" -" >/proc/scsi_tgt/[DEV_HANDLER_NAME/]trace_level\n" -" where TOKEN is one of [debug, function, line, pid, entryexit,\n" -" buff, mem, sg, out_of_mem, special, scsi,\n" -" mgmt, minor, mgmt_dbg]\n" -" Additionally for /proc/scsi_tgt/trace_level there are these TOKENs\n" -" [scsi_serializing, retry, recv_bot, send_bot, recv_top, send_top, pr, block]\n" -" echo \"dump_prs dev_name\" >/proc/scsi_tgt/trace_level\n" -#endif -; - -static char *scst_proc_dev_handler_type[] = { - "Direct-access device (e.g., magnetic disk)", - "Sequential-access device (e.g., magnetic tape)", - "Printer device", - "Processor device", - "Write-once device (e.g., some optical disks)", - "CD-ROM device", - "Scanner device (obsolete)", - "Optical memory device (e.g., some optical disks)", - "Medium changer device (e.g., jukeboxes)", - "Communications device (obsolete)", - "Defined by ASC IT8 (Graphic arts pre-press devices)", - "Defined by ASC IT8 (Graphic arts pre-press devices)", - "Storage array controller device (e.g., RAID)", - "Enclosure services device", - "Simplified direct-access device (e.g., magnetic disk)", - "Optical card reader/writer device" -}; - -static DEFINE_MUTEX(scst_proc_mutex); - -#include - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)) && (!defined(RHEL_RELEASE_CODE) || RHEL_RELEASE_CODE -0 < 5 * 256 + 3) -#if !defined(CONFIG_PPC) -/* - * If strcasecmp() and strncasecmp() have already been declared in - * , do not redefine these functions. Declarations for these - * functions are present in the header of the following - * kernels: - * - The PPC kernel headers for all kernel versions supported by SCST. - * - Kernel version 2.6.22 and later for all architectures. - * - RHEL 5.3 and later. - * - * Notes about the above preprocessor statement: - * - We can't use RHEL_RELEASE_CODE(5, 3) because it would trigger an error on - * non-RHEL/CentOS systems -- this expression would expand to "(5,3)". - * - There is no space between the minus sign and the zero in the expression - * "RHEL_RELEASE_CODE -0" such that it expands to a syntactically valid - * expression on non-RHEL/CentOS systems ("-0"). - * - The above statement has been put on one long line because as of r800 - * scripts/specialize-patch does not yet handle multi-line preprocessor - * statements correctly. - */ - -#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) -static int strcasecmp(const char *s1, const char *s2) -{ - int c1, c2; - - do { - c1 = tolower(*s1++); - c2 = tolower(*s2++); - } while (c1 == c2 && c1 != 0); - return c1 - c2; -} -#endif - -static int strncasecmp(const char *s1, const char *s2, size_t n) -{ - int c1, c2; - - do { - c1 = tolower(*s1++); - c2 = tolower(*s2++); - } while ((--n > 0) && c1 == c2 && c1 != 0); - return c1 - c2; -} - -#endif /* !CONFIG_PPC */ -#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)) && (!defined(RHEL_RELEASE_CODE) || RHEL_RELEASE_CODE -0 < 5 * 256 + 3) */ - -#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) - -static DEFINE_MUTEX(scst_log_mutex); - -int scst_proc_log_entry_write(struct file *file, const char __user *buf, - unsigned long length, unsigned long *log_level, - unsigned long default_level, const struct scst_trace_log *tbl) -{ - int res = length; - int action; - unsigned long level = 0, oldlevel; - char *buffer, *p, *e; - const struct scst_trace_log *t; - char *data = PDE_DATA(file_inode(file)); - - TRACE_ENTRY(); - - if (length > SCST_PROC_BLOCK_SIZE) { - res = -EOVERFLOW; - goto out; - } - if (!buf) { - res = -EINVAL; - goto out; - } - buffer = (char *)__get_free_page(GFP_KERNEL); - if (!buffer) { - res = -ENOMEM; - goto out; - } - if (copy_from_user(buffer, buf, length)) { - res = -EFAULT; - goto out_free; - } - if (length < PAGE_SIZE) { - buffer[length] = '\0'; - } else if (buffer[PAGE_SIZE-1]) { - res = -EINVAL; - goto out_free; - } - - /* - * Usage: - * echo "all|none|default" >/proc/scsi_tgt/trace_level - * echo "value DEC|0xHEX|0OCT" >/proc/scsi_tgt/trace_level - * echo "add|del TOKEN" >/proc/scsi_tgt/trace_level - */ - p = buffer; - if (!strncasecmp("all", p, 3)) { - action = SCST_PROC_ACTION_ALL; - } else if (!strncasecmp("none", p, 4) || !strncasecmp("null", p, 4)) { - action = SCST_PROC_ACTION_NONE; - } else if (!strncasecmp("default", p, 7)) { - action = SCST_PROC_ACTION_DEFAULT; - } else if (!strncasecmp("add ", p, 4)) { - p += 4; - action = SCST_PROC_ACTION_ADD; - } else if (!strncasecmp("del ", p, 4)) { - p += 4; - action = SCST_PROC_ACTION_DEL; - } else if (!strncasecmp("value ", p, 6)) { - p += 6; - action = SCST_PROC_ACTION_VALUE; - } else if (!strncasecmp("dump_prs ", p, 9)) { - p += 9; - action = SCST_PROC_ACTION_DUMP_PRS; - } else { - if (p[strlen(p) - 1] == '\n') - p[strlen(p) - 1] = '\0'; - PRINT_ERROR("Unknown action \"%s\"", p); - res = -EINVAL; - goto out_free; - } - - switch (action) { - case SCST_PROC_ACTION_ALL: - level = TRACE_ALL; - break; - case SCST_PROC_ACTION_DEFAULT: - level = default_level; - break; - case SCST_PROC_ACTION_NONE: - level = TRACE_NULL; - break; - case SCST_PROC_ACTION_ADD: - case SCST_PROC_ACTION_DEL: - while (isspace(*p) && *p != '\0') - p++; - e = p; - while (!isspace(*e) && *e != '\0') - e++; - *e = 0; - if (tbl) { - t = tbl; - while (t->token) { - if (!strcasecmp(p, t->token)) { - level = t->val; - break; - } - t++; - } - } - if (level == 0) { - t = scst_proc_trace_tbl; - while (t->token) { - if (!strcasecmp(p, t->token)) { - level = t->val; - break; - } - t++; - } - } - if (level == 0) { - PRINT_ERROR("Unknown token \"%s\"", p); - res = -EINVAL; - goto out_free; - } - break; - case SCST_PROC_ACTION_VALUE: - while (isspace(*p) && *p != '\0') - p++; - level = simple_strtoul(p, NULL, 0); - break; - case SCST_PROC_ACTION_DUMP_PRS: - { - struct scst_device *dev; - - while (isspace(*p) && *p != '\0') - p++; - e = p; - while (!isspace(*e) && *e != '\0') - e++; - *e = '\0'; - - if (mutex_lock_interruptible(&scst_mutex) != 0) { - res = -EINTR; - goto out_free; - } - - list_for_each_entry(dev, &scst_dev_list, dev_list_entry) { - if (strcmp(dev->virt_name, p) == 0) { - if (mutex_lock_interruptible(&dev->dev_pr_mutex) == 0) { - scst_pr_dump_prs(dev, true); - mutex_unlock(&dev->dev_pr_mutex); - } else { - res = -EINTR; - } - goto out_up; - } - } - - PRINT_ERROR("Device %s not found", p); - res = -ENOENT; -out_up: - mutex_unlock(&scst_mutex); - goto out_free; - } - } - - oldlevel = *log_level; - - switch (action) { - case SCST_PROC_ACTION_ADD: - *log_level |= level; - break; - case SCST_PROC_ACTION_DEL: - *log_level &= ~level; - break; - default: - *log_level = level; - break; - } - - PRINT_INFO("Changed trace level for \"%s\": " - "old 0x%08lx, new 0x%08lx", - (char *)data, oldlevel, *log_level); - -out_free: - free_page((unsigned long)buffer); -out: - TRACE_EXIT_RES(res); - return res; -} -EXPORT_SYMBOL_GPL(scst_proc_log_entry_write); - -static ssize_t scst_proc_scsi_tgt_gen_write_log(struct file *file, - const char __user *buf, - size_t length, loff_t *off) -{ - int res; - - TRACE_ENTRY(); - - if (mutex_lock_interruptible(&scst_log_mutex) != 0) { - res = -EINTR; - goto out; - } - - res = scst_proc_log_entry_write(file, buf, length, - &trace_flag, SCST_DEFAULT_LOG_FLAGS, - scst_proc_local_trace_tbl); - - mutex_unlock(&scst_log_mutex); - -out: - TRACE_EXIT_RES(res); - return res; -} - -#endif /* defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) */ - -static int __init scst_proc_init_module_log(void) -{ - int res = 0; -#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) - struct proc_dir_entry *generic; -#endif - - TRACE_ENTRY(); - -#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) - generic = scst_create_proc_entry(scst_proc_scsi_tgt, - SCST_PROC_LOG_ENTRY_NAME, - &scst_log_proc_data); - if (!generic) { - PRINT_ERROR("cannot init /proc/%s/%s", - SCST_PROC_ENTRY_NAME, SCST_PROC_LOG_ENTRY_NAME); - res = -ENOMEM; - } -#endif - - TRACE_EXIT_RES(res); - return res; -} - -static void scst_proc_cleanup_module_log(void) -{ - TRACE_ENTRY(); - -#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) - remove_proc_entry(SCST_PROC_LOG_ENTRY_NAME, scst_proc_scsi_tgt); -#endif - - TRACE_EXIT(); - return; -} - -static int scst_proc_group_add_tree(struct scst_acg *acg, const char *name) -{ - int res = 0; - struct proc_dir_entry *generic; - - TRACE_ENTRY(); - - acg->acg_proc_root = proc_mkdir(name, scst_proc_groups_root); - if (acg->acg_proc_root == NULL) { - PRINT_ERROR("Not enough memory to register %s entry in " - "/proc/%s/%s", name, SCST_PROC_ENTRY_NAME, - SCST_PROC_GROUPS_ENTRY_NAME); - goto out; - } - - scst_groups_addr_method_proc_data.data = acg; - generic = scst_create_proc_entry(acg->acg_proc_root, - SCST_PROC_GROUPS_ADDR_METHOD_ENTRY_NAME, - &scst_groups_addr_method_proc_data); - if (!generic) { - PRINT_ERROR("Cannot init /proc/%s/%s/%s/%s", - SCST_PROC_ENTRY_NAME, - SCST_PROC_GROUPS_ENTRY_NAME, - name, SCST_PROC_GROUPS_ADDR_METHOD_ENTRY_NAME); - res = -ENOMEM; - goto out_remove; - } - - scst_groups_devices_proc_data.data = acg; - generic = scst_create_proc_entry(acg->acg_proc_root, - SCST_PROC_GROUPS_DEVICES_ENTRY_NAME, - &scst_groups_devices_proc_data); - if (!generic) { - PRINT_ERROR("Cannot init /proc/%s/%s/%s/%s", - SCST_PROC_ENTRY_NAME, - SCST_PROC_GROUPS_ENTRY_NAME, - name, SCST_PROC_GROUPS_DEVICES_ENTRY_NAME); - res = -ENOMEM; - goto out_remove0; - } - - scst_groups_names_proc_data.data = acg; - generic = scst_create_proc_entry(acg->acg_proc_root, - SCST_PROC_GROUPS_USERS_ENTRY_NAME, - &scst_groups_names_proc_data); - if (!generic) { - PRINT_ERROR("Cannot init /proc/%s/%s/%s/%s", - SCST_PROC_ENTRY_NAME, - SCST_PROC_GROUPS_ENTRY_NAME, - name, SCST_PROC_GROUPS_USERS_ENTRY_NAME); - res = -ENOMEM; - goto out_remove1; - } - -out: - TRACE_EXIT_RES(res); - return res; - -out_remove1: - remove_proc_entry(SCST_PROC_GROUPS_DEVICES_ENTRY_NAME, - acg->acg_proc_root); - -out_remove0: - remove_proc_entry(SCST_PROC_GROUPS_ADDR_METHOD_ENTRY_NAME, - acg->acg_proc_root); -out_remove: - remove_proc_entry(name, scst_proc_groups_root); - goto out; -} - -static void scst_proc_del_acg_tree(struct proc_dir_entry *acg_proc_root, - const char *name) -{ - TRACE_ENTRY(); - - remove_proc_entry(SCST_PROC_GROUPS_ADDR_METHOD_ENTRY_NAME, acg_proc_root); - remove_proc_entry(SCST_PROC_GROUPS_USERS_ENTRY_NAME, acg_proc_root); - remove_proc_entry(SCST_PROC_GROUPS_DEVICES_ENTRY_NAME, acg_proc_root); - remove_proc_entry(name, scst_proc_groups_root); - - TRACE_EXIT(); - return; -} - -/* The activity supposed to be suspended and scst_mutex held */ -static int scst_proc_group_add(const char *p, unsigned int addr_method) -{ - int res = 0; - struct scst_acg *acg; - TRACE_ENTRY(); - - res = scst_alloc_add_acg(NULL, p, false, &acg); - if (res != 0) { - PRINT_ERROR("scst_alloc_add_acg() (name %s) failed", p); - goto out; - } - - acg->addr_method = addr_method; - - res = scst_proc_group_add_tree(acg, p); - if (res != 0) - goto out_free_acg; - -out: - TRACE_EXIT_RES(res); - return res; - -out_free_acg: - scst_proc_del_free_acg(acg, 0); - - res = -ENOMEM; - goto out; -} - -/* The activity supposed to be suspended and scst_mutex held */ -static int scst_proc_del_free_acg(struct scst_acg *acg, int remove_proc) -{ - struct proc_dir_entry *acg_proc_root = acg->acg_proc_root; - int res = 0; - - TRACE_ENTRY(); - - if (acg != scst_default_acg) { - if (!scst_acg_sess_is_empty(acg)) { - PRINT_ERROR("%s", "Session is not empty"); - res = -EBUSY; - goto out; - } - if (remove_proc) - scst_proc_del_acg_tree(acg_proc_root, acg->acg_name); - scst_del_free_acg(acg, false); - } -out: - TRACE_EXIT_RES(res); - return res; -} - -/* The activity supposed to be suspended and scst_mutex held */ -static int scst_proc_rename_acg(struct scst_acg *acg, const char *new_name) -{ - int res = 0, len = strlen(new_name) + 1; - char *name; - struct proc_dir_entry *old_acg_proc_root = acg->acg_proc_root; - - TRACE_ENTRY(); - - name = kmalloc(len, GFP_KERNEL); - if (name == NULL) { - PRINT_ERROR("Allocation of new name (size %d) failed", len); - goto out_nomem; - } - strlcpy(name, new_name, len); - - res = scst_proc_group_add_tree(acg, new_name); - if (res != 0) - goto out_free; - - scst_proc_del_acg_tree(old_acg_proc_root, acg->acg_name); - - kfree(acg->acg_name); - acg->acg_name = name; - - scst_check_reassign_sessions(); - -out: - TRACE_EXIT_RES(res); - return res; - -out_free: - kfree(name); - -out_nomem: - res = -ENOMEM; - goto out; -} - -static int __init scst_proc_init_groups(void) -{ - int res = 0; - - TRACE_ENTRY(); - - /* create the proc directory entry for the device */ - scst_proc_groups_root = proc_mkdir(SCST_PROC_GROUPS_ENTRY_NAME, - scst_proc_scsi_tgt); - if (scst_proc_groups_root == NULL) { - PRINT_ERROR("Not enough memory to register %s entry in " - "/proc/%s", SCST_PROC_GROUPS_ENTRY_NAME, - SCST_PROC_ENTRY_NAME); - goto out_nomem; - } - - res = scst_proc_group_add_tree(scst_default_acg, - SCST_DEFAULT_ACG_NAME); - if (res != 0) - goto out_remove; - -out: - TRACE_EXIT_RES(res); - return res; - -out_remove: - remove_proc_entry(SCST_PROC_GROUPS_ENTRY_NAME, scst_proc_scsi_tgt); - -out_nomem: - res = -ENOMEM; - goto out; -} - -static void scst_proc_cleanup_groups(void) -{ - struct scst_acg *acg_tmp, *acg; - - TRACE_ENTRY(); - - /* remove all groups (dir & entries) */ - list_for_each_entry_safe(acg, acg_tmp, &scst_acg_list, - acg_list_entry) { - scst_proc_del_free_acg(acg, 1); - } - - scst_proc_del_acg_tree(scst_default_acg->acg_proc_root, - SCST_DEFAULT_ACG_NAME); - TRACE_DBG("remove_proc_entry(%s, %p)", - SCST_PROC_GROUPS_ENTRY_NAME, scst_proc_scsi_tgt); - remove_proc_entry(SCST_PROC_GROUPS_ENTRY_NAME, scst_proc_scsi_tgt); - - TRACE_EXIT(); -} - -static int __init scst_proc_init_sgv(void) -{ - int res = 0; - struct proc_dir_entry *pr; - - TRACE_ENTRY(); - - pr = scst_create_proc_entry(scst_proc_scsi_tgt, "sgv", - &scst_sgv_proc_data); - if (pr == NULL) { - PRINT_ERROR("%s", "cannot create sgv /proc entry"); - res = -ENOMEM; - } - - TRACE_EXIT_RES(res); - return res; -} - -static void scst_proc_cleanup_sgv(void) -{ - TRACE_ENTRY(); - remove_proc_entry("sgv", scst_proc_scsi_tgt); - TRACE_EXIT(); -} - -int __init scst_proc_init_module(void) -{ - int res = 0; - struct proc_dir_entry *generic; - - TRACE_ENTRY(); - - scst_proc_scsi_tgt = proc_mkdir(SCST_PROC_ENTRY_NAME, NULL); - if (!scst_proc_scsi_tgt) { - PRINT_ERROR("cannot init /proc/%s", SCST_PROC_ENTRY_NAME); - goto out_nomem; - } - - generic = scst_create_proc_entry(scst_proc_scsi_tgt, - SCST_PROC_ENTRY_NAME, - &scst_tgt_proc_data); - if (!generic) { - PRINT_ERROR("cannot init /proc/%s/%s", - SCST_PROC_ENTRY_NAME, SCST_PROC_ENTRY_NAME); - goto out_remove; - } - - generic = scst_create_proc_entry(scst_proc_scsi_tgt, - SCST_PROC_VERSION_NAME, - &scst_version_proc_data); - if (!generic) { - PRINT_ERROR("cannot init /proc/%s/%s", - SCST_PROC_ENTRY_NAME, SCST_PROC_VERSION_NAME); - goto out_remove1; - } - - generic = scst_create_proc_entry(scst_proc_scsi_tgt, - SCST_PROC_SESSIONS_NAME, - &scst_sessions_proc_data); - if (!generic) { - PRINT_ERROR("cannot init /proc/%s/%s", - SCST_PROC_ENTRY_NAME, SCST_PROC_SESSIONS_NAME); - goto out_remove2; - } - - generic = scst_create_proc_entry(scst_proc_scsi_tgt, - SCST_PROC_HELP_NAME, - &scst_help_proc_data); - if (!generic) { - PRINT_ERROR("cannot init /proc/%s/%s", - SCST_PROC_ENTRY_NAME, SCST_PROC_HELP_NAME); - goto out_remove3; - } - - generic = scst_create_proc_entry(scst_proc_scsi_tgt, - SCST_PROC_THREADS_NAME, - &scst_threads_proc_data); - if (!generic) { - PRINT_ERROR("cannot init /proc/%s/%s", - SCST_PROC_ENTRY_NAME, SCST_PROC_THREADS_NAME); - goto out_remove4; - } - - if (scst_proc_init_module_log() < 0) - goto out_remove5; - - if (scst_proc_init_groups() < 0) - goto out_remove6; - - if (scst_proc_init_sgv() < 0) - goto out_remove7; - -out: - TRACE_EXIT_RES(res); - return res; - -out_remove7: - scst_proc_cleanup_groups(); - -out_remove6: - scst_proc_cleanup_module_log(); - -out_remove5: - remove_proc_entry(SCST_PROC_THREADS_NAME, scst_proc_scsi_tgt); - -out_remove4: - remove_proc_entry(SCST_PROC_HELP_NAME, scst_proc_scsi_tgt); - -out_remove3: - remove_proc_entry(SCST_PROC_SESSIONS_NAME, scst_proc_scsi_tgt); - -out_remove2: - remove_proc_entry(SCST_PROC_VERSION_NAME, scst_proc_scsi_tgt); - -out_remove1: - remove_proc_entry(SCST_PROC_ENTRY_NAME, scst_proc_scsi_tgt); - -out_remove: - remove_proc_entry(SCST_PROC_ENTRY_NAME, NULL); - -out_nomem: - res = -ENOMEM; - goto out; -} - -void scst_proc_cleanup_module(void) -{ - TRACE_ENTRY(); - - /* We may not bother about locks here */ - scst_proc_cleanup_sgv(); - - mutex_lock(&scst_mutex); - scst_proc_cleanup_groups(); - mutex_unlock(&scst_mutex); - - scst_proc_cleanup_module_log(); - remove_proc_entry(SCST_PROC_THREADS_NAME, scst_proc_scsi_tgt); - remove_proc_entry(SCST_PROC_HELP_NAME, scst_proc_scsi_tgt); - remove_proc_entry(SCST_PROC_SESSIONS_NAME, scst_proc_scsi_tgt); - remove_proc_entry(SCST_PROC_VERSION_NAME, scst_proc_scsi_tgt); - remove_proc_entry(SCST_PROC_ENTRY_NAME, scst_proc_scsi_tgt); - remove_proc_entry(SCST_PROC_ENTRY_NAME, NULL); - - TRACE_EXIT(); -} - -static ssize_t scst_proc_threads_write(struct file *file, - const char __user *buf, - size_t length, loff_t *off) -{ - int res = length; - int oldtn, newtn, delta; - char *buffer; - - TRACE_ENTRY(); - - if (length > SCST_PROC_BLOCK_SIZE) { - res = -EOVERFLOW; - goto out; - } - if (!buf) { - res = -EINVAL; - goto out; - } - buffer = (char *)__get_free_page(GFP_KERNEL); - if (!buffer) { - res = -ENOMEM; - goto out; - } - if (copy_from_user(buffer, buf, length)) { - res = -EFAULT; - goto out_free; - } - if (length < PAGE_SIZE) { - buffer[length] = '\0'; - } else if (buffer[PAGE_SIZE-1]) { - res = -EINVAL; - goto out_free; - } - - if (mutex_lock_interruptible(&scst_proc_mutex) != 0) { - res = -EINTR; - goto out_free; - } - - mutex_lock(&scst_mutex); - - oldtn = scst_main_cmd_threads.nr_threads; - newtn = simple_strtoul(buffer, NULL, 0); - if (newtn <= 0) { - PRINT_ERROR("Illegal threads num value %d", newtn); - res = -EINVAL; - goto out_up_thr_free; - } - delta = newtn - oldtn; - if (delta < 0) - scst_del_threads(&scst_main_cmd_threads, -delta); - else { - int rc = scst_add_threads(&scst_main_cmd_threads, NULL, NULL, - delta); - if (rc != 0) - res = rc; - } - - PRINT_INFO("Changed cmd threads num: old %d, new %d", oldtn, newtn); - -out_up_thr_free: - mutex_unlock(&scst_mutex); - - mutex_unlock(&scst_proc_mutex); - -out_free: - free_page((unsigned long)buffer); -out: - TRACE_EXIT_RES(res); - return res; -} - -int scst_build_proc_target_dir_entries(struct scst_tgt_template *vtt) -{ - int res = 0; - - TRACE_ENTRY(); - - /* create the proc directory entry for the device */ - vtt->proc_tgt_root = proc_mkdir(vtt->name, scst_proc_scsi_tgt); - if (vtt->proc_tgt_root == NULL) { - PRINT_ERROR("Not enough memory to register SCSI target %s " - "in /proc/%s", vtt->name, SCST_PROC_ENTRY_NAME); - goto out_nomem; - } - -out: - TRACE_EXIT_RES(res); - return res; - -out_nomem: - res = -ENOMEM; - goto out; -} - -void scst_cleanup_proc_target_dir_entries(struct scst_tgt_template *vtt) -{ - TRACE_ENTRY(); - - remove_proc_entry(vtt->name, scst_proc_scsi_tgt); - - TRACE_EXIT(); - return; -} - -/* Called under scst_mutex */ -int scst_build_proc_target_entries(struct scst_tgt *vtt) -{ - int res = 0; - struct proc_dir_entry *p; - char name[20]; - - TRACE_ENTRY(); - - if (vtt->tgtt->read_proc || vtt->tgtt->write_proc) { - /* create the proc file entry for the device */ - scnprintf(name, sizeof(name), "%d", vtt->tgtt->proc_dev_num); - scst_scsi_tgt_proc_data.data = (void *)vtt; - p = scst_create_proc_entry(vtt->tgtt->proc_tgt_root, - name, - &scst_scsi_tgt_proc_data); - if (p == NULL) { - PRINT_ERROR("Not enough memory to register SCSI " - "target entry %s in /proc/%s/%s", name, - SCST_PROC_ENTRY_NAME, vtt->tgtt->name); - res = -ENOMEM; - goto out; - } - vtt->proc_num = vtt->tgtt->proc_dev_num; - vtt->tgtt->proc_dev_num++; - } - -out: - TRACE_EXIT_RES(res); - return res; -} - -void scst_cleanup_proc_target_entries(struct scst_tgt *vtt) -{ - char name[20]; - - TRACE_ENTRY(); - - if (vtt->tgtt->read_proc || vtt->tgtt->write_proc) { - scnprintf(name, sizeof(name), "%d", vtt->proc_num); - remove_proc_entry(name, vtt->tgtt->proc_tgt_root); - } - - TRACE_EXIT(); - return; -} - -static ssize_t scst_proc_scsi_tgt_write(struct file *file, - const char __user *buf, - size_t length, loff_t *off) -{ - struct scst_tgt *vtt = PDE_DATA(file_inode(file)); - ssize_t res = 0; - char *buffer; - char *start; - int eof = 0; - - TRACE_ENTRY(); - - if (vtt->tgtt->write_proc == NULL) { - res = -ENOTSUPP; - goto out; - } - - if (length > SCST_PROC_BLOCK_SIZE) { - res = -EOVERFLOW; - goto out; - } - if (!buf) { - res = -EINVAL; - goto out; - } - buffer = (char *)__get_free_page(GFP_KERNEL); - if (!buffer) { - res = -ENOMEM; - goto out; - } - if (copy_from_user(buffer, buf, length)) { - res = -EFAULT; - goto out_free; - } - if (length < PAGE_SIZE) { - buffer[length] = '\0'; - } else if (buffer[PAGE_SIZE-1]) { - res = -EINVAL; - goto out_free; - } - - TRACE_BUFFER("Buffer", buffer, length); - - if (mutex_lock_interruptible(&scst_proc_mutex) != 0) { - res = -EINTR; - goto out_free; - } - - res = vtt->tgtt->write_proc(buffer, &start, 0, length, &eof, vtt); - - mutex_unlock(&scst_proc_mutex); - -out_free: - free_page((unsigned long)buffer); -out: - TRACE_EXIT_RES(res); - return res; -} - -int scst_build_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type) -{ - int res = 0; - struct proc_dir_entry *p; - const char *name; /* workaround to keep /proc ABI intact */ - - TRACE_ENTRY(); - - sBUG_ON(dev_type->proc_dev_type_root); - - if (strcmp(dev_type->name, "vdisk_fileio") == 0) - name = "vdisk"; - else - name = dev_type->name; - - /* create the proc directory entry for the dev type handler */ - dev_type->proc_dev_type_root = proc_mkdir(name, - scst_proc_scsi_tgt); - if (dev_type->proc_dev_type_root == NULL) { - PRINT_ERROR("Not enough memory to register dev handler dir " - "%s in /proc/%s", name, SCST_PROC_ENTRY_NAME); - goto out_nomem; - } - - scst_dev_handler_type_proc_data.data = dev_type; - if (dev_type->type >= 0) { - p = scst_create_proc_entry(dev_type->proc_dev_type_root, - SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME, - &scst_dev_handler_type_proc_data); - if (p == NULL) { - PRINT_ERROR("Not enough memory to register dev " - "handler entry %s in /proc/%s/%s", - SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME, - SCST_PROC_ENTRY_NAME, name); - goto out_remove; - } - } - - if (dev_type->read_proc || dev_type->write_proc) { - /* create the proc file entry for the dev type handler */ - scst_dev_handler_proc_data.data = (void *)dev_type; - p = scst_create_proc_entry(dev_type->proc_dev_type_root, - name, - &scst_dev_handler_proc_data); - if (p == NULL) { - PRINT_ERROR("Not enough memory to register dev " - "handler entry %s in /proc/%s/%s", name, - SCST_PROC_ENTRY_NAME, name); - goto out_remove1; - } - } - -out: - TRACE_EXIT_RES(res); - return res; - -out_remove1: - if (dev_type->type >= 0) - remove_proc_entry(SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME, - dev_type->proc_dev_type_root); - -out_remove: - remove_proc_entry(name, scst_proc_scsi_tgt); - -out_nomem: - res = -ENOMEM; - goto out; -} - -void scst_cleanup_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type) -{ - /* Workaround to keep /proc ABI intact */ - const char *name; - - TRACE_ENTRY(); - - sBUG_ON(dev_type->proc_dev_type_root == NULL); - - if (strcmp(dev_type->name, "vdisk_fileio") == 0) - name = "vdisk"; - else - name = dev_type->name; - - if (dev_type->type >= 0) { - remove_proc_entry(SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME, - dev_type->proc_dev_type_root); - } - if (dev_type->read_proc || dev_type->write_proc) - remove_proc_entry(name, dev_type->proc_dev_type_root); - remove_proc_entry(name, scst_proc_scsi_tgt); - dev_type->proc_dev_type_root = NULL; - - TRACE_EXIT(); - return; -} - -static ssize_t scst_proc_scsi_dev_handler_write(struct file *file, - const char __user *buf, - size_t length, loff_t *off) -{ - struct scst_dev_type *dev_type = PDE_DATA(file_inode(file)); - ssize_t res = 0; - char *buffer; - char *start; - int eof = 0; - - TRACE_ENTRY(); - - if (dev_type->write_proc == NULL) { - res = -ENOTSUPP; - goto out; - } - - if (length > SCST_PROC_BLOCK_SIZE) { - res = -EOVERFLOW; - goto out; - } - if (!buf) { - res = -EINVAL; - goto out; - } - - buffer = (char *)__get_free_page(GFP_KERNEL); - if (!buffer) { - res = -ENOMEM; - goto out; - } - - if (copy_from_user(buffer, buf, length)) { - res = -EFAULT; - goto out_free; - } - if (length < PAGE_SIZE) { - buffer[length] = '\0'; - } else if (buffer[PAGE_SIZE-1]) { - res = -EINVAL; - goto out_free; - } - - TRACE_BUFFER("Buffer", buffer, length); - - if (mutex_lock_interruptible(&scst_proc_mutex) != 0) { - res = -EINTR; - goto out_free; - } - - res = dev_type->write_proc(buffer, &start, 0, length, &eof, dev_type); - - mutex_unlock(&scst_proc_mutex); - -out_free: - free_page((unsigned long)buffer); - -out: - TRACE_EXIT_RES(res); - return res; -} - -static ssize_t scst_proc_scsi_tgt_gen_write(struct file *file, - const char __user *buf, - size_t length, loff_t *off) -{ - int res, rc = 0, action; - char *buffer, *p, *pp, *ppp; - struct scst_acg *a, *acg = NULL; - unsigned int addr_method = SCST_LUN_ADDR_METHOD_PERIPHERAL; - - TRACE_ENTRY(); - - if (length > SCST_PROC_BLOCK_SIZE) { - res = -EOVERFLOW; - goto out; - } - if (!buf) { - res = -EINVAL; - goto out; - } - buffer = (char *)__get_free_page(GFP_KERNEL); - if (!buffer) { - res = -ENOMEM; - goto out; - } - if (copy_from_user(buffer, buf, length)) { - res = -EFAULT; - goto out_free; - } - if (length < PAGE_SIZE) { - buffer[length] = '\0'; - } else if (buffer[PAGE_SIZE-1]) { - res = -EINVAL; - goto out_free; - } - - /* - * Usage: echo "add_group GROUP_NAME [FLAT]" >/proc/scsi_tgt/scsi_tgt - * or echo "add_group GROUP_NAME [LUN]" >/proc/scsi_tgt/scsi_tgt - * or echo "del_group GROUP_NAME" >/proc/scsi_tgt/scsi_tgt - * or echo "rename_group OLD_NAME NEW_NAME" >/proc/scsi_tgt/scsi_tgt" - * or echo "assign H:C:I:L HANDLER_NAME" >/proc/scsi_tgt/scsi_tgt - */ - p = buffer; - if (p[strlen(p) - 1] == '\n') - p[strlen(p) - 1] = '\0'; - if (!strncasecmp("assign ", p, 7)) { - p += 7; - action = SCST_PROC_ACTION_ASSIGN; - } else if (!strncasecmp("add_group ", p, 10)) { - p += 10; - action = SCST_PROC_ACTION_ADD_GROUP; - } else if (!strncasecmp("del_group ", p, 10)) { - p += 10; - action = SCST_PROC_ACTION_DEL_GROUP; - } else if (!strncasecmp("rename_group ", p, 13)) { - p += 13; - action = SCST_PROC_ACTION_RENAME_GROUP; - } else { - PRINT_ERROR("Unknown action \"%s\"", p); - res = -EINVAL; - goto out_free; - } - - res = scst_suspend_activity(SCST_SUSPEND_TIMEOUT_USER); - if (res != 0) - goto out_free; - - if (mutex_lock_interruptible(&scst_mutex) != 0) { - res = -EINTR; - goto out_free_resume; - } - - res = length; - - while (isspace(*p) && *p != '\0') - p++; - - switch (action) { - case SCST_PROC_ACTION_ADD_GROUP: - case SCST_PROC_ACTION_DEL_GROUP: - case SCST_PROC_ACTION_RENAME_GROUP: - pp = p; - while (!isspace(*pp) && *pp != '\0') - pp++; - if (*pp != '\0') { - *pp = '\0'; - pp++; - while (isspace(*pp) && *pp != '\0') - pp++; - if (*pp != '\0') { - switch (action) { - case SCST_PROC_ACTION_ADD_GROUP: - ppp = pp; - while (!isspace(*ppp) && *ppp != '\0') - ppp++; - if (*ppp != '\0') { - *ppp = '\0'; - ppp++; - while (isspace(*ppp) && *ppp != '\0') - ppp++; - if (*ppp != '\0') { - PRINT_ERROR("%s", "Too many " - "arguments"); - res = -EINVAL; - goto out_up_free; - } - } - if (strcasecmp(pp, "FLAT") == 0) - addr_method = SCST_LUN_ADDR_METHOD_FLAT; - else if (strcasecmp(pp, "LUN") == 0) - addr_method = SCST_LUN_ADDR_METHOD_LUN; - else { - PRINT_ERROR("Unexpected " - "argument %s", pp); - res = -EINVAL; - goto out_up_free; - } - break; - case SCST_PROC_ACTION_DEL_GROUP: - PRINT_ERROR("%s", "Too many " - "arguments"); - res = -EINVAL; - goto out_up_free; - } - } - } - - if (strcmp(p, SCST_DEFAULT_ACG_NAME) == 0) { - PRINT_ERROR("Attempt to add/delete/rename predefined " - "group \"%s\"", p); - res = -EINVAL; - goto out_up_free; - } - - list_for_each_entry(a, &scst_acg_list, acg_list_entry) { - if (strcmp(a->acg_name, p) == 0) { - TRACE_DBG("group (acg) %p %s found", - a, a->acg_name); - acg = a; - break; - } - } - - switch (action) { - case SCST_PROC_ACTION_ADD_GROUP: - if (acg) { - PRINT_ERROR("acg name %s exist", p); - res = -EINVAL; - goto out_up_free; - } - rc = scst_proc_group_add(p, addr_method); - break; - case SCST_PROC_ACTION_DEL_GROUP: - if (acg == NULL) { - PRINT_ERROR("acg name %s not found", p); - res = -EINVAL; - goto out_up_free; - } - rc = scst_proc_del_free_acg(acg, 1); - break; - case SCST_PROC_ACTION_RENAME_GROUP: - if (acg == NULL) { - PRINT_ERROR("acg name %s not found", p); - res = -EINVAL; - goto out_up_free; - } - - p = pp; - while (!isspace(*pp) && *pp != '\0') - pp++; - if (*pp != '\0') { - *pp = '\0'; - pp++; - while (isspace(*pp) && *pp != '\0') - pp++; - if (*pp != '\0') { - PRINT_ERROR("%s", "Too many arguments"); - res = -EINVAL; - goto out_up_free; - } - } - rc = scst_proc_rename_acg(acg, p); - break; - } - break; - case SCST_PROC_ACTION_ASSIGN: - rc = scst_proc_assign_handler(p); - break; - } - - if (rc != 0) - res = rc; - -out_up_free: - mutex_unlock(&scst_mutex); - -out_free_resume: - scst_resume_activity(); - -out_free: - free_page((unsigned long)buffer); - -out: - TRACE_EXIT_RES(res); - return res; -} - -/* The activity supposed to be suspended and scst_mutex held */ -static int scst_proc_assign_handler(char *buf) -{ - int res = 0; - char *p = buf, *e, *ee; - unsigned long host, channel = 0, id = 0, lun = 0; - struct scst_device *d, *dev = NULL; - struct scst_dev_type *dt, *handler = NULL; - - TRACE_ENTRY(); - - while (isspace(*p) && *p != '\0') - p++; - - host = simple_strtoul(p, &p, 0); - if ((host == ULONG_MAX) || (*p != ':')) - goto out_synt_err; - p++; - channel = simple_strtoul(p, &p, 0); - if ((channel == ULONG_MAX) || (*p != ':')) - goto out_synt_err; - p++; - id = simple_strtoul(p, &p, 0); - if ((channel == ULONG_MAX) || (*p != ':')) - goto out_synt_err; - p++; - lun = simple_strtoul(p, &p, 0); - if (lun == ULONG_MAX) - goto out_synt_err; - - e = p; - e++; - while (isspace(*e) && *e != '\0') - e++; - ee = e; - while (!isspace(*ee) && *ee != '\0') - ee++; - *ee = '\0'; - - TRACE_DBG("Dev %ld:%ld:%ld:%ld, handler %s", host, channel, id, lun, e); - - list_for_each_entry(d, &scst_dev_list, dev_list_entry) { - if ((d->virt_id == 0) && - d->scsi_dev->host->host_no == host && - d->scsi_dev->channel == channel && - d->scsi_dev->id == id && - d->scsi_dev->lun == lun) { - dev = d; - TRACE_DBG("Dev %p (%ld:%ld:%ld:%ld) found", - dev, host, channel, id, lun); - break; - } - } - - if (dev == NULL) { - PRINT_ERROR("Device %ld:%ld:%ld:%ld not found", - host, channel, id, lun); - res = -EINVAL; - goto out; - } - - list_for_each_entry(dt, &scst_dev_type_list, dev_type_list_entry) { - if (!strcmp(dt->name, e)) { - handler = dt; - TRACE_DBG("Dev handler %p with name %s found", - dt, dt->name); - break; - } - } - - if (handler == NULL) { - PRINT_ERROR("Handler %s not found", e); - res = -EINVAL; - goto out; - } - - if (dev->scsi_dev->type != handler->type) { - PRINT_ERROR("Type %d of device %s differs from type " - "%d of dev handler %s", dev->type, - dev->handler->name, handler->type, handler->name); - res = -EINVAL; - goto out; - } - - res = scst_assign_dev_handler(dev, handler); - -out: - TRACE_EXIT_RES(res); - return res; - -out_synt_err: - PRINT_ERROR("Syntax error on %s", p); - res = -EINVAL; - goto out; -} - -static ssize_t scst_proc_groups_devices_write(struct file *file, - const char __user *buf, - size_t length, loff_t *off) -{ - int res, action, rc, read_only = 0; - char *buffer, *p, *e = NULL; - unsigned int virt_lun; - struct scst_acg *acg = PDE_DATA(file_inode(file)); - struct scst_acg_dev *acg_dev = NULL, *acg_dev_tmp; - struct scst_device *d, *dev = NULL; - - TRACE_ENTRY(); - - if (length > SCST_PROC_BLOCK_SIZE) { - res = -EOVERFLOW; - goto out; - } - if (!buf) { - res = -EINVAL; - goto out; - } - buffer = (char *)__get_free_page(GFP_KERNEL); - if (!buffer) { - res = -ENOMEM; - goto out; - } - if (copy_from_user(buffer, buf, length)) { - res = -EFAULT; - goto out_free; - } - if (length < PAGE_SIZE) { - buffer[length] = '\0'; - } else if (buffer[PAGE_SIZE-1]) { - res = -EINVAL; - goto out_free; - } - - /* - * Usage: echo "add|del H:C:I:L lun [READ_ONLY]" \ - * >/proc/scsi_tgt/groups/GROUP_NAME/devices - * or echo "replace H:C:I:L lun [READ_ONLY]" \ - * >/proc/scsi_tgt/groups/GROUP_NAME/devices - * or echo "add|del V_NAME lun [READ_ONLY]" \ - * >/proc/scsi_tgt/groups/GROUP_NAME/devices - * or echo "replace V_NAME lun [READ_ONLY]" \ - * >/proc/scsi_tgt/groups/GROUP_NAME/devices - * or echo "clear" >/proc/scsi_tgt/groups/GROUP_NAME/devices - */ - p = buffer; - if (p[strlen(p) - 1] == '\n') - p[strlen(p) - 1] = '\0'; - if (!strncasecmp("clear", p, 5)) { - action = SCST_PROC_ACTION_CLEAR; - } else if (!strncasecmp("add ", p, 4)) { - p += 4; - action = SCST_PROC_ACTION_ADD; - } else if (!strncasecmp("del ", p, 4)) { - p += 4; - action = SCST_PROC_ACTION_DEL; - } else if (!strncasecmp("replace ", p, 8)) { - p += 8; - action = SCST_PROC_ACTION_REPLACE; - } else { - PRINT_ERROR("Unknown action \"%s\"", p); - res = -EINVAL; - goto out_free; - } - - res = scst_suspend_activity(SCST_SUSPEND_TIMEOUT_USER); - if (res != 0) - goto out_free; - - if (mutex_lock_interruptible(&scst_mutex) != 0) { - res = -EINTR; - goto out_free_resume; - } - - res = length; - - switch (action) { - case SCST_PROC_ACTION_ADD: - case SCST_PROC_ACTION_DEL: - case SCST_PROC_ACTION_REPLACE: - while (isspace(*p) && *p != '\0') - p++; - e = p; /* save p */ - while (!isspace(*e) && *e != '\0') - e++; - *e = 0; - - list_for_each_entry(d, &scst_dev_list, dev_list_entry) { - if (!strcmp(d->virt_name, p)) { - dev = d; - TRACE_DBG("Device %p (%s) found", dev, p); - break; - } - } - if (dev == NULL) { - PRINT_ERROR("Device %s not found", p); - res = -EINVAL; - goto out_free_up; - } - break; - } - - /* ToDo: create separate functions */ - - switch (action) { - case SCST_PROC_ACTION_ADD: - case SCST_PROC_ACTION_REPLACE: - { - bool dev_replaced = false; - - e++; - while (isspace(*e) && *e != '\0') - e++; - - virt_lun = simple_strtoul(e, &e, 0); - if (virt_lun > SCST_MAX_LUN) { - PRINT_ERROR("Too big LUN %d (max %d)", virt_lun, - SCST_MAX_LUN); - res = -EINVAL; - goto out_free_up; - } - - while (isspace(*e) && *e != '\0') - e++; - - if (*e != '\0') { - if (!strncasecmp("READ_ONLY", e, 9)) - read_only = 1; - else { - PRINT_ERROR("Unknown option \"%s\"", e); - res = -EINVAL; - goto out_free_up; - } - } - - list_for_each_entry(acg_dev_tmp, &acg->acg_dev_list, - acg_dev_list_entry) { - if (acg_dev_tmp->lun == virt_lun) { - acg_dev = acg_dev_tmp; - break; - } - } - if (acg_dev != NULL) { - if (action == SCST_PROC_ACTION_ADD) { - PRINT_ERROR("virt lun %d already exists in " - "group %s", virt_lun, acg->acg_name); - res = -EEXIST; - goto out_free_up; - } else { - /* Replace */ - rc = scst_acg_del_lun(acg, acg_dev->lun, - false); - if (rc) { - res = rc; - goto out_free_up; - } - dev_replaced = true; - } - } - - rc = scst_acg_add_lun(acg, NULL, dev, virt_lun, - read_only ? SCST_ADD_LUN_READ_ONLY : 0, - NULL); - if (rc) { - res = rc; - goto out_free_up; - } - - if (action == SCST_PROC_ACTION_ADD) - scst_report_luns_changed(acg); - - if (dev_replaced) { - struct scst_tgt_dev *tgt_dev; - - list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list, - dev_tgt_dev_list_entry) { - if ((tgt_dev->acg_dev->acg == acg) && - (tgt_dev->lun == virt_lun)) { - TRACE_MGMT_DBG("INQUIRY DATA HAS CHANGED" - " on tgt_dev %p", tgt_dev); - scst_gen_aen_or_ua(tgt_dev, - SCST_LOAD_SENSE(scst_sense_inquiry_data_changed)); - } - } - } - break; - } - case SCST_PROC_ACTION_DEL: - { - /* - * This code doesn't handle if there are >1 LUNs for the same - * device in the group. Instead, it always deletes the first - * entry. It wasn't fixed for compatibility reasons, because - * procfs is now obsoleted. - */ - struct scst_acg_dev *a; - - list_for_each_entry(a, &acg->acg_dev_list, acg_dev_list_entry) { - if (a->dev == dev) { - rc = scst_acg_del_lun(acg, a->lun, true); - if (rc) - res = rc; - goto out_free_up; - } - } - PRINT_ERROR("Device is not found in group %s", acg->acg_name); - break; - } - case SCST_PROC_ACTION_CLEAR: - list_for_each_entry_safe(acg_dev, acg_dev_tmp, - &acg->acg_dev_list, - acg_dev_list_entry) { - rc = scst_acg_del_lun(acg, acg_dev->lun, - list_is_last(&acg_dev->acg_dev_list_entry, - &acg->acg_dev_list)); - if (rc) { - res = rc; - goto out_free_up; - } - } - break; - } - -out_free_up: - mutex_unlock(&scst_mutex); - -out_free_resume: - scst_resume_activity(); - -out_free: - free_page((unsigned long)buffer); - -out: - TRACE_EXIT_RES(res); - return res; -} - -static ssize_t scst_proc_groups_names_write(struct file *file, - const char __user *buf, - size_t length, loff_t *off) -{ - int res = length, rc = 0, action; - char *buffer, *p, *pp = NULL; - struct scst_acg *acg = PDE_DATA(file_inode(file)); - struct scst_acn *n, *nn; - - TRACE_ENTRY(); - - if (length > SCST_PROC_BLOCK_SIZE) { - res = -EOVERFLOW; - goto out; - } - if (!buf) { - res = -EINVAL; - goto out; - } - buffer = (char *)__get_free_page(GFP_KERNEL); - if (!buffer) { - res = -ENOMEM; - goto out; - } - if (copy_from_user(buffer, buf, length)) { - res = -EFAULT; - goto out_free; - } - if (length < PAGE_SIZE) { - buffer[length] = '\0'; - } else if (buffer[PAGE_SIZE-1]) { - res = -EINVAL; - goto out_free; - } - - /* - * Usage: echo "add|del NAME" >/proc/scsi_tgt/groups/GROUP_NAME/names - * or echo "move NAME NEW_GROUP_NAME" >/proc/scsi_tgt/groups/OLD_GROUP_NAME/names" - * or echo "clear" >/proc/scsi_tgt/groups/GROUP_NAME/names - */ - p = buffer; - if (p[strlen(p) - 1] == '\n') - p[strlen(p) - 1] = '\0'; - if (!strncasecmp("clear", p, 5)) { - action = SCST_PROC_ACTION_CLEAR; - } else if (!strncasecmp("add ", p, 4)) { - p += 4; - action = SCST_PROC_ACTION_ADD; - } else if (!strncasecmp("del ", p, 4)) { - p += 4; - action = SCST_PROC_ACTION_DEL; - } else if (!strncasecmp("move ", p, 5)) { - p += 5; - action = SCST_PROC_ACTION_MOVE; - } else { - PRINT_ERROR("Unknown action \"%s\"", p); - res = -EINVAL; - goto out_free; - } - - switch (action) { - case SCST_PROC_ACTION_ADD: - case SCST_PROC_ACTION_DEL: - case SCST_PROC_ACTION_MOVE: - while (isspace(*p) && *p != '\0') - p++; - pp = p; - while (!isspace(*pp) && *pp != '\0') - pp++; - if (*pp != '\0') { - *pp = '\0'; - pp++; - while (isspace(*pp) && *pp != '\0') - pp++; - if (*pp != '\0') { - switch (action) { - case SCST_PROC_ACTION_ADD: - case SCST_PROC_ACTION_DEL: - PRINT_ERROR("%s", "Too many " - "arguments"); - res = -EINVAL; - goto out_free; - } - } - } - break; - } - - rc = scst_suspend_activity(SCST_SUSPEND_TIMEOUT_USER); - if (rc != 0) - goto out_free; - - if (mutex_lock_interruptible(&scst_mutex) != 0) { - res = -EINTR; - goto out_free_resume; - } - - switch (action) { - case SCST_PROC_ACTION_ADD: - rc = scst_acg_add_acn(acg, p); - break; - case SCST_PROC_ACTION_DEL: - rc = scst_acg_remove_name(acg, p, true); - break; - case SCST_PROC_ACTION_MOVE: - { - struct scst_acg *a, *new_acg = NULL; - char *name = p; - - p = pp; - while (!isspace(*pp) && *pp != '\0') - pp++; - if (*pp != '\0') { - *pp = '\0'; - pp++; - while (isspace(*pp) && *pp != '\0') - pp++; - if (*pp != '\0') { - PRINT_ERROR("%s", "Too many arguments"); - res = -EINVAL; - goto out_free_unlock; - } - } - list_for_each_entry(a, &scst_acg_list, acg_list_entry) { - if (strcmp(a->acg_name, p) == 0) { - TRACE_DBG("group (acg) %p %s found", - a, a->acg_name); - new_acg = a; - break; - } - } - if (new_acg == NULL) { - PRINT_ERROR("Group %s not found", p); - res = -EINVAL; - goto out_free_unlock; - } - rc = scst_acg_remove_name(acg, name, false); - if (rc != 0) - goto out_free_unlock; - rc = scst_acg_add_acn(new_acg, name); - if (rc != 0) - scst_acg_add_acn(acg, name); - break; - } - case SCST_PROC_ACTION_CLEAR: - list_for_each_entry_safe(n, nn, &acg->acn_list, - acn_list_entry) { - scst_del_free_acn(n, false); - } - scst_check_reassign_sessions(); - break; - } - -out_free_unlock: - mutex_unlock(&scst_mutex); - -out_free_resume: - scst_resume_activity(); - -out_free: - free_page((unsigned long)buffer); - -out: - if (rc < 0) - res = rc; - - TRACE_EXIT_RES(res); - return res; -} - -static int scst_version_info_show(struct seq_file *seq, void *v) -{ - TRACE_ENTRY(); - - seq_printf(seq, "%s\n", SCST_VERSION_STRING); - -#ifdef CONFIG_SCST_STRICT_SERIALIZING - seq_printf(seq, "STRICT_SERIALIZING\n"); -#endif - -#ifdef CONFIG_SCST_EXTRACHECKS - seq_printf(seq, "EXTRACHECKS\n"); -#endif - -#ifdef CONFIG_SCST_TRACING - seq_printf(seq, "TRACING\n"); -#endif - -#ifdef CONFIG_SCST_DEBUG - seq_printf(seq, "DEBUG\n"); -#endif - -#ifdef CONFIG_SCST_DEBUG_TM - seq_printf(seq, "DEBUG_TM\n"); -#endif - -#ifdef CONFIG_SCST_DEBUG_RETRY - seq_printf(seq, "DEBUG_RETRY\n"); -#endif - -#ifdef CONFIG_SCST_DEBUG_OOM - seq_printf(seq, "DEBUG_OOM\n"); -#endif - -#ifdef CONFIG_SCST_DEBUG_SN - seq_printf(seq, "DEBUG_SN\n"); -#endif - -#ifdef CONFIG_SCST_USE_EXPECTED_VALUES - seq_printf(seq, "USE_EXPECTED_VALUES\n"); -#endif - -#ifdef CONFIG_SCST_TEST_IO_IN_SIRQ - seq_printf(seq, "TEST_IO_IN_SIRQ\n"); -#endif - -#ifdef CONFIG_SCST_STRICT_SECURITY - seq_printf(seq, "STRICT_SECURITY\n"); -#endif - - TRACE_EXIT(); - return 0; -} - -static struct scst_proc_data scst_version_proc_data = { - SCST_DEF_RW_SEQ_OP(NULL) - .show = scst_version_info_show, -}; - -static int scst_help_info_show(struct seq_file *seq, void *v) -{ - TRACE_ENTRY(); - - seq_printf(seq, "%s\n", scst_proc_help_string); - - TRACE_EXIT(); - return 0; -} - -static struct scst_proc_data scst_help_proc_data = { - SCST_DEF_RW_SEQ_OP(NULL) - .show = scst_help_info_show, -}; - -static int scst_dev_handler_type_info_show(struct seq_file *seq, void *v) -{ - struct scst_dev_type *dev_type = (struct scst_dev_type *)seq->private; - - TRACE_ENTRY(); - - seq_printf(seq, "%d - %s\n", dev_type->type, - dev_type->type >= (int)ARRAY_SIZE(scst_proc_dev_handler_type) - ? "unknown" : scst_proc_dev_handler_type[dev_type->type]); - - TRACE_EXIT(); - return 0; -} - -static struct scst_proc_data scst_dev_handler_type_proc_data = { - SCST_DEF_RW_SEQ_OP(NULL) - .show = scst_dev_handler_type_info_show, -}; - -static int scst_sessions_info_show(struct seq_file *seq, void *v) -{ - int res = 0; - struct scst_acg *acg; - struct scst_session *sess; - - TRACE_ENTRY(); - - if (mutex_lock_interruptible(&scst_mutex) != 0) { - res = -EINTR; - goto out; - } - - seq_printf(seq, "%-20s %-45s %-35s %-15s\n", - "Target name", "Initiator name", - "Group name", "Active/All Commands Count"); - - list_for_each_entry(acg, &scst_acg_list, acg_list_entry) { - list_for_each_entry(sess, &acg->acg_sess_list, - acg_sess_list_entry) { - int active_cmds = 0, t; - - rcu_read_lock(); - for (t = SESS_TGT_DEV_LIST_HASH_SIZE-1; t >= 0; t--) { - struct list_head *head = - &sess->sess_tgt_dev_list[t]; - struct scst_tgt_dev *tgt_dev; - - list_for_each_entry_rcu(tgt_dev, head, - sess_tgt_dev_list_entry) { - active_cmds += atomic_read(&tgt_dev->tgt_dev_cmd_count); - } - } - rcu_read_unlock(); - - seq_printf(seq, "%-20s %-45s %-35s %d/%d\n", - sess->tgt->tgtt->name, - sess->initiator_name, - acg->acg_name, active_cmds, - atomic_read(&sess->sess_cmd_count)); - } - } - - mutex_unlock(&scst_mutex); - -out: - TRACE_EXIT_RES(res); - return res; -} - -static struct scst_proc_data scst_sessions_proc_data = { - SCST_DEF_RW_SEQ_OP(NULL) - .show = scst_sessions_info_show, -}; - -static struct scst_proc_data scst_sgv_proc_data = { - SCST_DEF_RW_SEQ_OP(NULL) - .show = sgv_procinfo_show, -}; - -static int scst_groups_names_show(struct seq_file *seq, void *v) -{ - int res = 0; - struct scst_acg *acg = (struct scst_acg *)seq->private; - struct scst_acn *name; - - TRACE_ENTRY(); - - if (mutex_lock_interruptible(&scst_mutex) != 0) { - res = -EINTR; - goto out; - } - - list_for_each_entry(name, &acg->acn_list, acn_list_entry) { - seq_printf(seq, "%s\n", name->name); - } - - mutex_unlock(&scst_mutex); - -out: - TRACE_EXIT_RES(res); - return res; -} - -static struct scst_proc_data scst_groups_names_proc_data = { - SCST_DEF_RW_SEQ_OP(scst_proc_groups_names_write) - .show = scst_groups_names_show, -}; - -static int scst_groups_addr_method_show(struct seq_file *seq, void *v) -{ - int res = 0; - struct scst_acg *acg = (struct scst_acg *)seq->private; - - TRACE_ENTRY(); - - if (mutex_lock_interruptible(&scst_mutex) != 0) { - res = -EINTR; - goto out; - } - - switch (acg->addr_method) { - case SCST_LUN_ADDR_METHOD_FLAT: - seq_printf(seq, "%s\n", "FLAT"); - break; - case SCST_LUN_ADDR_METHOD_PERIPHERAL: - seq_printf(seq, "%s\n", "PERIPHERAL"); - break; - case SCST_LUN_ADDR_METHOD_LUN: - seq_printf(seq, "%s\n", "LUN"); - break; - case SCST_LUN_ADDR_METHOD_EXTENDED_LUN: - default: - seq_printf(seq, "%s\n", "UNKNOWN"); - break; - } - - mutex_unlock(&scst_mutex); - -out: - TRACE_EXIT_RES(res); - return res; -} -static struct scst_proc_data scst_groups_addr_method_proc_data = { - SCST_DEF_RW_SEQ_OP(NULL) - .show = scst_groups_addr_method_show, -}; -static int scst_groups_devices_show(struct seq_file *seq, void *v) -{ - int res = 0; - struct scst_acg *acg = (struct scst_acg *)seq->private; - struct scst_acg_dev *acg_dev; - - TRACE_ENTRY(); - - if (mutex_lock_interruptible(&scst_mutex) != 0) { - res = -EINTR; - goto out; - } - - seq_printf(seq, "%-60s%-13s%s\n", "Device (host:ch:id:lun or name)", - "LUN", "Options"); - - list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) { - seq_printf(seq, "%-60s%-13lld%s\n", - acg_dev->dev->virt_name, - (unsigned long long)acg_dev->lun, - acg_dev->acg_dev_rd_only ? "RO" : ""); - } - mutex_unlock(&scst_mutex); - -out: - TRACE_EXIT_RES(res); - return res; -} - -static struct scst_proc_data scst_groups_devices_proc_data = { - SCST_DEF_RW_SEQ_OP(scst_proc_groups_devices_write) - .show = scst_groups_devices_show, -}; - -#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) - -static int scst_proc_read_tbl(const struct scst_trace_log *tbl, - struct seq_file *seq, - unsigned long log_level, int *first) -{ - const struct scst_trace_log *t = tbl; - int res = 0; - - while (t->token) { - if (log_level & t->val) { - seq_printf(seq, "%s%s", *first ? "" : " | ", t->token); - *first = 0; - } - t++; - } - return res; -} - -int scst_proc_log_entry_read(struct seq_file *seq, unsigned long log_level, - const struct scst_trace_log *tbl) -{ - int res = 0, first = 1; - - TRACE_ENTRY(); - - scst_proc_read_tbl(scst_proc_trace_tbl, seq, log_level, &first); - - if (tbl) - scst_proc_read_tbl(tbl, seq, log_level, &first); - - seq_printf(seq, "%s\n", first ? "none" : ""); - - TRACE_EXIT_RES(res); - return res; -} -EXPORT_SYMBOL_GPL(scst_proc_log_entry_read); - -static int log_info_show(struct seq_file *seq, void *v) -{ - int res; - - TRACE_ENTRY(); - - if (mutex_lock_interruptible(&scst_log_mutex) != 0) { - res = -EINTR; - goto out; - } - - res = scst_proc_log_entry_read(seq, trace_flag, - scst_proc_local_trace_tbl); - - mutex_unlock(&scst_log_mutex); - -out: - TRACE_EXIT_RES(res); - return res; -} - -static struct scst_proc_data scst_log_proc_data = { - SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_gen_write_log) - .show = log_info_show, - .data = "scsi_tgt", -}; - -#endif - -static int scst_tgt_info_show(struct seq_file *seq, void *v) -{ - int res = 0; - struct scst_device *dev; - - TRACE_ENTRY(); - - if (mutex_lock_interruptible(&scst_mutex) != 0) { - res = -EINTR; - goto out; - } - - seq_printf(seq, "%-60s%s\n", "Device (host:ch:id:lun or name)", - "Device handler"); - list_for_each_entry(dev, &scst_dev_list, dev_list_entry) { - seq_printf(seq, "%-60s%s\n", - dev->virt_name, dev->handler->name); - } - - mutex_unlock(&scst_mutex); - -out: - TRACE_EXIT_RES(res); - return res; -} - -static struct scst_proc_data scst_tgt_proc_data = { - SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_gen_write) - .show = scst_tgt_info_show, -}; - -static int scst_threads_info_show(struct seq_file *seq, void *v) -{ - TRACE_ENTRY(); - - seq_printf(seq, "%d\n", scst_main_cmd_threads.nr_threads); - - TRACE_EXIT(); - return 0; -} - -static struct scst_proc_data scst_threads_proc_data = { - SCST_DEF_RW_SEQ_OP(scst_proc_threads_write) - .show = scst_threads_info_show, -}; - -static int scst_scsi_tgtinfo_show(struct seq_file *seq, void *v) -{ - struct scst_tgt *vtt = seq->private; - int res = 0; - - TRACE_ENTRY(); - - if (mutex_lock_interruptible(&scst_proc_mutex) != 0) { - res = -EINTR; - goto out; - } - - if (vtt->tgtt->read_proc) - res = vtt->tgtt->read_proc(seq, vtt); - - mutex_unlock(&scst_proc_mutex); -out: - TRACE_EXIT_RES(res); - return res; -} - -static struct scst_proc_data scst_scsi_tgt_proc_data = { - SCST_DEF_RW_SEQ_OP(scst_proc_scsi_tgt_write) - .show = scst_scsi_tgtinfo_show, -}; - -static int scst_dev_handler_info_show(struct seq_file *seq, void *v) -{ - struct scst_dev_type *dev_type = seq->private; - int res = 0; - - TRACE_ENTRY(); - - if (mutex_lock_interruptible(&scst_proc_mutex) != 0) { - res = -EINTR; - goto out; - } - - if (dev_type->read_proc) - res = dev_type->read_proc(seq, dev_type); - - mutex_unlock(&scst_proc_mutex); - -out: - TRACE_EXIT_RES(res); - return res; -} - -static struct scst_proc_data scst_dev_handler_proc_data = { - SCST_DEF_RW_SEQ_OP(scst_proc_scsi_dev_handler_write) - .show = scst_dev_handler_info_show, -}; - -struct proc_dir_entry *scst_create_proc_entry(struct proc_dir_entry *root, - const char *name, struct scst_proc_data *pdata) -{ - struct proc_dir_entry *p = NULL; - - TRACE_ENTRY(); - - if (root) { - mode_t mode; - - mode = S_IFREG | S_IRUGO | (pdata->seq_op.write ? S_IWUSR : 0); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) - p = proc_create_data(name, mode, root, &pdata->seq_op, - pdata->data); -#else - /* - * See also "proc: introduce proc_create_data to setup de->data" - * (commit 59b7435149eab2dd06dd678742faff6049cb655f) and also - * "proc: Kill create_proc_entry()" - * (commit 80e928f7ebb958f4d79d4099d1c5c0a015a23b93). - */ - p = create_proc_entry(name, mode, root); - if (p) { - p->proc_fops = &pdata->seq_op; - p->data = pdata->data; - } -#endif - if (!p) - PRINT_ERROR("Fail to create entry %s in /proc", name); - } - - TRACE_EXIT(); - return p; -} -EXPORT_SYMBOL_GPL(scst_create_proc_entry); - -int scst_single_seq_open(struct inode *inode, struct file *file) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) \ - || defined(RHEL_MAJOR) && RHEL_MAJOR -0 >= 5 && RHEL_MINOR -0 >= 7 - struct scst_proc_data *pdata = container_of(PDE(inode)->proc_fops, - struct scst_proc_data, seq_op); -#else - struct scst_proc_data *pdata = container_of(inode->i_fop, - struct scst_proc_data, seq_op); -#endif - return single_open(file, pdata->show, PDE_DATA(inode)); -} -EXPORT_SYMBOL_GPL(scst_single_seq_open); - -struct proc_dir_entry *scst_proc_get_tgt_root( - struct scst_tgt_template *vtt) -{ - return vtt->proc_tgt_root; -} -EXPORT_SYMBOL_GPL(scst_proc_get_tgt_root); - -struct proc_dir_entry *scst_proc_get_dev_type_root( - struct scst_dev_type *dtt) -{ - return dtt->proc_dev_type_root; -} -EXPORT_SYMBOL_GPL(scst_proc_get_dev_type_root);