mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-18 13:16:34 +00:00
- Fixed problems with big amount of LUNs. Tested on 1500 LUNS
- Docs update git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@32 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
+48
-39
@@ -323,20 +323,20 @@ subdirectories "disk_fileio" and "cdrom_fileio". They have similar layout:
|
||||
way as "*_perf" handlers.
|
||||
|
||||
- NV_CACHE - enables "non-volatile cache" mode. In this mode it is
|
||||
assumed that the target has GOOD uninterruptable power supply
|
||||
and software/hardware bug free, i.e. all data from the target's
|
||||
cache are guaranteed sooner or later to go to the media, hence
|
||||
all data synchronization with media operations, like
|
||||
SYNCHRONIZE_CACHE, are ignored (BTW, so violating SCSI standard)
|
||||
in order to bring a bit more performance. Use with extreme
|
||||
caution, since in this mode after a crash of the target
|
||||
journaled file systems don't guarantee the consistency after
|
||||
journal recovery, therefore manual fsck MUST be ran. The main
|
||||
intent for it is to determine the performance impact caused by
|
||||
the cache synchronization. Note, that since usually the journal
|
||||
barrier protection (see "IMPORTANT" below) turned off, enabling
|
||||
NV_CACHE could change nothing, since no data synchronization
|
||||
with media operations will go from the initiator.
|
||||
assumed that the target has GOOD UPS and software/hardware bug
|
||||
free, i.e. all data from the target's cache are guaranteed
|
||||
sooner or later to go to the media, hence all data
|
||||
synchronization with media operations, like SYNCHRONIZE_CACHE,
|
||||
are ignored (BTW, so violating SCSI standard) in order to bring
|
||||
a bit more performance. Use with extreme caution, since in this
|
||||
mode after a crash of the target journaled file systems don't
|
||||
guarantee the consistency after journal recovery, therefore
|
||||
manual fsck MUST be ran. The main intent for it is to determine
|
||||
the performance impact caused by the cache synchronization.
|
||||
Note, that since usually the journal barrier protection (see
|
||||
"IMPORTANT" below) turned off, enabling NV_CACHE could change
|
||||
nothing, since no data synchronization with media operations
|
||||
will go from the initiator.
|
||||
|
||||
* "close NAME" - closes device "NAME".
|
||||
|
||||
@@ -349,32 +349,36 @@ IMPORTANT: By default for performance reasons FILEIO devices use write back
|
||||
========= caching policy. This is generally safe from the consistence of
|
||||
journaled file systems, laying over them, point of view, but
|
||||
your unsaved cached data will be lost in case of
|
||||
power/hardware/software faulure, so you must supply your
|
||||
power/hardware/software failure, so you must supply your
|
||||
target server with some kind of UPS or disable write back
|
||||
caching using WRITE_THROUGH flag. You also should note, that
|
||||
the file systems journaling over write back caching enabled
|
||||
devices works reliably *ONLY* if it uses some kind of data
|
||||
protection barriers (i.e. after writing journaling data some
|
||||
kind of synchronization with media operations will be used),
|
||||
otherwise, because of possible reordering in the cache, even
|
||||
after successful journal rollback you very much risk to loose
|
||||
your data on the FS. On Linux initiators for EXT3 and
|
||||
ReiserFS file systems the barrier protection could be turned
|
||||
on using "barrier=1" and "barrier=flush" mount options
|
||||
correspondingly. Note, that usually it turned off by default
|
||||
and the status of barriers usage isn't reported anywhere in
|
||||
the system logs as well as there is no way to know it on the
|
||||
mounted file system (at least no known one). Also note
|
||||
that on some real-life workloads write through caching might
|
||||
perform better, than write back one with the barrier protection
|
||||
turned on.
|
||||
devices works reliably *ONLY* if the order of journal writes
|
||||
is guaranteed or it uses some kind of data protection
|
||||
barriers (i.e. after writing journal data some kind of
|
||||
synchronization with media operations is used), otherwise,
|
||||
because of possible reordering in the cache, even after
|
||||
successful journal rollback, you very much risk to loose your
|
||||
data on the FS. Currently, Linux IO subsystem guarantees
|
||||
order of write operations only using data protection
|
||||
barriers. Some info about it from the XFS point of view could
|
||||
be found at http://oss.sgi.com/projects/xfs/faq.html#wcache.
|
||||
On Linux initiators for EXT3 and ReiserFS file systems the
|
||||
barrier protection could be turned on using "barrier=1" and
|
||||
"barrier=flush" mount options correspondingly. Note, that
|
||||
usually it turned off by default and the status of barriers
|
||||
usage isn't reported anywhere in the system logs as well as
|
||||
there is no way to know it on the mounted file system (at
|
||||
least no known one). Also note that on some real-life
|
||||
workloads write through caching might perform better, than
|
||||
write back one with the barrier protection turned on.
|
||||
|
||||
IMPORTANT: Many disk and partition table mananagement utilities don't support
|
||||
IMPORTANT: Many disk and partition table management utilities don't support
|
||||
========= block sizes >512 bytes, therefore make sure that your favorite one
|
||||
supports it. Also, if you export disk file or device with
|
||||
some block size, different from one, with which it was
|
||||
already divided on partitions, you could get various weird
|
||||
things like utilities hang up or other unexpected behaviour.
|
||||
things like utilities hang up or other unexpected behavior.
|
||||
Hence, to be sure, zero the exported file or device before the
|
||||
first access to it from the remote initiator with another
|
||||
block size.
|
||||
@@ -384,10 +388,15 @@ Performance
|
||||
|
||||
Before doing any performance measurements note that:
|
||||
|
||||
I. Maximum performance is possible only with real SCSI devices or
|
||||
performance handlers. If you have enough CPU power, FILEIO handler could
|
||||
provide the same results, when aggregate throughput is close to
|
||||
aggregate throuput locally on the target on the same disks.
|
||||
I. Currently maximum performance is possible only with real SCSI devices
|
||||
with several simultaneously executed commands (SCSI tagged queuing) or
|
||||
performance handlers. If you have enough CPU power, FILEIO handler also
|
||||
could provide the same results, when aggregate throughput is close to
|
||||
the aggregate throughput locally on the target from the same disks. Also
|
||||
note, that currently IO subsystem in Linux implemented on such way, so a
|
||||
FILEIO device over a single file occupied entire formatted with some
|
||||
file system device (eg /dev/hdc) could perform considerably better, than
|
||||
a FILEIO device over /dev/hdc itself without the file system involved.
|
||||
|
||||
II. In order to get the maximum performance you should:
|
||||
|
||||
@@ -414,8 +423,8 @@ IMPORTANT: Some of those options enabled by default, i.e. SCST is optimized
|
||||
|
||||
- The default kernel read-ahead and queuing settings are optimized
|
||||
for locally attached disks, therefore they are not optimal if they
|
||||
attached remotly (our case), which sometimes could lead to unexpectedly
|
||||
low throughput. You should increase read-ahead size
|
||||
attached remotely (our case), which sometimes could lead to
|
||||
unexpectedly low throughput. You should increase read-ahead size
|
||||
(/sys/block/device/queue/read_ahead_kb) to at least 256Kb or even
|
||||
more on all initiators and the target. Also experiment with other
|
||||
parameters in /sys/block/device directory, they also affect the
|
||||
@@ -448,7 +457,7 @@ IMPORTANT: If you use on initiator some versions of Windows (at least W2K)
|
||||
a device node is used. Both values are on the target.
|
||||
|
||||
Just for reference: we had with 0.9.2 and "old" Qlogic driver on 2.4.2x
|
||||
kernel, where we did carefull performance study, aggregate throuhput
|
||||
kernel, where we did careful performance study, aggregate throughput
|
||||
about 390 Mb/sec from 2 qla2300 cards sitting on different 64-bit PCI
|
||||
buses and working simultaneously for two different initiators with
|
||||
several simultaneously working load programs on each. From one card -
|
||||
|
||||
@@ -2066,7 +2066,7 @@ restart:
|
||||
* value less, than requested. Let's restart.
|
||||
*/
|
||||
int i, e = eiv_count;
|
||||
TRACE(TRACE_MINOR, "write() returned %d from %zd "
|
||||
TRACE_MGMT_DBG("write() returned %d from %zd "
|
||||
"(iv_count=%d)", (int)err, full_len,
|
||||
eiv_count);
|
||||
if (err == 0) {
|
||||
@@ -2261,20 +2261,43 @@ out:
|
||||
return dev;
|
||||
}
|
||||
|
||||
static int fileio_proc_update_size(int size, int *len,
|
||||
off_t *begin, off_t *pos, off_t *offset)
|
||||
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;
|
||||
if (size > 0) {
|
||||
*len += size;
|
||||
*pos = *begin + *len;
|
||||
if (*pos < *offset) {
|
||||
*len = 0;
|
||||
*begin = *pos;
|
||||
p->len += size;
|
||||
p->pos = p->begin + p->len;
|
||||
if (p->pos < offset) {
|
||||
p->len = 0;
|
||||
p->begin = p->pos;
|
||||
}
|
||||
res = 0;
|
||||
} else
|
||||
if (p->pos > offset + length) {
|
||||
p->begin = p->pbegin;
|
||||
p->len = p->plen;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -2288,10 +2311,12 @@ static int disk_fileio_proc(char *buffer, char **start, off_t offset,
|
||||
int res = 0, action;
|
||||
char *p, *name, *file_name;
|
||||
struct scst_fileio_dev *virt_dev, *vv;
|
||||
int size, len = 0;
|
||||
off_t begin = 0, pos = 0;
|
||||
int size;
|
||||
struct fileio_proc_update_struct pu;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
memset(&pu, 0, sizeof(pu));
|
||||
|
||||
/* VERY UGLY code. You can rewrite it if you want */
|
||||
|
||||
@@ -2303,99 +2328,84 @@ static int disk_fileio_proc(char *buffer, char **start, off_t offset,
|
||||
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, &len, &begin, &pos, &offset)) {
|
||||
res = len;
|
||||
goto out_up;
|
||||
}
|
||||
if (fileio_proc_update_size(size, offset, length, &pu, 1))
|
||||
goto stop_output;
|
||||
|
||||
list_for_each_entry(virt_dev, &disk_fileio_dev_list,
|
||||
fileio_dev_list_entry)
|
||||
{
|
||||
int c;
|
||||
size = scnprintf(buffer + len, length - len,
|
||||
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, &len, &begin, &pos,
|
||||
&offset)) {
|
||||
res = len;
|
||||
goto out_up;
|
||||
if (fileio_proc_update_size(size, offset, length, &pu,
|
||||
1)) {
|
||||
goto stop_output;
|
||||
}
|
||||
c = 0;
|
||||
if (virt_dev->wt_flag) {
|
||||
size = scnprintf(buffer + len, length - len, "WT");
|
||||
size = scnprintf(buffer + pu.len, length - pu.len, "WT");
|
||||
c += size;
|
||||
if (fileio_proc_update_size(size, &len, &begin,
|
||||
&pos, &offset)) {
|
||||
res = len;
|
||||
goto out_up;
|
||||
if (fileio_proc_update_size(size, offset,
|
||||
length, &pu, 0)) {
|
||||
goto stop_output;
|
||||
}
|
||||
}
|
||||
if (virt_dev->nv_cache) {
|
||||
size = scnprintf(buffer + len, length - len,
|
||||
size = scnprintf(buffer + pu.len, length - pu.len,
|
||||
c ? ",NV" : "NV");
|
||||
c += size;
|
||||
if (fileio_proc_update_size(size, &len, &begin,
|
||||
&pos, &offset)) {
|
||||
res = len;
|
||||
goto out_up;
|
||||
if (fileio_proc_update_size(size, offset,
|
||||
length, &pu, 0)) {
|
||||
goto stop_output;
|
||||
}
|
||||
}
|
||||
if (virt_dev->rd_only_flag) {
|
||||
size = scnprintf(buffer + len, length - len,
|
||||
size = scnprintf(buffer + pu.len, length - pu.len,
|
||||
c ? ",RO" : "RO");
|
||||
c += size;
|
||||
if (fileio_proc_update_size(size, &len, &begin,
|
||||
&pos, &offset)) {
|
||||
res = len;
|
||||
goto out_up;
|
||||
if (fileio_proc_update_size(size, offset,
|
||||
length, &pu, 0)) {
|
||||
goto stop_output;
|
||||
}
|
||||
}
|
||||
if (virt_dev->o_direct_flag) {
|
||||
size = scnprintf(buffer + len, length - len,
|
||||
size = scnprintf(buffer + pu.len, length - pu.len,
|
||||
c ? ",DR" : "DR");
|
||||
c += size;
|
||||
if (fileio_proc_update_size(size, &len, &begin,
|
||||
&pos, &offset)) {
|
||||
res = len;
|
||||
goto out_up;
|
||||
if (fileio_proc_update_size(size, offset,
|
||||
length, &pu, 0)) {
|
||||
goto stop_output;
|
||||
}
|
||||
}
|
||||
if (virt_dev->nullio) {
|
||||
size = scnprintf(buffer + len, length - len,
|
||||
size = scnprintf(buffer + pu.len, length - pu.len,
|
||||
c ? ",NIO" : "NIO");
|
||||
c += size;
|
||||
if (fileio_proc_update_size(size, &len, &begin,
|
||||
&pos, &offset)) {
|
||||
res = len;
|
||||
goto out_up;
|
||||
if (fileio_proc_update_size(size, offset,
|
||||
length, &pu, 0)) {
|
||||
goto stop_output;
|
||||
}
|
||||
}
|
||||
while (c < 16) {
|
||||
size = scnprintf(buffer + len, length - len, " ");
|
||||
if (fileio_proc_update_size(size, &len, &begin, &pos,
|
||||
&offset)) {
|
||||
res = len;
|
||||
goto out_up;
|
||||
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 + len, length - len, "%s\n",
|
||||
size = scnprintf(buffer + pu.len, length - pu.len, "%s\n",
|
||||
virt_dev->file_name);
|
||||
if (fileio_proc_update_size(size, &len, &begin,
|
||||
&pos, &offset)) {
|
||||
res = len;
|
||||
goto out_up;
|
||||
if (fileio_proc_update_size(size, offset, length, &pu,
|
||||
0)) {
|
||||
goto stop_output;
|
||||
}
|
||||
}
|
||||
*start = buffer + (offset - begin);
|
||||
len -= (offset - begin);
|
||||
if (len > length)
|
||||
len = length;
|
||||
res = len;
|
||||
*eof = 1;
|
||||
}
|
||||
else { /* write */
|
||||
goto stop_output;
|
||||
} else { /* write */
|
||||
uint32_t block_size = DEF_DISK_BLOCKSIZE;
|
||||
int block_shift = DEF_DISK_BLOCKSIZE_SHIFT;
|
||||
p = buffer;
|
||||
@@ -2545,15 +2555,15 @@ static int disk_fileio_proc(char *buffer, char **start, off_t offset,
|
||||
|
||||
strcpy(virt_dev->name, name);
|
||||
|
||||
len = strlen(file_name) + 1;
|
||||
virt_dev->file_name = kmalloc(len, GFP_KERNEL);
|
||||
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, len);
|
||||
strncpy(virt_dev->file_name, file_name, pu.len);
|
||||
|
||||
list_add_tail(&virt_dev->fileio_dev_list_entry,
|
||||
&disk_fileio_dev_list);
|
||||
@@ -2605,6 +2615,14 @@ 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;
|
||||
|
||||
out_free_vpath:
|
||||
list_del(&virt_dev->fileio_dev_list_entry);
|
||||
kfree(virt_dev->file_name);
|
||||
@@ -2924,11 +2942,13 @@ static int cdrom_fileio_proc(char *buffer, char **start, off_t offset,
|
||||
int res = 0, action;
|
||||
char *p, *name;
|
||||
struct scst_fileio_dev *virt_dev;
|
||||
int size, len = 0;
|
||||
off_t begin = 0, pos = 0;
|
||||
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;
|
||||
@@ -2937,32 +2957,24 @@ static int cdrom_fileio_proc(char *buffer, char **start, off_t offset,
|
||||
if (inout == 0) { /* read */
|
||||
size = scnprintf(buffer, length, "%-17s %-9s %s\n",
|
||||
"Name", "Size(MB)", "File name");
|
||||
if (fileio_proc_update_size(size, &len, &begin, &pos,
|
||||
&offset)) {
|
||||
res = len;
|
||||
goto out_up;
|
||||
}
|
||||
if (fileio_proc_update_size(size, offset, length, &pu, 1))
|
||||
goto stop_output;
|
||||
|
||||
list_for_each_entry(virt_dev, &cdrom_fileio_dev_list,
|
||||
fileio_dev_list_entry)
|
||||
{
|
||||
size = scnprintf(buffer + len, length - len,
|
||||
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, &len, &begin,
|
||||
&pos, &offset)) {
|
||||
res = len;
|
||||
goto out_up;
|
||||
if (fileio_proc_update_size(size, offset, length, &pu,
|
||||
1)) {
|
||||
goto stop_output;
|
||||
}
|
||||
}
|
||||
*start = buffer + (offset - begin);
|
||||
len -= (offset - begin);
|
||||
if (len > length)
|
||||
len = length;
|
||||
res = len;
|
||||
}
|
||||
else { /* write */
|
||||
*eof = 1;
|
||||
goto stop_output;
|
||||
} else { /* write */
|
||||
p = buffer;
|
||||
if (p[strlen(p) - 1] == '\n') {
|
||||
p[strlen(p) - 1] = '\0';
|
||||
@@ -3022,6 +3034,13 @@ 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_proc_help_build(struct scst_dev_type *dev_type)
|
||||
|
||||
+5
-1
@@ -341,7 +341,7 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
|
||||
dev->scsi_dev->lun, (uint64_t)tgt_dev->acg_dev->lun);
|
||||
}
|
||||
else {
|
||||
TRACE(TRACE_MINOR, "Virtual device SCST lun=%Ld",
|
||||
TRACE_MGMT_DBG("Virtual device SCST lun=%Ld",
|
||||
(uint64_t)tgt_dev->acg_dev->lun);
|
||||
}
|
||||
|
||||
@@ -1562,6 +1562,7 @@ lun_t scst_unpack_lun(const uint8_t *lun, int len)
|
||||
address_method = (*lun) >> 6; /* high 2 bits of byte 0 */
|
||||
switch (address_method) {
|
||||
case 0: /* peripheral device addressing method */
|
||||
#if 0 /* At least QLA2300 Linux ini uses it as the flat space addressing method */
|
||||
if (*lun) {
|
||||
PRINT_ERROR_PR("Illegal BUS INDENTIFIER in LUN "
|
||||
"peripheral device addressing method 0x%02x, "
|
||||
@@ -1570,6 +1571,9 @@ lun_t scst_unpack_lun(const uint8_t *lun, int len)
|
||||
}
|
||||
res = *(lun + 1);
|
||||
break;
|
||||
#else
|
||||
/* go through */
|
||||
#endif
|
||||
|
||||
case 1: /* flat space addressing method */
|
||||
res = *(lun + 1) | (((*lun) & 0x3f) << 8);
|
||||
|
||||
+126
-49
@@ -726,45 +726,62 @@ static void scst_proc_cleanup_groups(void)
|
||||
TRACE_EXIT();
|
||||
}
|
||||
|
||||
static int scst_proc_update_size(int size, int *len,
|
||||
off_t *begin, off_t *pos, off_t *offset, int length)
|
||||
struct scst_proc_update_struct {
|
||||
int len, plen, pplen;
|
||||
off_t begin, pbegin, ppbegin;
|
||||
off_t pos;
|
||||
};
|
||||
|
||||
static int scst_proc_update_size(int size, off_t offset, int length,
|
||||
struct scst_proc_update_struct *p)
|
||||
{
|
||||
int res;
|
||||
if (size > 0) {
|
||||
*len += size;
|
||||
*pos = *begin + *len;
|
||||
if (*pos < *offset) {
|
||||
*len = 0;
|
||||
*begin = *pos;
|
||||
p->len += size;
|
||||
p->pos = p->begin + p->len;
|
||||
if (p->pos < offset) {
|
||||
p->len = 0;
|
||||
p->begin = p->pos;
|
||||
}
|
||||
if (pos > offset + length)
|
||||
if (p->pos > offset + length) {
|
||||
p->begin = p->pbegin;
|
||||
p->len = p->plen;
|
||||
res = 1;
|
||||
else
|
||||
goto out;
|
||||
} else
|
||||
res = 0;
|
||||
} else
|
||||
} else {
|
||||
p->begin = p->ppbegin;
|
||||
p->len = p->pplen;
|
||||
res = 1;
|
||||
goto out;
|
||||
}
|
||||
p->ppbegin = p->pbegin;
|
||||
p->pplen = p->plen;
|
||||
p->pbegin = p->begin;
|
||||
p->plen = p->len;
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static int scst_proc_sgv_read_1(char *buffer, int *len,
|
||||
off_t *begin, off_t *pos, off_t *offset, int length,
|
||||
static int scst_proc_sgv_read_1(char *buffer, off_t offset, int length,
|
||||
struct scst_proc_update_struct *p,
|
||||
const struct sgv_pool *pool, const char *name)
|
||||
{
|
||||
int i, size;
|
||||
|
||||
size = scnprintf(buffer + *len, length - *len, "\n%-20s %-11d %-11d\n",
|
||||
size = scnprintf(buffer + p->len, length - p->len, "\n%-20s %-11d %-11d\n",
|
||||
name, atomic_read(&pool->acc.hit_alloc),
|
||||
atomic_read(&pool->acc.total_alloc));
|
||||
if (scst_proc_update_size(size, len, begin, pos, offset, length))
|
||||
if (scst_proc_update_size(size, offset, length, p))
|
||||
return 1;
|
||||
|
||||
for(i = 0; i < SGV_POOL_ELEMENTS; i++) {
|
||||
size = scnprintf(buffer + *len, length - *len,
|
||||
size = scnprintf(buffer + p->len, length - p->len,
|
||||
" %-18s %-11d %-11d\n", pool->cache_names[i],
|
||||
atomic_read(&pool->cache_acc[i].hit_alloc),
|
||||
atomic_read(&pool->cache_acc[i].total_alloc));
|
||||
if (scst_proc_update_size(size, len, begin, pos, offset,
|
||||
length))
|
||||
if (scst_proc_update_size(size, offset, length, p))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -774,48 +791,52 @@ static int scst_proc_sgv_read(char *buffer, char **start,
|
||||
off_t offset, int length, int *eof, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
int size, len = 0;
|
||||
off_t begin = 0, pos = 0;
|
||||
int size;
|
||||
struct scst_proc_update_struct st;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
TRACE_DBG("offset: %d, length %d", (int) offset, length);
|
||||
|
||||
size = scnprintf(buffer + len, length - len, "%-20s %-11s %-11s",
|
||||
memset(&st, 0, sizeof(st));
|
||||
|
||||
size = scnprintf(buffer + st.len, length - st.len, "%-20s %-11s %-11s",
|
||||
"Name", "Hit", "Total");
|
||||
if (scst_proc_update_size(size, &len, &begin, &pos, &offset, length))
|
||||
if (scst_proc_update_size(size, offset, length, &st))
|
||||
goto stop_output;
|
||||
|
||||
if (scst_proc_sgv_read_1(buffer, &len, &begin, &pos, &offset, length,
|
||||
&scst_sgv.norm, "sgv"))
|
||||
if (scst_proc_sgv_read_1(buffer, offset, length, &st, &scst_sgv.norm,
|
||||
"sgv"))
|
||||
goto stop_output;
|
||||
|
||||
if (scst_proc_sgv_read_1(buffer, &len, &begin, &pos, &offset, length,
|
||||
if (scst_proc_sgv_read_1(buffer, offset, length, &st,
|
||||
&scst_sgv.norm_clust, "sgv-clust"))
|
||||
goto stop_output;
|
||||
|
||||
if (scst_proc_sgv_read_1(buffer, &len, &begin, &pos, &offset, length,
|
||||
if (scst_proc_sgv_read_1(buffer, offset, length, &st,
|
||||
&scst_sgv.dma, "sgv-dma"))
|
||||
goto stop_output;
|
||||
|
||||
#ifdef SCST_HIGHMEM
|
||||
if (scst_proc_sgv_read_1(buffer, &len, &begin, &pos, &offset, length,
|
||||
if (scst_proc_sgv_read_1(buffer, offset, length, &st,
|
||||
&scst_sgv.highmem, "sgv-highmem"))
|
||||
goto stop_output;
|
||||
|
||||
#endif
|
||||
|
||||
size = scnprintf(buffer + len, length - len, "\n%-32s %-11d\n",
|
||||
size = scnprintf(buffer + st.len, length - st.len, "\n%-32s %-11d\n",
|
||||
"big", atomic_read(&sgv_big_total_alloc));
|
||||
if (scst_proc_update_size(size, &len, &begin, &pos, &offset, length))
|
||||
if (scst_proc_update_size(size, offset, length, &st))
|
||||
goto stop_output;
|
||||
|
||||
*eof = 1;
|
||||
|
||||
stop_output:
|
||||
*start = buffer + (offset - begin);
|
||||
len -= (offset - begin);
|
||||
if (len > length)
|
||||
len = length;
|
||||
res = len;
|
||||
*start = buffer + (offset - st.begin);
|
||||
st.len -= (offset - st.begin);
|
||||
if (st.len > length)
|
||||
st.len = length;
|
||||
res = st.len;
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
@@ -979,8 +1000,8 @@ static int scst_scsi_tgt_proc_info(char *buffer, char **start,
|
||||
void *data)
|
||||
{
|
||||
int res = 0;
|
||||
int size, len = 0;
|
||||
off_t begin = 0, pos = 0;
|
||||
int size, len = 0, plen, pplen;
|
||||
off_t begin = 0, pos = 0, pbegin, ppbegin;
|
||||
struct scst_device *dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
@@ -1005,6 +1026,8 @@ static int scst_scsi_tgt_proc_info(char *buffer, char **start,
|
||||
} else
|
||||
goto stop_output;
|
||||
|
||||
ppbegin = pbegin = begin;
|
||||
pplen = plen = len;
|
||||
list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
|
||||
if (dev->virt_id == 0) {
|
||||
size = scnprintf(buffer + len, length - len,
|
||||
@@ -1027,12 +1050,24 @@ static int scst_scsi_tgt_proc_info(char *buffer, char **start,
|
||||
len = 0;
|
||||
begin = pos;
|
||||
}
|
||||
if (pos > offset + length)
|
||||
if (pos > offset + length) {
|
||||
begin = pbegin;
|
||||
len = plen;
|
||||
goto stop_output;
|
||||
} else
|
||||
}
|
||||
} else {
|
||||
begin = ppbegin;
|
||||
len = pplen;
|
||||
goto stop_output;
|
||||
}
|
||||
ppbegin = pbegin;
|
||||
pplen = plen;
|
||||
pbegin = begin;
|
||||
plen = len;
|
||||
}
|
||||
|
||||
*eof = 1;
|
||||
|
||||
stop_output:
|
||||
*start = buffer + (offset - begin);
|
||||
len -= (offset - begin);
|
||||
@@ -1771,8 +1806,8 @@ static int scst_proc_groups_devices_read(char *buffer, char **start,
|
||||
int res = 0;
|
||||
struct scst_acg *acg = (struct scst_acg *)data;
|
||||
struct scst_acg_dev *acg_dev;
|
||||
int size, len = 0;
|
||||
off_t begin = 0, pos = 0;
|
||||
int size, len = 0, plen, pplen;
|
||||
off_t begin = 0, pos = 0, pbegin, ppbegin;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -1796,6 +1831,8 @@ static int scst_proc_groups_devices_read(char *buffer, char **start,
|
||||
} else
|
||||
goto stop_output;
|
||||
|
||||
ppbegin = pbegin = begin;
|
||||
pplen = plen = len;
|
||||
list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) {
|
||||
if (acg_dev->dev->virt_id == 0) {
|
||||
size = scnprintf(buffer + len, length - len,
|
||||
@@ -1819,12 +1856,24 @@ static int scst_proc_groups_devices_read(char *buffer, char **start,
|
||||
len = 0;
|
||||
begin = pos;
|
||||
}
|
||||
if (pos > offset + length)
|
||||
if (pos > offset + length) {
|
||||
begin = pbegin;
|
||||
len = plen;
|
||||
goto stop_output;
|
||||
} else
|
||||
}
|
||||
} else {
|
||||
begin = ppbegin;
|
||||
len = pplen;
|
||||
goto stop_output;
|
||||
}
|
||||
ppbegin = pbegin;
|
||||
pplen = plen;
|
||||
pbegin = begin;
|
||||
plen = len;
|
||||
}
|
||||
|
||||
*eof = 1;
|
||||
|
||||
stop_output:
|
||||
*start = buffer + (offset - begin);
|
||||
len -= (offset - begin);
|
||||
@@ -2034,8 +2083,8 @@ static int scst_proc_sessions_read(char *buffer, char **start,
|
||||
int res = 0;
|
||||
struct scst_acg *acg;
|
||||
struct scst_session *sess;
|
||||
int size, len = 0;
|
||||
off_t begin = 0, pos = 0;
|
||||
int size, len = 0, plen, pplen;
|
||||
off_t begin = 0, pos = 0, pbegin, ppbegin;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -2059,6 +2108,8 @@ static int scst_proc_sessions_read(char *buffer, char **start,
|
||||
} else
|
||||
goto stop_output;
|
||||
|
||||
ppbegin = pbegin = begin;
|
||||
pplen = plen = len;
|
||||
list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
|
||||
list_for_each_entry(sess, &acg->acg_sess_list, acg_sess_list_entry) {
|
||||
size = scnprintf(buffer + len, length - len,
|
||||
@@ -2074,13 +2125,25 @@ static int scst_proc_sessions_read(char *buffer, char **start,
|
||||
len = 0;
|
||||
begin = pos;
|
||||
}
|
||||
if (pos > offset + length)
|
||||
if (pos > offset + length) {
|
||||
begin = pbegin;
|
||||
len = plen;
|
||||
goto stop_output;
|
||||
} else
|
||||
}
|
||||
} else {
|
||||
begin = ppbegin;
|
||||
len = pplen;
|
||||
goto stop_output;
|
||||
}
|
||||
ppbegin = pbegin;
|
||||
pplen = plen;
|
||||
pbegin = begin;
|
||||
plen = len;
|
||||
}
|
||||
}
|
||||
|
||||
*eof = 1;
|
||||
|
||||
stop_output:
|
||||
*start = buffer + (offset - begin);
|
||||
len -= (offset - begin);
|
||||
@@ -2102,8 +2165,8 @@ static int scst_proc_groups_names_read(char *buffer, char **start,
|
||||
int res = 0;
|
||||
struct scst_acg *acg = (struct scst_acg *)data;
|
||||
struct scst_acn *name;
|
||||
int size, len = 0;
|
||||
off_t begin = 0, pos = 0;
|
||||
int size, len = 0, plen, pplen;
|
||||
off_t begin = 0, pos = 0, pbegin, ppbegin;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -2112,6 +2175,8 @@ static int scst_proc_groups_names_read(char *buffer, char **start,
|
||||
goto out;
|
||||
}
|
||||
|
||||
ppbegin = pbegin = begin;
|
||||
pplen = plen = len;
|
||||
list_for_each_entry(name, &acg->acn_list, acn_list_entry) {
|
||||
size = scnprintf(buffer + len, length - len, "%s\n",
|
||||
name->name);
|
||||
@@ -2122,12 +2187,24 @@ static int scst_proc_groups_names_read(char *buffer, char **start,
|
||||
len = 0;
|
||||
begin = pos;
|
||||
}
|
||||
if (pos > offset + length)
|
||||
if (pos > offset + length) {
|
||||
begin = pbegin;
|
||||
len = plen;
|
||||
goto stop_output;
|
||||
} else
|
||||
}
|
||||
} else {
|
||||
begin = ppbegin;
|
||||
len = pplen;
|
||||
goto stop_output;
|
||||
}
|
||||
ppbegin = pbegin;
|
||||
pplen = plen;
|
||||
pbegin = begin;
|
||||
plen = len;
|
||||
}
|
||||
|
||||
*eof = 1;
|
||||
|
||||
stop_output:
|
||||
*start = buffer + (offset - begin);
|
||||
len -= (offset - begin);
|
||||
|
||||
+46
-15
@@ -306,7 +306,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
|
||||
cmd->cdb[0], dev->handler->name);
|
||||
}
|
||||
if (scst_cmd_is_expected_set(cmd)) {
|
||||
TRACE(TRACE_MINOR, "Using initiator supplied values: "
|
||||
TRACE(TRACE_SCSI, "Using initiator supplied values: "
|
||||
"direction %d, transfer_len %d",
|
||||
cmd->expected_data_direction,
|
||||
cmd->expected_transfer_len);
|
||||
@@ -1234,6 +1234,7 @@ static int scst_report_luns_local(struct scst_cmd *cmd)
|
||||
int buffer_size;
|
||||
struct scst_tgt_dev *tgt_dev = NULL;
|
||||
uint8_t *buffer;
|
||||
int offs, overflow = 0;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -1243,45 +1244,70 @@ static int scst_report_luns_local(struct scst_cmd *cmd)
|
||||
cmd->host_status = DID_OK;
|
||||
cmd->driver_status = 0;
|
||||
|
||||
/* ToDo: use full SG buffer, not only the first entry */
|
||||
if (cmd->cdb[2] != 0) {
|
||||
PRINT_ERROR_PR("Unsupported SELECT REPORT value %x in REPORT "
|
||||
"LUNS command", cmd->cdb[2]);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
buffer_size = scst_get_buf_first(cmd, &buffer);
|
||||
if (unlikely(buffer_size <= 0))
|
||||
goto out_err;
|
||||
|
||||
if (buffer_size < 16) {
|
||||
if (buffer_size < 16)
|
||||
goto out_put_err;
|
||||
}
|
||||
|
||||
memset(buffer, 0, buffer_size);
|
||||
offs = 8;
|
||||
|
||||
/* sess->sess_tgt_dev_list is protected by suspended activity */
|
||||
list_for_each_entry(tgt_dev, &cmd->sess->sess_tgt_dev_list,
|
||||
sess_tgt_dev_list_entry)
|
||||
{
|
||||
if (8 + 8 * dev_cnt + 2 <= buffer_size) {
|
||||
buffer[8 + 8 * dev_cnt] = (tgt_dev->acg_dev->lun >> 8) & 0xff;
|
||||
buffer[8 + 8 * dev_cnt + 1] = tgt_dev->acg_dev->lun & 0xff;
|
||||
if (!overflow) {
|
||||
if (offs >= buffer_size) {
|
||||
scst_put_buf(cmd, buffer);
|
||||
buffer_size = scst_get_buf_first(cmd, &buffer);
|
||||
if (buffer_size > 0) {
|
||||
memset(buffer, 0, buffer_size);
|
||||
offs = 0;
|
||||
} else {
|
||||
overflow = 1;
|
||||
goto inc_dev_cnt;
|
||||
}
|
||||
}
|
||||
if ((buffer_size - offs) < 8) {
|
||||
PRINT_ERROR_PR("Buffer allocated for REPORT "
|
||||
"LUNS command doesn't allow to fit 8 "
|
||||
"byte entry (buffer_size=%d)",
|
||||
buffer_size);
|
||||
goto out_put_hw_err;
|
||||
}
|
||||
buffer[offs] = (tgt_dev->acg_dev->lun >> 8) & 0xff;
|
||||
buffer[offs + 1] = tgt_dev->acg_dev->lun & 0xff;
|
||||
offs += 8;
|
||||
}
|
||||
inc_dev_cnt:
|
||||
dev_cnt++;
|
||||
/* Tmp, until ToDo above done */
|
||||
if (dev_cnt >= ((PAGE_SIZE >> 3) - 2))
|
||||
break;
|
||||
}
|
||||
if (!overflow)
|
||||
scst_put_buf(cmd, buffer);
|
||||
|
||||
/* Set the response header */
|
||||
buffer_size = scst_get_buf_first(cmd, &buffer);
|
||||
if (unlikely(buffer_size <= 0))
|
||||
goto out_err;
|
||||
dev_cnt *= 8;
|
||||
buffer[0] = (dev_cnt >> 24) & 0xff;
|
||||
buffer[1] = (dev_cnt >> 16) & 0xff;
|
||||
buffer[2] = (dev_cnt >> 8) & 0xff;
|
||||
buffer[3] = dev_cnt & 0xff;
|
||||
|
||||
dev_cnt += 8;
|
||||
|
||||
scst_put_buf(cmd, buffer);
|
||||
|
||||
if (buffer_size > dev_cnt)
|
||||
dev_cnt += 8;
|
||||
if (dev_cnt < cmd->resp_data_len)
|
||||
scst_set_resp_data_len(cmd, dev_cnt);
|
||||
|
||||
|
||||
out_done:
|
||||
cmd->completed = 1;
|
||||
|
||||
@@ -1298,6 +1324,11 @@ out_err:
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
|
||||
goto out_done;
|
||||
|
||||
out_put_hw_err:
|
||||
scst_put_buf(cmd, buffer);
|
||||
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
|
||||
goto out_done;
|
||||
}
|
||||
|
||||
static int scst_pre_select(struct scst_cmd *cmd)
|
||||
|
||||
Reference in New Issue
Block a user