- 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:
Vladislav Bolkhovitin
2006-11-13 17:14:19 +00:00
parent e721a3e0bd
commit 02d31f62c0
5 changed files with 329 additions and 189 deletions
+48 -39
View File
@@ -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 -
+104 -85
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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)