/proc implementation moved to seq_*() library. Mostly done by Ming Zhang.

git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@57 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2006-12-14 17:08:46 +00:00
parent f375c2e756
commit f1e2c33ac7
7 changed files with 992 additions and 1334 deletions
+1 -1
View File
@@ -287,7 +287,7 @@ static struct scst_tgt_template tgt_template = {
.rdy_to_xfer = mpt_rdy_to_xfer,
.on_free_cmd = mpt_on_free_cmd,
.task_mgmt_fn_done = mpt_task_mgmt_fn_done,
.proc_info = mpt_proc_info,
//ToDo: .proc_info = mpt_proc_info,
};
static inline void
+34 -32
View File
@@ -28,7 +28,7 @@
#include <scsi/scsi_host.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/seq_file.h>
#include <linux/list.h>
#include <scsi_tgt.h>
@@ -2054,36 +2054,40 @@ out:
#include <linux/proc_fs.h>
static int qla2x00t_proc_log_entry_read(char *buffer, char **start,
off_t offset, int length, int *eof,
void *data)
{
int res = 0;
TRACE_ENTRY();
res = scst_proc_log_entry_read(buffer, start, offset, length, eof,
data, trace_flag, NULL);
TRACE_EXIT_RES(res);
return res;
}
static int qla2x00t_proc_log_entry_write(struct file *file, const char *buf,
unsigned long length, void *data)
static int q2t_log_info_show(struct seq_file *seq, void *v)
{
int res = 0;
TRACE_ENTRY();
res = scst_proc_log_entry_write(file, buf, length, data,
&trace_flag, SCST_DEFAULT_QLA_LOG_FLAGS, NULL);
res = scst_proc_log_entry_read(seq, trace_flag, NULL);
TRACE_EXIT_RES(res);
return res;
}
static int q2t_proc_log_entry_write(struct file *file, const char __user *buf,
size_t length, loff_t *off)
{
int res = 0;
TRACE_ENTRY();
res = scst_proc_log_entry_write(file, buf, length, &trace_flag,
SCST_DEFAULT_QLA_LOG_FLAGS, NULL);
TRACE_EXIT_RES(res);
return res;
}
static struct scst_proc_data q2t_log_proc_data = {
SCST_DEF_RW_SEQ_OP(q2t_proc_log_entry_write)
.show = q2t_log_info_show,
};
#endif
static int qla2x00t_proc_log_entry_build(struct scst_tgt_template *templ)
static int q2t_proc_log_entry_build(struct scst_tgt_template *templ)
{
int res = 0;
#if defined(DEBUG) || defined(TRACING)
@@ -2094,10 +2098,9 @@ static int qla2x00t_proc_log_entry_build(struct scst_tgt_template *templ)
if (root) {
/* create the proc file entry for the device */
p = create_proc_read_entry(Q2T_PROC_LOG_ENTRY_NAME,
S_IFREG | S_IRUGO | S_IWUSR, root,
qla2x00t_proc_log_entry_read,
(void *)templ->name);
q2t_log_proc_data.data = (void *)templ->name;
p = scst_create_proc_entry(root, Q2T_PROC_LOG_ENTRY_NAME,
&q2t_log_proc_data);
if (p == NULL) {
PRINT_ERROR("Not enough memory to register "
"target driver %s entry %s in /proc",
@@ -2105,7 +2108,6 @@ static int qla2x00t_proc_log_entry_build(struct scst_tgt_template *templ)
res = -ENOMEM;
goto out;
}
p->write_proc = qla2x00t_proc_log_entry_write;
}
out:
@@ -2115,7 +2117,7 @@ out:
return res;
}
static void qla2x00t_proc_log_entry_clean(struct scst_tgt_template *templ)
static void q2t_proc_log_entry_clean(struct scst_tgt_template *templ)
{
#if defined(DEBUG) || defined(TRACING)
struct proc_dir_entry *root;
@@ -2131,7 +2133,7 @@ static void qla2x00t_proc_log_entry_clean(struct scst_tgt_template *templ)
#endif
}
static int __init qla2x00t_init(void)
static int __init q2t_init(void)
{
int res = 0;
@@ -2154,7 +2156,7 @@ static int __init qla2x00t_init(void)
* called via scst_register_target_template()
*/
res = qla2x00t_proc_log_entry_build(&tgt_template);
res = q2t_proc_log_entry_build(&tgt_template);
if (res < 0) {
goto out_unreg_target;
}
@@ -2169,11 +2171,11 @@ out_unreg_target:
goto out;
}
static void __exit qla2x00t_exit(void)
static void __exit q2t_exit(void)
{
TRACE_ENTRY();
qla2x00t_proc_log_entry_clean(&tgt_template);
q2t_proc_log_entry_clean(&tgt_template);
scst_unregister_target_template(&tgt_template);
@@ -2185,8 +2187,8 @@ static void __exit qla2x00t_exit(void)
return;
}
module_init(qla2x00t_init);
module_exit(qla2x00t_exit);
module_init(q2t_init);
module_exit(q2t_exit);
MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar & Nathaniel Clark");
MODULE_DESCRIPTION("Target mode logic for qla2xxx");
+45 -16
View File
@@ -24,10 +24,15 @@
#include <linux/version.h>
#include <linux/blkdev.h>
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#ifdef SCST_HIGHMEM
#include <asm/kmap_types.h>
#endif
#include <../drivers/scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi.h>
/* Version numbers, the same as for the kernel */
#define SCST_VERSION_CODE 0x000906
@@ -694,14 +699,15 @@ struct scst_tgt_template
*/
int (*report_aen) (int mgmt_fn, const uint8_t *lun, int lun_len);
/*
* This function can be used to export the driver's statistics and
* other infos to the world outside the kernel.
/*
* Those functions can be used to export the driver's statistics and
* other infos to the world outside the kernel.
*
* OPTIONAL
*/
int (*proc_info) (char *buffer, char **start, off_t offset,
int length, int *eof, struct scst_tgt *tgt, int inout);
int (*read_proc) (struct seq_file *seq, struct scst_tgt *tgt);
int (*write_proc) (char *buffer, char **start, off_t offset,
int length, int *eof, struct scst_tgt *tgt);
/*
* Name of the template. Must be unique to identify
@@ -836,15 +842,15 @@ struct scst_dev_type
int (*task_mgmt_fn) (struct scst_mgmt_cmd *mgmt_cmd,
struct scst_tgt_dev *tgt_dev);
/*
* This function can be used to export the handler's statistics and
* other infos to the world outside the kernel.
/*
* Those functions can be used to export the handler's statistics and
* other infos to the world outside the kernel.
*
* OPTIONAL
*/
int (*proc_info) (char *buffer, char **start, off_t offset,
int length, int *eof, struct scst_dev_type *dev_type,
int inout);
int (*read_proc) (struct seq_file *seq, struct scst_dev_type *dev_type);
int (*write_proc) (char *buffer, char **start, off_t offset,
int length, int *eof, struct scst_dev_type *dev_type);
struct module *module;
@@ -2149,14 +2155,37 @@ struct scst_proc_log {
const char *token;
};
int scst_proc_log_entry_read(char *buffer, char **start,
off_t offset, int length, int *eof, void *data,
unsigned long log_level, const struct scst_proc_log *tbl);
int scst_proc_log_entry_read(struct seq_file *seq, unsigned long log_level,
const struct scst_proc_log *tbl);
int scst_proc_log_entry_write(struct file *file, const char *buf,
unsigned long length, void *data, unsigned long *log_level,
unsigned long length, unsigned long *log_level,
unsigned long default_level, const struct scst_proc_log *tbl);
/*
* helper data structure and function to create proc entry.
*/
struct scst_proc_data {
struct file_operations seq_op;
int (*show)(struct seq_file *, void *);
void *data;
};
int scst_single_seq_open(struct inode *inode, struct file *file);
struct proc_dir_entry *scst_create_proc_entry(struct proc_dir_entry * root,
const char *name, struct scst_proc_data *pdata);
#define SCST_DEF_RW_SEQ_OP(x) \
.seq_op = { \
.owner = THIS_MODULE, \
.open = scst_single_seq_open,\
.read = seq_read, \
.write = x, \
.llseek = seq_lseek, \
.release = single_release, \
},
/*
* Adds and deletes (stops) num SCST's threads. Returns 0 on success,
* error code otherwise.
+18 -13
View File
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#ifdef DEBUG
#define SCST_DEFAULT_DEV_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_PID | \
@@ -17,28 +18,28 @@
#define SCST_DEFAULT_DEV_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MINOR)
#endif
static int scst_dev_handler_proc_log_entry_read(char *buffer, char **start,
off_t offset, int length, int *eof, void *data)
static struct scst_proc_data dev_handler_log_proc_data;
static int dev_handler_log_info_show(struct seq_file *seq, void *v)
{
int res = 0;
TRACE_ENTRY();
res = scst_proc_log_entry_read(buffer, start, offset, length, eof,
data, trace_flag, NULL);
res = scst_proc_log_entry_read(seq, trace_flag, NULL);
TRACE_EXIT_RES(res);
return res;
}
static int scst_dev_handler_proc_log_entry_write(struct file *file,
const char *buf, unsigned long length, void *data)
static int scst_dev_handler_proc_log_entry_write(struct file *file, const char __user *buf,
size_t length, loff_t *off)
{
int res = 0;
TRACE_ENTRY();
res = scst_proc_log_entry_write(file, buf, length, data,
&trace_flag, SCST_DEFAULT_DEV_LOG_FLAGS, NULL);
res = scst_proc_log_entry_write(file, buf, length, &trace_flag,
SCST_DEFAULT_DEV_LOG_FLAGS, NULL);
TRACE_EXIT_RES(res);
return res;
@@ -57,10 +58,9 @@ static int scst_dev_handler_build_std_proc(struct scst_dev_type *dev_type)
if (root) {
/* create the proc file entry for the device */
p = create_proc_read_entry(DEV_HANDLER_LOG_ENTRY_NAME,
S_IFREG | S_IRUGO | S_IWUSR, root,
scst_dev_handler_proc_log_entry_read,
(void *)dev_type->name);
dev_handler_log_proc_data.data = (void *)dev_type->name;
p = scst_create_proc_entry(root, DEV_HANDLER_LOG_ENTRY_NAME,
&dev_handler_log_proc_data);
if (p == NULL) {
PRINT_ERROR_PR("Not enough memory to register dev "
"handler %s entry %s in /proc",
@@ -68,7 +68,6 @@ static int scst_dev_handler_build_std_proc(struct scst_dev_type *dev_type)
res = -ENOMEM;
goto out;
}
p->write_proc = scst_dev_handler_proc_log_entry_write;
}
out:
@@ -93,3 +92,9 @@ static void scst_dev_handler_destroy_std_proc(struct scst_dev_type *dev_type)
#endif
}
#if defined(DEBUG) || defined(TRACING)
static struct scst_proc_data dev_handler_log_proc_data = {
SCST_DEF_RW_SEQ_OP(scst_dev_handler_proc_log_entry_write)
.show = dev_handler_log_info_show,
};
#endif
+359 -437
View File
@@ -141,12 +141,12 @@ static void fileio_exec_read_toc(struct scst_cmd *cmd);
static void fileio_exec_prevent_allow_medium_removal(struct scst_cmd *cmd);
static int fileio_fsync(struct scst_fileio_tgt_dev *ftgt_dev,
loff_t loff, loff_t len, struct scst_cmd *cmd);
static int disk_fileio_proc(char *buffer, char **start, off_t offset,
int length, int *eof, struct scst_dev_type *dev_type, int inout);
static int cdrom_fileio_proc(char *buffer, char **start, off_t offset,
int length, int *eof, struct scst_dev_type *dev_type, int inout);
static int fileio_proc_help_read(char *buffer, char **start,off_t offset,
int length, int *eof, void *data);
static int disk_fileio_read_proc(struct seq_file *seq, struct scst_dev_type *dev_type);
static int disk_fileio_write_proc(char *buffer, char **start, off_t offset,
int length, int *eof, struct scst_dev_type *dev_type);
static int cdrom_fileio_read_proc(struct seq_file *seq, struct scst_dev_type *dev_type);
static int cdrom_fileio_write_proc(char *buffer, char **start, off_t offset,
int length, int *eof, struct scst_dev_type *dev_type);
#define DISK_TYPE_FILEIO { \
name: DISK_FILEIO_NAME, \
@@ -161,7 +161,8 @@ static int fileio_proc_help_read(char *buffer, char **start,off_t offset,
parse: disk_fileio_parse, \
exec: disk_fileio_exec, \
task_mgmt_fn: fileio_task_mgmt_fn, \
proc_info: disk_fileio_proc, \
read_proc: disk_fileio_read_proc, \
write_proc: disk_fileio_write_proc, \
}
#define CDROM_TYPE_FILEIO { \
@@ -177,7 +178,8 @@ static int fileio_proc_help_read(char *buffer, char **start,off_t offset,
parse: cdrom_fileio_parse, \
exec: cdrom_fileio_exec, \
task_mgmt_fn: fileio_task_mgmt_fn, \
proc_info: cdrom_fileio_proc, \
read_proc: cdrom_fileio_read_proc, \
write_proc: cdrom_fileio_write_proc,\
}
DECLARE_MUTEX(scst_fileio_mutex);
@@ -2262,349 +2264,285 @@ out:
return dev;
}
struct fileio_proc_update_struct {
int len, plen, pplen;
off_t begin, pbegin, ppbegin;
off_t pos;
};
static int fileio_proc_update_size(int size, off_t offset, int length,
struct fileio_proc_update_struct *p, int is_start)
{
int res = 0;
if (size > 0) {
p->len += size;
p->pos = p->begin + p->len;
if (p->pos <= offset) {
p->len = 0;
p->begin = p->pos;
} else if (p->pos >= offset + length) {
res = 1;
goto out;
} else
res = 0;
} else {
p->begin = p->ppbegin;
p->len = p->pplen;
res = 1;
goto out;
}
if (is_start) {
p->ppbegin = p->pbegin;
p->pplen = p->plen;
p->pbegin = p->begin;
p->plen = p->len;
}
out:
return res;
}
/*
* Called when a file in the /proc/DISK_FILEIO_NAME/DISK_FILEIO_NAME is read
* or written
*/
static int disk_fileio_proc(char *buffer, char **start, off_t offset,
int length, int *eof, struct scst_dev_type *dev_type, int inout)
static int disk_fileio_read_proc(struct seq_file *seq, struct scst_dev_type *dev_type)
{
int res = 0, action;
char *p, *name, *file_name;
struct scst_fileio_dev *virt_dev, *vv;
int size;
struct fileio_proc_update_struct pu;
int res = 0;
struct scst_fileio_dev *virt_dev;
TRACE_ENTRY();
memset(&pu, 0, sizeof(pu));
/* VERY UGLY code. You can rewrite it if you want */
if (down_interruptible(&scst_fileio_mutex) != 0) {
res = -EINTR;
goto out;
}
if (inout == 0) { /* read */
size = scnprintf(buffer, length, "%-17s %-11s %-11s %-15s %s\n",
"Name", "Size(MB)", "Block size", "Options", "File name");
if (fileio_proc_update_size(size, offset, length, &pu, 1))
goto stop_output;
seq_printf(seq, "%-17s %-11s %-11s %-15s %s\n",
"Name", "Size(MB)", "Block size", "Options", "File name");
list_for_each_entry(virt_dev, &disk_fileio_dev_list,
fileio_dev_list_entry)
list_for_each_entry(virt_dev, &disk_fileio_dev_list, fileio_dev_list_entry) {
int c;
seq_printf(seq, "%-17s %-11d %-12d", virt_dev->name,
(uint32_t)(virt_dev->file_size >> 20),
virt_dev->block_size);
c = 0;
if (virt_dev->wt_flag) {
seq_printf(seq, "WT ");
c += 3;
}
if (virt_dev->nv_cache) {
seq_printf(seq, "NV ");
c += 3;
}
if (virt_dev->rd_only_flag) {
seq_printf(seq, "RO ");
c += 3;
}
if (virt_dev->o_direct_flag) {
seq_printf(seq, "DR ");
c += 3;
}
if (virt_dev->nullio) {
seq_printf(seq, "NIO ");
c += 4;
}
while (c < 16) {
seq_printf(seq, " ");
c++;
}
seq_printf(seq, "%s\n", virt_dev->file_name);
}
up(&scst_fileio_mutex);
out:
TRACE_EXIT_RES(res);
return res;
}
/*
* Called when a file in the /proc/DISK_FILEIO_NAME/DISK_FILEIO_NAME is written
*/
static int disk_fileio_write_proc(char *buffer, char **start, off_t offset,
int length, int *eof, struct scst_dev_type *dev_type)
{
int res = 0, action;
char *p, *name, *file_name;
struct scst_fileio_dev *virt_dev, *vv;
uint32_t block_size = DEF_DISK_BLOCKSIZE;
int block_shift = DEF_DISK_BLOCKSIZE_SHIFT;
size_t len;
TRACE_ENTRY();
/* VERY UGLY code. You can rewrite it if you want */
if (buffer[0] == '\0')
goto out;
if (down_interruptible(&scst_fileio_mutex) != 0) {
res = -EINTR;
goto out;
}
p = buffer;
if (p[strlen(p) - 1] == '\n') {
p[strlen(p) - 1] = '\0';
}
if (!strncmp("close ", p, 6)) {
p += 6;
action = 0;
} else if (!strncmp("open ", p, 5)) {
p += 5;
action = 2;
} else {
PRINT_ERROR_PR("Unknown action \"%s\"", p);
res = -EINVAL;
goto out_up;
}
while (isspace(*p) && *p != '\0')
p++;
name = p;
while (!isspace(*p) && *p != '\0')
p++;
*p++ = '\0';
if (*name == '\0') {
PRINT_ERROR_PR("%s", "Name required");
res = -EINVAL;
goto out_up;
} else if (strlen(name) >= sizeof(virt_dev->name)) {
PRINT_ERROR_PR("Name is too long (max %zd "
"characters)", sizeof(virt_dev->name)-1);
res = -EINVAL;
goto out_up;
}
if (action) { /* open */
virt_dev = NULL;
list_for_each_entry(vv, &disk_fileio_dev_list,
fileio_dev_list_entry)
{
int c;
size = scnprintf(buffer + pu.len, length - pu.len,
"%-17s %-11d %-12d", virt_dev->name,
(uint32_t)(virt_dev->file_size >> 20),
virt_dev->block_size);
if (fileio_proc_update_size(size, offset, length, &pu,
1)) {
goto stop_output;
}
c = 0;
if (virt_dev->wt_flag) {
size = scnprintf(buffer + pu.len, length - pu.len, "WT");
c += size;
if (fileio_proc_update_size(size, offset,
length, &pu, 0)) {
goto stop_output;
}
}
if (virt_dev->nv_cache) {
size = scnprintf(buffer + pu.len, length - pu.len,
c ? ",NV" : "NV");
c += size;
if (fileio_proc_update_size(size, offset,
length, &pu, 0)) {
goto stop_output;
}
}
if (virt_dev->rd_only_flag) {
size = scnprintf(buffer + pu.len, length - pu.len,
c ? ",RO" : "RO");
c += size;
if (fileio_proc_update_size(size, offset,
length, &pu, 0)) {
goto stop_output;
}
}
if (virt_dev->o_direct_flag) {
size = scnprintf(buffer + pu.len, length - pu.len,
c ? ",DR" : "DR");
c += size;
if (fileio_proc_update_size(size, offset,
length, &pu, 0)) {
goto stop_output;
}
}
if (virt_dev->nullio) {
size = scnprintf(buffer + pu.len, length - pu.len,
c ? ",NIO" : "NIO");
c += size;
if (fileio_proc_update_size(size, offset,
length, &pu, 0)) {
goto stop_output;
}
}
while (c < 16) {
size = scnprintf(buffer + pu.len, length - pu.len, " ");
if (fileio_proc_update_size(size, offset,
length, &pu, 0)) {
goto stop_output;
}
c++;
}
size = scnprintf(buffer + pu.len, length - pu.len, "%s\n",
virt_dev->file_name);
if (fileio_proc_update_size(size, offset, length, &pu,
0)) {
goto stop_output;
if (strcmp(vv->name, name) == 0) {
virt_dev = vv;
break;
}
}
*eof = 1;
goto stop_output;
} else { /* write */
uint32_t block_size = DEF_DISK_BLOCKSIZE;
int block_shift = DEF_DISK_BLOCKSIZE_SHIFT;
p = buffer;
if (p[strlen(p) - 1] == '\n') {
p[strlen(p) - 1] = '\0';
}
if (!strncmp("close ", p, 6)) {
p += 6;
action = 0;
} else if (!strncmp("open ", p, 5)) {
p += 5;
action = 2;
} else {
PRINT_ERROR_PR("Unknown action \"%s\"", p);
if (virt_dev) {
PRINT_ERROR_PR("Virtual device with name "
"%s already exist", name);
res = -EINVAL;
goto out_up;
}
while (isspace(*p) && *p != '\0')
p++;
name = p;
file_name = p;
while (!isspace(*p) && *p != '\0')
p++;
*p++ = '\0';
if (*name == '\0') {
PRINT_ERROR_PR("%s", "Name required");
if (*file_name == '\0') {
PRINT_ERROR_PR("%s", "File name required");
res = -EINVAL;
goto out_up;
} else if (strlen(name) >= sizeof(virt_dev->name)) {
PRINT_ERROR_PR("Name is too long (max %zd "
"characters)", sizeof(virt_dev->name)-1);
} else if (*file_name != '/') {
PRINT_ERROR_PR("File path \"%s\" is not "
"absolute", file_name);
res = -EINVAL;
goto out_up;
}
if (action) { /* open */
virt_dev = NULL;
list_for_each_entry(vv, &disk_fileio_dev_list,
fileio_dev_list_entry)
{
if (strcmp(vv->name, name) == 0) {
virt_dev = vv;
break;
}
}
if (virt_dev) {
PRINT_ERROR_PR("Virtual device with name "
"%s already exist", name);
virt_dev = fileio_alloc_dev();
if (virt_dev == NULL) {
TRACE(TRACE_OUT_OF_MEM, "%s",
"Allocation of virt_dev failed");
res = -ENOMEM;
goto out_up;
}
while (isspace(*p) && *p != '\0')
p++;
if (isdigit(*p)) {
char *pp;
uint32_t t;
block_size = simple_strtoul(p, &pp, 0);
p = pp;
if ((*p != '\0') && !isspace(*p)) {
PRINT_ERROR_PR("Parse error: \"%s\"", p);
res = -EINVAL;
goto out_up;
}
while (isspace(*p) && *p != '\0')
p++;
file_name = p;
while (!isspace(*p) && *p != '\0')
p++;
*p++ = '\0';
if (*file_name == '\0') {
PRINT_ERROR_PR("%s", "File name required");
res = -EINVAL;
goto out_up;
} else if (*file_name != '/') {
PRINT_ERROR_PR("File path \"%s\" is not "
"absolute", file_name);
res = -EINVAL;
goto out_up;
}
virt_dev = fileio_alloc_dev();
if (virt_dev == NULL) {
TRACE(TRACE_OUT_OF_MEM, "%s",
"Allocation of virt_dev failed");
res = -ENOMEM;
goto out_up;
}
while (isspace(*p) && *p != '\0')
p++;
if (isdigit(*p)) {
char *pp;
uint32_t t;
block_size = simple_strtoul(p, &pp, 0);
p = pp;
if ((*p != '\0') && !isspace(*p)) {
PRINT_ERROR_PR("Parse error: \"%s\"", p);
res = -EINVAL;
goto out_free_vdev;
}
while (isspace(*p) && *p != '\0')
p++;
t = block_size;
block_shift = 0;
while(1) {
if ((t & 1) != 0)
break;
t >>= 1;
block_shift++;
}
if (block_shift < 9) {
PRINT_ERROR_PR("Wrong block size %d",
block_size);
res = -EINVAL;
goto out_free_vdev;
}
}
virt_dev->block_size = block_size;
virt_dev->block_shift = block_shift;
while (*p != '\0') {
if (!strncmp("WRITE_THROUGH", p, 13)) {
p += 13;
virt_dev->wt_flag = 1;
TRACE_DBG("%s", "WRITE_THROUGH");
} else if (!strncmp("NV_CACHE", p, 8)) {
p += 8;
virt_dev->nv_cache = 1;
TRACE_DBG("%s", "NON-VOLATILE CACHE");
} else if (!strncmp("READ_ONLY", p, 9)) {
p += 9;
virt_dev->rd_only_flag = 1;
TRACE_DBG("%s", "READ_ONLY");
} else if (!strncmp("O_DIRECT", p, 8)) {
p += 8;
#if 0
virt_dev->o_direct_flag = 1;
TRACE_DBG("%s", "O_DIRECT");
#else
PRINT_INFO_PR("%s flag doesn't currently"
" work, ignoring it", "O_DIRECT");
#endif
} else if (!strncmp("NULLIO", p, 6)) {
p += 6;
virt_dev->nullio = 1;
TRACE_DBG("%s", "NULLIO");
} else {
PRINT_ERROR_PR("Unknown flag \"%s\"", p);
res = -EINVAL;
goto out_free_vdev;
}
while (isspace(*p) && *p != '\0')
p++;
}
strcpy(virt_dev->name, name);
pu.len = strlen(file_name) + 1;
virt_dev->file_name = kmalloc(pu.len, GFP_KERNEL);
if (virt_dev->file_name == NULL) {
TRACE(TRACE_OUT_OF_MEM, "%s",
"Allocation of file_name failed");
res = -ENOMEM;
goto out_free_vdev;
}
strncpy(virt_dev->file_name, file_name, pu.len);
while (isspace(*p) && *p != '\0')
p++;
list_add_tail(&virt_dev->fileio_dev_list_entry,
&disk_fileio_dev_list);
virt_dev->virt_id =
scst_register_virtual_device(&disk_devtype_fileio,
virt_dev->name);
if (virt_dev->virt_id < 0) {
res = virt_dev->virt_id;
goto out_free_vpath;
}
TRACE_DBG("Added virt_dev (name %s, file name %s, "
"id %d, block size %d) to "
"disk_fileio_dev_list", virt_dev->name,
virt_dev->file_name, virt_dev->virt_id,
virt_dev->block_size);
} else { /* close */
virt_dev = NULL;
list_for_each_entry(vv, &disk_fileio_dev_list,
fileio_dev_list_entry)
{
if (strcmp(vv->name, name) == 0) {
virt_dev = vv;
t = block_size;
block_shift = 0;
while(1) {
if ((t & 1) != 0)
break;
}
t >>= 1;
block_shift++;
}
if (virt_dev == NULL) {
PRINT_ERROR_PR("Device %s not found", name);
if (block_shift < 9) {
PRINT_ERROR_PR("Wrong block size %d",
block_size);
res = -EINVAL;
goto out_up;
goto out_free_vdev;
}
scst_unregister_virtual_device(virt_dev->virt_id);
PRINT_INFO_PR("Virtual device %s unregistered",
virt_dev->name);
TRACE_DBG("virt_id %d unregister", virt_dev->virt_id);
list_del(&virt_dev->fileio_dev_list_entry);
kfree(virt_dev->file_name);
kfree(virt_dev);
}
res = length;
virt_dev->block_size = block_size;
virt_dev->block_shift = block_shift;
while (*p != '\0') {
if (!strncmp("WRITE_THROUGH", p, 13)) {
p += 13;
virt_dev->wt_flag = 1;
TRACE_DBG("%s", "WRITE_THROUGH");
} else if (!strncmp("NV_CACHE", p, 8)) {
p += 8;
virt_dev->nv_cache = 1;
TRACE_DBG("%s", "NON-VOLATILE CACHE");
} else if (!strncmp("READ_ONLY", p, 9)) {
p += 9;
virt_dev->rd_only_flag = 1;
TRACE_DBG("%s", "READ_ONLY");
} else if (!strncmp("O_DIRECT", p, 8)) {
p += 8;
#if 0
virt_dev->o_direct_flag = 1;
TRACE_DBG("%s", "O_DIRECT");
#else
PRINT_INFO_PR("%s flag doesn't currently"
" work, ignoring it", "O_DIRECT");
#endif
} else if (!strncmp("NULLIO", p, 6)) {
p += 6;
virt_dev->nullio = 1;
TRACE_DBG("%s", "NULLIO");
} else {
PRINT_ERROR_PR("Unknown flag \"%s\"", p);
res = -EINVAL;
goto out_free_vdev;
}
while (isspace(*p) && *p != '\0')
p++;
}
strcpy(virt_dev->name, name);
len = strlen(file_name) + 1;
virt_dev->file_name = kmalloc(len, GFP_KERNEL);
if (virt_dev->file_name == NULL) {
TRACE(TRACE_OUT_OF_MEM, "%s",
"Allocation of file_name failed");
res = -ENOMEM;
goto out_free_vdev;
}
strncpy(virt_dev->file_name, file_name, len);
list_add_tail(&virt_dev->fileio_dev_list_entry,
&disk_fileio_dev_list);
virt_dev->virt_id =
scst_register_virtual_device(&disk_devtype_fileio,
virt_dev->name);
if (virt_dev->virt_id < 0) {
res = virt_dev->virt_id;
goto out_free_vpath;
}
TRACE_DBG("Added virt_dev (name %s, file name %s, "
"id %d, block size %d) to "
"disk_fileio_dev_list", virt_dev->name,
virt_dev->file_name, virt_dev->virt_id,
virt_dev->block_size);
} else { /* close */
virt_dev = NULL;
list_for_each_entry(vv, &disk_fileio_dev_list,
fileio_dev_list_entry)
{
if (strcmp(vv->name, name) == 0) {
virt_dev = vv;
break;
}
}
if (virt_dev == NULL) {
PRINT_ERROR_PR("Device %s not found", name);
res = -EINVAL;
goto out_up;
}
scst_unregister_virtual_device(virt_dev->virt_id);
PRINT_INFO_PR("Virtual device %s unregistered",
virt_dev->name);
TRACE_DBG("virt_id %d unregister", virt_dev->virt_id);
list_del(&virt_dev->fileio_dev_list_entry);
kfree(virt_dev->file_name);
kfree(virt_dev);
}
res = length;
out_up:
up(&scst_fileio_mutex);
@@ -2613,14 +2551,6 @@ out:
TRACE_EXIT_RES(res);
return res;
stop_output:
*start = buffer + (offset - pu.begin);
pu.len -= (offset - pu.begin);
if (pu.len > length)
pu.len = length;
res = max(0, pu.len);
goto out_up;
out_free_vpath:
list_del(&virt_dev->fileio_dev_list_entry);
kfree(virt_dev->file_name);
@@ -2630,6 +2560,7 @@ out_free_vdev:
goto out_up;
}
/* scst_fileio_mutex supposed to be held */
static int cdrom_fileio_open(char *p, char *name)
{
@@ -2640,8 +2571,7 @@ static int cdrom_fileio_open(char *p, char *name)
int cdrom_empty;
virt_dev = NULL;
list_for_each_entry(vv, &cdrom_fileio_dev_list,
fileio_dev_list_entry)
list_for_each_entry(vv, &cdrom_fileio_dev_list, fileio_dev_list_entry)
{
if (strcmp(vv->name, name) == 0) {
virt_dev = vv;
@@ -2932,115 +2862,128 @@ out_err_resume:
/*
* Called when a file in the /proc/CDROM_FILEIO_NAME/CDROM_FILEIO_NAME is read
* or written
*/
static int cdrom_fileio_proc(char *buffer, char **start, off_t offset,
int length, int *eof, struct scst_dev_type *dev_type, int inout)
static int cdrom_fileio_read_proc(struct seq_file *seq, struct scst_dev_type *dev_type)
{
int res = 0, action;
char *p, *name;
int res = 0;
struct scst_fileio_dev *virt_dev;
int size;
struct fileio_proc_update_struct pu;
TRACE_ENTRY();
memset(&pu, 0, sizeof(pu));
if (down_interruptible(&scst_fileio_mutex) != 0) {
res = -EINTR;
goto out;
}
if (inout == 0) { /* read */
size = scnprintf(buffer, length, "%-17s %-9s %s\n",
"Name", "Size(MB)", "File name");
if (fileio_proc_update_size(size, offset, length, &pu, 1))
goto stop_output;
seq_printf(seq, "%-17s %-9s %s\n", "Name", "Size(MB)", "File name");
list_for_each_entry(virt_dev, &cdrom_fileio_dev_list,
fileio_dev_list_entry)
{
size = scnprintf(buffer + pu.len, length - pu.len,
"%-17s %-9d %s\n", virt_dev->name,
(uint32_t)(virt_dev->file_size >> 20),
virt_dev->file_name);
if (fileio_proc_update_size(size, offset, length, &pu,
1)) {
goto stop_output;
}
}
*eof = 1;
goto stop_output;
} else { /* write */
p = buffer;
if (p[strlen(p) - 1] == '\n') {
p[strlen(p) - 1] = '\0';
}
if (!strncmp("close ", p, 6)) {
p += 6;
action = 0;
} else if (!strncmp("change ", p, 5)) {
p += 7;
action = 1;
} else if (!strncmp("open ", p, 5)) {
p += 5;
action = 2;
} else {
PRINT_ERROR_PR("Unknown action \"%s\"", p);
res = -EINVAL;
goto out_up;
}
while (isspace(*p) && *p != '\0')
p++;
name = p;
while (!isspace(*p) && *p != '\0')
p++;
*p++ = '\0';
if (*name == '\0') {
PRINT_ERROR_PR("%s", "Name required");
res = -EINVAL;
goto out_up;
} else if (strlen(name) >= sizeof(virt_dev->name)) {
PRINT_ERROR_PR("Name is too long (max %zd "
"characters)", sizeof(virt_dev->name)-1);
res = -EINVAL;
goto out_up;
}
if (action == 2) { /* open */
res = cdrom_fileio_open(p, name);
if (res != 0)
goto out_up;
} else if (action == 1) { /* change */
res = cdrom_fileio_change(p, name);
if (res != 0)
goto out_up;
} else { /* close */
res = cdrom_fileio_close(name);
if (res != 0)
goto out_up;
}
res = length;
list_for_each_entry(virt_dev, &cdrom_fileio_dev_list,
fileio_dev_list_entry) {
seq_printf(seq, "%-17s %-9d %s\n", virt_dev->name,
(uint32_t)(virt_dev->file_size >> 20),
virt_dev->file_name);
}
up(&scst_fileio_mutex);
out:
TRACE_EXIT_RES(res);
return res;
}
/*
* Called when a file in the /proc/CDROM_FILEIO_NAME/CDROM_FILEIO_NAME is written
*/
static int cdrom_fileio_write_proc(char *buffer, char **start, off_t offset,
int length, int *eof, struct scst_dev_type *dev_type)
{
int res = 0, action;
char *p, *name;
struct scst_fileio_dev *virt_dev;
TRACE_ENTRY();
if (down_interruptible(&scst_fileio_mutex) != 0) {
res = -EINTR;
goto out;
}
p = buffer;
if (p[strlen(p) - 1] == '\n') {
p[strlen(p) - 1] = '\0';
}
if (!strncmp("close ", p, 6)) {
p += 6;
action = 0;
} else if (!strncmp("change ", p, 5)) {
p += 7;
action = 1;
} else if (!strncmp("open ", p, 5)) {
p += 5;
action = 2;
} else {
PRINT_ERROR_PR("Unknown action \"%s\"", p);
res = -EINVAL;
goto out_up;
}
while (isspace(*p) && *p != '\0')
p++;
name = p;
while (!isspace(*p) && *p != '\0')
p++;
*p++ = '\0';
if (*name == '\0') {
PRINT_ERROR_PR("%s", "Name required");
res = -EINVAL;
goto out_up;
} else if (strlen(name) >= sizeof(virt_dev->name)) {
PRINT_ERROR_PR("Name is too long (max %zd "
"characters)", sizeof(virt_dev->name)-1);
res = -EINVAL;
goto out_up;
}
if (action == 2) { /* open */
res = cdrom_fileio_open(p, name);
if (res != 0)
goto out_up;
} else if (action == 1) { /* change */
res = cdrom_fileio_change(p, name);
if (res != 0)
goto out_up;
} else { /* close */
res = cdrom_fileio_close(name);
if (res != 0)
goto out_up;
}
res = length;
out_up:
up(&scst_fileio_mutex);
out:
TRACE_EXIT_RES(res);
return res;
stop_output:
*start = buffer + (offset - pu.begin);
pu.len -= (offset - pu.begin);
if (pu.len > length)
pu.len = length;
res = pu.len;
goto out_up;
}
static int fileio_help_info_show(struct seq_file *seq, void *v)
{
char *s = (char*)seq->private;
TRACE_ENTRY();
seq_printf(seq, "%s", s);
TRACE_EXIT();
return 0;
}
static struct scst_proc_data fileio_help_proc_data = {
SCST_DEF_RW_SEQ_OP(NULL)
.show = fileio_help_info_show,
};
static int fileio_proc_help_build(struct scst_dev_type *dev_type)
{
int res = 0;
@@ -3049,23 +2992,17 @@ static int fileio_proc_help_build(struct scst_dev_type *dev_type)
TRACE_ENTRY();
root = scst_proc_get_dev_type_root(dev_type);
if (root) {
p = create_proc_read_entry(FILEIO_PROC_HELP,
S_IFREG | S_IRUGO, root,
fileio_proc_help_read,
(dev_type->type == TYPE_DISK) ?
disk_fileio_proc_help_string :
cdrom_fileio_proc_help_string);
if (p == NULL) {
PRINT_ERROR_PR("Not enough memory to register dev "
"handler %s entry %s in /proc",
dev_type->name, FILEIO_PROC_HELP);
res = -ENOMEM;
goto out;
}
fileio_help_proc_data.data = (dev_type->type == TYPE_DISK) ?
disk_fileio_proc_help_string :
cdrom_fileio_proc_help_string;
p = scst_create_proc_entry(root, FILEIO_PROC_HELP, &fileio_help_proc_data);
if (p == NULL) {
PRINT_ERROR_PR("Not enough memory to register dev "
"handler %s entry %s in /proc",
dev_type->name, FILEIO_PROC_HELP);
res = -ENOMEM;
}
out:
TRACE_EXIT_RES(res);
return res;
}
@@ -3083,21 +3020,6 @@ static void fileio_proc_help_destroy(struct scst_dev_type *dev_type)
TRACE_EXIT();
}
static int fileio_proc_help_read(char *buffer, char **start, off_t offset,
int length, int *eof, void *data)
{
int res = 0;
char *s = (char*)data;
TRACE_ENTRY();
if (offset < strlen(s))
res = scnprintf(buffer, length, "%s", &s[offset]);
TRACE_EXIT_RES(res);
return res;
}
static int __init init_scst_fileio(struct scst_dev_type *devtype)
{
int res = 0;
+3
View File
@@ -1254,6 +1254,9 @@ EXPORT_SYMBOL(scst_proc_log_entry_read);
EXPORT_SYMBOL(scst_proc_log_entry_write);
#endif
EXPORT_SYMBOL(scst_create_proc_entry);
EXPORT_SYMBOL(scst_single_seq_open);
EXPORT_SYMBOL(__scst_get_buf);
EXPORT_SYMBOL(scst_check_mem);
EXPORT_SYMBOL(scst_get);
+532 -835
View File
File diff suppressed because it is too large Load Diff