Merge branch 'svn-trunk'

This commit is contained in:
Bart Van Assche
2017-01-08 04:47:58 -08:00
44 changed files with 3945 additions and 373 deletions
+1 -1
View File
@@ -419,7 +419,7 @@ scst-dist-gzip:
else \
scripts/list-source-files; \
fi | \
grep -E '^doc/|^fcst/|^iscsi-scst/|^Makefile|^qla2x00t(|_git)/|^scst.spec|^scst/|^scst_local/|^srpt/'|\
grep -E '^doc/|^fcst/|^iscsi-scst/|^Makefile|^qla2x00t(|_git)/|^scst.spec|^scst/|^scst_local/|^srpt/|^usr/'|\
tar -T- -cf- | \
tar -C $${name}-$(VERSION) -xf-; \
} && \
+1
View File
@@ -22,3 +22,4 @@ SRPT 1.0.0 450
3.1.x branch start 6591, which is a copy of trunk r6590
3.1.0 6783 on the 3.1.x branch
3.2.x branch start 6925, which is a copy of trunk r6921
3.2.0 7058 on the 3.2.x branch
+10
View File
@@ -363,6 +363,9 @@ Each session subdirectory contains the following entries:
- commands - contains overall number of SCSI commands in this session.
- thread_pid - Process IDs (PIDs) of the iscsi{wr,rd} kernel threads that
process the SCSI commands for this session.
Each connection subdirectory contains the following entries:
- cid - contains CID of this connection.
@@ -371,6 +374,13 @@ Each connection subdirectory contains the following entries:
- state - contains processing state of this connection.
Each initiator group subdirectory contains:
- per_sess_dedicated_tgt_threads - if set, each iSCSI session has
dedicated, i.e. not shared with other sessions, pool of the
iscsi{wr,rd} kernel threads. Useful to control per-session CPU
affinity to improve performance. Default: not set.
See SCST README for info about other attributes.
Below is a sample script, which configures 1 virtual disk "disk1" using
+10
View File
@@ -192,6 +192,9 @@ Each session subdirectory contains the following entries:
- commands - contains overall number of SCSI commands in this session.
- thread_pid - Process IDs (PIDs) of the iscsi{wr,rd} kernel threads that
process the SCSI commands for this session.
Each connection subdirectory contains the following entries:
- cid - contains CID of this connection.
@@ -200,6 +203,13 @@ Each connection subdirectory contains the following entries:
- state - contains processing state of this connection.
Each initiator group subdirectory contains:
- per_sess_dedicated_tgt_threads - if set, each iSCSI session has
dedicated, i.e. not shared with other sessions, pool of the
iscsi{wr,rd} kernel threads. Useful to control per-session CPU
affinity to improve performance. Default: not set.
See SCST README for info about other attributes.
Below is a sample script, which configures 1 virtual disk "disk1" using
+68
View File
@@ -184,6 +184,66 @@ static ssize_t iscsi_conn_ip_show(struct kobject *kobj,
static struct kobj_attribute iscsi_conn_ip_attr =
__ATTR(ip, S_IRUGO, iscsi_conn_ip_show, NULL);
static ssize_t iscsi_get_target_ip(struct iscsi_conn *conn,
char *buf, int size)
{
int pos;
struct sock *sk;
TRACE_ENTRY();
sk = conn->sock->sk;
switch (sk->sk_family) {
case AF_INET:
pos = scnprintf(buf, size,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
"%u.%u.%u.%u", NIPQUAD(inet_sk(sk)->saddr));
#else
"%pI4", &inet_sk(sk)->inet_saddr);
#endif
break;
case AF_INET6:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
pos = scnprintf(buf, size,
"[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
NIP6(inet6_sk(sk)->saddr));
#else
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
pos = scnprintf(buf, size, "[%p6]", &inet6_sk(sk)->saddr);
#else
pos = scnprintf(buf, size, "[%p6]", &sk->sk_v6_rcv_saddr);
#endif
#endif
break;
default:
pos = scnprintf(buf, size, "Unknown family %d",
sk->sk_family);
break;
}
TRACE_EXIT_RES(pos);
return pos;
}
static ssize_t iscsi_conn_target_ip_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
int pos;
struct iscsi_conn *conn;
TRACE_ENTRY();
conn = container_of(kobj, struct iscsi_conn, conn_kobj);
pos = iscsi_get_target_ip(conn, buf, SCST_SYSFS_BLOCK_SIZE);
TRACE_EXIT_RES(pos);
return pos;
}
static struct kobj_attribute iscsi_conn_target_ip_attr =
__ATTR(target_ip, S_IRUGO, iscsi_conn_target_ip_show, NULL);
static ssize_t iscsi_conn_cid_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
@@ -304,6 +364,14 @@ restart:
goto out_err;
}
res = sysfs_create_file(&conn->conn_kobj,
&iscsi_conn_target_ip_attr.attr);
if (res != 0) {
PRINT_ERROR("Unable create sysfs attribute %s for conn %s",
iscsi_conn_target_ip_attr.attr.name, addr);
goto out_err;
}
out:
TRACE_EXIT_RES(res);
return res;
+18 -5
View File
@@ -4091,6 +4091,7 @@ struct scst_tgt_template iscsi_template = {
.tgtt_attrs = iscsi_attrs,
.tgt_attrs = iscsi_tgt_attrs,
.sess_attrs = iscsi_sess_attrs,
.acg_attrs = iscsi_acg_attrs,
.enable_target = iscsi_enable_target,
.is_target_enabled = iscsi_is_target_enabled,
.add_target = iscsi_sysfs_add_target,
@@ -4192,7 +4193,7 @@ void iscsi_threads_pool_put(struct iscsi_thread_pool *p)
return;
}
int iscsi_threads_pool_get(const cpumask_t *cpu_mask,
int iscsi_threads_pool_get(bool dedicated, const cpumask_t *cpu_mask,
struct iscsi_thread_pool **out_pool)
{
int res;
@@ -4205,9 +4206,16 @@ int iscsi_threads_pool_get(const cpumask_t *cpu_mask,
mutex_lock(&iscsi_threads_pool_mutex);
if (dedicated) {
/* Ignore cpu_mask, if set */
cpu_mask = NULL;
goto create;
}
list_for_each_entry(p, &iscsi_thread_pools_list,
thread_pools_list_entry) {
if (!cpu_mask || cpumask_equal(cpu_mask, &p->cpu_mask)) {
if ((!cpu_mask || cpumask_equal(cpu_mask, &p->cpu_mask)) &&
!p->dedicated) {
p->thread_pool_ref++;
TRACE_DBG("iSCSI thread pool %p found (new ref %d)",
p, p->thread_pool_ref);
@@ -4216,7 +4224,9 @@ int iscsi_threads_pool_get(const cpumask_t *cpu_mask,
}
}
TRACE_DBG("%s", "Creating new iSCSI thread pool");
create:
TRACE_DBG("Creating new iSCSI thread pool (dedicated %d, cpu_mask %p)",
dedicated, cpu_mask);
p = kmem_cache_zalloc(iscsi_thread_pool_cache, GFP_KERNEL);
if (p == NULL) {
@@ -4247,8 +4257,11 @@ int iscsi_threads_pool_get(const cpumask_t *cpu_mask,
p->thread_pool_ref = 1;
mutex_init(&p->tp_mutex);
INIT_LIST_HEAD(&p->threads_list);
p->dedicated = dedicated;
if (cpu_mask == NULL)
if (dedicated)
count = 1;
else if (cpu_mask == NULL)
count = max_t(int, num_online_cpus(), 2);
else {
count = 0;
@@ -4395,7 +4408,7 @@ static int __init iscsi_init(void)
iscsi_conn_ktype.sysfs_ops = scst_sysfs_get_sysfs_ops();
#endif
err = iscsi_threads_pool_get(NULL, &iscsi_main_thread_pool);
err = iscsi_threads_pool_get(false, NULL, &iscsi_main_thread_pool);
if (err != 0)
goto out_thr;
+3 -1
View File
@@ -87,6 +87,7 @@ struct iscsi_thread_pool {
wait_queue_head_t wr_waitQ;
cpumask_t cpu_mask;
bool dedicated;
int thread_pool_ref;
@@ -558,7 +559,7 @@ extern int iscsi_preliminary_complete(struct iscsi_cmnd *req,
struct iscsi_cmnd *orig_req, bool get_data);
extern int set_scst_preliminary_status_rsp(struct iscsi_cmnd *req,
bool get_data, int key, int asc, int ascq);
extern int iscsi_threads_pool_get(const cpumask_t *cpu_mask,
extern int iscsi_threads_pool_get(bool dedicated, const cpumask_t *cpu_mask,
struct iscsi_thread_pool **out_pool);
extern void iscsi_threads_pool_put(struct iscsi_thread_pool *p);
@@ -633,6 +634,7 @@ extern void __iscsi_del_attr(struct iscsi_target *target,
/* session.c */
#ifndef CONFIG_SCST_PROC
extern const struct attribute *iscsi_sess_attrs[];
extern const struct attribute *iscsi_acg_attrs[];
#endif
extern const struct file_operations session_seq_fops;
extern struct iscsi_session *session_lookup(struct iscsi_target *, u64);
@@ -0,0 +1,257 @@
diff -upr linux-2.6.18/include/linux/mm.h linux-2.6.18/include/linux/mm.h
--- linux-2.6.18/include/linux/mm.h 2006-09-20 07:42:06.000000000 +0400
+++ linux-2.6.18/include/linux/mm.h 2007-08-07 19:35:51.000000000 +0400
@@ -277,6 +277,15 @@ struct page {
void *virtual; /* Kernel virtual address (NULL if
not kmapped, ie. highmem) */
#endif /* WANT_PAGE_VIRTUAL */
+ /*
+ * Used to implement support for notification on zero-copy TCP transfer
+ * completion. Not good to have this field here, it's better to have
+ * it in struct sk_buff, but it would make the code much more
+ * complicated and fragile, if maintained as a separate patch, since all
+ * skb then would have to contain only pages with the same value in this
+ * field.
+ */
+ void *net_priv;
};
#define page_private(page) ((page)->private)
diff -upr linux-2.6.18/include/linux/net.h linux-2.6.18/include/linux/net.h
--- linux-2.6.18/include/linux/net.h 2006-09-20 07:42:06.000000000 +0400
+++ linux-2.6.18/include/linux/net.h 2007-08-29 18:28:21.000000000 +0400
@@ -56,6 +56,7 @@ typedef enum {
#ifdef __KERNEL__
#include <linux/stringify.h>
+#include <linux/mm.h>
#define SOCK_ASYNC_NOSPACE 0
#define SOCK_ASYNC_WAITDATA 1
@@ -324,5 +325,30 @@ extern int net_msg_cost;
extern int net_msg_burst;
#endif
+/* Support for notification on zero-copy TCP transfer completion */
+#define CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION
+typedef void (*net_get_page_callback_t)(struct page *page);
+typedef void (*net_put_page_callback_t)(struct page *page);
+
+extern net_get_page_callback_t net_get_page_callback;
+extern net_put_page_callback_t net_put_page_callback;
+
+extern int net_set_get_put_page_callbacks(
+ net_get_page_callback_t get_callback,
+ net_put_page_callback_t put_callback);
+
+static inline void net_get_page(struct page *page)
+{
+ if (page->net_priv != 0)
+ net_get_page_callback(page);
+ get_page(page);
+}
+static inline void net_put_page(struct page *page)
+{
+ if (page->net_priv != 0)
+ net_put_page_callback(page);
+ put_page(page);
+}
+
#endif /* __KERNEL__ */
#endif /* _LINUX_NET_H */
diff -upr linux-2.6.18/net/core/skbuff.c linux-2.6.18/net/core/skbuff.c
--- linux-2.6.18/net/core/skbuff.c 2006-09-20 07:42:06.000000000 +0400
+++ linux-2.6.18/net/core/skbuff.c 2007-08-07 19:35:51.000000000 +0400
@@ -324,7 +324,7 @@ static void skb_release_data(struct sk_b
if (skb_shinfo(skb)->nr_frags) {
int i;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
- put_page(skb_shinfo(skb)->frags[i].page);
+ net_put_page(skb_shinfo(skb)->frags[i].page);
}
if (skb_shinfo(skb)->frag_list)
@@ -666,7 +666,7 @@ struct sk_buff *pskb_copy(struct sk_buff
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i];
- get_page(skb_shinfo(n)->frags[i].page);
+ net_get_page(skb_shinfo(n)->frags[i].page);
}
skb_shinfo(n)->nr_frags = i;
}
@@ -720,7 +720,7 @@ int pskb_expand_head(struct sk_buff *skb
memcpy(data + size, skb->end, sizeof(struct skb_shared_info));
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
- get_page(skb_shinfo(skb)->frags[i].page);
+ net_get_page(skb_shinfo(skb)->frags[i].page);
if (skb_shinfo(skb)->frag_list)
skb_clone_fraglist(skb);
@@ -902,7 +902,7 @@ drop_pages:
skb_shinfo(skb)->nr_frags = i;
for (; i < nfrags; i++)
- put_page(skb_shinfo(skb)->frags[i].page);
+ net_put_page(skb_shinfo(skb)->frags[i].page);
if (skb_shinfo(skb)->frag_list)
skb_drop_fraglist(skb);
@@ -1071,7 +1071,7 @@ pull_pages:
k = 0;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
if (skb_shinfo(skb)->frags[i].size <= eat) {
- put_page(skb_shinfo(skb)->frags[i].page);
+ net_put_page(skb_shinfo(skb)->frags[i].page);
eat -= skb_shinfo(skb)->frags[i].size;
} else {
skb_shinfo(skb)->frags[k] = skb_shinfo(skb)->frags[i];
@@ -1653,7 +1653,7 @@ static inline void skb_split_no_header(s
* where splitting is expensive.
* 2. Split is accurately. We make this.
*/
- get_page(skb_shinfo(skb)->frags[i].page);
+ net_get_page(skb_shinfo(skb)->frags[i].page);
skb_shinfo(skb1)->frags[0].page_offset += len - pos;
skb_shinfo(skb1)->frags[0].size -= len - pos;
skb_shinfo(skb)->frags[i].size = len - pos;
@@ -2021,7 +2021,7 @@ struct sk_buff *skb_segment(struct sk_bu
BUG_ON(i >= nfrags);
*frag = skb_shinfo(skb)->frags[i];
- get_page(frag->page);
+ net_get_page(frag->page);
size = frag->size;
if (pos < offset) {
diff -upr linux-2.6.18/net/core/utils.c linux-2.6.18/net/core/utils.c
--- linux-2.6.18/net/core/utils.c 2006-09-20 07:42:06.000000000 +0400
+++ linux-2.6.18/net/core/utils.c 2007-08-23 19:49:40.000000000 +0400
@@ -24,11 +24,15 @@
#include <linux/random.h>
#include <linux/percpu.h>
#include <linux/init.h>
+#include <linux/skbuff.h>
#include <asm/byteorder.h>
#include <asm/system.h>
#include <asm/uaccess.h>
+net_get_page_callback_t net_get_page_callback __read_mostly;
+net_put_page_callback_t net_put_page_callback __read_mostly;
+
/*
This is a maximally equidistributed combined Tausworthe generator
based on code from GNU Scientific Library 1.5 (30 Jun 2004)
@@ -203,3 +203,32 @@ __be32 in_aton(const char *str)
}
EXPORT_SYMBOL(in_aton);
+
+int net_set_get_put_page_callbacks(
+ net_get_page_callback_t get_callback,
+ net_put_page_callback_t put_callback)
+{
+ int res = 0;
+
+ if ((net_get_page_callback != NULL) && (get_callback != NULL) &&
+ (net_get_page_callback != get_callback)) {
+ res = -EBUSY;
+ goto out;
+ }
+
+ if ((net_put_page_callback != NULL) && (put_callback != NULL) &&
+ (net_put_page_callback != put_callback)) {
+ res = -EBUSY;
+ goto out;
+ }
+
+ net_get_page_callback = get_callback;
+ net_put_page_callback = put_callback;
+
+out:
+ return res;
+}
+EXPORT_SYMBOL(net_set_get_put_page_callbacks);
+
+EXPORT_SYMBOL(net_get_page_callback);
+EXPORT_SYMBOL(net_put_page_callback);
diff -upr linux-2.6.18/net/ipv4/ip_output.c linux-2.6.18/net/ipv4/ip_output.c
--- linux-2.6.18/net/ipv4/ip_output.c 2006-09-20 07:42:06.000000000 +0400
+++ linux-2.6.18/net/ipv4/ip_output.c 2007-08-07 19:37:24.000000000 +0400
@@ -1006,7 +1006,7 @@ alloc_new_skb:
err = -EMSGSIZE;
goto error;
}
- get_page(page);
+ net_get_page(page);
skb_fill_page_desc(skb, i, page, sk->sk_sndmsg_off, 0);
frag = &skb_shinfo(skb)->frags[i];
}
@@ -1166,7 +1166,7 @@ ssize_t ip_append_page(struct sock *sk,
if (skb_can_coalesce(skb, i, page, offset)) {
skb_shinfo(skb)->frags[i-1].size += len;
} else if (i < MAX_SKB_FRAGS) {
- get_page(page);
+ net_get_page(page);
skb_fill_page_desc(skb, i, page, offset, len);
} else {
err = -EMSGSIZE;
diff -upr linux-2.6.18/net/ipv4/tcp.c linux-2.6.18/net/ipv4/tcp.c
--- linux-2.6.18/net/ipv4/tcp.c 2006-09-20 07:42:06.000000000 +0400
+++ linux-2.6.18/net/ipv4/tcp.c 2007-08-07 19:35:51.000000000 +0400
@@ -560,7 +560,7 @@ new_segment:
if (can_coalesce) {
skb_shinfo(skb)->frags[i - 1].size += copy;
} else {
- get_page(page);
+ net_get_page(page);
skb_fill_page_desc(skb, i, page, offset, copy);
}
@@ -763,7 +763,7 @@ new_segment:
goto new_segment;
} else if (page) {
if (off == PAGE_SIZE) {
- put_page(page);
+ net_put_page(page);
TCP_PAGE(sk) = page = NULL;
off = 0;
}
@@ -804,9 +804,9 @@ new_segment:
} else {
skb_fill_page_desc(skb, i, page, off, copy);
if (TCP_PAGE(sk)) {
- get_page(page);
+ net_get_page(page);
} else if (off + copy < PAGE_SIZE) {
- get_page(page);
+ net_get_page(page);
TCP_PAGE(sk) = page;
}
}
diff -upr linux-2.6.18/net/ipv4/tcp_output.c linux-2.6.18/net/ipv4/tcp_output.c
--- linux-2.6.18/net/ipv4/tcp_output.c 2006-09-20 07:42:06.000000000 +0400
+++ linux-2.6.18/net/ipv4/tcp_output.c 2007-08-07 19:35:51.000000000 +0400
@@ -659,7 +659,7 @@ static void __pskb_trim_head(struct sk_b
k = 0;
for (i=0; i<skb_shinfo(skb)->nr_frags; i++) {
if (skb_shinfo(skb)->frags[i].size <= eat) {
- put_page(skb_shinfo(skb)->frags[i].page);
+ net_put_page(skb_shinfo(skb)->frags[i].page);
eat -= skb_shinfo(skb)->frags[i].size;
} else {
skb_shinfo(skb)->frags[k] = skb_shinfo(skb)->frags[i];
diff -upr linux-2.6.18/net/ipv6/ip6_output.c linux-2.6.18/net/ipv6/ip6_output.c
--- linux-2.6.18/net/ipv6/ip6_output.c 2006-09-20 07:42:06.000000000 +0400
+++ linux-2.6.18/net/ipv6/ip6_output.c 2007-08-07 19:35:51.000000000 +0400
@@ -1212,7 +1212,7 @@ alloc_new_skb:
err = -EMSGSIZE;
goto error;
}
- get_page(page);
+ net_get_page(page);
skb_fill_page_desc(skb, i, page, sk->sk_sndmsg_off, 0);
frag = &skb_shinfo(skb)->frags[i];
}
@@ -0,0 +1,401 @@
diff -uNrp linux-2.6.32-131.4.1.el6.x86_64.orig/include/linux/Kbuild linux-2.6.32-131.4.1.el6.x86_64.new/include/linux/Kbuild
--- linux-2.6.32-131.4.1.el6.x86_64.orig/include/linux/Kbuild 2011-07-09 00:47:13.884215174 +0200
+++ linux-2.6.32-131.4.1.el6.x86_64.new/include/linux/Kbuild 2011-07-09 00:47:47.530389221 +0200
@@ -113,6 +113,7 @@ header-y += map_to_7segment.h
header-y += matroxfb.h
header-y += meye.h
header-y += minix_fs.h
+header-y += mm.h
header-y += mmtimer.h
header-y += mqueue.h
header-y += mtio.h
diff -uNrp linux-2.6.32-131.4.1.el6.x86_64.orig/include/linux/mm_types.h linux-2.6.32-131.4.1.el6.x86_64.new/include/linux/mm_types.h
--- linux-2.6.32-131.4.1.el6.x86_64.orig/include/linux/mm_types.h 2011-07-09 00:47:13.893191775 +0200
+++ linux-2.6.32-131.4.1.el6.x86_64.new/include/linux/mm_types.h 2011-07-09 00:47:47.533311169 +0200
@@ -106,6 +106,18 @@ struct page {
*/
void *shadow;
#endif
+
+#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
+ /*
+ * Used to implement support for notification on zero-copy TCP transfer
+ * completion. It might look as not good to have this field here and
+ * it's better to have it in struct sk_buff, but it would make the code
+ * much more complicated and fragile, since all skb then would have to
+ * contain only pages with the same value in this field.
+ */
+ void *net_priv;
+#endif
+
};
/*
diff -uNrp linux-2.6.32-131.4.1.el6.x86_64.orig/include/linux/net.h linux-2.6.32-131.4.1.el6.x86_64.new/include/linux/net.h
--- linux-2.6.32-131.4.1.el6.x86_64.orig/include/linux/net.h 2011-07-09 00:47:13.867629724 +0200
+++ linux-2.6.32-131.4.1.el6.x86_64.new/include/linux/net.h 2011-07-09 00:47:47.536207157 +0200
@@ -20,6 +20,7 @@
#include <linux/socket.h>
#include <asm/socket.h>
+#include <linux/mm.h>
#define NPROTO AF_MAX
@@ -365,5 +366,44 @@ static const struct proto_ops name##_ops
extern struct ratelimit_state net_ratelimit_state;
#endif
+#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
+/* Support for notification on zero-copy TCP transfer completion */
+typedef void (*net_get_page_callback_t)(struct page *page);
+typedef void (*net_put_page_callback_t)(struct page *page);
+
+extern net_get_page_callback_t net_get_page_callback;
+extern net_put_page_callback_t net_put_page_callback;
+
+extern int net_set_get_put_page_callbacks(
+ net_get_page_callback_t get_callback,
+ net_put_page_callback_t put_callback);
+
+/*
+ * See comment for net_set_get_put_page_callbacks() why those functions
+ * don't need any protection.
+ */
+static inline void net_get_page(struct page *page)
+{
+ if (page->net_priv != 0)
+ net_get_page_callback(page);
+ get_page(page);
+}
+static inline void net_put_page(struct page *page)
+{
+ if (page->net_priv != 0)
+ net_put_page_callback(page);
+ put_page(page);
+}
+#else
+static inline void net_get_page(struct page *page)
+{
+ get_page(page);
+}
+static inline void net_put_page(struct page *page)
+{
+ put_page(page);
+}
+#endif /* CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION */
+
#endif /* __KERNEL__ */
#endif /* _LINUX_NET_H */
diff -uNrp linux-2.6.32-131.4.1.el6.x86_64.orig/net/core/dev.c linux-2.6.32-131.4.1.el6.x86_64.new/net/core/dev.c
--- linux-2.6.32-131.4.1.el6.x86_64.orig/net/core/dev.c 2011-07-09 00:47:14.491417046 +0200
+++ linux-2.6.32-131.4.1.el6.x86_64.new/net/core/dev.c 2011-07-09 00:47:47.538194361 +0200
@@ -2903,7 +2903,7 @@ pull:
skb_shinfo(skb)->frags[0].size -= grow;
if (unlikely(!skb_shinfo(skb)->frags[0].size)) {
- put_page(skb_shinfo(skb)->frags[0].page);
+ net_put_page(skb_shinfo(skb)->frags[0].page);
memmove(skb_shinfo(skb)->frags,
skb_shinfo(skb)->frags + 1,
--skb_shinfo(skb)->nr_frags);
diff -uNrp linux-2.6.32-131.4.1.el6.x86_64.orig/net/core/skbuff.c linux-2.6.32-131.4.1.el6.x86_64.new/net/core/skbuff.c
--- linux-2.6.32-131.4.1.el6.x86_64.orig/net/core/skbuff.c 2011-07-09 00:47:14.491417046 +0200
+++ linux-2.6.32-131.4.1.el6.x86_64.new/net/core/skbuff.c 2011-07-09 00:47:47.542260687 +0200
@@ -76,13 +76,13 @@ static struct kmem_cache *skbuff_fclone_
static void sock_pipe_buf_release(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
{
- put_page(buf->page);
+ net_put_page(buf->page);
}
static void sock_pipe_buf_get(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
{
- get_page(buf->page);
+ net_get_page(buf->page);
}
static int sock_pipe_buf_steal(struct pipe_inode_info *pipe,
@@ -344,7 +344,7 @@ static void skb_release_data(struct sk_b
if (skb_shinfo(skb)->nr_frags) {
int i;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
- put_page(skb_shinfo(skb)->frags[i].page);
+ net_put_page(skb_shinfo(skb)->frags[i].page);
}
if (skb_has_frags(skb))
@@ -766,7 +766,7 @@ struct sk_buff *pskb_copy(struct sk_buff
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i];
- get_page(skb_shinfo(n)->frags[i].page);
+ net_get_page(skb_shinfo(n)->frags[i].page);
}
skb_shinfo(n)->nr_frags = i;
}
@@ -832,7 +832,7 @@ int pskb_expand_head(struct sk_buff *skb
sizeof(struct skb_shared_info));
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
- get_page(skb_shinfo(skb)->frags[i].page);
+ net_get_page(skb_shinfo(skb)->frags[i].page);
if (skb_has_frags(skb))
skb_clone_fraglist(skb);
@@ -1106,7 +1106,7 @@ drop_pages:
skb_shinfo(skb)->nr_frags = i;
for (; i < nfrags; i++)
- put_page(skb_shinfo(skb)->frags[i].page);
+ net_put_page(skb_shinfo(skb)->frags[i].page);
if (skb_has_frags(skb))
skb_drop_fraglist(skb);
@@ -1275,7 +1275,7 @@ pull_pages:
k = 0;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
if (skb_shinfo(skb)->frags[i].size <= eat) {
- put_page(skb_shinfo(skb)->frags[i].page);
+ net_put_page(skb_shinfo(skb)->frags[i].page);
eat -= skb_shinfo(skb)->frags[i].size;
} else {
skb_shinfo(skb)->frags[k] = skb_shinfo(skb)->frags[i];
@@ -1376,7 +1376,7 @@ EXPORT_SYMBOL(skb_copy_bits);
*/
static void sock_spd_release(struct splice_pipe_desc *spd, unsigned int i)
{
- put_page(spd->pages[i]);
+ net_put_page(spd->pages[i]);
}
static inline struct page *linear_to_page(struct page *page, unsigned int *len,
@@ -1400,7 +1400,7 @@ new_page:
off = sk->sk_sndmsg_off;
mlen = PAGE_SIZE - off;
if (mlen < 64 && mlen < *len) {
- put_page(p);
+ net_put_page(p);
goto new_page;
}
@@ -1410,7 +1410,7 @@ new_page:
memcpy(page_address(p) + off, page_address(page) + *offset, *len);
sk->sk_sndmsg_off += *len;
*offset = off;
- get_page(p);
+ net_get_page(p);
return p;
}
@@ -1431,7 +1431,7 @@ static inline int spd_fill_page(struct s
if (!page)
return 1;
} else
- get_page(page);
+ net_get_page(page);
spd->pages[spd->nr_pages] = page;
spd->partial[spd->nr_pages].len = *len;
@@ -2061,7 +2061,7 @@ static inline void skb_split_no_header(s
* where splitting is expensive.
* 2. Split is accurately. We make this.
*/
- get_page(skb_shinfo(skb)->frags[i].page);
+ net_get_page(skb_shinfo(skb)->frags[i].page);
skb_shinfo(skb1)->frags[0].page_offset += len - pos;
skb_shinfo(skb1)->frags[0].size -= len - pos;
skb_shinfo(skb)->frags[i].size = len - pos;
@@ -2183,7 +2183,7 @@ int skb_shift(struct sk_buff *tgt, struc
to++;
} else {
- get_page(fragfrom->page);
+ net_get_page(fragfrom->page);
fragto->page = fragfrom->page;
fragto->page_offset = fragfrom->page_offset;
fragto->size = todo;
@@ -2205,7 +2205,7 @@ int skb_shift(struct sk_buff *tgt, struc
fragto = &skb_shinfo(tgt)->frags[merge];
fragto->size += fragfrom->size;
- put_page(fragfrom->page);
+ net_put_page(fragfrom->page);
}
/* Reposition in the original skb */
@@ -2600,7 +2600,7 @@ struct sk_buff *skb_segment(struct sk_bu
while (pos < offset + len && i < nfrags) {
*frag = skb_shinfo(skb)->frags[i];
- get_page(frag->page);
+ net_get_page(frag->page);
size = frag->size;
if (pos < offset) {
diff -uNrp linux-2.6.32-131.4.1.el6.x86_64.orig/net/ipv4/ip_output.c linux-2.6.32-131.4.1.el6.x86_64.new/net/ipv4/ip_output.c
--- linux-2.6.32-131.4.1.el6.x86_64.orig/net/ipv4/ip_output.c 2011-07-09 00:47:14.538469946 +0200
+++ linux-2.6.32-131.4.1.el6.x86_64.new/net/ipv4/ip_output.c 2011-07-09 00:47:47.544855733 +0200
@@ -981,7 +981,7 @@ alloc_new_skb:
err = -EMSGSIZE;
goto error;
}
- get_page(page);
+ net_get_page(page);
skb_fill_page_desc(skb, i, page, off, 0);
frag = &skb_shinfo(skb)->frags[i];
}
@@ -1213,7 +1213,7 @@ ssize_t ip_append_page(struct sock *sk,
if (skb_can_coalesce(skb, i, page, offset)) {
skb_shinfo(skb)->frags[i-1].size += len;
} else if (i < MAX_SKB_FRAGS) {
- get_page(page);
+ net_get_page(page);
skb_fill_page_desc(skb, i, page, offset, len);
} else {
err = -EMSGSIZE;
diff -uNrp linux-2.6.32-131.4.1.el6.x86_64.orig/net/ipv4/Makefile linux-2.6.32-131.4.1.el6.x86_64.new/net/ipv4/Makefile
--- linux-2.6.32-131.4.1.el6.x86_64.orig/net/ipv4/Makefile 2011-07-09 00:47:14.540204846 +0200
+++ linux-2.6.32-131.4.1.el6.x86_64.new/net/ipv4/Makefile 2011-07-09 00:47:47.544855733 +0200
@@ -49,6 +49,7 @@ obj-$(CONFIG_TCP_CONG_LP) += tcp_lp.o
obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o
obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o
obj-$(CONFIG_NETLABEL) += cipso_ipv4.o
+obj-$(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION) += tcp_zero_copy.o
obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \
xfrm4_output.o
diff -uNrp linux-2.6.32-131.4.1.el6.x86_64.orig/net/ipv4/tcp.c linux-2.6.32-131.4.1.el6.x86_64.new/net/ipv4/tcp.c
--- linux-2.6.32-131.4.1.el6.x86_64.orig/net/ipv4/tcp.c 2011-07-09 00:47:14.522494769 +0200
+++ linux-2.6.32-131.4.1.el6.x86_64.new/net/ipv4/tcp.c 2011-07-09 00:47:47.548279863 +0200
@@ -799,7 +799,7 @@ new_segment:
if (can_coalesce) {
skb_shinfo(skb)->frags[i - 1].size += copy;
} else {
- get_page(page);
+ net_get_page(page);
skb_fill_page_desc(skb, i, page, offset, copy);
}
@@ -1007,7 +1007,7 @@ new_segment:
goto new_segment;
} else if (page) {
if (off == PAGE_SIZE) {
- put_page(page);
+ net_put_page(page);
TCP_PAGE(sk) = page = NULL;
off = 0;
}
@@ -1048,9 +1048,9 @@ new_segment:
} else {
skb_fill_page_desc(skb, i, page, off, copy);
if (TCP_PAGE(sk)) {
- get_page(page);
+ net_get_page(page);
} else if (off + copy < PAGE_SIZE) {
- get_page(page);
+ net_get_page(page);
TCP_PAGE(sk) = page;
}
}
diff -uNrp linux-2.6.32-131.4.1.el6.x86_64.orig/net/ipv4/tcp_output.c linux-2.6.32-131.4.1.el6.x86_64.new/net/ipv4/tcp_output.c
--- linux-2.6.32-131.4.1.el6.x86_64.orig/net/ipv4/tcp_output.c 2011-07-09 00:47:14.535532920 +0200
+++ linux-2.6.32-131.4.1.el6.x86_64.new/net/ipv4/tcp_output.c 2011-07-09 00:47:47.548279863 +0200
@@ -909,7 +909,7 @@ static void __pskb_trim_head(struct sk_b
k = 0;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
if (skb_shinfo(skb)->frags[i].size <= eat) {
- put_page(skb_shinfo(skb)->frags[i].page);
+ net_put_page(skb_shinfo(skb)->frags[i].page);
eat -= skb_shinfo(skb)->frags[i].size;
} else {
skb_shinfo(skb)->frags[k] = skb_shinfo(skb)->frags[i];
diff -uNrp linux-2.6.32-131.4.1.el6.x86_64.orig/net/ipv4/tcp_zero_copy.c linux-2.6.32-131.4.1.el6.x86_64.new/net/ipv4/tcp_zero_copy.c
--- linux-2.6.32-131.4.1.el6.x86_64.orig/net/ipv4/tcp_zero_copy.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.32-131.4.1.el6.x86_64.new/net/ipv4/tcp_zero_copy.c 2011-07-09 00:47:47.548279863 +0200
@@ -0,0 +1,49 @@
+/*
+ * Support routines for TCP zero copy transmit
+ *
+ * Created by Vladislav Bolkhovitin
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/skbuff.h>
+
+net_get_page_callback_t net_get_page_callback __read_mostly;
+EXPORT_SYMBOL(net_get_page_callback);
+
+net_put_page_callback_t net_put_page_callback __read_mostly;
+EXPORT_SYMBOL(net_put_page_callback);
+
+/*
+ * Caller of this function must ensure that at the moment when it's called
+ * there are no pages in the system with net_priv field set to non-zero
+ * value. Hence, this function, as well as net_get_page() and net_put_page(),
+ * don't need any protection.
+ */
+int net_set_get_put_page_callbacks(
+ net_get_page_callback_t get_callback,
+ net_put_page_callback_t put_callback)
+{
+ int res = 0;
+
+ if ((net_get_page_callback != NULL) && (get_callback != NULL) &&
+ (net_get_page_callback != get_callback)) {
+ res = -EBUSY;
+ goto out;
+ }
+
+ if ((net_put_page_callback != NULL) && (put_callback != NULL) &&
+ (net_put_page_callback != put_callback)) {
+ res = -EBUSY;
+ goto out;
+ }
+
+ net_get_page_callback = get_callback;
+ net_put_page_callback = put_callback;
+
+out:
+ return res;
+}
+EXPORT_SYMBOL(net_set_get_put_page_callbacks);
diff -uNrp linux-2.6.32-131.4.1.el6.x86_64.orig/net/ipv6/ip6_output.c linux-2.6.32-131.4.1.el6.x86_64.new/net/ipv6/ip6_output.c
--- linux-2.6.32-131.4.1.el6.x86_64.orig/net/ipv6/ip6_output.c 2011-07-09 00:47:14.498374289 +0200
+++ linux-2.6.32-131.4.1.el6.x86_64.new/net/ipv6/ip6_output.c 2011-07-09 00:47:47.557327813 +0200
@@ -1370,7 +1370,7 @@ alloc_new_skb:
err = -EMSGSIZE;
goto error;
}
- get_page(page);
+ net_get_page(page);
skb_fill_page_desc(skb, i, page, sk->sk_sndmsg_off, 0);
frag = &skb_shinfo(skb)->frags[i];
}
diff -uNrp linux-2.6.32-131.4.1.el6.x86_64.orig/net/Kconfig linux-2.6.32-131.4.1.el6.x86_64.new/net/Kconfig
--- linux-2.6.32-131.4.1.el6.x86_64.orig/net/Kconfig 2011-07-09 00:47:14.452504858 +0200
+++ linux-2.6.32-131.4.1.el6.x86_64.new/net/Kconfig 2011-07-09 00:47:47.557327813 +0200
@@ -72,6 +72,18 @@ config INET
Short answer: say Y.
+config TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION
+ bool "TCP/IP zero-copy transfer completion notification"
+ depends on INET
+ default SCST_ISCSI
+ ---help---
+ Adds support for sending a notification upon completion of a
+ zero-copy TCP/IP transfer. This can speed up certain TCP/IP
+ software. Currently this is only used by the iSCSI target driver
+ iSCSI-SCST.
+
+ If unsure, say N.
+
if INET
source "net/ipv4/Kconfig"
source "net/ipv6/Kconfig"
+5 -6
View File
@@ -99,7 +99,9 @@ static int iscsi_session_alloc(struct iscsi_target *target,
}
if (!session->sess_params.rdma_extensions) {
err = iscsi_threads_pool_get(&session->scst_sess->acg->acg_cpu_mask,
err = iscsi_threads_pool_get(
(bool)scst_get_acg_tgt_priv(session->scst_sess->acg),
&session->scst_sess->acg->acg_cpu_mask,
&session->sess_thr_pool);
if (err != 0)
goto err_unreg;
@@ -289,6 +291,8 @@ out_err_unlock:
static void __session_free(struct iscsi_session *session)
{
if (session->sess_thr_pool)
iscsi_threads_pool_put(session->sess_thr_pool);
kfree(session->initiator_name);
kmem_cache_free(iscsi_sess_cache, session);
}
@@ -347,11 +351,6 @@ int session_free(struct iscsi_session *session, bool del)
if (del)
list_del(&session->session_list_entry);
if (session->sess_thr_pool != NULL) {
iscsi_threads_pool_put(session->sess_thr_pool);
session->sess_thr_pool = NULL;
}
if (session->scst_sess != NULL) {
/*
* We must NOT call scst_unregister_session() in the waiting
+59
View File
@@ -655,4 +655,63 @@ ssize_t iscsi_sysfs_mgmt_cmd(char *cmd)
return res;
}
static ssize_t iscsi_acg_sess_dedicated_threads_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
int pos;
struct scst_acg *acg;
bool dedicated;
TRACE_ENTRY();
acg = container_of(kobj, struct scst_acg, acg_kobj);
dedicated = (bool)scst_get_acg_tgt_priv(acg);
pos = sprintf(buf, "%d\n%s", dedicated,
dedicated ? SCST_SYSFS_KEY_MARK "\n" : "");
TRACE_EXIT_RES(pos);
return pos;
}
static ssize_t iscsi_acg_sess_dedicated_threads_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
int res;
struct scst_acg *acg;
unsigned long val;
TRACE_ENTRY();
acg = container_of(kobj, struct scst_acg, acg_kobj);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
res = kstrtoul(buf, 0, &val);
#else
res = strict_strtoul(buf, 0, &val);
#endif
if (res != 0) {
PRINT_ERROR("strict_strtoul() for %s failed: %d ", buf, res);
goto out;
}
scst_set_acg_tgt_priv(acg, (void *)(unsigned long)(val != 0));
res = count;
out:
TRACE_EXIT_RES(res);
return res;
}
static struct kobj_attribute iscsi_acg_attr_sess_dedicated_threads =
__ATTR(per_sess_dedicated_tgt_threads, S_IRUGO | S_IWUSR,
iscsi_acg_sess_dedicated_threads_show,
iscsi_acg_sess_dedicated_threads_store);
const struct attribute *iscsi_acg_attrs[] = {
&iscsi_acg_attr_sess_dedicated_threads.attr,
NULL,
};
#endif /* CONFIG_SCST_PROC */
+26 -2
View File
@@ -501,6 +501,9 @@ following entries:
or -errno for error). The following two shell functions show how to do
this:
- force_global_sgv_pool - if not set, buffers for SCSI commands are
allocated from per-CPU SGV pool. Otherwise, global SGV pool is used.
# Read the SCST sysfs attribute $1. See also scst/README for more information.
scst_sysfs_read() {
local EAGAIN val
@@ -563,6 +566,13 @@ SCST dev handlers can have the following common entries:
- type - SCSI type of this device
- max_tgt_dev_commands - maximum number of SCSI commands any session to
this device can have in flight.
- numa_node_id - NUMA node id this device physically belongs to. SCST
NUMA handling assumes that being used in the system NUMA memory
allocation policy is to always allocate from the current node.
Attribute "block" allows to temporary block and unblock this device.
"Blocking" means that no new commands for this device will go into the
execution stage, but instead will be suspended just before it. The
@@ -845,6 +855,14 @@ Each sessions/<sess>/lun<X> subdirectory contains the following entries:
(PIDs) of the kernel threads that process SCSI commands intended for
lun<X> in session <sess>.
- thread_index - thread index assigned by scst_add_threads().
Can be used to look up which export thread is serving which target
since this index also appears in the export thread name. This
information then could be used to set CPU affinity for those threads
to improve performance. Has a value in the range 0..n-1 for
threads_pool_type per_initiator or -1 when using a shared thread pool
per LUN or the global thread pool.
Access and devices visibility management (LUN masking)
------------------------------------------------------
@@ -1246,6 +1264,11 @@ Each vdisk_fileio's device has the following attributes in
- thin_provisioned - contains thin provisioning status of this virtual
device.
- gen_tp_soft_threshold_reached_UA - for thin provisioned devices
writing of anything into this write-only attribute will generate THIN
PROVISIONING SOFT THRESHOLD REACHED Unit Attention to all connected
to this device initiators.
- removable - contains removable status of this virtual device.
- rotational - contains rotational status of this virtual device.
@@ -1347,8 +1370,9 @@ For example:
Each vdisk_blockio's device has the following attributes in
/sys/kernel/scst_tgt/devices/device_name: blocksize, filename, nv_cache,
read_only, removable, resync_size, rotational, size_mb, t10_dev_id,
thin_provisioned, threads_num, threads_pool_type, tst, type, usn. See
above description of those parameters.
thin_provisioned, gen_tp_soft_threshold_reached_UA, threads_num,
threads_pool_type, tst, type, usn. See above description of those
parameters.
Each vdisk_nullio's device has the following attributes in
/sys/kernel/scst_tgt/devices/device_name: blocksize, read_only,
+26 -2
View File
@@ -365,6 +365,9 @@ following entries:
or -errno for error). The following two shell functions show how to do
this:
- force_global_sgv_pool - if not set, buffers for SCSI commands are
allocated from per-CPU SGV pool. Otherwise, global SGV pool is used.
# Read the SCST sysfs attribute $1. See also scst/README for more information.
scst_sysfs_read() {
local EAGAIN val
@@ -427,6 +430,13 @@ SCST dev handlers can have the following common entries:
- type - SCSI type of this device
- max_tgt_dev_commands - maximum number of SCSI commands any session to
this device can have in flight.
- numa_node_id - NUMA node id this device physically belongs to. SCST
NUMA handling assumes that being used in the system NUMA memory
allocation policy is to always allocate from the current node.
Attribute "block" allows to temporary block and unblock this device.
"Blocking" means that no new commands for this device will go into the
execution stage, but instead will be suspended just before it. The
@@ -709,6 +719,14 @@ Each sessions/<sess>/lun<X> subdirectory contains the following entries:
(PIDs) of the kernel threads that process SCSI commands intended for
lun<X> in session <sess>.
- thread_index - thread index assigned by scst_add_threads().
Can be used to look up which export thread is serving which target
since this index also appears in the export thread name. This
information then could be used to set CPU affinity for those threads
to improve performance. Has a value in the range 0..n-1 for
threads_pool_type per_initiator or -1 when using a shared thread pool
per LUN or the global thread pool.
Access and devices visibility management (LUN masking)
------------------------------------------------------
@@ -1106,6 +1124,11 @@ Each vdisk_fileio's device has the following attributes in
- thin_provisioned - contains thin provisioning status of this virtual
device.
- gen_tp_soft_threshold_reached_UA - for thin provisioned devices
writing of anything into this write-only attribute will generate THIN
PROVISIONING SOFT THRESHOLD REACHED Unit Attention to all connected
to this device initiators.
- removable - contains removable status of this virtual device.
- rotational - contains rotational status of this virtual device.
@@ -1205,8 +1228,9 @@ For example:
Each vdisk_blockio's device has the following attributes in
/sys/kernel/scst_tgt/devices/device_name: blocksize, filename, nv_cache,
read_only, removable, resync_size, rotational, size_mb, t10_dev_id,
thin_provisioned, threads_num, threads_pool_type, tst, type, usn. See
above description of those parameters.
thin_provisioned, gen_tp_soft_threshold_reached_UA, threads_num,
threads_pool_type, tst, type, usn. See above description of those
parameters.
Each vdisk_nullio's device has the following attributes in
/sys/kernel/scst_tgt/devices/device_name: blocksize, read_only,
+3 -1
View File
@@ -335,13 +335,15 @@ enum umh_wait {
LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 41)) && \
! (LINUX_VERSION_CODE >> 8 == KERNEL_VERSION(3, 2, 0) >> 8 && \
LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 44)) && \
!defined(CONFIG_SUSE_KERNEL) && \
(!defined(CONFIG_SUSE_KERNEL) || \
LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 101)) && \
(!defined(RHEL_MAJOR) || RHEL_MAJOR -0 < 6 || \
(RHEL_MAJOR -0 == 6 && RHEL_MINOR -0 < 6))
/*
* See also commit 4b20db3 (kref: Implement kref_get_unless_zero v3 -- v3.8).
* See also commit e3a5505 in branch stable/linux-3.4.y (v3.4.41).
* See also commit 3fa8ee5 in branch stable/linux-3.2.y (v3.2.44).
* See also commit 6b9508d in the SuSE kernel tree.
*/
static inline int __must_check kref_get_unless_zero(struct kref *kref)
{
+105 -18
View File
@@ -73,6 +73,26 @@
#include <scst_const.h>
#endif
#ifdef NOLOCKDEP_SUPPORTED
#define spin_lock_nolockdep(lock) do { current->nolockdep_call = 1; spin_lock(lock); current->nolockdep_call = 0; } while (0)
#define spin_unlock_nolockdep(lock) do { current->nolockdep_call = 1; spin_unlock(lock); current->nolockdep_call = 0; } while (0)
#define mutex_lock_nolockdep(lock) do { current->nolockdep_call = 1; mutex_lock(lock); current->nolockdep_call = 0; } while (0)
#define mutex_unlock_nolockdep(lock) do { current->nolockdep_call = 1; mutex_unlock(lock); current->nolockdep_call = 0; } while (0)
#define down_read_nolockdep(lock) do { current->nolockdep_call = 1; down_read(lock); current->nolockdep_call = 0; } while (0)
#define up_read_nolockdep(lock) do { current->nolockdep_call = 1; up_read(lock); current->nolockdep_call = 0; } while (0)
#define down_write_nolockdep(lock) do { current->nolockdep_call = 1; down_write(lock); current->nolockdep_call = 0; } while (0)
#define up_write_nolockdep(lock) do { current->nolockdep_call = 1; up_write(lock); current->nolockdep_call = 0; } while (0)
#else
#define spin_lock_nolockdep spin_lock
#define spin_unlock_nolockdep spin_unlock
#define mutex_lock_nolockdep mutex_lock
#define mutex_unlock_nolockdep mutex_unlock
#define down_read_nolockdep down_read
#define up_read_nolockdep up_read
#define down_write_nolockdep down_write
#define up_write_nolockdep up_write
#endif
#ifdef INSIDE_KERNEL_TREE
#include <scst/scst_sgv.h>
#else
@@ -449,7 +469,7 @@ enum scst_exec_context {
/*
* Set if no response should be sent to the target about this cmd.
* Must be set together with SCST_CMD_ABORTED for better processing
* Must be set together with SCST_CMD_ABORTED for better ACA processing
* in scst_pre_xmit_response2().
*/
#define SCST_CMD_NO_RESP 2
@@ -770,13 +790,6 @@ struct scst_tgt_template {
unsigned enabled_attr_not_needed:1;
#endif
/*
* True if SCST should report that it supports ACA although it does
* not yet support ACA. Necessary for the IBM virtual SCSI target
* driver.
*/
unsigned fake_aca:1;
/*
* True, if this target adapter can call scst_cmd_init_done() from
* several threads at the same time.
@@ -1219,6 +1232,9 @@ struct scst_tgt_template {
/* sysfs session attributes, if any */
const struct attribute **sess_attrs;
/* sysfs ACG attributes, if any */
const struct attribute **acg_attrs;
#endif
/* Optional help string for mgmt_cmd commands */
@@ -1651,6 +1667,13 @@ struct scst_dev_type {
*/
int threads_num;
/*
* Maximum count of uncompleted commands that an initiator could
* queue on any device of this handler by default. Then it will start
* getting TASK QUEUE FULL status.
*/
int max_tgt_dev_commands;
/* Threads pool type. Valid only if threads_num > 0. */
enum scst_dev_type_threads_pool_type threads_pool_type;
@@ -2088,13 +2111,22 @@ struct scst_order_data {
struct list_head skipped_sn_list;
struct list_head deferred_cmd_list;
spinlock_t sn_lock;
spinlock_t sn_lock; /* IRQ lock */
int hq_cmd_count;
/* Set if the prev cmd was ORDERED */
bool prev_cmd_ordered;
/*
* tgt_dev initiated ACA, if any, or 0 otherwise. It can be deleted
* and freed during LUN deletion, so must not be dereferenced.
*/
unsigned long aca_tgt_dev;
/* Active ACA cmd, if any */
struct scst_cmd *aca_cmd;
int def_cmd_count;
unsigned int expected_sn;
unsigned int curr_sn;
@@ -2205,6 +2237,9 @@ struct scst_cmd {
/* Set if cmd has NACA bit set in CDB */
unsigned int cmd_naca:1;
/* Set if cmd was allowed during ACA */
unsigned int cmd_aca_allowed:1;
/*
* Set if the target driver wants to alloc data buffers on its own.
* In this case tgt_alloc_data_buf() must be provided in the target
@@ -2337,7 +2372,7 @@ struct scst_cmd {
unsigned long start_time;
/* List entry for tgt_dev's deferred (SN, etc.) lists */
/* List entry for tgt_dev's deferred (SN, ACA, etc.) lists */
struct list_head deferred_cmd_list_entry;
/* Cmd's serial number, used to execute cmd's in order of arrival */
@@ -2554,11 +2589,13 @@ struct scst_cmd {
#endif
#ifdef CONFIG_SCST_MEASURE_LATENCY
uint64_t start, curr_start, parse_time, alloc_buf_time;
uint64_t start, curr_start, parse_time;
uint64_t tgt_alloc_buf_time, dev_alloc_buf_time;
uint64_t restart_waiting_time, rdy_to_xfer_time;
uint64_t pre_exec_time, exec_time, dev_done_time;
uint64_t xmit_time;
uint64_t pre_exec_time;
bool exec_time_counting;
uint64_t exec_time, dev_done_time;
uint64_t xmit_time;
#endif
#ifdef CONFIG_SCST_DEBUG_TM
@@ -2885,6 +2922,13 @@ struct scst_device {
atomic_t dev_cmd_count;
#endif
/*
* Maximum count of uncompleted commands that an initiator could
* queue on this device. Then it will start getting TASK QUEUE FULL
* status.
*/
int max_tgt_dev_commands;
/*
* How many times device was blocked for new cmds execution.
* Protected by dev_lock.
@@ -2999,6 +3043,9 @@ struct scst_device {
/* End of persistent reservation fields protected by dev_pr_mutex. */
/* NUMA node id of this device, if any (default - NUMA_NO_NODE) */
int dev_numa_node_id;
/*
* Count of connected tgt_devs from transports, which don't support
* PRs, i.e. don't have get_initiator_port_transport_id(). Protected
@@ -3098,7 +3145,11 @@ struct scst_tgt_dev {
gfp_t tgt_dev_gfp_mask;
/* SGV pool from which buffers of this tgt_dev's cmds should be allocated */
struct sgv_pool *pool;
#ifdef CONFIG_CPUMASK_OFFSTACK
struct sgv_pool **pools;
#else
struct sgv_pool *pools[NR_CPUS];
#endif
/* Max number of allowed in this tgt_dev SG segments */
int max_sg_cnt;
@@ -3200,6 +3251,16 @@ struct scst_tgt_dev {
unsigned short tgt_dev_valid_sense_len;
uint8_t tgt_dev_sense[SCST_SENSE_BUFFERSIZE];
/*
* LUN thread index assigned by scst_add_threads(). Exported via
* sysfs. Can be used to look up which export thread is serving which
* target since this index also appears in the export thread name. Has
* a value in the range 0..n-1 for threads_pool_type per_initiator or
* -1 when using a shared thread pool per LUN or the global thread
* pool.
*/
int thread_index;
#ifndef CONFIG_SCST_PROC
/* sysfs release completion */
struct completion *tgt_dev_kobj_release_cmpl;
@@ -3326,7 +3387,11 @@ struct scst_acg {
struct kobject *initiators_kobj;
#endif
/* LUNS addressing method for all LUNs in this ACG */
enum scst_lun_addr_method addr_method;
/* Private stuff for target drivers */
void *acg_tgt_priv;
};
/*
@@ -3457,7 +3522,7 @@ struct scst_aen {
int delivery_status;
};
#define SCST_OD_DEFAULT_CONTROL_BYTE 0
#define SCST_OD_DEFAULT_CONTROL_BYTE 4 /* NACA */
struct scst_opcode_descriptor {
uint16_t od_serv_action;
@@ -3697,8 +3762,14 @@ struct scst_cmd *scst_find_cmd(struct scst_session *sess, void *data,
enum dma_data_direction scst_to_dma_dir(int scst_dir);
enum dma_data_direction scst_to_tgt_dma_dir(int scst_dir);
int scst_register_virtual_device(struct scst_dev_type *dev_handler,
const char *dev_name);
int scst_register_virtual_device_node(struct scst_dev_type *dev_handler,
const char *dev_name, int nodeid);
static inline int scst_register_virtual_device(struct scst_dev_type *dev_handler,
const char *dev_name)
{
return scst_register_virtual_device_node(dev_handler, dev_name,
NUMA_NO_NODE);
}
void scst_unregister_virtual_device(int id);
/*
@@ -4859,6 +4930,19 @@ static inline void scst_set_aen_delivery_status(struct scst_aen *aen,
aen->delivery_status = status;
}
/*
* Get/Set functions for tgt's target private data
*/
static inline void *scst_get_acg_tgt_priv(struct scst_acg *acg)
{
return acg->acg_tgt_priv;
}
static inline void scst_set_acg_tgt_priv(struct scst_acg *acg, void *val)
{
acg->acg_tgt_priv = val;
}
void scst_aen_done(struct scst_aen *aen);
static inline struct scatterlist *__sg_next_inline(struct scatterlist *sg)
@@ -5176,7 +5260,7 @@ void scst_resume_activity(void);
void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic);
void scst_post_parse(struct scst_cmd *cmd);
void scst_post_alloc_data_buf(struct scst_cmd *cmd);
void scst_post_dev_alloc_data_buf(struct scst_cmd *cmd);
int __scst_check_local_events(struct scst_cmd *cmd, bool preempt_tests_only);
@@ -5596,6 +5680,7 @@ void scst_init_threads(struct scst_cmd_threads *cmd_threads);
void scst_deinit_threads(struct scst_cmd_threads *cmd_threads);
void scst_pass_through_cmd_done(void *data, char *sense, int result, int resid);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
int scst_scsi_exec_async(struct scst_cmd *cmd, void *data,
void (*done)(void *data, char *sense, int result, int resid));
@@ -5629,6 +5714,8 @@ void scst_path_put(struct nameidata *nd);
#endif
int scst_remove_file(const char *name);
void scst_set_tp_soft_threshold_reached_UA(struct scst_tgt_dev *tgt_dev);
int scst_pr_set_cluster_mode(struct scst_device *dev, bool cluster_mode,
const char *cl_dev_id);
int scst_pr_init_dev(struct scst_device *dev);
+3 -8
View File
@@ -337,11 +337,13 @@ static inline int scst_sense_response_code(const uint8_t *sense)
#define scst_sense_asym_access_state_changed UNIT_ATTENTION, 0x2A, 0x06
#define scst_sense_capacity_data_changed UNIT_ATTENTION, 0x2A, 0x9
#define scst_sense_cleared_by_another_ini_UA UNIT_ATTENTION, 0x2F, 0
#define scst_sense_tp_soft_threshold_reached UNIT_ATTENTION, 0x38, 0x7
#define scst_sense_inquiry_data_changed UNIT_ATTENTION, 0x3F, 0x3
#define scst_sense_reported_luns_data_changed UNIT_ATTENTION, 0x3F, 0xE
/* DATA_PROTECT is 7 */
#define scst_sense_data_protect DATA_PROTECT, 0x27, 0
#define scst_sense_data_protect DATA_PROTECT, 0x00, 0
#define scst_space_allocation_failed_write_protect DATA_PROTECT, 0x27, 7
/* ABORTED_COMMAND is 0xb */
#define scst_sense_aborted_command ABORTED_COMMAND, 0x00, 0
@@ -511,13 +513,6 @@ static inline int scst_sense_response_code(const uint8_t *sense)
*************************************************************/
#define SCST_INQ_EVPD 0x01
/*************************************************************
** Byte 3 in Standard INQUIRY data
*************************************************************/
#define SCST_INQ_BYTE3 3
#define SCST_INQ_NORMACA_BIT 0x20
/*************************************************************
** TPGS field in byte 5 of the INQUIRY response (SPC-4).
*************************************************************/
+10
View File
@@ -71,6 +71,16 @@ enum sgv_clustering_types {
sgv_full_clustering,
};
struct sgv_pool *sgv_pool_create_node(const char *name,
enum sgv_clustering_types clustered, int single_alloc_pages,
bool shared, int purge_interval, int nodeid);
static inline struct sgv_pool *sgv_pool_create(const char *name,
enum sgv_clustering_types clustered, int single_alloc_pages,
bool shared, int purge_interval)
{
return sgv_pool_create_node(name, clustered, single_alloc_pages,
shared, purge_interval, NUMA_NO_NODE);
}
struct sgv_pool *sgv_pool_create(const char *name,
enum sgv_clustering_types clustered, int single_alloc_pages,
bool shared, int purge_interval);
+17
View File
@@ -0,0 +1,17 @@
In some cases SCST needs to take multiple locks recursivly, e.g. to lock
all tgt_devs in a session. For this case SCST takes those locks in their
current sort order, e.g. by LUN for tgt_devs, then releases in the
opposite order. Unfortunately, lockdep complains on such actions as
recursive locking, then disables itself. The disabling itself action is
the most unpleasant one leading to lockdep being useless after this
point.
Unfortunately, nested locking annotations can't help, because after
free, then alloc again, or after LUN change (in case of tgt_devs) order
of locks can change.
So, SCST has a set of nolockdep-x.y patches together with "*_nolockdep"
locks to implement a way to annotate some lock and unlock actions as "no
lockdep", so lockdep will not track them.
This is a debug aid useful only with lockdep enabled kernels.
+116
View File
@@ -0,0 +1,116 @@
=== modified file 'include/linux/lockdep.h'
--- old/include/linux/lockdep.h 2013-07-23 02:45:53 +0000
+++ new/include/linux/lockdep.h 2013-07-23 03:31:57 +0000
@@ -355,7 +355,7 @@ extern void lockdep_set_current_reclaim_
extern void lockdep_clear_current_reclaim_state(void);
extern void lockdep_trace_alloc(gfp_t mask);
-# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0,
+# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0, .nolockdep_call = 0,
#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0)
=== modified file 'include/linux/sched.h'
--- old/include/linux/sched.h 2013-07-23 02:45:53 +0000
+++ new/include/linux/sched.h 2013-07-23 03:31:57 +0000
@@ -1273,6 +1273,9 @@ struct task_struct {
# define MAX_LOCK_DEPTH 48UL
u64 curr_chain_key;
int lockdep_depth;
+# define NOLOCKDEP_SUPPORTED 1
+ unsigned int nolockdep_call:1;
+ unsigned int nolockdep_call_irq_saved:1;
unsigned int lockdep_recursion;
struct held_lock held_locks[MAX_LOCK_DEPTH];
gfp_t lockdep_reclaim_gfp;
=== modified file 'kernel/lockdep.c'
--- old/kernel/lockdep.c 2013-07-23 02:45:53 +0000
+++ new/kernel/lockdep.c 2013-07-23 03:31:57 +0000
@@ -3593,9 +3593,11 @@ void lock_acquire(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
-
current->lockdep_recursion = 1;
trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip);
__lock_acquire(lock, subclass, trylock, read, check,
@@ -3613,6 +3615,9 @@ void lock_release(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3806,6 +3811,9 @@ void lock_contended(struct lockdep_map *
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3826,6 +3834,9 @@ void lock_acquired(struct lockdep_map *l
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
=== modified file 'kernel/softirq.c'
--- old/kernel/softirq.c 2013-07-23 02:45:53 +0000
+++ new/kernel/softirq.c 2013-07-23 03:31:57 +0000
@@ -314,6 +314,18 @@ void irq_enter(void)
{
int cpu = smp_processor_id();
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call) {
+ current->nolockdep_call_irq_saved = 1;
+ current->nolockdep_call = 0;
+ }
+ local_irq_restore(flags);
+ }
+#endif
+
rcu_irq_enter();
if (is_idle_task(current) && !in_interrupt()) {
/*
@@ -368,6 +380,18 @@ void irq_exit(void)
tick_irq_exit();
rcu_irq_exit();
+
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call_irq_saved)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call_irq_saved) {
+ current->nolockdep_call_irq_saved = 0;
+ current->nolockdep_call = 1;
+ }
+ local_irq_restore(flags);
+ }
+#endif
}
/*
+116
View File
@@ -0,0 +1,116 @@
=== modified file 'include/linux/lockdep.h'
--- old/include/linux/lockdep.h 2013-09-28 00:14:38 +0000
+++ new/include/linux/lockdep.h 2013-09-28 03:00:19 +0000
@@ -355,7 +355,7 @@ extern void lockdep_set_current_reclaim_
extern void lockdep_clear_current_reclaim_state(void);
extern void lockdep_trace_alloc(gfp_t mask);
-# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0,
+# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0, .nolockdep_call = 0,
#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0)
=== modified file 'include/linux/sched.h'
--- old/include/linux/sched.h 2013-09-28 00:14:38 +0000
+++ new/include/linux/sched.h 2013-09-28 03:00:19 +0000
@@ -1266,6 +1266,9 @@ struct task_struct {
# define MAX_LOCK_DEPTH 48UL
u64 curr_chain_key;
int lockdep_depth;
+# define NOLOCKDEP_SUPPORTED 1
+ unsigned int nolockdep_call:1;
+ unsigned int nolockdep_call_irq_saved:1;
unsigned int lockdep_recursion;
struct held_lock held_locks[MAX_LOCK_DEPTH];
gfp_t lockdep_reclaim_gfp;
=== modified file 'kernel/lockdep.c'
--- old/kernel/lockdep.c 2013-09-28 00:14:38 +0000
+++ new/kernel/lockdep.c 2013-09-28 03:00:19 +0000
@@ -3593,9 +3593,11 @@ void lock_acquire(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
-
current->lockdep_recursion = 1;
trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip);
__lock_acquire(lock, subclass, trylock, read, check,
@@ -3613,6 +3615,9 @@ void lock_release(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3806,6 +3811,9 @@ void lock_contended(struct lockdep_map *
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3826,6 +3834,9 @@ void lock_acquired(struct lockdep_map *l
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
=== modified file 'kernel/softirq.c'
--- old/kernel/softirq.c 2013-09-28 00:14:38 +0000
+++ new/kernel/softirq.c 2013-09-28 03:00:19 +0000
@@ -312,6 +312,18 @@ void irq_enter(void)
{
int cpu = smp_processor_id();
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call) {
+ current->nolockdep_call_irq_saved = 1;
+ current->nolockdep_call = 0;
+ }
+ local_irq_restore(flags);
+ }
+#endif
+
rcu_irq_enter();
if (is_idle_task(current) && !in_interrupt()) {
/*
@@ -366,6 +378,18 @@ void irq_exit(void)
tick_irq_exit();
rcu_irq_exit();
+
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call_irq_saved)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call_irq_saved) {
+ current->nolockdep_call_irq_saved = 0;
+ current->nolockdep_call = 1;
+ }
+ local_irq_restore(flags);
+ }
+#endif
}
/*
+116
View File
@@ -0,0 +1,116 @@
=== modified file 'include/linux/lockdep.h'
--- old/include/linux/lockdep.h 2013-11-30 00:34:22 +0000
+++ new/include/linux/lockdep.h 2013-11-30 00:57:33 +0000
@@ -355,7 +355,7 @@ extern void lockdep_set_current_reclaim_
extern void lockdep_clear_current_reclaim_state(void);
extern void lockdep_trace_alloc(gfp_t mask);
-# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0,
+# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0, .nolockdep_call = 0,
#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0)
=== modified file 'include/linux/sched.h'
--- old/include/linux/sched.h 2013-11-30 00:34:22 +0000
+++ new/include/linux/sched.h 2013-11-30 00:57:33 +0000
@@ -1265,6 +1265,9 @@ struct task_struct {
# define MAX_LOCK_DEPTH 48UL
u64 curr_chain_key;
int lockdep_depth;
+# define NOLOCKDEP_SUPPORTED 1
+ unsigned int nolockdep_call:1;
+ unsigned int nolockdep_call_irq_saved:1;
unsigned int lockdep_recursion;
struct held_lock held_locks[MAX_LOCK_DEPTH];
gfp_t lockdep_reclaim_gfp;
=== modified file 'kernel/lockdep.c'
--- old/kernel/lockdep.c 2013-11-30 00:34:22 +0000
+++ new/kernel/lockdep.c 2013-11-30 00:57:33 +0000
@@ -3593,9 +3593,11 @@ void lock_acquire(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
-
current->lockdep_recursion = 1;
trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip);
__lock_acquire(lock, subclass, trylock, read, check,
@@ -3613,6 +3615,9 @@ void lock_release(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3806,6 +3811,9 @@ void lock_contended(struct lockdep_map *
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3826,6 +3834,9 @@ void lock_acquired(struct lockdep_map *l
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
=== modified file 'kernel/softirq.c'
--- old/kernel/softirq.c 2013-11-30 00:34:22 +0000
+++ new/kernel/softirq.c 2013-11-30 00:57:33 +0000
@@ -312,6 +312,18 @@ void irq_enter(void)
{
int cpu = smp_processor_id();
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call) {
+ current->nolockdep_call_irq_saved = 1;
+ current->nolockdep_call = 0;
+ }
+ local_irq_restore(flags);
+ }
+#endif
+
rcu_irq_enter();
if (is_idle_task(current) && !in_interrupt()) {
/*
@@ -375,6 +387,18 @@ void irq_exit(void)
tick_irq_exit();
rcu_irq_exit();
+
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call_irq_saved)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call_irq_saved) {
+ current->nolockdep_call_irq_saved = 0;
+ current->nolockdep_call = 1;
+ }
+ local_irq_restore(flags);
+ }
+#endif
}
/*
+116
View File
@@ -0,0 +1,116 @@
=== modified file 'include/linux/lockdep.h'
--- old/include/linux/lockdep.h 2014-01-30 00:25:53 +0000
+++ new/include/linux/lockdep.h 2014-01-30 01:13:44 +0000
@@ -355,7 +355,7 @@ extern void lockdep_set_current_reclaim_
extern void lockdep_clear_current_reclaim_state(void);
extern void lockdep_trace_alloc(gfp_t mask);
-# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0,
+# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0, .nolockdep_call = 0,
#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0)
=== modified file 'include/linux/sched.h'
--- old/include/linux/sched.h 2014-01-30 00:25:53 +0000
+++ new/include/linux/sched.h 2014-01-30 01:13:44 +0000
@@ -1277,6 +1277,9 @@ struct task_struct {
# define MAX_LOCK_DEPTH 48UL
u64 curr_chain_key;
int lockdep_depth;
+# define NOLOCKDEP_SUPPORTED 1
+ unsigned int nolockdep_call:1;
+ unsigned int nolockdep_call_irq_saved:1;
unsigned int lockdep_recursion;
struct held_lock held_locks[MAX_LOCK_DEPTH];
gfp_t lockdep_reclaim_gfp;
=== modified file 'kernel/locking/lockdep.c'
--- old/kernel/locking/lockdep.c 2014-01-30 00:25:53 +0000
+++ new/kernel/locking/lockdep.c 2014-01-30 01:13:44 +0000
@@ -3593,9 +3593,11 @@ void lock_acquire(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
-
current->lockdep_recursion = 1;
trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip);
__lock_acquire(lock, subclass, trylock, read, check,
@@ -3613,6 +3615,9 @@ void lock_release(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3806,6 +3811,9 @@ void lock_contended(struct lockdep_map *
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3826,6 +3834,9 @@ void lock_acquired(struct lockdep_map *l
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
=== modified file 'kernel/softirq.c'
--- old/kernel/softirq.c 2014-01-30 00:25:53 +0000
+++ new/kernel/softirq.c 2014-01-30 01:13:44 +0000
@@ -313,6 +313,18 @@ void irq_enter(void)
{
int cpu = smp_processor_id();
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call) {
+ current->nolockdep_call_irq_saved = 1;
+ current->nolockdep_call = 0;
+ }
+ local_irq_restore(flags);
+ }
+#endif
+
rcu_irq_enter();
if (is_idle_task(current) && !in_interrupt()) {
/*
@@ -382,6 +394,18 @@ void irq_exit(void)
tick_irq_exit();
rcu_irq_exit();
+
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call_irq_saved)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call_irq_saved) {
+ current->nolockdep_call_irq_saved = 0;
+ current->nolockdep_call = 1;
+ }
+ local_irq_restore(flags);
+ }
+#endif
}
/*
+114
View File
@@ -0,0 +1,114 @@
=== modified file 'include/linux/lockdep.h'
--- old/include/linux/lockdep.h 2014-04-17 22:02:06 +0000
+++ new/include/linux/lockdep.h 2014-04-17 22:55:34 +0000
@@ -355,7 +355,7 @@ extern void lockdep_set_current_reclaim_
extern void lockdep_clear_current_reclaim_state(void);
extern void lockdep_trace_alloc(gfp_t mask);
-# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0,
+# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0, .nolockdep_call = 0,
#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0)
=== modified file 'include/linux/sched.h'
--- old/include/linux/sched.h 2014-04-17 22:02:06 +0000
+++ new/include/linux/sched.h 2014-04-17 22:55:34 +0000
@@ -1404,6 +1404,9 @@ struct task_struct {
# define MAX_LOCK_DEPTH 48UL
u64 curr_chain_key;
int lockdep_depth;
+# define NOLOCKDEP_SUPPORTED 1
+ unsigned int nolockdep_call:1;
+ unsigned int nolockdep_call_irq_saved:1;
unsigned int lockdep_recursion;
struct held_lock held_locks[MAX_LOCK_DEPTH];
gfp_t lockdep_reclaim_gfp;
=== modified file 'kernel/locking/lockdep.c'
--- old/kernel/locking/lockdep.c 2014-04-17 22:02:06 +0000
+++ new/kernel/locking/lockdep.c 2014-04-17 22:55:34 +0000
@@ -3595,9 +3595,11 @@ void lock_acquire(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
-
current->lockdep_recursion = 1;
trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip);
__lock_acquire(lock, subclass, trylock, read, check,
@@ -3615,6 +3617,9 @@ void lock_release(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3808,6 +3813,9 @@ void lock_contended(struct lockdep_map *
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3828,6 +3836,9 @@ void lock_acquired(struct lockdep_map *l
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
=== modified file 'kernel/softirq.c'
--- old/kernel/softirq.c 2014-04-17 22:02:06 +0000
+++ new/kernel/softirq.c 2014-04-17 22:55:34 +0000
@@ -321,6 +321,17 @@ asmlinkage void do_softirq(void)
*/
void irq_enter(void)
{
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call) {
+ current->nolockdep_call_irq_saved = 1;
+ current->nolockdep_call = 0;
+ }
+ local_irq_restore(flags);
+ }
+#endif
rcu_irq_enter();
if (is_idle_task(current) && !in_interrupt()) {
/*
@@ -389,6 +400,17 @@ void irq_exit(void)
tick_irq_exit();
rcu_irq_exit();
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call_irq_saved)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call_irq_saved) {
+ current->nolockdep_call_irq_saved = 0;
+ current->nolockdep_call = 1;
+ }
+ local_irq_restore(flags);
+ }
+#endif
trace_hardirq_exit(); /* must be last! */
}
+114
View File
@@ -0,0 +1,114 @@
=== modified file 'include/linux/lockdep.h'
--- old/include/linux/lockdep.h 2014-06-18 01:32:48 +0000
+++ new/include/linux/lockdep.h 2014-06-18 01:45:33 +0000
@@ -354,7 +354,7 @@ extern void lockdep_set_current_reclaim_
extern void lockdep_clear_current_reclaim_state(void);
extern void lockdep_trace_alloc(gfp_t mask);
-# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0,
+# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0, .nolockdep_call = 0,
#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0)
=== modified file 'include/linux/sched.h'
--- old/include/linux/sched.h 2014-06-18 01:32:48 +0000
+++ new/include/linux/sched.h 2014-06-18 01:45:33 +0000
@@ -1422,6 +1422,9 @@ struct task_struct {
# define MAX_LOCK_DEPTH 48UL
u64 curr_chain_key;
int lockdep_depth;
+# define NOLOCKDEP_SUPPORTED 1
+ unsigned int nolockdep_call:1;
+ unsigned int nolockdep_call_irq_saved:1;
unsigned int lockdep_recursion;
struct held_lock held_locks[MAX_LOCK_DEPTH];
gfp_t lockdep_reclaim_gfp;
=== modified file 'kernel/locking/lockdep.c'
--- old/kernel/locking/lockdep.c 2014-06-18 01:32:48 +0000
+++ new/kernel/locking/lockdep.c 2014-06-18 01:45:33 +0000
@@ -3592,9 +3592,11 @@ void lock_acquire(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
-
current->lockdep_recursion = 1;
trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip);
__lock_acquire(lock, subclass, trylock, read, check,
@@ -3612,6 +3614,9 @@ void lock_release(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3805,6 +3810,9 @@ void lock_contended(struct lockdep_map *
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3825,6 +3833,9 @@ void lock_acquired(struct lockdep_map *l
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
=== modified file 'kernel/softirq.c'
--- old/kernel/softirq.c 2014-06-18 01:32:48 +0000
+++ new/kernel/softirq.c 2014-06-18 01:45:33 +0000
@@ -322,6 +322,17 @@ asmlinkage __visible void do_softirq(voi
*/
void irq_enter(void)
{
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call) {
+ current->nolockdep_call_irq_saved = 1;
+ current->nolockdep_call = 0;
+ }
+ local_irq_restore(flags);
+ }
+#endif
rcu_irq_enter();
if (is_idle_task(current) && !in_interrupt()) {
/*
@@ -390,6 +401,17 @@ void irq_exit(void)
tick_irq_exit();
rcu_irq_exit();
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call_irq_saved)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call_irq_saved) {
+ current->nolockdep_call_irq_saved = 0;
+ current->nolockdep_call = 1;
+ }
+ local_irq_restore(flags);
+ }
+#endif
trace_hardirq_exit(); /* must be last! */
}
+114
View File
@@ -0,0 +1,114 @@
=== modified file 'include/linux/lockdep.h'
--- old/include/linux/lockdep.h 2014-08-19 01:00:36 +0000
+++ new/include/linux/lockdep.h 2014-08-19 01:18:25 +0000
@@ -354,7 +354,7 @@ extern void lockdep_set_current_reclaim_
extern void lockdep_clear_current_reclaim_state(void);
extern void lockdep_trace_alloc(gfp_t mask);
-# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0,
+# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0, .nolockdep_call = 0,
#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0)
=== modified file 'include/linux/sched.h'
--- old/include/linux/sched.h 2014-08-19 01:00:36 +0000
+++ new/include/linux/sched.h 2014-08-19 01:18:25 +0000
@@ -1467,6 +1467,9 @@ struct task_struct {
# define MAX_LOCK_DEPTH 48UL
u64 curr_chain_key;
int lockdep_depth;
+# define NOLOCKDEP_SUPPORTED 1
+ unsigned int nolockdep_call:1;
+ unsigned int nolockdep_call_irq_saved:1;
unsigned int lockdep_recursion;
struct held_lock held_locks[MAX_LOCK_DEPTH];
gfp_t lockdep_reclaim_gfp;
=== modified file 'kernel/locking/lockdep.c'
--- old/kernel/locking/lockdep.c 2014-08-19 01:00:36 +0000
+++ new/kernel/locking/lockdep.c 2014-08-19 01:18:25 +0000
@@ -3592,9 +3592,11 @@ void lock_acquire(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
-
current->lockdep_recursion = 1;
trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip);
__lock_acquire(lock, subclass, trylock, read, check,
@@ -3612,6 +3614,9 @@ void lock_release(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3805,6 +3810,9 @@ void lock_contended(struct lockdep_map *
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3825,6 +3833,9 @@ void lock_acquired(struct lockdep_map *l
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
=== modified file 'kernel/softirq.c'
--- old/kernel/softirq.c 2014-08-19 01:00:36 +0000
+++ new/kernel/softirq.c 2014-08-19 01:18:25 +0000
@@ -320,6 +320,17 @@ asmlinkage __visible void do_softirq(voi
*/
void irq_enter(void)
{
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call) {
+ current->nolockdep_call_irq_saved = 1;
+ current->nolockdep_call = 0;
+ }
+ local_irq_restore(flags);
+ }
+#endif
rcu_irq_enter();
if (is_idle_task(current) && !in_interrupt()) {
/*
@@ -388,6 +399,17 @@ void irq_exit(void)
tick_irq_exit();
rcu_irq_exit();
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call_irq_saved)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call_irq_saved) {
+ current->nolockdep_call_irq_saved = 0;
+ current->nolockdep_call = 1;
+ }
+ local_irq_restore(flags);
+ }
+#endif
trace_hardirq_exit(); /* must be last! */
}
+114
View File
@@ -0,0 +1,114 @@
=== modified file 'include/linux/lockdep.h'
--- old/include/linux/lockdep.h 2014-11-21 03:17:49 +0000
+++ new/include/linux/lockdep.h 2014-11-21 03:51:56 +0000
@@ -354,7 +354,7 @@ extern void lockdep_set_current_reclaim_
extern void lockdep_clear_current_reclaim_state(void);
extern void lockdep_trace_alloc(gfp_t mask);
-# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0,
+# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0, .nolockdep_call = 0,
#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0)
=== modified file 'include/linux/sched.h'
--- old/include/linux/sched.h 2014-11-21 03:17:49 +0000
+++ new/include/linux/sched.h 2014-11-21 03:51:56 +0000
@@ -1462,6 +1462,9 @@ struct task_struct {
# define MAX_LOCK_DEPTH 48UL
u64 curr_chain_key;
int lockdep_depth;
+# define NOLOCKDEP_SUPPORTED 1
+ unsigned int nolockdep_call:1;
+ unsigned int nolockdep_call_irq_saved:1;
unsigned int lockdep_recursion;
struct held_lock held_locks[MAX_LOCK_DEPTH];
gfp_t lockdep_reclaim_gfp;
=== modified file 'kernel/locking/lockdep.c'
--- old/kernel/locking/lockdep.c 2014-11-21 03:17:49 +0000
+++ new/kernel/locking/lockdep.c 2014-11-21 03:51:56 +0000
@@ -3594,9 +3594,11 @@ void lock_acquire(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
-
current->lockdep_recursion = 1;
trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip);
__lock_acquire(lock, subclass, trylock, read, check,
@@ -3614,6 +3616,9 @@ void lock_release(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3807,6 +3812,9 @@ void lock_contended(struct lockdep_map *
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3827,6 +3835,9 @@ void lock_acquired(struct lockdep_map *l
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
=== modified file 'kernel/softirq.c'
--- old/kernel/softirq.c 2014-11-21 03:17:49 +0000
+++ new/kernel/softirq.c 2014-11-21 03:51:56 +0000
@@ -320,6 +320,17 @@ asmlinkage __visible void do_softirq(voi
*/
void irq_enter(void)
{
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call) {
+ current->nolockdep_call_irq_saved = 1;
+ current->nolockdep_call = 0;
+ }
+ local_irq_restore(flags);
+ }
+#endif
rcu_irq_enter();
if (is_idle_task(current) && !in_interrupt()) {
/*
@@ -388,6 +399,17 @@ void irq_exit(void)
tick_irq_exit();
rcu_irq_exit();
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call_irq_saved)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call_irq_saved) {
+ current->nolockdep_call_irq_saved = 0;
+ current->nolockdep_call = 1;
+ }
+ local_irq_restore(flags);
+ }
+#endif
trace_hardirq_exit(); /* must be last! */
}
+116
View File
@@ -0,0 +1,116 @@
=== modified file 'include/linux/lockdep.h'
--- old/include/linux/lockdep.h 2012-08-08 02:57:29 +0000
+++ new/include/linux/lockdep.h 2012-08-28 21:26:26 +0000
@@ -355,7 +355,7 @@ extern void lockdep_set_current_reclaim_
extern void lockdep_clear_current_reclaim_state(void);
extern void lockdep_trace_alloc(gfp_t mask);
-# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0,
+# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0, .nolockdep_call = 0,
#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0)
=== modified file 'include/linux/sched.h'
--- old/include/linux/sched.h 2012-08-08 02:57:29 +0000
+++ new/include/linux/sched.h 2012-08-28 22:49:36 +0000
@@ -1454,6 +1454,9 @@ struct task_struct {
# define MAX_LOCK_DEPTH 48UL
u64 curr_chain_key;
int lockdep_depth;
+# define NOLOCKDEP_SUPPORTED 1
+ unsigned int nolockdep_call:1;
+ unsigned int nolockdep_call_irq_saved:1;
unsigned int lockdep_recursion;
struct held_lock held_locks[MAX_LOCK_DEPTH];
gfp_t lockdep_reclaim_gfp;
=== modified file 'kernel/lockdep.c'
--- old/kernel/lockdep.c 2012-08-08 02:57:29 +0000
+++ new/kernel/lockdep.c 2012-08-28 23:02:47 +0000
@@ -3547,9 +3547,11 @@ void lock_acquire(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
-
current->lockdep_recursion = 1;
trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip);
__lock_acquire(lock, subclass, trylock, read, check,
@@ -3567,6 +3569,9 @@ void lock_release(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3760,6 +3765,9 @@ void lock_contended(struct lockdep_map *
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3780,6 +3788,9 @@ void lock_acquired(struct lockdep_map *l
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
=== modified file 'kernel/softirq.c'
--- old/kernel/softirq.c 2012-08-08 02:57:29 +0000
+++ new/kernel/softirq.c 2012-08-28 23:23:07 +0000
@@ -296,6 +296,18 @@ void irq_enter(void)
{
int cpu = smp_processor_id();
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call) {
+ current->nolockdep_call_irq_saved = 1;
+ current->nolockdep_call = 0;
+ }
+ local_irq_restore(flags);
+ }
+#endif
+
rcu_irq_enter();
if (is_idle_task(current) && !in_interrupt()) {
/*
@@ -344,6 +356,18 @@ void irq_exit(void)
#endif
rcu_irq_exit();
sched_preempt_enable_no_resched();
+
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call_irq_saved)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call_irq_saved) {
+ current->nolockdep_call_irq_saved = 0;
+ current->nolockdep_call = 1;
+ }
+ local_irq_restore(flags);
+ }
+#endif
}
/*
+116
View File
@@ -0,0 +1,116 @@
=== modified file 'include/linux/lockdep.h'
--- old/include/linux/lockdep.h 2012-10-01 18:39:34 +0000
+++ new/include/linux/lockdep.h 2012-10-01 22:12:06 +0000
@@ -355,7 +355,7 @@ extern void lockdep_set_current_reclaim_
extern void lockdep_clear_current_reclaim_state(void);
extern void lockdep_trace_alloc(gfp_t mask);
-# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0,
+# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0, .nolockdep_call = 0,
#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0)
=== modified file 'include/linux/sched.h'
--- old/include/linux/sched.h 2012-10-01 18:39:34 +0000
+++ new/include/linux/sched.h 2012-10-01 22:12:06 +0000
@@ -1462,6 +1462,9 @@ struct task_struct {
# define MAX_LOCK_DEPTH 48UL
u64 curr_chain_key;
int lockdep_depth;
+# define NOLOCKDEP_SUPPORTED 1
+ unsigned int nolockdep_call:1;
+ unsigned int nolockdep_call_irq_saved:1;
unsigned int lockdep_recursion;
struct held_lock held_locks[MAX_LOCK_DEPTH];
gfp_t lockdep_reclaim_gfp;
=== modified file 'kernel/lockdep.c'
--- old/kernel/lockdep.c 2012-10-01 18:39:34 +0000
+++ new/kernel/lockdep.c 2012-10-01 22:12:06 +0000
@@ -3547,9 +3547,11 @@ void lock_acquire(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
-
current->lockdep_recursion = 1;
trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip);
__lock_acquire(lock, subclass, trylock, read, check,
@@ -3567,6 +3569,9 @@ void lock_release(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3760,6 +3765,9 @@ void lock_contended(struct lockdep_map *
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3780,6 +3788,9 @@ void lock_acquired(struct lockdep_map *l
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
=== modified file 'kernel/softirq.c'
--- old/kernel/softirq.c 2012-10-01 18:39:34 +0000
+++ new/kernel/softirq.c 2012-10-01 22:12:06 +0000
@@ -305,6 +305,18 @@ void irq_enter(void)
{
int cpu = smp_processor_id();
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call) {
+ current->nolockdep_call_irq_saved = 1;
+ current->nolockdep_call = 0;
+ }
+ local_irq_restore(flags);
+ }
+#endif
+
rcu_irq_enter();
if (is_idle_task(current) && !in_interrupt()) {
/*
@@ -353,6 +365,18 @@ void irq_exit(void)
#endif
rcu_irq_exit();
sched_preempt_enable_no_resched();
+
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call_irq_saved)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call_irq_saved) {
+ current->nolockdep_call_irq_saved = 0;
+ current->nolockdep_call = 1;
+ }
+ local_irq_restore(flags);
+ }
+#endif
}
/*
+116
View File
@@ -0,0 +1,116 @@
=== modified file 'include/linux/lockdep.h'
--- old/include/linux/lockdep.h 2012-12-17 19:41:04 +0000
+++ new/include/linux/lockdep.h 2012-12-17 23:12:00 +0000
@@ -355,7 +355,7 @@ extern void lockdep_set_current_reclaim_
extern void lockdep_clear_current_reclaim_state(void);
extern void lockdep_trace_alloc(gfp_t mask);
-# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0,
+# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0, .nolockdep_call = 0,
#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0)
=== modified file 'include/linux/sched.h'
--- old/include/linux/sched.h 2012-12-17 19:41:04 +0000
+++ new/include/linux/sched.h 2012-12-17 23:12:00 +0000
@@ -1418,6 +1418,9 @@ struct task_struct {
# define MAX_LOCK_DEPTH 48UL
u64 curr_chain_key;
int lockdep_depth;
+# define NOLOCKDEP_SUPPORTED 1
+ unsigned int nolockdep_call:1;
+ unsigned int nolockdep_call_irq_saved:1;
unsigned int lockdep_recursion;
struct held_lock held_locks[MAX_LOCK_DEPTH];
gfp_t lockdep_reclaim_gfp;
=== modified file 'kernel/lockdep.c'
--- old/kernel/lockdep.c 2012-12-17 19:41:04 +0000
+++ new/kernel/lockdep.c 2012-12-17 23:12:00 +0000
@@ -3586,9 +3586,11 @@ void lock_acquire(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
-
current->lockdep_recursion = 1;
trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip);
__lock_acquire(lock, subclass, trylock, read, check,
@@ -3606,6 +3608,9 @@ void lock_release(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3799,6 +3804,9 @@ void lock_contended(struct lockdep_map *
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3819,6 +3827,9 @@ void lock_acquired(struct lockdep_map *l
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
=== modified file 'kernel/softirq.c'
--- old/kernel/softirq.c 2012-12-17 19:41:04 +0000
+++ new/kernel/softirq.c 2012-12-17 23:12:00 +0000
@@ -306,6 +306,18 @@ void irq_enter(void)
{
int cpu = smp_processor_id();
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call) {
+ current->nolockdep_call_irq_saved = 1;
+ current->nolockdep_call = 0;
+ }
+ local_irq_restore(flags);
+ }
+#endif
+
rcu_irq_enter();
if (is_idle_task(current) && !in_interrupt()) {
/*
@@ -354,6 +366,18 @@ void irq_exit(void)
#endif
rcu_irq_exit();
sched_preempt_enable_no_resched();
+
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call_irq_saved)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call_irq_saved) {
+ current->nolockdep_call_irq_saved = 0;
+ current->nolockdep_call = 1;
+ }
+ local_irq_restore(flags);
+ }
+#endif
}
/*
+116
View File
@@ -0,0 +1,116 @@
=== modified file 'include/linux/lockdep.h'
--- old/include/linux/lockdep.h 2013-02-22 21:12:31 +0000
+++ new/include/linux/lockdep.h 2013-02-23 00:19:37 +0000
@@ -355,7 +355,7 @@ extern void lockdep_set_current_reclaim_
extern void lockdep_clear_current_reclaim_state(void);
extern void lockdep_trace_alloc(gfp_t mask);
-# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0,
+# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0, .nolockdep_call = 0,
#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0)
=== modified file 'include/linux/sched.h'
--- old/include/linux/sched.h 2013-02-22 21:12:31 +0000
+++ new/include/linux/sched.h 2013-02-23 00:19:37 +0000
@@ -1466,6 +1466,9 @@ struct task_struct {
# define MAX_LOCK_DEPTH 48UL
u64 curr_chain_key;
int lockdep_depth;
+# define NOLOCKDEP_SUPPORTED 1
+ unsigned int nolockdep_call:1;
+ unsigned int nolockdep_call_irq_saved:1;
unsigned int lockdep_recursion;
struct held_lock held_locks[MAX_LOCK_DEPTH];
gfp_t lockdep_reclaim_gfp;
=== modified file 'kernel/lockdep.c'
--- old/kernel/lockdep.c 2013-02-22 21:12:31 +0000
+++ new/kernel/lockdep.c 2013-02-23 00:19:37 +0000
@@ -3586,9 +3586,11 @@ void lock_acquire(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
-
current->lockdep_recursion = 1;
trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip);
__lock_acquire(lock, subclass, trylock, read, check,
@@ -3606,6 +3608,9 @@ void lock_release(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3799,6 +3804,9 @@ void lock_contended(struct lockdep_map *
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3819,6 +3827,9 @@ void lock_acquired(struct lockdep_map *l
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
=== modified file 'kernel/softirq.c'
--- old/kernel/softirq.c 2013-02-22 21:12:31 +0000
+++ new/kernel/softirq.c 2013-02-23 00:19:37 +0000
@@ -306,6 +306,18 @@ void irq_enter(void)
{
int cpu = smp_processor_id();
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call) {
+ current->nolockdep_call_irq_saved = 1;
+ current->nolockdep_call = 0;
+ }
+ local_irq_restore(flags);
+ }
+#endif
+
rcu_irq_enter();
if (is_idle_task(current) && !in_interrupt()) {
/*
@@ -354,6 +366,18 @@ void irq_exit(void)
#endif
rcu_irq_exit();
sched_preempt_enable_no_resched();
+
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call_irq_saved)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call_irq_saved) {
+ current->nolockdep_call_irq_saved = 0;
+ current->nolockdep_call = 1;
+ }
+ local_irq_restore(flags);
+ }
+#endif
}
/*
+116
View File
@@ -0,0 +1,116 @@
=== modified file 'include/linux/lockdep.h'
--- old/include/linux/lockdep.h 2013-05-11 05:39:14 +0000
+++ new/include/linux/lockdep.h 2013-05-18 03:43:23 +0000
@@ -355,7 +355,7 @@ extern void lockdep_set_current_reclaim_
extern void lockdep_clear_current_reclaim_state(void);
extern void lockdep_trace_alloc(gfp_t mask);
-# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0,
+# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0, .nolockdep_call = 0,
#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0)
=== modified file 'include/linux/sched.h'
--- old/include/linux/sched.h 2013-05-11 05:39:14 +0000
+++ new/include/linux/sched.h 2013-05-18 03:43:23 +0000
@@ -1438,6 +1438,9 @@ struct task_struct {
# define MAX_LOCK_DEPTH 48UL
u64 curr_chain_key;
int lockdep_depth;
+# define NOLOCKDEP_SUPPORTED 1
+ unsigned int nolockdep_call:1;
+ unsigned int nolockdep_call_irq_saved:1;
unsigned int lockdep_recursion;
struct held_lock held_locks[MAX_LOCK_DEPTH];
gfp_t lockdep_reclaim_gfp;
=== modified file 'kernel/lockdep.c'
--- old/kernel/lockdep.c 2013-05-11 05:39:14 +0000
+++ new/kernel/lockdep.c 2013-05-18 03:43:23 +0000
@@ -3591,9 +3591,11 @@ void lock_acquire(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
-
current->lockdep_recursion = 1;
trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip);
__lock_acquire(lock, subclass, trylock, read, check,
@@ -3611,6 +3613,9 @@ void lock_release(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3804,6 +3809,9 @@ void lock_contended(struct lockdep_map *
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3824,6 +3832,9 @@ void lock_acquired(struct lockdep_map *l
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
=== modified file 'kernel/softirq.c'
--- old/kernel/softirq.c 2013-05-11 05:39:14 +0000
+++ new/kernel/softirq.c 2013-05-18 03:43:23 +0000
@@ -307,6 +307,18 @@ void irq_enter(void)
{
int cpu = smp_processor_id();
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call) {
+ current->nolockdep_call_irq_saved = 1;
+ current->nolockdep_call = 0;
+ }
+ local_irq_restore(flags);
+ }
+#endif
+
rcu_irq_enter();
if (is_idle_task(current) && !in_interrupt()) {
/*
@@ -352,6 +364,18 @@ void irq_exit(void)
tick_nohz_irq_exit();
#endif
rcu_irq_exit();
+
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call_irq_saved)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call_irq_saved) {
+ current->nolockdep_call_irq_saved = 0;
+ current->nolockdep_call = 1;
+ }
+ local_irq_restore(flags);
+ }
+#endif
}
/*
+114
View File
@@ -0,0 +1,114 @@
=== modified file 'include/linux/lockdep.h'
--- old/include/linux/lockdep.h 2016-06-17 23:23:35 +0000
+++ new/include/linux/lockdep.h 2016-06-17 23:38:32 +0000
@@ -359,7 +359,7 @@ extern void lockdep_trace_alloc(gfp_t ma
extern void lock_pin_lock(struct lockdep_map *lock);
extern void lock_unpin_lock(struct lockdep_map *lock);
-# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0,
+# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0, .nolockdep_call = 0,
#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0)
=== modified file 'include/linux/sched.h'
--- old/include/linux/sched.h 2016-06-17 23:23:35 +0000
+++ new/include/linux/sched.h 2016-06-17 23:38:32 +0000
@@ -1649,6 +1649,9 @@ struct task_struct {
# define MAX_LOCK_DEPTH 48UL
u64 curr_chain_key;
int lockdep_depth;
+# define NOLOCKDEP_SUPPORTED 1
+ unsigned int nolockdep_call:1;
+ unsigned int nolockdep_call_irq_saved:1;
unsigned int lockdep_recursion;
struct held_lock held_locks[MAX_LOCK_DEPTH];
gfp_t lockdep_reclaim_gfp;
=== modified file 'kernel/locking/lockdep.c'
--- old/kernel/locking/lockdep.c 2016-06-17 23:23:35 +0000
+++ new/kernel/locking/lockdep.c 2016-06-17 23:38:32 +0000
@@ -3700,9 +3700,11 @@ void lock_acquire(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
-
current->lockdep_recursion = 1;
trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip);
__lock_acquire(lock, subclass, trylock, read, check,
@@ -3720,6 +3722,9 @@ void lock_release(struct lockdep_map *lo
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3948,6 +3953,9 @@ void lock_contended(struct lockdep_map *
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
@@ -3968,6 +3976,9 @@ void lock_acquired(struct lockdep_map *l
if (unlikely(current->lockdep_recursion))
return;
+ if (unlikely(current->nolockdep_call))
+ return;
+
raw_local_irq_save(flags);
check_flags(flags);
current->lockdep_recursion = 1;
=== modified file 'kernel/softirq.c'
--- old/kernel/softirq.c 2016-06-17 23:23:35 +0000
+++ new/kernel/softirq.c 2016-06-17 23:38:32 +0000
@@ -324,6 +324,17 @@ asmlinkage __visible void do_softirq(voi
*/
void irq_enter(void)
{
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call) {
+ current->nolockdep_call_irq_saved = 1;
+ current->nolockdep_call = 0;
+ }
+ local_irq_restore(flags);
+ }
+#endif
rcu_irq_enter();
if (is_idle_task(current) && !in_interrupt()) {
/*
@@ -392,6 +403,17 @@ void irq_exit(void)
tick_irq_exit();
rcu_irq_exit();
+#ifdef CONFIG_LOCKDEP
+ if (unlikely(current->nolockdep_call_irq_saved)) {
+ unsigned long flags;
+ local_irq_save(flags);
+ if (current->nolockdep_call_irq_saved) {
+ current->nolockdep_call_irq_saved = 0;
+ current->nolockdep_call = 1;
+ }
+ local_irq_restore(flags);
+ }
+#endif
trace_hardirq_exit(); /* must be last! */
}
@@ -0,0 +1,109 @@
diff -upr linux-2.6.18/drivers/scsi/scsi_lib.c linux-2.6.18/drivers/scsi/scsi_lib.c
--- linux-2.6.18/drivers/scsi/scsi_lib.c 2006-09-20 07:42:06.000000000 +0400
+++ linux-2.6.18/drivers/scsi/scsi_lib.c 2007-07-04 21:15:32.000000000 +0400
@@ -367,7 +367,7 @@ free_bios:
}
/**
- * scsi_execute_async - insert request
+ * __scsi_execute_async - insert request
* @sdev: scsi device
* @cmd: scsi command
* @cmd_len: length of scsi cdb
@@ -378,11 +378,14 @@ free_bios:
* @timeout: request timeout in seconds
* @retries: number of times to retry request
* @flags: or into request flags
+ * @at_head: insert request at head or tail of queue
**/
-int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
+static inline int __scsi_execute_async(struct scsi_device *sdev,
+ const unsigned char *cmd,
int cmd_len, int data_direction, void *buffer, unsigned bufflen,
int use_sg, int timeout, int retries, void *privdata,
- void (*done)(void *, char *, int, int), gfp_t gfp)
+ void (*done)(void *, char *, int, int), gfp_t gfp,
+ int at_head)
{
struct request *req;
struct scsi_io_context *sioc;
@@ -418,7 +421,7 @@ int scsi_execute_async(struct scsi_devic
sioc->data = privdata;
sioc->done = done;
- blk_execute_rq_nowait(req->q, NULL, req, 1, scsi_end_async);
+ blk_execute_rq_nowait(req->q, NULL, req, at_head, scsi_end_async);
return 0;
free_req:
@@ -427,8 +430,53 @@ free_sense:
kfree(sioc);
return DRIVER_ERROR << 24;
}
+
+/**
+ * scsi_execute_async - insert request
+ * @sdev: scsi device
+ * @cmd: scsi command
+ * @cmd_len: length of scsi cdb
+ * @data_direction: data direction
+ * @buffer: data buffer (this can be a kernel buffer or scatterlist)
+ * @bufflen: len of buffer
+ * @use_sg: if buffer is a scatterlist this is the number of elements
+ * @timeout: request timeout in seconds
+ * @retries: number of times to retry request
+ * @flags: or into request flags
+ **/
+int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
+ int cmd_len, int data_direction, void *buffer, unsigned bufflen,
+ int use_sg, int timeout, int retries, void *privdata,
+ void (*done)(void *, char *, int, int), gfp_t gfp)
+{
+ return __scsi_execute_async(sdev, cmd, cmd_len, data_direction, buffer,
+ bufflen, use_sg, timeout, retries, privdata, done, gfp, 1);
+}
EXPORT_SYMBOL_GPL(scsi_execute_async);
+/**
+ * scsi_execute_async_fifo - insert request at tail, in FIFO order
+ * @sdev: scsi device
+ * @cmd: scsi command
+ * @cmd_len: length of scsi cdb
+ * @data_direction: data direction
+ * @buffer: data buffer (this can be a kernel buffer or scatterlist)
+ * @bufflen: len of buffer
+ * @use_sg: if buffer is a scatterlist this is the number of elements
+ * @timeout: request timeout in seconds
+ * @retries: number of times to retry request
+ * @flags: or into request flags
+ **/
+int scsi_execute_async_fifo(struct scsi_device *sdev, const unsigned char *cmd,
+ int cmd_len, int data_direction, void *buffer, unsigned bufflen,
+ int use_sg, int timeout, int retries, void *privdata,
+ void (*done)(void *, char *, int, int), gfp_t gfp)
+{
+ return __scsi_execute_async(sdev, cmd, cmd_len, data_direction, buffer,
+ bufflen, use_sg, timeout, retries, privdata, done, gfp, 0);
+}
+EXPORT_SYMBOL_GPL(scsi_execute_async_fifo);
+
/*
* Function: scsi_init_cmd_errh()
*
diff -upr linux-2.6.18/include/scsi/scsi_device.h linux-2.6.18/include/scsi/scsi_device.h
--- linux-2.6.18/include/scsi/scsi_device.h 2006-09-20 07:42:06.000000000 +0400
+++ linux-2.6.18/include/scsi/scsi_device.h 2007-07-04 21:15:32.000000000 +0400
@@ -335,6 +335,13 @@ extern int scsi_execute_async(struct scs
int timeout, int retries, void *privdata,
void (*done)(void *, char *, int, int),
gfp_t gfp);
+#define SCSI_EXEC_REQ_FIFO_DEFINED
+extern int scsi_execute_async_fifo(struct scsi_device *sdev,
+ const unsigned char *cmd, int cmd_len, int data_direction,
+ void *buffer, unsigned bufflen, int use_sg,
+ int timeout, int retries, void *privdata,
+ void (*done)(void *, char *, int, int),
+ gfp_t gfp);
static inline void scsi_device_reprobe(struct scsi_device *sdev)
{
+10 -2
View File
@@ -1344,7 +1344,7 @@ static int dev_user_process_reply_alloc(struct scst_user_cmd *ucmd,
}
out_process:
scst_post_alloc_data_buf(cmd);
scst_post_dev_alloc_data_buf(cmd);
scst_process_active_cmd(cmd, false);
TRACE_DBG("%s", "ALLOC_MEM finished");
@@ -1828,6 +1828,14 @@ static int dev_user_process_reply_exec(struct scst_user_cmd *ucmd,
scst_set_resp_data_len(cmd, ereply->resp_data_len);
}
#ifdef CONFIG_SCST_EXTRACHECKS
if (unlikely((ereply->resp_data_len == 0) && (ereply->pbuf != 0))) {
PRINT_WARNING("Supplied pbuf 0x%llx ignored, because "
"resp_data_len is 0. Memory leak? (op %s)",
(unsigned long long)ereply->pbuf, scst_get_opcode_name(cmd));
}
#endif
cmd->status = ereply->status;
if (ereply->sense_len != 0) {
int sense_len, rc;
@@ -2655,7 +2663,7 @@ static void dev_user_unjam_cmd(struct scst_user_cmd *ucmd, int busy,
if (state == UCMD_STATE_PARSING)
scst_post_parse(ucmd->cmd);
else
scst_post_alloc_data_buf(ucmd->cmd);
scst_post_dev_alloc_data_buf(ucmd->cmd);
TRACE_MGMT_DBG("Adding ucmd %p to active list", ucmd);
list_add(&ucmd->cmd->cmd_list_entry,
+129 -23
View File
@@ -248,6 +248,7 @@ struct scst_vdisk_dev {
/* Only to pass it to attach() callback. Don't use them anywhere else! */
int blk_shift;
int numa_node_id;
enum scst_dif_mode dif_mode;
int dif_type;
__be64 dif_static_app_tag_combined;
@@ -399,6 +400,8 @@ static ssize_t vdisk_sysfs_wt_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
static ssize_t vdisk_sysfs_tp_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
static ssize_t vdisk_sysfs_gen_tp_soft_threshold_reached_UA(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count);
static ssize_t vdisk_sysfs_tst_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
static ssize_t vdisk_sysfs_rotational_show(struct kobject *kobj,
@@ -495,6 +498,9 @@ static struct kobj_attribute vdisk_wt_attr =
__ATTR(write_through, S_IRUGO, vdisk_sysfs_wt_show, NULL);
static struct kobj_attribute vdisk_tp_attr =
__ATTR(thin_provisioned, S_IRUGO, vdisk_sysfs_tp_show, NULL);
static struct kobj_attribute gen_tp_soft_threshold_reached_UA_attr =
__ATTR(gen_tp_soft_threshold_reached_UA, S_IWUSR, NULL,
vdisk_sysfs_gen_tp_soft_threshold_reached_UA);
static struct kobj_attribute vdisk_tst_attr =
__ATTR(tst, S_IRUGO, vdisk_sysfs_tst_show, NULL);
static struct kobj_attribute vdisk_rotational_attr =
@@ -725,6 +731,7 @@ static struct scst_dev_type vdisk_file_devtype = {
.add_device_parameters =
"blocksize, "
"filename, "
"numa_node_id, "
"nv_cache, "
"o_direct, "
"cluster_mode, "
@@ -784,6 +791,7 @@ static struct scst_dev_type vdisk_blk_devtype = {
"dif_static_app_tag, "
"dif_filename, "
"filename, "
"numa_node_id, "
"nv_cache, "
"cluster_mode, "
"read_only, "
@@ -828,10 +836,11 @@ static struct scst_dev_type vdisk_null_devtype = {
.dev_attrs = vdisk_nullio_attrs,
.add_device_parameters =
"blocksize, "
"dummy, "
"dif_mode, "
"dif_type, "
"dif_static_app_tag, ",
"dummy, "
"numa_node_id, "
"cluster_mode, "
"read_only, "
"removable, "
@@ -1054,6 +1063,17 @@ check:
if (virt_dev->thin_provisioned) {
int block_shift = virt_dev->dev->block_shift;
#ifndef CONFIG_SCST_PROC
int rc;
rc = sysfs_create_file(&virt_dev->dev->dev_kobj,
&gen_tp_soft_threshold_reached_UA_attr.attr);
if (rc != 0) {
PRINT_ERROR("Can't create attr %s for dev %s",
gen_tp_soft_threshold_reached_UA_attr.attr.name,
virt_dev->name);
}
#endif
if (virt_dev->blockio) {
struct request_queue *q;
@@ -3429,7 +3449,9 @@ enomem:
TRACE_EXIT_RES(-ENOMEM);
return scst_get_cmd_abnormal_done_state(cmd);
}
#else
static int fileio_alloc_data_buf(struct scst_cmd *cmd)
{
struct vdisk_cmd_params *p;
@@ -3447,6 +3469,7 @@ static int fileio_alloc_data_buf(struct scst_cmd *cmd)
static void finish_read(struct scatterlist *sg, int sg_cnt)
{
}
#endif
static int vdev_do_job(struct scst_cmd *cmd, const vdisk_op_fn *ops)
@@ -4303,8 +4326,7 @@ static int vdisk_inq(uint8_t *buf, struct scst_cmd *cmd,
buf[1] = 0x80; /* removable */
buf[2] = 6; /* Device complies to SPC-4 */
buf[3] = 0x02; /* Data in format specified in SPC */
if (cmd->tgtt->fake_aca)
buf[3] |= 0x20;
buf[3] |= 0x20; /* ACA supported */
buf[4] = 31;/* n - 4 = 35 - 4 = 31 for full 36 byte data */
if (cmd->dev->dev_dif_mode != SCST_DIF_MODE_NONE)
buf[5] |= 1; /* PROTECT */
@@ -6359,10 +6381,13 @@ restart:
full_len);
if (err == -EAGAIN)
scst_set_busy(cmd);
else {
else if (err == -ENOSPC) {
WARN_ON(!virt_dev->thin_provisioned);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_space_allocation_failed_write_protect));
} else
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_write_error));
}
goto out_set_fs;
} else if (err < full_len) {
/*
@@ -6517,15 +6542,21 @@ static void blockio_endio(struct bio *bio)
spin_lock_irqsave(&vdev_err_lock, flags);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
if (bio->bi_rw & (1 << BIO_RW))
if (bio->bi_rw & (1 << BIO_RW)) {
#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
if (bio->bi_rw & REQ_WRITE)
if (bio->bi_rw & REQ_WRITE) {
#else
if (op_is_write(bio_op(bio)))
if (op_is_write(bio_op(bio))) {
#endif
scst_set_cmd_error(blockio_work->cmd,
SCST_LOAD_SENSE(scst_sense_write_error));
else
if (error == -ENOSPC) {
struct scst_vdisk_dev *virt_dev = blockio_work->cmd->dev->dh_priv;
WARN_ON(!virt_dev->thin_provisioned);
scst_set_cmd_error(blockio_work->cmd,
SCST_LOAD_SENSE(scst_space_allocation_failed_write_protect));
} else
scst_set_cmd_error(blockio_work->cmd,
SCST_LOAD_SENSE(scst_sense_write_error));
} else
scst_set_cmd_error(blockio_work->cmd,
SCST_LOAD_SENSE(scst_sense_read_error));
@@ -7743,8 +7774,8 @@ static void vdev_inq_changed_fn(struct work_struct *work)
}
/* scst_vdisk_mutex supposed to be held */
static int vdev_create(struct scst_dev_type *devt,
const char *name, struct scst_vdisk_dev **res_virt_dev)
static int vdev_create_node(struct scst_dev_type *devt,
const char *name, int nodeid, struct scst_vdisk_dev **res_virt_dev)
{
int res;
struct scst_vdisk_dev *virt_dev, *vv;
@@ -7755,7 +7786,7 @@ static int vdev_create(struct scst_dev_type *devt,
goto out;
/* It's read-mostly, so cache alignment isn't needed */
virt_dev = kzalloc(sizeof(*virt_dev), GFP_KERNEL);
virt_dev = kzalloc_node(sizeof(*virt_dev), GFP_KERNEL, nodeid);
if (virt_dev == NULL) {
PRINT_ERROR("Allocation of virtual device %s failed",
devt->name);
@@ -7778,6 +7809,7 @@ static int vdev_create(struct scst_dev_type *devt,
INIT_WORK(&virt_dev->vdev_inq_changed_work, vdev_inq_changed_fn);
virt_dev->blk_shift = DEF_DISK_BLOCK_SHIFT;
virt_dev->numa_node_id = NUMA_NO_NODE;
if (strlen(name) >= sizeof(virt_dev->name)) {
PRINT_ERROR("Name %s is too long (max allowed %zd)", name,
@@ -7835,6 +7867,12 @@ out_free:
goto out;
}
static inline int vdev_create(struct scst_dev_type *devt,
const char *name, struct scst_vdisk_dev **res_virt_dev)
{
return vdev_create_node(devt, name, NUMA_NO_NODE, res_virt_dev);
}
static void vdev_destroy(struct scst_vdisk_dev *virt_dev)
{
cancel_work_sync(&virt_dev->vdev_inq_changed_work);
@@ -7848,6 +7886,33 @@ static void vdev_destroy(struct scst_vdisk_dev *virt_dev)
return;
}
static void vdev_check_node(struct scst_vdisk_dev **pvirt_dev, int orig_nodeid)
{
struct scst_vdisk_dev *virt_dev = *pvirt_dev;
int nodeid = virt_dev->numa_node_id;
TRACE_ENTRY();
if (virt_dev->numa_node_id != orig_nodeid) {
struct scst_vdisk_dev *v;
TRACE_MEM("Realloc virt_dev %s on node %d", virt_dev->name, nodeid);
/* It's read-mostly, so cache alignment isn't needed */
v = kzalloc_node(sizeof(*v), GFP_KERNEL, nodeid);
if (v == NULL) {
PRINT_ERROR("Reallocation of virtual device %s failed",
virt_dev->name);
goto out;
}
*v = *virt_dev;
kfree(virt_dev);
*pvirt_dev = v;
}
out:
TRACE_EXIT();
return;
}
#ifndef CONFIG_SCST_PROC
static int vdev_parse_add_dev_params(struct scst_vdisk_dev *virt_dev,
@@ -8056,6 +8121,14 @@ static int vdev_parse_add_dev_params(struct scst_vdisk_dev *virt_dev,
}
TRACE_DBG("block size %lld, block shift %d",
val, virt_dev->blk_shift);
} else if (!strcasecmp("numa_node_id", p)) {
virt_dev->numa_node_id = val;
BUILD_BUG_ON(NUMA_NO_NODE != -1);
if (virt_dev->numa_node_id < NUMA_NO_NODE) {
res = -EINVAL;
goto out;
}
TRACE_DBG("numa_node_id %d", virt_dev->numa_node_id);
} else if (!strcasecmp("dif_type", p)) {
virt_dev->dif_type = val;
TRACE_DBG("DIF type %d", virt_dev->dif_type);
@@ -8117,12 +8190,14 @@ static int vdev_fileio_add_device(const char *device_name, char *params)
goto out_destroy;
}
vdev_check_node(&virt_dev, NUMA_NO_NODE);
list_add_tail(&virt_dev->vdev_list_entry, &vdev_list);
vdisk_report_registering(virt_dev);
virt_dev->virt_id = scst_register_virtual_device(virt_dev->vdev_devt,
virt_dev->name);
virt_dev->virt_id = scst_register_virtual_device_node(virt_dev->vdev_devt,
virt_dev->name, virt_dev->numa_node_id);
if (virt_dev->virt_id < 0) {
res = virt_dev->virt_id;
goto out_del;
@@ -8151,7 +8226,8 @@ static int vdev_blockio_add_device(const char *device_name, char *params)
"removable", "blocksize", "nv_cache",
"rotational", "cluster_mode",
"thin_provisioned", "tst",
"dif_mode", "dif_type", "dif_static_app_tag",
"numa_node_id", "dif_mode",
"dif_type", "dif_static_app_tag",
"dif_filename", NULL };
struct scst_vdisk_dev *virt_dev;
@@ -8178,6 +8254,8 @@ static int vdev_blockio_add_device(const char *device_name, char *params)
goto out_destroy;
}
vdev_check_node(&virt_dev, NUMA_NO_NODE);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
res = vdisk_create_bioset(virt_dev);
if (res != 0)
@@ -8188,8 +8266,8 @@ static int vdev_blockio_add_device(const char *device_name, char *params)
vdisk_report_registering(virt_dev);
virt_dev->virt_id = scst_register_virtual_device(virt_dev->vdev_devt,
virt_dev->name);
virt_dev->virt_id = scst_register_virtual_device_node(virt_dev->vdev_devt,
virt_dev->name, virt_dev->numa_node_id);
if (virt_dev->virt_id < 0) {
res = virt_dev->virt_id;
goto out_del;
@@ -8216,8 +8294,8 @@ static int vdev_nullio_add_device(const char *device_name, char *params)
int res = 0;
static const char *const allowed_params[] = {
"read_only", "dummy", "removable", "blocksize", "rotational",
"cluster_mode", "dif_mode", "dif_type", "dif_static_app_tag",
"size", "size_mb", "tst", NULL
"size", "size_mb", "tst", "numa_node_id",
"cluster_mode", "dif_mode", "dif_type", "dif_static_app_tag", NULL
};
struct scst_vdisk_dev *virt_dev;
@@ -8236,12 +8314,14 @@ static int vdev_nullio_add_device(const char *device_name, char *params)
if (res != 0)
goto out_destroy;
vdev_check_node(&virt_dev, NUMA_NO_NODE);
list_add_tail(&virt_dev->vdev_list_entry, &vdev_list);
vdisk_report_registering(virt_dev);
virt_dev->virt_id = scst_register_virtual_device(virt_dev->vdev_devt,
virt_dev->name);
virt_dev->virt_id = scst_register_virtual_device_node(virt_dev->vdev_devt,
virt_dev->name, virt_dev->numa_node_id);
if (virt_dev->virt_id < 0) {
res = virt_dev->virt_id;
goto out_del;
@@ -8899,6 +8979,32 @@ static ssize_t vdisk_sysfs_tp_show(struct kobject *kobj,
return pos;
}
static ssize_t vdisk_sysfs_gen_tp_soft_threshold_reached_UA(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
struct scst_device *dev;
struct scst_vdisk_dev *virt_dev;
struct scst_tgt_dev *tgt_dev;
TRACE_ENTRY();
dev = container_of(kobj, struct scst_device, dev_kobj);
virt_dev = dev->dh_priv;
if (!virt_dev->thin_provisioned)
return -EINVAL;
spin_lock_bh(&dev->dev_lock);
list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
dev_tgt_dev_list_entry) {
scst_set_tp_soft_threshold_reached_UA(tgt_dev);
}
spin_unlock_bh(&dev->dev_lock);
TRACE_EXIT_RES(count);
return count;
}
static ssize_t vdisk_sysfs_expl_alua_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
+2 -2
View File
@@ -1788,7 +1788,7 @@ bool scst_cm_check_block_all_devs(struct scst_cmd *cmd)
#if !defined(__CHECKER__)
list_for_each_entry(e, &d->cm_sorted_devs_list, cm_sorted_devs_list_entry) {
spin_lock(&e->cm_fcmd->dev->dev_lock);
spin_lock_nolockdep(&e->cm_fcmd->dev->dev_lock);
}
#endif
@@ -1817,7 +1817,7 @@ bool scst_cm_check_block_all_devs(struct scst_cmd *cmd)
#if !defined(__CHECKER__)
list_for_each_entry_reverse(e, &d->cm_sorted_devs_list,
cm_sorted_devs_list_entry) {
spin_unlock(&e->cm_fcmd->dev->dev_lock);
spin_unlock_nolockdep(&e->cm_fcmd->dev->dev_lock);
}
#endif
+313 -72
View File
@@ -1285,8 +1285,7 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
{.ops = 0x84, .devkey = "O ", /* implemented only for disks */
.info_op_name = "RECEIVE COPY RESULT",
.info_data_direction = SCST_DATA_READ,
.info_op_flags = SCST_FULLY_LOCAL_CMD|SCST_LOCAL_CMD|
SCST_WRITE_EXCL_ALLOWED|SCST_EXCL_ACCESS_ALLOWED,
.info_op_flags = SCST_LOCAL_CMD|SCST_WRITE_EXCL_ALLOWED|SCST_EXCL_ACCESS_ALLOWED,
.info_len_off = 10, .info_len_len = 4,
.get_cdb_info = get_cdb_info_len_4},
{.ops = 0x85, .devkey = "O O O ",
@@ -1322,7 +1321,7 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
.info_op_name = "COMPARE AND WRITE",
.info_data_direction = SCST_DATA_WRITE,
.info_op_flags = SCST_TRANSFER_LEN_TYPE_FIXED|
SCST_FULLY_LOCAL_CMD|SCST_LOCAL_CMD|
SCST_LOCAL_CMD|
SCST_WRITE_MEDIUM|SCST_SCSI_ATOMIC,
.info_lba_off = 2, .info_lba_len = 8,
.info_len_off = 13, .info_len_len = 1,
@@ -2660,7 +2659,7 @@ static void scst_queue_report_luns_changed_UA(struct scst_session *sess,
list_for_each_entry_rcu(tgt_dev, head,
sess_tgt_dev_list_entry) {
/* Lockdep triggers here a false positive.. */
spin_lock(&tgt_dev->tgt_dev_lock);
spin_lock_nolockdep(&tgt_dev->tgt_dev_lock);
}
}
#endif
@@ -2691,7 +2690,7 @@ static void scst_queue_report_luns_changed_UA(struct scst_session *sess,
list_for_each_entry_rcu(tgt_dev, head,
sess_tgt_dev_list_entry) {
spin_unlock(&tgt_dev->tgt_dev_lock);
spin_unlock_nolockdep(&tgt_dev->tgt_dev_lock);
}
}
#endif
@@ -4190,19 +4189,21 @@ static int scst_dif_none_type1(struct scst_cmd *cmd);
#endif
/* Called under scst_mutex and suspended activity */
int scst_alloc_device(gfp_t gfp_mask, struct scst_device **out_dev)
int scst_alloc_device(gfp_t gfp_mask, int nodeid,
struct scst_device **out_dev)
{
struct scst_device *dev;
int res = 0;
TRACE_ENTRY();
dev = kmem_cache_zalloc(scst_dev_cachep, gfp_mask);
dev = kmem_cache_alloc_node(scst_dev_cachep, gfp_mask, nodeid);
if (dev == NULL) {
PRINT_ERROR("%s", "Allocation of scst_device failed");
res = -ENOMEM;
goto out;
}
memset(dev, 0, sizeof(*dev));
dev->handler = &scst_null_devtype;
#ifdef CONFIG_SCST_PER_DEVICE_CMD_COUNT_LIMIT
@@ -4222,6 +4223,7 @@ int scst_alloc_device(gfp_t gfp_mask, struct scst_device **out_dev)
#endif
dev->dev_double_ua_possible = 1;
dev->queue_alg = SCST_QUEUE_ALG_1_UNRESTRICTED_REORDER;
dev->dev_numa_node_id = nodeid;
scst_pr_init(dev);
@@ -5121,6 +5123,8 @@ int scst_tgt_dev_setup_threads(struct scst_tgt_dev *tgt_dev)
TRACE_ENTRY();
tgt_dev->thread_index = -1;
if (dev->threads_num < 0)
goto out;
@@ -5140,7 +5144,8 @@ int scst_tgt_dev_setup_threads(struct scst_tgt_dev *tgt_dev)
tgt_dev->dev->virt_name);
} else {
/* Create new context */
aic_keeper = kzalloc(sizeof(*aic_keeper), GFP_KERNEL);
aic_keeper = kzalloc_node(sizeof(*aic_keeper), GFP_KERNEL,
dev->dev_numa_node_id);
if (aic_keeper == NULL) {
PRINT_ERROR("Unable to alloc aic_keeper "
"(size %zd)", sizeof(*aic_keeper));
@@ -5348,6 +5353,16 @@ static int scst_alloc_add_tgt_dev(struct scst_session *sess,
else
clear_bit(SCST_TGT_DEV_BLACK_HOLE, &tgt_dev->tgt_dev_flags);
#ifdef CONFIG_CPUMASK_OFFSTACK
tgt_dev->pools = kzalloc_node(sizeof(tgt_dev->pools[0])*NR_CPUS,
GFP_KERNEL, dev->dev_numa_node_id);
if (tgt_dev->pools == NULL) {
PRINT_ERROR("Unable to alloc tgt_dev->pools (size %zd)",
sizeof(tgt_dev->pools[0])*NR_CPUS);
goto out_free;
}
#endif
scst_sgv_pool_use_norm(tgt_dev);
if (dev->scsi_dev != NULL) {
@@ -5405,7 +5420,7 @@ static int scst_alloc_add_tgt_dev(struct scst_session *sess,
"Persistent Reservations", sess->tgt->tgtt->name,
dev->virt_name);
res = -EPERM;
goto out_free;
goto out_free_ua;
}
dev->not_pr_supporting_tgt_devs_num++;
}
@@ -5468,8 +5483,13 @@ out_dec_free:
if (tgtt->get_initiator_port_transport_id == NULL)
dev->not_pr_supporting_tgt_devs_num--;
out_free:
out_free_ua:
scst_free_all_UA(tgt_dev);
#ifdef CONFIG_CPUMASK_OFFSTACK
kfree(tgt_dev->pools);
out_free:
#endif
kmem_cache_free(scst_tgtd_cachep, tgt_dev);
goto out;
}
@@ -5545,6 +5565,10 @@ static void scst_free_tgt_dev(struct scst_tgt_dev *tgt_dev)
scst_tgt_dev_stop_threads(tgt_dev);
#ifdef CONFIG_CPUMASK_OFFSTACK
kfree(tgt_dev->pools);
#endif
kmem_cache_free(scst_tgtd_cachep, tgt_dev);
TRACE_EXIT();
@@ -6089,7 +6113,7 @@ static int scst_ws_push_single_write(struct scst_write_same_priv *wsp,
dif_bufflen = blocks << SCST_DIF_TAG_SHIFT;
cmd->expected_transfer_len_full += dif_bufflen;
dif_sg = sgv_pool_alloc(ws_cmd->tgt_dev->pool,
dif_sg = sgv_pool_alloc(ws_cmd->tgt_dev->pools[raw_smp_processor_id()],
dif_bufflen, GFP_KERNEL, 0, &dif_sg_cnt, &dif_sgv,
&cmd->dev->dev_mem_lim, NULL);
if (unlikely(dif_sg == NULL)) {
@@ -6815,7 +6839,6 @@ out_done:
goto out;
}
int scst_finish_internal_cmd(struct scst_cmd *cmd)
{
int res;
@@ -7598,8 +7621,9 @@ int scst_alloc_space(struct scst_cmd *cmd)
if (cmd->no_sgv)
flags |= SGV_POOL_ALLOC_NO_CACHED;
cmd->sg = sgv_pool_alloc(tgt_dev->pool, cmd->bufflen, gfp_mask, flags,
&cmd->sg_cnt, &cmd->sgv, &cmd->dev->dev_mem_lim, NULL);
cmd->sg = sgv_pool_alloc(tgt_dev->pools[raw_smp_processor_id()],
cmd->bufflen, gfp_mask, flags, &cmd->sg_cnt, &cmd->sgv,
&cmd->dev->dev_mem_lim, NULL);
if (unlikely(cmd->sg == NULL))
goto out;
@@ -7618,8 +7642,9 @@ int scst_alloc_space(struct scst_cmd *cmd)
else
dif_bufflen = cmd->bufflen;
cmd->dif_sg = sgv_pool_alloc(tgt_dev->pool, dif_bufflen, gfp_mask, flags,
&cmd->dif_sg_cnt, &cmd->dif_sgv, &cmd->dev->dev_mem_lim, NULL);
cmd->dif_sg = sgv_pool_alloc(tgt_dev->pools[raw_smp_processor_id()],
dif_bufflen, gfp_mask, flags, &cmd->dif_sg_cnt, &cmd->dif_sgv,
&cmd->dev->dev_mem_lim, NULL);
if (unlikely(cmd->dif_sg == NULL))
goto out_sg_free;
@@ -7646,9 +7671,9 @@ int scst_alloc_space(struct scst_cmd *cmd)
if (cmd->data_direction != SCST_DATA_BIDI)
goto success;
cmd->out_sg = sgv_pool_alloc(tgt_dev->pool, cmd->out_bufflen, gfp_mask,
flags, &cmd->out_sg_cnt, &cmd->out_sgv,
&cmd->dev->dev_mem_lim, NULL);
cmd->out_sg = sgv_pool_alloc(tgt_dev->pools[raw_smp_processor_id()],
cmd->out_bufflen, gfp_mask, flags, &cmd->out_sg_cnt,
&cmd->out_sgv, &cmd->dev->dev_mem_lim, NULL);
if (unlikely(cmd->out_sg == NULL))
goto out_dif_sg_free;
@@ -12586,6 +12611,15 @@ void scst_process_reset(struct scst_device *dev,
spin_unlock_irq(&sess->sess_list_lock);
}
/*
* We need at first abort all affected commands and only then
* release them as part of clearing ACA
*/
list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
dev_tgt_dev_list_entry) {
scst_clear_aca(tgt_dev, (tgt_dev->sess != originator));
}
if (setUA) {
uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN];
int sl = scst_set_sense(sense_buffer, sizeof(sense_buffer),
@@ -12675,7 +12709,7 @@ again:
list_for_each_entry_rcu(tgt_dev, head,
sess_tgt_dev_list_entry) {
/* Lockdep triggers here a false positive.. */
spin_lock(&tgt_dev->tgt_dev_lock);
spin_lock_nolockdep(&tgt_dev->tgt_dev_lock);
}
}
#endif
@@ -12749,7 +12783,7 @@ out_unlock:
list_for_each_entry_rcu(tgt_dev, head,
sess_tgt_dev_list_entry) {
spin_unlock(&tgt_dev->tgt_dev_lock);
spin_unlock_nolockdep(&tgt_dev->tgt_dev_lock);
}
}
rcu_read_unlock();
@@ -12924,6 +12958,23 @@ void scst_dev_check_set_UA(struct scst_device *dev,
return;
}
void scst_set_tp_soft_threshold_reached_UA(struct scst_tgt_dev *tgt_dev)
{
uint8_t sense[SCST_STANDARD_SENSE_LEN];
int len;
TRACE_ENTRY();
len = scst_set_sense(sense, sizeof(sense), tgt_dev->dev->d_sense,
SCST_LOAD_SENSE(scst_sense_tp_soft_threshold_reached));
scst_check_set_UA(tgt_dev, sense, len, 0);
TRACE_EXIT();
return;
}
EXPORT_SYMBOL_GPL(scst_set_tp_soft_threshold_reached_UA);
/* Called under tgt_dev_lock or when tgt_dev is unused */
static void scst_free_all_UA(struct scst_tgt_dev *tgt_dev)
{
@@ -12966,9 +13017,27 @@ struct scst_cmd *__scst_check_deferred_commands_locked(
restart:
list_for_each_entry_safe(cmd, t, &order_data->deferred_cmd_list,
deferred_cmd_list_entry) {
EXTRACHECKS_BUG_ON((cmd->queue_type != SCST_CMD_QUEUE_SIMPLE) &&
(cmd->queue_type != SCST_CMD_QUEUE_ORDERED));
if (cmd->sn == expected_sn) {
EXTRACHECKS_BUG_ON(cmd->queue_type == SCST_CMD_QUEUE_ACA);
if (unlikely(order_data->aca_tgt_dev != 0)) {
if (!test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)) {
/* To prevent defer/release storms during ACA */
continue;
}
}
if (unlikely(cmd->done)) {
TRACE_MGMT_DBG("Releasing deferred done cmd %p", cmd);
order_data->def_cmd_count--;
list_del(&cmd->deferred_cmd_list_entry);
spin_lock(&cmd->cmd_threads->cmd_list_lock);
TRACE_DBG("Adding cmd %p to active cmd list", cmd);
list_add_tail(&cmd->cmd_list_entry,
&cmd->cmd_threads->active_cmd_list);
wake_up(&cmd->cmd_threads->cmd_list_waitQ);
spin_unlock(&cmd->cmd_threads->cmd_list_lock);
} else if ((cmd->sn == expected_sn) || !cmd->sn_set) {
bool stop = (cmd->sn_slot == NULL);
TRACE_SN("Deferred command %p (sn %d, set %d) found",
@@ -13574,21 +13643,100 @@ static void scst_process_qerr(struct scst_cmd *cmd)
int scst_process_check_condition(struct scst_cmd *cmd)
{
int res;
struct scst_order_data *order_data;
struct scst_device *dev;
TRACE_ENTRY();
EXTRACHECKS_BUG_ON(test_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags));
TRACE_DBG("CHECK CONDITION for cmd %p (tgt_dev %p)", cmd, cmd->tgt_dev);
order_data = cmd->cur_order_data;
dev = cmd->dev;
TRACE((order_data->aca_tgt_dev != 0) ? TRACE_MGMT_DEBUG : TRACE_DEBUG,
"CHECK CONDITION for cmd %p (naca %d, cmd_aca_allowed %d, "
"ACA allowed cmd %d, tgt_dev %p, aca_tgt_dev %lu, aca_cmd %p)",
cmd, cmd->cmd_naca, cmd->cmd_aca_allowed,
cmd->queue_type == SCST_CMD_QUEUE_ACA, cmd->tgt_dev,
order_data->aca_tgt_dev, order_data->aca_cmd);
spin_lock_irq(&order_data->sn_lock);
if (order_data->aca_tgt_dev != 0) {
if (((cmd->queue_type == SCST_CMD_QUEUE_ACA) &&
(order_data->aca_tgt_dev == (unsigned long)cmd->tgt_dev)) ||
((cmd->cdb[0] == PERSISTENT_RESERVE_OUT) &&
((cmd->cdb[1] & 0x1f) == PR_PREEMPT_AND_ABORT))) {
if (!cmd->cmd_naca) {
if (order_data->aca_cmd == cmd) {
/*
* Clear it to prevent from be
* aborted during ACA clearing
*/
TRACE_MGMT_DBG("Check condition of ACA "
"cmd %p", cmd);
order_data->aca_cmd = NULL;
}
spin_unlock_irq(&order_data->sn_lock);
scst_clear_aca(cmd->tgt_dev,
(order_data->aca_tgt_dev != (unsigned long)cmd->tgt_dev));
/*
* Goto directly to avoid race when ACA
* reestablished during retaking sn_lock
* once again.
*/
goto process_qerr;
}
}
if (test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)) {
/*
* cmd can be aborted and the unblock
* procedure finished while we were
* entering here. I.e. cmd can not be
* blocked anymore for any case.
*/
res = 1;
goto out_unlock;
} else if (!cmd->cmd_aca_allowed) {
TRACE_MGMT_DBG("Deferring CHECK CONDITION "
"cmd %p due to ACA active (tgt_dev %p)",
cmd, cmd->tgt_dev);
order_data->def_cmd_count++;
/*
* Put cmd in the head to let restart earlier:
* it is already completed and completed with
* CHECK CONDITION
*/
list_add(&cmd->deferred_cmd_list_entry,
&order_data->deferred_cmd_list);
res = -1;
goto out_unlock;
}
}
if (cmd->cmd_naca) {
TRACE_MGMT_DBG("Establishing ACA for dev %s (lun %lld, cmd %p, "
"tgt_dev %p)", dev->virt_name, (unsigned long long)cmd->lun,
cmd, cmd->tgt_dev);
order_data->aca_tgt_dev = (unsigned long)cmd->tgt_dev;
}
spin_unlock_irq(&order_data->sn_lock);
process_qerr:
scst_process_qerr(cmd);
scst_store_sense(cmd);
res = 0;
out:
TRACE_EXIT_RES(res);
return res;
out_unlock:
spin_unlock_irq(&order_data->sn_lock);
goto out;
}
void scst_xmit_process_aborted_cmd(struct scst_cmd *cmd)
@@ -13645,7 +13793,56 @@ out:
*/
int scst_get_max_lun_commands(struct scst_session *sess, uint64_t lun)
{
return SCST_MAX_TGT_DEV_COMMANDS;
const int init_res = 0xFFFFFF;
int res = init_res, i;
TRACE_ENTRY();
mutex_lock(&scst_mutex);
if (sess == NULL) {
struct scst_device *dev;
list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
if (dev->handler == &scst_null_devtype)
continue;
TRACE_DBG("dev %s, max_tgt_dev_commands %d (res %d)",
dev->virt_name, dev->max_tgt_dev_commands, res);
if (res > dev->max_tgt_dev_commands)
res = dev->max_tgt_dev_commands;
}
goto out_unlock;
}
if (lun != NO_SUCH_LUN) {
struct list_head *head =
&sess->sess_tgt_dev_list[SESS_TGT_DEV_LIST_HASH_FN(lun)];
struct scst_tgt_dev *tgt_dev;
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
if (tgt_dev->lun == lun) {
res = tgt_dev->dev->max_tgt_dev_commands;
TRACE_DBG("tgt_dev %p, dev %s, max_tgt_dev_commands "
"%d (res %d)", tgt_dev, tgt_dev->dev->virt_name,
tgt_dev->dev->max_tgt_dev_commands, res);
break;
}
}
goto out_unlock;
}
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
struct list_head *head = &sess->sess_tgt_dev_list[i];
struct scst_tgt_dev *tgt_dev;
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
if (res > tgt_dev->dev->max_tgt_dev_commands)
res = tgt_dev->dev->max_tgt_dev_commands;
}
}
out_unlock:
mutex_unlock(&scst_mutex);
TRACE_EXIT_RES(res);
return res;
}
EXPORT_SYMBOL(scst_get_max_lun_commands);
@@ -15405,22 +15602,28 @@ void scst_check_debug_sn(struct scst_cmd *cmd)
#ifdef CONFIG_SCST_MEASURE_LATENCY
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
static uint64_t scst_get_usec(void)
{
struct timespec ts;
ktime_get_ts(&ts);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
return ((uint64_t)ts.tv_sec * 1000000000 + ts.tv_nsec) / 1000;
#else
#if (BITS_PER_LONG > 32)
return timespec_to_ns(&ts) / 1000;
#else
return timespec_to_ns(&ts) >> 10;
#endif
#endif
}
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) */
static uint64_t scst_get_usec(void)
{
ktime_t t;
t = ktime_get();
return ktime_to_us(t);
}
#endif
void scst_set_start_time(struct scst_cmd *cmd)
{
cmd->start = scst_get_usec();
@@ -15439,10 +15642,16 @@ void scst_set_parse_time(struct scst_cmd *cmd)
TRACE_DBG("cmd %p: parse_time %lld", cmd, cmd->parse_time);
}
void scst_set_alloc_buf_time(struct scst_cmd *cmd)
void scst_set_dev_alloc_buf_time(struct scst_cmd *cmd)
{
cmd->alloc_buf_time += scst_get_usec() - cmd->curr_start;
TRACE_DBG("cmd %p: alloc_buf_time %lld", cmd, cmd->alloc_buf_time);
cmd->dev_alloc_buf_time += scst_get_usec() - cmd->curr_start;
TRACE_DBG("cmd %p: dev_alloc_buf_time %lld", cmd, cmd->dev_alloc_buf_time);
}
void scst_set_tgt_alloc_buf_time(struct scst_cmd *cmd)
{
cmd->tgt_alloc_buf_time += scst_get_usec() - cmd->curr_start;
TRACE_DBG("cmd %p: tgt_alloc_buf_time %lld", cmd, cmd->tgt_alloc_buf_time);
}
void scst_set_restart_waiting_time(struct scst_cmd *cmd)
@@ -15472,6 +15681,9 @@ void scst_set_exec_start(struct scst_cmd *cmd)
void scst_set_exec_time(struct scst_cmd *cmd)
{
if (!cmd->exec_time_counting)
return;
cmd->exec_time_counting = false;
cmd->exec_time += scst_get_usec() - cmd->curr_start;
TRACE_DBG("cmd %p: exec_time %lld", cmd, cmd->exec_time);
}
@@ -15490,11 +15702,12 @@ void scst_set_xmit_time(struct scst_cmd *cmd)
void scst_update_lat_stats(struct scst_cmd *cmd)
{
uint64_t finish, scst_time, tgt_time, dev_time;
int64_t finish, scst_time, tgt_time, dev_time;
struct scst_session *sess = cmd->sess;
int data_len;
int i;
struct scst_ext_latency_stat *latency_stat, *dev_latency_stat;
bool ignore_max = false;
finish = scst_get_usec();
@@ -15517,12 +15730,30 @@ void scst_update_lat_stats(struct scst_cmd *cmd)
/* Calculate the latencies */
scst_time = finish - cmd->start - (cmd->parse_time +
cmd->alloc_buf_time + cmd->restart_waiting_time +
cmd->dev_alloc_buf_time + cmd->tgt_alloc_buf_time +
cmd->restart_waiting_time +
cmd->rdy_to_xfer_time + cmd->pre_exec_time +
cmd->exec_time + cmd->dev_done_time + cmd->xmit_time);
tgt_time = cmd->alloc_buf_time + cmd->restart_waiting_time +
cmd->rdy_to_xfer_time + cmd->pre_exec_time;
dev_time = cmd->parse_time + cmd->exec_time + cmd->dev_done_time;
tgt_time = cmd->tgt_alloc_buf_time + cmd->restart_waiting_time +
cmd->rdy_to_xfer_time + cmd->pre_exec_time + cmd->xmit_time;
dev_time = cmd->parse_time + cmd->dev_alloc_buf_time +
cmd->exec_time + cmd->dev_done_time;
if (unlikely((scst_time < 0) || (tgt_time < 0) || (dev_time < 0))) {
/* It might happen due to small difference in time between CPUs */
static int q;
if (q++ < 20) {
PRINT_WARNING("Ignoring max latency sample, because time is "
"moving backward (cmd %p, scst %lld, tgt %lld, "
"dev %lld)", cmd, (long long) scst_time,
(long long) tgt_time, (long long) dev_time);
}
ignore_max = true;
/*
* We should not ignore this sample, because the time
* difference mistake can be both negative and positive.
*/
}
spin_lock_bh(&sess->lat_lock);
@@ -15542,12 +15773,14 @@ void scst_update_lat_stats(struct scst_cmd *cmd)
(sess->min_dev_time > dev_time))
sess->min_dev_time = dev_time;
if (sess->max_scst_time < scst_time)
sess->max_scst_time = scst_time;
if (sess->max_tgt_time < tgt_time)
sess->max_tgt_time = tgt_time;
if (sess->max_dev_time < dev_time)
sess->max_dev_time = dev_time;
if (likely(!ignore_max)) {
if (sess->max_scst_time < scst_time)
sess->max_scst_time = scst_time;
if (sess->max_tgt_time < tgt_time)
sess->max_tgt_time = tgt_time;
if (sess->max_dev_time < dev_time)
sess->max_dev_time = dev_time;
}
/* Save the extended latency information */
if (cmd->data_direction & SCST_DATA_READ) {
@@ -15566,12 +15799,14 @@ void scst_update_lat_stats(struct scst_cmd *cmd)
(latency_stat->min_dev_time_rd > dev_time))
latency_stat->min_dev_time_rd = dev_time;
if (latency_stat->max_scst_time_rd < scst_time)
latency_stat->max_scst_time_rd = scst_time;
if (latency_stat->max_tgt_time_rd < tgt_time)
latency_stat->max_tgt_time_rd = tgt_time;
if (latency_stat->max_dev_time_rd < dev_time)
latency_stat->max_dev_time_rd = dev_time;
if (likely(!ignore_max)) {
if (latency_stat->max_scst_time_rd < scst_time)
latency_stat->max_scst_time_rd = scst_time;
if (latency_stat->max_tgt_time_rd < tgt_time)
latency_stat->max_tgt_time_rd = tgt_time;
if (latency_stat->max_dev_time_rd < dev_time)
latency_stat->max_dev_time_rd = dev_time;
}
if (dev_latency_stat != NULL) {
dev_latency_stat->scst_time_rd += scst_time;
@@ -15589,12 +15824,14 @@ void scst_update_lat_stats(struct scst_cmd *cmd)
(dev_latency_stat->min_dev_time_rd > dev_time))
dev_latency_stat->min_dev_time_rd = dev_time;
if (dev_latency_stat->max_scst_time_rd < scst_time)
dev_latency_stat->max_scst_time_rd = scst_time;
if (dev_latency_stat->max_tgt_time_rd < tgt_time)
dev_latency_stat->max_tgt_time_rd = tgt_time;
if (dev_latency_stat->max_dev_time_rd < dev_time)
dev_latency_stat->max_dev_time_rd = dev_time;
if (likely(!ignore_max)) {
if (dev_latency_stat->max_scst_time_rd < scst_time)
dev_latency_stat->max_scst_time_rd = scst_time;
if (dev_latency_stat->max_tgt_time_rd < tgt_time)
dev_latency_stat->max_tgt_time_rd = tgt_time;
if (dev_latency_stat->max_dev_time_rd < dev_time)
dev_latency_stat->max_dev_time_rd = dev_time;
}
}
} else if (cmd->data_direction & SCST_DATA_WRITE) {
latency_stat->scst_time_wr += scst_time;
@@ -15612,12 +15849,14 @@ void scst_update_lat_stats(struct scst_cmd *cmd)
(latency_stat->min_dev_time_wr > dev_time))
latency_stat->min_dev_time_wr = dev_time;
if (latency_stat->max_scst_time_wr < scst_time)
latency_stat->max_scst_time_wr = scst_time;
if (latency_stat->max_tgt_time_wr < tgt_time)
latency_stat->max_tgt_time_wr = tgt_time;
if (latency_stat->max_dev_time_wr < dev_time)
latency_stat->max_dev_time_wr = dev_time;
if (likely(!ignore_max)) {
if (latency_stat->max_scst_time_wr < scst_time)
latency_stat->max_scst_time_wr = scst_time;
if (latency_stat->max_tgt_time_wr < tgt_time)
latency_stat->max_tgt_time_wr = tgt_time;
if (latency_stat->max_dev_time_wr < dev_time)
latency_stat->max_dev_time_wr = dev_time;
}
if (dev_latency_stat != NULL) {
dev_latency_stat->scst_time_wr += scst_time;
@@ -15635,12 +15874,14 @@ void scst_update_lat_stats(struct scst_cmd *cmd)
(dev_latency_stat->min_dev_time_wr > dev_time))
dev_latency_stat->min_dev_time_wr = dev_time;
if (dev_latency_stat->max_scst_time_wr < scst_time)
dev_latency_stat->max_scst_time_wr = scst_time;
if (dev_latency_stat->max_tgt_time_wr < tgt_time)
dev_latency_stat->max_tgt_time_wr = tgt_time;
if (dev_latency_stat->max_dev_time_wr < dev_time)
dev_latency_stat->max_dev_time_wr = dev_time;
if (likely(!ignore_max)) {
if (dev_latency_stat->max_scst_time_wr < scst_time)
dev_latency_stat->max_scst_time_wr = scst_time;
if (dev_latency_stat->max_tgt_time_wr < tgt_time)
dev_latency_stat->max_tgt_time_wr = tgt_time;
if (dev_latency_stat->max_dev_time_wr < dev_time)
dev_latency_stat->max_dev_time_wr = dev_time;
}
}
}
+27 -16
View File
@@ -1154,7 +1154,7 @@ static int scst_register_device(struct scsi_device *scsidp)
goto out;
#endif
res = scst_alloc_device(GFP_KERNEL, &dev);
res = scst_alloc_device(GFP_KERNEL, NUMA_NO_NODE, &dev);
if (res != 0)
goto out_unlock;
@@ -1365,6 +1365,9 @@ static int scst_dev_handler_check(struct scst_dev_type *dev_handler)
if (dev_handler->dev_done == NULL)
dev_handler->dev_done_atomic = 1;
if (dev_handler->max_tgt_dev_commands == 0)
dev_handler->max_tgt_dev_commands = SCST_MAX_TGT_DEV_COMMANDS;
out:
TRACE_EXIT_RES(res);
return res;
@@ -1395,16 +1398,17 @@ out:
}
/**
* scst_register_virtual_device() - register a virtual device.
* scst_register_virtual_device_node() - register a virtual device.
* @dev_handler: the device's device handler
* @dev_name: the new device name, NULL-terminated string. Must be uniq
* among all virtual devices in the system.
* @nodeid: NUMA node id this device belongs to or NUMA_NO_NODE.
*
* Registers a virtual device and returns ID assigned to the device on
* success, or negative value otherwise
*/
int scst_register_virtual_device(struct scst_dev_type *dev_handler,
const char *dev_name)
int scst_register_virtual_device_node(struct scst_dev_type *dev_handler,
const char *dev_name, int nodeid)
{
int res;
struct scst_device *dev, *d;
@@ -1441,7 +1445,7 @@ int scst_register_virtual_device(struct scst_dev_type *dev_handler,
if (res != 0)
goto out_resume;
res = scst_alloc_device(GFP_KERNEL, &dev);
res = scst_alloc_device(GFP_KERNEL, nodeid, &dev);
if (res != 0)
goto out_unlock;
@@ -1545,7 +1549,7 @@ out_resume:
scst_resume_activity();
goto out;
}
EXPORT_SYMBOL_GPL(scst_register_virtual_device);
EXPORT_SYMBOL_GPL(scst_register_virtual_device_node);
/**
* scst_unregister_virtual_device() - unegister a virtual device.
@@ -1892,7 +1896,7 @@ int scst_add_threads(struct scst_cmd_threads *cmd_threads,
{
int res = 0, i;
struct scst_cmd_thread_t *thr;
int n = 0, tgt_dev_num = 0;
int n = 0, tgt_dev_num = 0, nodeid = NUMA_NO_NODE;
TRACE_ENTRY();
@@ -1906,7 +1910,7 @@ int scst_add_threads(struct scst_cmd_threads *cmd_threads,
spin_unlock(&cmd_threads->thr_lock);
TRACE_DBG("cmd_threads %p, dev %s, tgt_dev %p, num %d, n %d",
cmd_threads, dev ? dev->virt_name : NULL, tgt_dev, num, n);
cmd_threads, dev ? dev->virt_name : "NULL", tgt_dev, num, n);
if (tgt_dev != NULL) {
struct scst_tgt_dev *t;
@@ -1917,29 +1921,34 @@ int scst_add_threads(struct scst_cmd_threads *cmd_threads,
break;
tgt_dev_num++;
}
}
tgt_dev->thread_index = tgt_dev_num;
nodeid = tgt_dev->dev->dev_numa_node_id;
} else if (dev != NULL)
nodeid = dev->dev_numa_node_id;
for (i = 0; i < num; i++) {
thr = kmem_cache_zalloc(scst_thr_cachep, GFP_KERNEL);
thr = kmem_cache_alloc_node(scst_thr_cachep, GFP_KERNEL, nodeid);
if (!thr) {
res = -ENOMEM;
PRINT_ERROR("Fail to allocate thr %d", res);
goto out_wait;
}
memset(thr, 0, sizeof(*thr));
INIT_LIST_HEAD(&thr->thr_active_cmd_list);
spin_lock_init(&thr->thr_cmd_list_lock);
thr->thr_cmd_threads = cmd_threads;
if (dev != NULL) {
thr->cmd_thread = kthread_create(scst_cmd_thread,
thr, "%.13s%d", dev->virt_name, n++);
thr->cmd_thread = kthread_create_on_node(scst_cmd_thread,
thr, nodeid, "%.13s%d", dev->virt_name, n++);
} else if (tgt_dev != NULL) {
thr->cmd_thread = kthread_create(scst_cmd_thread,
thr, "%.10s%d_%d",
thr->cmd_thread = kthread_create_on_node(scst_cmd_thread,
thr, nodeid, "%.10s%d_%d",
tgt_dev->dev->virt_name, tgt_dev_num, n++);
} else
thr->cmd_thread = kthread_create(scst_cmd_thread,
thr, "scstd%d", n++);
thr->cmd_thread = kthread_create_on_node(scst_cmd_thread,
thr, nodeid, "scstd%d", n++);
if (IS_ERR(thr->cmd_thread)) {
res = PTR_ERR(thr->cmd_thread);
@@ -2152,6 +2161,7 @@ assign:
dev->handler = handler;
dev->threads_num = handler->threads_num;
dev->threads_pool_type = handler->threads_pool_type;
dev->max_tgt_dev_commands = handler->max_tgt_dev_commands;
dev->max_write_same_len = 256 * 1024 * 1024; /* 256 MB */
if (handler->attach) {
@@ -2833,6 +2843,7 @@ static void __exit exit_scst(void)
scst_deinit_threads(&scst_main_cmd_threads);
scsi_unregister_interface(&scst_interface);
#ifdef CONFIG_SCST_PROC
scst_del_free_acg(scst_default_acg, false);
#endif
+130 -124
View File
@@ -40,6 +40,12 @@
/* Max pages freed from a pool per shrinking iteration */
#define MAX_PAGES_PER_POOL 50
bool scst_force_global_sgv_pool;
static struct sgv_pool *sgv_dma_pool_per_cpu[NR_CPUS];
static struct sgv_pool *sgv_norm_clust_pool_per_cpu[NR_CPUS];
static struct sgv_pool *sgv_norm_pool_per_cpu[NR_CPUS];
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
#if defined(CONFIG_LOCKDEP) && !defined(CONFIG_SCST_PROC)
static struct lock_class_key scst_pool_key;
@@ -61,10 +67,6 @@ static int sgv_max_local_pages, sgv_max_trans_pages;
static DEFINE_SPINLOCK(sgv_pools_lock); /* inner lock for sgv_pool_lock! */
static DEFINE_MUTEX(sgv_pools_mutex);
/* Both protected by sgv_pools_lock */
static struct sgv_pool *sgv_cur_purge_pool;
static LIST_HEAD(sgv_active_pools_list);
static atomic_t sgv_releases_on_hiwmk = ATOMIC_INIT(0);
static atomic_t sgv_releases_on_hiwmk_failed = ATOMIC_INIT(0);
@@ -97,24 +99,39 @@ static inline bool sgv_pool_clustered(const struct sgv_pool *pool)
void scst_sgv_pool_use_norm(struct scst_tgt_dev *tgt_dev)
{
int i;
tgt_dev->tgt_dev_gfp_mask = __GFP_NOWARN;
tgt_dev->pool = sgv_norm_pool;
for (i = 0; i < NR_CPUS; i++)
if (!scst_force_global_sgv_pool)
tgt_dev->pools[i] = sgv_norm_pool_per_cpu[i];
else
tgt_dev->pools[i] = sgv_norm_pool;
tgt_dev->tgt_dev_clust_pool = 0;
}
void scst_sgv_pool_use_norm_clust(struct scst_tgt_dev *tgt_dev)
{
int i;
TRACE_MEM("%s", "Use clustering");
tgt_dev->tgt_dev_gfp_mask = __GFP_NOWARN;
tgt_dev->pool = sgv_norm_clust_pool;
for (i = 0; i < NR_CPUS; i++)
if (!scst_force_global_sgv_pool)
tgt_dev->pools[i] = sgv_norm_clust_pool_per_cpu[i];
else
tgt_dev->pools[i] = sgv_norm_clust_pool;
tgt_dev->tgt_dev_clust_pool = 1;
}
void scst_sgv_pool_use_dma(struct scst_tgt_dev *tgt_dev)
{
int i;
TRACE_MEM("%s", "Use ISA DMA memory");
tgt_dev->tgt_dev_gfp_mask = __GFP_NOWARN | GFP_DMA;
tgt_dev->pool = sgv_dma_pool;
for (i = 0; i < NR_CPUS; i++)
if (!scst_force_global_sgv_pool)
tgt_dev->pools[i] = sgv_dma_pool_per_cpu[i];
else
tgt_dev->pools[i] = sgv_dma_pool;
tgt_dev->tgt_dev_clust_pool = 0;
}
@@ -143,49 +160,11 @@ static void sgv_dtor_and_free(struct sgv_pool_obj *obj)
return;
}
/* Might be called under sgv_pool_lock */
static inline void sgv_del_from_active(struct sgv_pool *pool)
{
struct list_head *next;
TRACE_MEM("Deleting sgv pool %p from the active list", pool);
spin_lock_bh(&sgv_pools_lock);
next = pool->sgv_active_pools_list_entry.next;
list_del(&pool->sgv_active_pools_list_entry);
if (sgv_cur_purge_pool == pool) {
TRACE_MEM("Sgv pool %p is sgv cur purge pool", pool);
if (next == &sgv_active_pools_list)
next = next->next;
if (next == &sgv_active_pools_list) {
sgv_cur_purge_pool = NULL;
TRACE_MEM("%s", "Sgv active list now empty");
} else {
sgv_cur_purge_pool = list_entry(next, typeof(*pool),
sgv_active_pools_list_entry);
TRACE_MEM("New sgv cur purge pool %p",
sgv_cur_purge_pool);
}
}
spin_unlock_bh(&sgv_pools_lock);
return;
}
/* Must be called under sgv_pool_lock held */
static void sgv_dec_cached_entries(struct sgv_pool *pool, int pages)
{
pool->cached_entries--;
pool->cached_pages -= pages;
if (pool->cached_entries == 0)
sgv_del_from_active(pool);
return;
}
/* Must be called under sgv_pool_lock held */
@@ -286,68 +265,28 @@ static int __sgv_shrink(int nr, int min_interval, int *out_freed)
{
struct sgv_pool *pool;
unsigned long cur_time = jiffies;
int prev_nr = nr;
bool circle = false;
int prev_nr = nr + 1;
TRACE_ENTRY();
TRACE_MEM("Trying to shrink %d pages from all sgv pools "
"(min_interval %d)", nr, min_interval);
while (nr > 0) {
struct list_head *next;
while (prev_nr > nr && nr > 0) {
prev_nr = nr;
spin_lock_bh(&sgv_pools_lock);
pool = sgv_cur_purge_pool;
if (pool == NULL) {
if (list_empty(&sgv_active_pools_list)) {
TRACE_MEM("%s", "Active pools list is empty");
goto out_unlock;
}
pool = list_first_entry(&sgv_active_pools_list,
typeof(*pool),
sgv_active_pools_list_entry);
}
sgv_pool_get(pool);
next = pool->sgv_active_pools_list_entry.next;
if (next == &sgv_active_pools_list) {
if (circle && (prev_nr == nr)) {
TRACE_MEM("Full circle done, but no progress, "
"leaving (nr %d)", nr);
goto out_unlock_put;
}
circle = true;
prev_nr = nr;
next = next->next;
}
sgv_cur_purge_pool = list_entry(next, typeof(*pool),
sgv_active_pools_list_entry);
TRACE_MEM("New cur purge pool %p", sgv_cur_purge_pool);
spin_unlock_bh(&sgv_pools_lock);
nr = sgv_shrink_pool(pool, nr, min_interval, cur_time, out_freed);
sgv_pool_put(pool);
mutex_lock(&sgv_pools_mutex);
list_for_each_entry(pool, &sgv_pools_list,
sgv_pools_list_entry) {
if (pool->cached_entries)
nr = sgv_shrink_pool(pool, nr, min_interval,
cur_time, out_freed);
}
mutex_unlock(&sgv_pools_mutex);
}
out:
TRACE_EXIT_RES(nr);
return nr;
out_unlock:
spin_unlock_bh(&sgv_pools_lock);
goto out;
out_unlock_put:
spin_unlock_bh(&sgv_pools_lock);
sgv_pool_put(pool);
goto out;
}
static unsigned long __sgv_can_be_shrunk(void)
@@ -359,8 +298,7 @@ static unsigned long __sgv_can_be_shrunk(void)
TRACE_ENTRY();
spin_lock_bh(&sgv_pools_lock);
list_for_each_entry(pool, &sgv_active_pools_list,
sgv_active_pools_list_entry) {
list_for_each_entry(pool, &sgv_pools_list, sgv_pools_list_entry) {
if (pool->purge_interval > 0)
inactive_pages += pool->inactive_cached_pages;
}
@@ -774,14 +712,6 @@ static struct sgv_pool_obj *sgv_get_obj(struct sgv_pool *pool, int cache_num,
}
get_new:
if (pool->cached_entries == 0) {
TRACE_MEM("Adding pool %p to the active list", pool);
spin_lock_bh(&sgv_pools_lock);
list_add_tail(&pool->sgv_active_pools_list_entry,
&sgv_active_pools_list);
spin_unlock_bh(&sgv_pools_lock);
}
pool->cached_entries++;
pool->cached_pages += pages;
@@ -1390,7 +1320,8 @@ void scst_free_sg(struct scatterlist *sg, int count)
EXPORT_SYMBOL_GPL(scst_free_sg);
/* Must be called under sgv_pools_mutex */
static void sgv_pool_init_cache(struct sgv_pool *pool, int cache_num)
static void sgv_pool_init_cache(struct sgv_pool *pool, int cache_num,
bool per_cpu)
{
int size;
int pages;
@@ -1423,14 +1354,15 @@ static void sgv_pool_init_cache(struct sgv_pool *pool, int cache_num)
/* both sgv and trans_tbl are kmalloc'ed() */
}
TRACE_MEM("pages=%d, size=%d", pages, size);
TRACE_MEM("pages=%d, size=%d (per cpu %d)", pages, size, per_cpu);
scnprintf(pool->cache_names[cache_num],
sizeof(pool->cache_names[cache_num]),
"%s-%uK", pool->name, (pages << PAGE_SHIFT) >> 10);
pool->caches[cache_num] = kmem_cache_create(
pool->cache_names[cache_num], size,
0, SCST_SLAB_FLAGS|SLAB_HWCACHE_ALIGN, NULL
0, per_cpu ? SCST_SLAB_FLAGS :
(SCST_SLAB_FLAGS|SLAB_HWCACHE_ALIGN), NULL
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23))
, NULL);
#else
@@ -1442,7 +1374,7 @@ static void sgv_pool_init_cache(struct sgv_pool *pool, int cache_num)
/* Must be called under sgv_pools_mutex */
static int sgv_pool_init(struct sgv_pool *pool, const char *name,
enum sgv_clustering_types clustering_type, int single_alloc_pages,
int purge_interval)
int purge_interval, bool per_cpu)
{
int res = -ENOMEM;
int i;
@@ -1495,7 +1427,7 @@ static int sgv_pool_init(struct sgv_pool *pool, const char *name,
pool->owner_mm = current->mm;
for (i = 0; i < pool->max_caches; i++) {
sgv_pool_init_cache(pool, i);
sgv_pool_init_cache(pool, i, per_cpu);
if (pool->caches[i] == NULL) {
PRINT_ERROR("Allocation of sgv_pool "
"cache %s(%d) failed", name, i);
@@ -1653,7 +1585,7 @@ void sgv_pool_set_allocator(struct sgv_pool *pool,
EXPORT_SYMBOL_GPL(sgv_pool_set_allocator);
/**
* sgv_pool_create - creates and initializes an SGV pool
* sgv_pool_create_node - creates and initializes an SGV pool
* @name: the name of the SGV pool
* @clustered: sets type of the pages clustering.
* @single_alloc_pages: if 0, then the SGV pool will work in the set of
@@ -1663,7 +1595,7 @@ EXPORT_SYMBOL_GPL(sgv_pool_set_allocator);
* @shared: sets if the SGV pool can be shared between devices or not.
* The cache sharing allowed only between devices created inside
* the same address space. If an SGV pool is shared, each
* subsequent call of sgv_pool_create() with the same cache name
* subsequent call of sgv_pool_create*() with the same cache name
* will not create a new cache, but instead return a reference
* to it.
* @purge_interval: sets the cache purging interval. I.e., an SG buffer
@@ -1671,20 +1603,27 @@ EXPORT_SYMBOL_GPL(sgv_pool_set_allocator);
* purge_interval <= t < 2*purge_interval. If purge_interval
* is 0, then the default interval will be used (60 seconds).
* If purge_interval <0, then the automatic purging will be
* disabled.
* disabled. In HZ.
* @nodeid: NUMA node for this pool. Can be NUMA_NO_NODE, if the
* caller doesn't care.
*
* Description:
* Returns the resulting SGV pool or NULL in case of any error.
*/
struct sgv_pool *sgv_pool_create(const char *name,
struct sgv_pool *sgv_pool_create_node(const char *name,
enum sgv_clustering_types clustering_type,
int single_alloc_pages, bool shared, int purge_interval)
int single_alloc_pages, bool shared, int purge_interval, int nodeid)
{
struct sgv_pool *pool;
int rc;
TRACE_ENTRY();
TRACE_MEM("Creating pool %s (clustering_type %d, "
"single_alloc_pages %d, shared %d, purge_interval %d, "
"nodeid %d)", name, clustering_type, single_alloc_pages,
shared, purge_interval, nodeid);
mutex_lock(&sgv_pools_mutex);
list_for_each_entry(pool, &sgv_pools_list, sgv_pools_list_entry) {
@@ -1706,15 +1645,16 @@ struct sgv_pool *sgv_pool_create(const char *name,
}
}
pool = kmem_cache_zalloc(sgv_pool_cachep, GFP_KERNEL);
pool = kmem_cache_alloc_node(sgv_pool_cachep, GFP_KERNEL, nodeid);
if (pool == NULL) {
PRINT_ERROR("Allocation of sgv_pool failed (size %zd)",
sizeof(*pool));
goto out_unlock;
}
memset(pool, 0, sizeof(*pool));
rc = sgv_pool_init(pool, name, clustering_type, single_alloc_pages,
purge_interval);
purge_interval, nodeid != NUMA_NO_NODE);
if (rc != 0)
goto out_free;
@@ -1729,7 +1669,7 @@ out_free:
pool = NULL;
goto out_unlock;
}
EXPORT_SYMBOL_GPL(sgv_pool_create);
EXPORT_SYMBOL_GPL(sgv_pool_create_node);
/**
* sgv_pool_get - increase ref counter for the corresponding SGV pool
@@ -1783,7 +1723,7 @@ EXPORT_SYMBOL_GPL(sgv_pool_del);
/* Both parameters in pages */
int scst_sgv_pools_init(unsigned long mem_hwmark, unsigned long mem_lwmark)
{
int res = 0;
int res = 0, i;
TRACE_ENTRY();
@@ -1810,6 +1750,44 @@ int scst_sgv_pools_init(unsigned long mem_hwmark, unsigned long mem_lwmark)
if (sgv_dma_pool == NULL)
goto out_free_clust;
/*
* ToDo: not compatible with CPU hotplug! Notification
* callbacks must be installed!
*/
for (i = 0; i < NR_CPUS; i++) {
char name[60];
if (!cpu_online(i))
continue;
scnprintf(name, sizeof(name), "sgv-%d", i);
sgv_norm_pool_per_cpu[i] = sgv_pool_create_node(name,
sgv_no_clustering, 0, false, 0, cpu_to_node(i));
if (sgv_norm_pool_per_cpu[i] == NULL)
goto out_free_per_cpu_norm;
}
for (i = 0; i < NR_CPUS; i++) {
char name[60];
if (!cpu_online(i))
continue;
scnprintf(name, sizeof(name), "sgv-clust-%d", i);
sgv_norm_clust_pool_per_cpu[i] = sgv_pool_create_node(name,
sgv_full_clustering, 0, false, 0, cpu_to_node(i));
if (sgv_norm_clust_pool_per_cpu[i] == NULL)
goto out_free_per_cpu_clust;
}
for (i = 0; i < NR_CPUS; i++) {
char name[60];
if (!cpu_online(i))
continue;
scnprintf(name, sizeof(name), "sgv-dma-%d", i);
sgv_dma_pool_per_cpu[i] = sgv_pool_create_node(name,
sgv_no_clustering, 0, false, 0, cpu_to_node(i));
if (sgv_dma_pool_per_cpu[i] == NULL)
goto out_free_per_cpu_dma;
}
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23))
sgv_shrinker = set_shrinker(DEFAULT_SEEKS, sgv_shrink);
#else
@@ -1827,6 +1805,23 @@ out:
TRACE_EXIT_RES(res);
return res;
out_free_per_cpu_dma:
for (i = 0; i < NR_CPUS; i++)
if (sgv_dma_pool_per_cpu[i] != NULL)
sgv_pool_destroy(sgv_dma_pool_per_cpu[i]);
out_free_per_cpu_clust:
for (i = 0; i < NR_CPUS; i++)
if (sgv_norm_clust_pool_per_cpu[i] != NULL)
sgv_pool_destroy(sgv_norm_clust_pool_per_cpu[i]);
out_free_per_cpu_norm:
for (i = 0; i < NR_CPUS; i++)
if (sgv_norm_pool_per_cpu[i] != NULL)
sgv_pool_destroy(sgv_norm_pool_per_cpu[i]);
sgv_pool_destroy(sgv_dma_pool);
out_free_clust:
sgv_pool_destroy(sgv_norm_clust_pool);
@@ -1843,6 +1838,8 @@ out_err:
void scst_sgv_pools_deinit(void)
{
int i;
TRACE_ENTRY();
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23))
@@ -1852,8 +1849,19 @@ void scst_sgv_pools_deinit(void)
#endif
sgv_pool_destroy(sgv_dma_pool);
for (i = 0; i < NR_CPUS; i++)
if (sgv_dma_pool_per_cpu[i] != NULL)
sgv_pool_destroy(sgv_dma_pool_per_cpu[i]);
sgv_pool_destroy(sgv_norm_pool);
for (i = 0; i < NR_CPUS; i++)
if (sgv_norm_pool_per_cpu[i] != NULL)
sgv_pool_destroy(sgv_norm_pool_per_cpu[i]);
sgv_pool_destroy(sgv_norm_clust_pool);
for (i = 0; i < NR_CPUS; i++)
if (sgv_norm_clust_pool_per_cpu[i] != NULL)
sgv_pool_destroy(sgv_norm_clust_pool_per_cpu[i]);
kmem_cache_destroy(sgv_pool_cachep);
@@ -1925,8 +1933,7 @@ int sgv_procinfo_show(struct seq_file *seq, void *v)
TRACE_ENTRY();
spin_lock_bh(&sgv_pools_lock);
list_for_each_entry(pool, &sgv_active_pools_list,
sgv_active_pools_list_entry) {
list_for_each_entry(pool, &sgv_pools_list, sgv_pools_list_entry) {
inactive_pages += pool->inactive_cached_pages;
}
spin_unlock_bh(&sgv_pools_lock);
@@ -2051,8 +2058,7 @@ static ssize_t sgv_sysfs_global_stat_show(struct kobject *kobj,
TRACE_ENTRY();
spin_lock_bh(&sgv_pools_lock);
list_for_each_entry(pool, &sgv_active_pools_list,
sgv_active_pools_list_entry) {
list_for_each_entry(pool, &sgv_pools_list, sgv_pools_list_entry) {
inactive_pages += pool->inactive_cached_pages;
}
spin_unlock_bh(&sgv_pools_lock);
+2 -2
View File
@@ -114,8 +114,6 @@ struct sgv_pool {
struct work_struct sgv_purge_work;
#endif
struct list_head sgv_active_pools_list_entry;
atomic_t big_alloc, big_pages, big_merged;
atomic_t other_alloc, other_pages, other_merged;
@@ -137,6 +135,8 @@ struct sgv_pool {
struct completion *sgv_kobj_release_cmpl;
};
extern bool scst_force_global_sgv_pool;
static inline struct scatterlist *sgv_pool_sg(struct sgv_pool_obj *obj)
{
return obj->sg_entries;
+9 -4
View File
@@ -98,7 +98,9 @@ extern unsigned long scst_trace_flag;
/**
** Maximum count of uncompleted commands that an initiator could
** queue on any device. Then it will start getting TASK QUEUE FULL status.
** queue on any device by default, i.e. its dev handler doesn't have
** max_tgt_dev_commands defined. Then it will start getting TASK QUEUE FULL
** status.
**/
#define SCST_MAX_TGT_DEV_COMMANDS 64
@@ -352,7 +354,7 @@ void scst_queue_retry_cmd(struct scst_cmd *cmd);
int scst_alloc_tgt(struct scst_tgt_template *tgtt, struct scst_tgt **tgt);
void scst_free_tgt(struct scst_tgt *tgt);
int scst_alloc_device(gfp_t gfp_mask, struct scst_device **out_dev);
int scst_alloc_device(gfp_t gfp_mask, int nodeid, struct scst_device **out_dev);
void scst_free_device(struct scst_device *dev);
bool scst_device_is_exported(struct scst_device *dev);
@@ -713,6 +715,7 @@ void scst_process_reset(struct scst_device *dev,
void scst_unblock_aborted_cmds(const struct scst_tgt *tgt,
const struct scst_session *sess, const struct scst_device *device,
bool scst_mutex_held);
void scst_clear_aca(struct scst_tgt_dev *tgt_dev, bool other_ini);
bool scst_is_ua_global(const uint8_t *sense, int len);
void scst_requeue_ua(struct scst_cmd *cmd, const uint8_t *buf, int size);
@@ -1030,7 +1033,8 @@ void scst_trace_mcmds(scst_show_fn show, void *arg);
void scst_set_start_time(struct scst_cmd *cmd);
void scst_set_cur_start(struct scst_cmd *cmd);
void scst_set_parse_time(struct scst_cmd *cmd);
void scst_set_alloc_buf_time(struct scst_cmd *cmd);
void scst_set_dev_alloc_buf_time(struct scst_cmd *cmd);
void scst_set_tgt_alloc_buf_time(struct scst_cmd *cmd);
void scst_set_restart_waiting_time(struct scst_cmd *cmd);
void scst_set_rdy_to_xfer_time(struct scst_cmd *cmd);
void scst_set_pre_exec_time(struct scst_cmd *cmd);
@@ -1045,7 +1049,8 @@ void scst_update_lat_stats(struct scst_cmd *cmd);
static inline void scst_set_start_time(struct scst_cmd *cmd) {}
static inline void scst_set_cur_start(struct scst_cmd *cmd) {}
static inline void scst_set_parse_time(struct scst_cmd *cmd) {}
static inline void scst_set_alloc_buf_time(struct scst_cmd *cmd) {}
static inline void scst_set_dev_alloc_buf_time(struct scst_cmd *cmd) {}
static inline void scst_set_tgt_alloc_buf_time(struct scst_cmd *cmd) {}
static inline void scst_set_restart_waiting_time(struct scst_cmd *cmd) {}
static inline void scst_set_rdy_to_xfer_time(struct scst_cmd *cmd) {}
static inline void scst_set_pre_exec_time(struct scst_cmd *cmd) {}
+194 -6
View File
@@ -32,6 +32,7 @@
#endif
#include "scst_priv.h"
#include "scst_pres.h"
#include "scst_mem.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
#ifdef CONFIG_LOCKDEP
@@ -3075,8 +3076,6 @@ static ssize_t scst_dev_sysfs_pr_file_name_show(struct kobject *kobj,
res = mutex_lock_interruptible(&dev->dev_pr_mutex);
if (res != 0)
goto out;
/* pr_file_name is NULL for SCSI pass-through devices */
WARN_ON_ONCE(!dev->pr_file_name);
res = scnprintf(buf, PAGE_SIZE, "%s\n%s", dev->pr_file_name ? : "",
dev->pr_file_name_is_set ? SCST_SYSFS_KEY_MARK "\n" :
"");
@@ -3473,6 +3472,132 @@ static struct kobj_attribute dev_threads_pool_type_attr =
scst_dev_sysfs_threads_pool_type_show,
scst_dev_sysfs_threads_pool_type_store);
static ssize_t scst_dev_sysfs_max_tgt_dev_commands_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
int pos = 0;
struct scst_device *dev;
TRACE_ENTRY();
dev = container_of(kobj, struct scst_device, dev_kobj);
pos = sprintf(buf, "%d\n%s", dev->max_tgt_dev_commands,
(dev->max_tgt_dev_commands != dev->handler->max_tgt_dev_commands) ?
SCST_SYSFS_KEY_MARK "\n" : "");
TRACE_EXIT_RES(pos);
return pos;
}
static ssize_t scst_dev_sysfs_max_tgt_dev_commands_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
int res;
struct scst_device *dev;
long newtn;
TRACE_ENTRY();
dev = container_of(kobj, struct scst_device, dev_kobj);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
res = kstrtol(buf, 0, &newtn);
#else
res = strict_strtol(buf, 0, &newtn);
#endif
if (res != 0) {
PRINT_ERROR("strtol() for %s failed: %d ", buf, res);
goto out;
}
if (newtn < 0) {
PRINT_ERROR("Illegal max tgt dev value %ld", newtn);
res = -EINVAL;
goto out;
}
if (dev->max_tgt_dev_commands != newtn) {
PRINT_INFO("Setting new queue depth %ld for device %s (old %d)",
newtn, dev->virt_name, dev->max_tgt_dev_commands);
dev->max_tgt_dev_commands = newtn;
}
out:
if (res == 0)
res = count;
TRACE_EXIT_RES(res);
return res;
}
static struct kobj_attribute dev_max_tgt_dev_commands_attr =
__ATTR(max_tgt_dev_commands, S_IRUGO | S_IWUSR,
scst_dev_sysfs_max_tgt_dev_commands_show,
scst_dev_sysfs_max_tgt_dev_commands_store);
static ssize_t scst_dev_numa_node_id_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
int pos = 0;
struct scst_device *dev;
TRACE_ENTRY();
dev = container_of(kobj, struct scst_device, dev_kobj);
pos = sprintf(buf, "%d\n%s", dev->dev_numa_node_id,
(dev->dev_numa_node_id != NUMA_NO_NODE) ?
SCST_SYSFS_KEY_MARK "\n" : "");
TRACE_EXIT_RES(pos);
return pos;
}
static ssize_t scst_dev_numa_node_id_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
int res;
struct scst_device *dev;
long newtn;
TRACE_ENTRY();
dev = container_of(kobj, struct scst_device, dev_kobj);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
res = kstrtol(buf, 0, &newtn);
#else
res = strict_strtol(buf, 0, &newtn);
#endif
if (res != 0) {
PRINT_ERROR("strtol() for %s failed: %d ", buf, res);
goto out;
}
BUILD_BUG_ON(NUMA_NO_NODE != -1);
if (newtn < NUMA_NO_NODE) {
PRINT_ERROR("Illegal numa_node_id value %ld", newtn);
res = -EINVAL;
goto out;
}
if (dev->dev_numa_node_id != newtn) {
PRINT_INFO("Setting new NUMA node id %ld for device %s (old %d)",
newtn, dev->virt_name, dev->dev_numa_node_id);
dev->dev_numa_node_id = newtn;
}
out:
if (res == 0)
res = count;
TRACE_EXIT_RES(res);
return res;
}
static struct kobj_attribute dev_numa_node_id_attr =
__ATTR(numa_node_id, S_IRUGO | S_IWUSR, scst_dev_numa_node_id_show,
scst_dev_numa_node_id_store);
static ssize_t scst_dev_block_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
@@ -3603,6 +3728,8 @@ static struct kobj_attribute dev_block_attr =
static struct attribute *scst_dev_attrs[] = {
&dev_type_attr.attr,
&dev_max_tgt_dev_commands_attr.attr,
&dev_numa_node_id_attr.attr,
&dev_block_attr.attr,
NULL,
};
@@ -3770,7 +3897,9 @@ int scst_dev_sysfs_create(struct scst_device *dev)
dev->virt_name);
goto out_del;
}
} else {
}
if (dev->pr_file_name != NULL) {
res = sysfs_create_file(&dev->dev_kobj,
&dev_pr_file_name_attr.attr);
if (res != 0) {
@@ -3779,10 +3908,8 @@ int scst_dev_sysfs_create(struct scst_device *dev)
dev->virt_name);
goto out_del;
}
}
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
if (dev->scsi_dev == NULL) {
res = sysfs_create_file(&dev->dev_kobj,
&dev_dump_prs_attr.attr);
if (res != 0) {
@@ -3790,8 +3917,8 @@ int scst_dev_sysfs_create(struct scst_device *dev)
dev_dump_prs_attr.attr.name, dev->virt_name);
goto out_del;
}
}
#endif
}
out:
TRACE_EXIT_RES(res);
@@ -3985,6 +4112,19 @@ out:
** Tgt_dev implementation
**/
static ssize_t scst_tgt_dev_thread_index_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buffer)
{
struct scst_tgt_dev *tgt_dev =
container_of(kobj, struct scst_tgt_dev, tgt_dev_kobj);
return sprintf(buffer, "%d\n", tgt_dev->thread_index);
}
static struct kobj_attribute tgt_dev_thread_idx_attr =
__ATTR(thread_index, S_IRUGO, scst_tgt_dev_thread_index_show, NULL);
#ifdef CONFIG_SCST_MEASURE_LATENCY
static char *scst_io_size_names[] = {
@@ -4191,6 +4331,7 @@ static struct kobj_attribute tgt_dev_dif_checks_failed_attr =
scst_tgt_dev_dif_checks_failed_store);
static struct attribute *scst_tgt_dev_attrs[] = {
&tgt_dev_thread_idx_attr.attr,
&tgt_dev_thread_pid_attr.attr,
&tgt_dev_active_commands_attr.attr,
#ifdef CONFIG_SCST_MEASURE_LATENCY
@@ -5563,6 +5704,16 @@ int scst_acg_sysfs_create(struct scst_tgt *tgt,
goto out_del;
}
if (acg->tgt->tgtt->acg_attrs) {
res = sysfs_create_files(&acg->acg_kobj,
acg->tgt->tgtt->acg_attrs);
if (res != 0) {
PRINT_ERROR("Can't add attributes for acg %s",
acg->acg_name);
goto out_del;
}
}
out:
TRACE_EXIT_RES(res);
return res;
@@ -7195,6 +7346,42 @@ static struct kobj_attribute scst_main_trace_level_attr =
#endif /* defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) */
static ssize_t scst_force_global_sgv_pool_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n%s\n", scst_force_global_sgv_pool,
scst_force_global_sgv_pool ? SCST_SYSFS_KEY_MARK "\n": "");
}
static ssize_t scst_force_global_sgv_pool_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
int res;
unsigned long v;
TRACE_ENTRY();
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
res = kstrtoul(buf, 0, &v);
#else
res = strict_strtoul(buf, 0, &v);
#endif
if (res)
goto out;
scst_force_global_sgv_pool = v;
res = count;
out:
TRACE_EXIT_RES(res);
return res;
}
static struct kobj_attribute scst_force_global_sgv_pool_attr =
__ATTR(force_global_sgv_pool, S_IRUGO | S_IWUSR,
scst_force_global_sgv_pool_show, scst_force_global_sgv_pool_store);
static void __printf(2, 3) scst_append(void *arg, const char *fmt, ...)
{
char *buf = arg;
@@ -7391,6 +7578,7 @@ static struct attribute *scst_sysfs_root_default_attrs[] = {
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
&scst_main_trace_level_attr.attr,
#endif
&scst_force_global_sgv_pool_attr.attr,
&scst_trace_cmds_attr.attr,
&scst_trace_mcmds_attr.attr,
&scst_version_attr.attr,
+376 -71
View File
@@ -60,17 +60,17 @@ void scst_post_parse(struct scst_cmd *cmd)
EXPORT_SYMBOL_GPL(scst_post_parse);
/**
* scst_post_alloc_data_buf() - do post dev_alloc_data_buf actions
* scst_post_dev_alloc_data_buf() - do post dev_alloc_data_buf actions
*
* This function must be called by dev handler after its dev_alloc_data_buf()
* callback returned SCST_CMD_STATE_STOP before calling
* scst_process_active_cmd().
*/
void scst_post_alloc_data_buf(struct scst_cmd *cmd)
void scst_post_dev_alloc_data_buf(struct scst_cmd *cmd)
{
scst_set_alloc_buf_time(cmd);
scst_set_dev_alloc_buf_time(cmd);
}
EXPORT_SYMBOL_GPL(scst_post_alloc_data_buf);
EXPORT_SYMBOL_GPL(scst_post_dev_alloc_data_buf);
static inline void scst_schedule_tasklet(struct scst_cmd *cmd)
{
@@ -877,7 +877,7 @@ void scst_cmd_init_done(struct scst_cmd *cmd,
spin_unlock_irqrestore(&sess->sess_list_lock, flags);
if (unlikely(cmd->queue_type >= SCST_CMD_QUEUE_ACA)) {
if (unlikely(cmd->queue_type > SCST_CMD_QUEUE_ACA)) {
PRINT_ERROR("Unsupported queue type %d", cmd->queue_type);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_invalid_message));
@@ -976,7 +976,7 @@ int scst_pre_parse(struct scst_cmd *cmd)
#ifdef CONFIG_SCST_STRICT_SERIALIZING
cmd->inc_expected_sn_on_done = 1;
#else
cmd->inc_expected_sn_on_done = devt->exec_sync ||
cmd->inc_expected_sn_on_done = devt->exec_sync || cmd->cmd_naca ||
(!dev->has_own_order_mgmt &&
(dev->queue_alg == SCST_QUEUE_ALG_0_RESTRICTED_REORDER ||
cmd->queue_type == SCST_CMD_QUEUE_ORDERED));
@@ -1162,14 +1162,6 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
cmd->op_flags &= ~SCST_UNKNOWN_LENGTH;
}
if (unlikely(cmd->cmd_naca)) {
PRINT_ERROR("NACA bit in control byte CDB is not supported "
"(opcode 0x%02x)", cmd->cdb[0]);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_invalid_message));
goto out_done;
}
if (unlikely(cmd->cmd_linked)) {
PRINT_ERROR("Linked commands are not supported "
"(opcode %s)", scst_get_opcode_name(cmd));
@@ -1523,7 +1515,7 @@ static int scst_prepare_space(struct scst_cmd *cmd)
switch (state) {
case SCST_CMD_STATE_NEED_THREAD_CTX:
scst_set_alloc_buf_time(cmd);
scst_set_dev_alloc_buf_time(cmd);
TRACE_DBG("Dev handler %s dev_alloc_data_buf() requested "
"thread context, rescheduling", devt->name);
res = SCST_CMD_STATE_RES_NEED_THREAD;
@@ -1537,7 +1529,7 @@ static int scst_prepare_space(struct scst_cmd *cmd)
goto out;
}
scst_set_alloc_buf_time(cmd);
scst_set_dev_alloc_buf_time(cmd);
if (unlikely(state != SCST_CMD_STATE_DEFAULT)) {
cmd->state = state;
@@ -1553,7 +1545,7 @@ static int scst_prepare_space(struct scst_cmd *cmd)
scst_set_cur_start(cmd);
r = cmd->tgtt->tgt_alloc_data_buf(cmd);
scst_set_alloc_buf_time(cmd);
scst_set_tgt_alloc_buf_time(cmd);
if (r > 0)
goto alloc;
@@ -2543,7 +2535,7 @@ static int scst_report_supported_tm_fns(struct scst_cmd *cmd)
memset(buf, 0, sizeof(buf));
buf[0] = 0xD8; /* ATS, ATSS, CTSS, LURS */
buf[0] = 0xF8; /* ATS, ATSS, CACAS, CTSS, LURS */
buf[1] = 0;
if ((cmd->cdb[2] & 0x80) == 0)
resp_len = 4;
@@ -2551,7 +2543,7 @@ static int scst_report_supported_tm_fns(struct scst_cmd *cmd)
buf[3] = 0x0C;
#if 1
buf[4] = 1; /* TMFTMOV */
buf[6] = 0x80; /* ATTS */
buf[6] = 0xA0; /* ATTS, CACATS */
put_unaligned_be32(300, &buf[8]); /* long timeout - 30 sec. */
put_unaligned_be32(150, &buf[12]); /* short timeout - 15 sec. */
#endif
@@ -3219,8 +3211,7 @@ int __scst_check_local_events(struct scst_cmd *cmd, bool preempt_tests_only)
* All the checks are supposed to be done on the
* forwarding requester's side.
*/
res = 0;
goto out;
goto skip_reserve;
}
/*
@@ -3253,6 +3244,7 @@ int __scst_check_local_events(struct scst_cmd *cmd, bool preempt_tests_only)
* Let's check for ABORTED after scst_pr_is_cmd_allowed(), because
* we might sleep for a while there.
*/
skip_reserve:
if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) {
TRACE_MGMT_DBG("ABORTED set, aborting cmd %p", cmd);
goto out_uncomplete;
@@ -3760,6 +3752,7 @@ done:
break;
EXTRACHECKS_BUG_ON(cmd->state != SCST_CMD_STATE_EXEC_CHECK_SN);
EXTRACHECKS_BUG_ON(cmd->done);
cmd->state = SCST_CMD_STATE_EXEC_CHECK_BLOCKING;
@@ -3801,9 +3794,79 @@ static int scst_exec_check_sn(struct scst_cmd **active_cmd)
if (unlikely(cmd->internal))
goto exec;
if (unlikely(order_data->aca_tgt_dev != 0)) {
if (!cmd->cmd_aca_allowed) {
spin_lock_irq(&order_data->sn_lock);
if (test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)) {
/*
* cmd can be aborted and the unblock
* procedure finished while we were
* entering here. I.e. cmd can not be ACA
* blocked/deferred anymore for any case,
* hence let it pass through.
*/
} else if (order_data->aca_tgt_dev != 0) {
unsigned int qerr, q;
bool this_nex = ((unsigned long)cmd->tgt_dev == order_data->aca_tgt_dev);
/*
* Commands can potentially "leak" from
* scst_process_check_condition() after
* establishing ACA due to separate locks, so
* let's catch such "leaked" commands here.
* In any case, if QErr requests them to be
* aborted, they must not be deferred/blocked.
*/
/* dev->qerr can be changed behind our back */
q = cmd->dev->qerr;
/* ACCESS_ONCE doesn't work for bit fields */
qerr = ACCESS_ONCE(q);
switch (qerr) {
case SCST_QERR_2_RESERVED:
default:
case SCST_QERR_0_ALL_RESUME:
defer:
TRACE_MGMT_DBG("Deferring cmd %p due to "
"ACA active (tgt_dev %p)", cmd,
cmd->tgt_dev);
order_data->def_cmd_count++;
list_add_tail(&cmd->deferred_cmd_list_entry,
&order_data->deferred_cmd_list);
spin_unlock_irq(&order_data->sn_lock);
res = SCST_CMD_STATE_RES_CONT_NEXT;
goto out;
case SCST_QERR_3_ABORT_THIS_NEXUS_ONLY:
if (!this_nex)
goto defer;
/* else go through */
case SCST_QERR_1_ABORT_ALL:
TRACE_MGMT_DBG("Aborting cmd %p due to "
"ACA active (tgt_dev %p)", cmd,
cmd->tgt_dev);
scst_abort_cmd(cmd, NULL, !this_nex, 0);
scst_set_cmd_abnormal_done_state(cmd);
res = SCST_CMD_STATE_RES_CONT_SAME;
spin_unlock_irq(&order_data->sn_lock);
goto out;
}
}
spin_unlock_irq(&order_data->sn_lock);
} else
goto exec;
}
if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE))
goto exec;
/* Must check here to catch ACA cmds after just cleared ACA */
if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) {
scst_set_cmd_abnormal_done_state(cmd);
res = SCST_CMD_STATE_RES_CONT_SAME;
goto out;
}
EXTRACHECKS_BUG_ON(!cmd->sn_set);
expected_sn = READ_ONCE(order_data->expected_sn);
@@ -4100,44 +4163,6 @@ next:
scst_put_buf_full(cmd, address);
}
/*
* Check and clear NormACA option for the device, if necessary,
* since we don't support ACA
*/
if (unlikely((cmd->cdb[0] == INQUIRY)) &&
/* Std INQUIRY data (no EVPD) */
!(cmd->cdb[1] & SCST_INQ_EVPD) &&
(cmd->resp_data_len > SCST_INQ_BYTE3)) {
uint8_t *buffer;
int buflen;
bool err = false;
buflen = scst_get_buf_full(cmd, &buffer);
if (buflen > SCST_INQ_BYTE3 && !cmd->tgtt->fake_aca) {
#ifdef CONFIG_SCST_EXTRACHECKS
if (buffer[SCST_INQ_BYTE3] & SCST_INQ_NORMACA_BIT) {
PRINT_INFO("NormACA set for device: "
"lun=%lld, type 0x%02x. Clear it, "
"since it's unsupported.",
(unsigned long long int)cmd->lun,
buffer[0]);
}
#endif
buffer[SCST_INQ_BYTE3] &= ~SCST_INQ_NORMACA_BIT;
} else if (buflen <= SCST_INQ_BYTE3 && buflen != 0) {
PRINT_ERROR("%s", "Unable to get INQUIRY "
"buffer");
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_internal_failure));
err = true;
}
if (buflen > 0)
scst_put_buf_full(cmd, buffer);
if (err)
goto out;
}
if (unlikely((cmd->cdb[0] == MODE_SELECT) ||
(cmd->cdb[0] == MODE_SELECT_10) ||
(cmd->cdb[0] == LOG_SELECT))) {
@@ -4393,6 +4418,50 @@ again:
} else if (rc == 1)
goto again;
}
} else if (likely(cmd->tgt_dev != NULL)) {
struct scst_order_data *order_data = cmd->cur_order_data;
if (unlikely(order_data->aca_tgt_dev != 0)) {
if (!cmd->cmd_aca_allowed) {
spin_lock_irq(&order_data->sn_lock);
if (test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)) {
/*
* cmd can be aborted and the unblock
* procedure finished while we were
* entering here. I.e. cmd can not be
* blocked anymore for any case.
*/
spin_unlock_irq(&order_data->sn_lock);
goto again;
}
if (order_data->aca_tgt_dev != 0) {
TRACE_MGMT_DBG("Deferring done cmd %p due "
"to ACA active (tgt_dev %p)",
cmd, cmd->tgt_dev);
order_data->def_cmd_count++;
/*
* Put cmd in the head to let restart
* earlier, because it's already completed
*/
list_add(&cmd->deferred_cmd_list_entry,
&order_data->deferred_cmd_list);
spin_unlock_irq(&order_data->sn_lock);
res = SCST_CMD_STATE_RES_CONT_NEXT;
goto out;
}
spin_unlock_irq(&order_data->sn_lock);
}
}
}
if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_ACA) &&
(cmd->tgt_dev != NULL)) {
struct scst_order_data *order_data = cmd->cur_order_data;
spin_lock_irq(&order_data->sn_lock);
if (order_data->aca_cmd == cmd) {
TRACE_MGMT_DBG("ACA cmd %p finished", cmd);
order_data->aca_cmd = NULL;
}
spin_unlock_irq(&order_data->sn_lock);
}
if (unlikely(test_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags))) {
@@ -4873,6 +4942,10 @@ ordered:
cmd->hq_cmd_inced = 1;
goto out;
case SCST_CMD_QUEUE_ACA:
/* Nothing to do */
goto out;
default:
sBUG();
}
@@ -4989,6 +5062,8 @@ static int scst_translate_lun(struct scst_cmd *cmd)
static int __scst_init_cmd(struct scst_cmd *cmd)
{
int res = 0;
unsigned long flags;
struct scst_order_data *order_data;
TRACE_ENTRY();
@@ -4997,10 +5072,12 @@ static int __scst_init_cmd(struct scst_cmd *cmd)
int cnt;
bool failure = false;
order_data = cmd->cur_order_data;
cmd->state = SCST_CMD_STATE_PARSE;
cnt = atomic_inc_return(&cmd->tgt_dev->tgt_dev_cmd_count);
if (unlikely(cnt > SCST_MAX_TGT_DEV_COMMANDS)) {
if (unlikely(cnt > cmd->dev->max_tgt_dev_commands)) {
TRACE(TRACE_FLOW_CONTROL,
"Too many pending commands (%d) in "
"session, returning BUSY to initiator \"%s\"",
@@ -5025,8 +5102,13 @@ static int __scst_init_cmd(struct scst_cmd *cmd)
}
#endif
if (unlikely(failure))
goto out_busy;
if (unlikely(failure)) {
/*
* Better to delivery BUSY ASAP, than to delay
* it due to ACA
*/
goto out_busy_bypass_aca;
}
/*
* SCST_IMPLICIT_HQ for unknown commands not implemented for
@@ -5037,6 +5119,73 @@ static int __scst_init_cmd(struct scst_cmd *cmd)
* queue_type to change it if needed. ToDo.
*/
scst_pre_parse(cmd);
again:
if (unlikely(order_data->aca_tgt_dev != 0)) {
spin_lock_irqsave(&order_data->sn_lock, flags);
if (order_data->aca_tgt_dev == 0) {
spin_unlock_irqrestore(&order_data->sn_lock, flags);
goto again;
}
if (order_data->aca_tgt_dev == (unsigned long)cmd->tgt_dev) {
if ((cmd->queue_type != SCST_CMD_QUEUE_ACA) ||
(order_data->aca_cmd != NULL) ||
cmd->dev->tmf_only) {
TRACE_DBG("Refusing cmd %p, because ACA "
"active (aca_cmd %p, tgt_dev %p)",
cmd, order_data->aca_cmd,
cmd->tgt_dev);
goto out_unlock_aca_active;
} else {
TRACE_MGMT_DBG("ACA cmd %p (tgt_dev %p)",
cmd, cmd->tgt_dev);
order_data->aca_cmd = cmd;
/* allow it */
}
} else {
/* Non-faulted I_T nexus */
EXTRACHECKS_BUG_ON(cmd->dev->tst != SCST_TST_0_SINGLE_TASK_SET);
if (cmd->queue_type == SCST_CMD_QUEUE_ACA) {
TRACE_MGMT_DBG("Refusing ACA cmd %p "
"from wrong I_T nexus (aca_tgt_dev %ld, "
"cmd->tgt_dev %p)", cmd,
order_data->aca_tgt_dev, cmd->tgt_dev);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_invalid_message));
goto out_unlock_aca_active;
} else {
if ((cmd->cdb[0] == PERSISTENT_RESERVE_OUT) &&
((cmd->cdb[1] & 0x1f) == PR_PREEMPT_AND_ABORT)) {
TRACE_MGMT_DBG("Allow PR PREEMPT AND "
"ABORT cmd %p during ACA "
"(tgt_dev %p)", cmd, cmd->tgt_dev);
/* allow it */
} else {
TRACE_DBG("Refusing other IT-nexus "
"cmd %p, because ACA active "
"(tgt_dev %p)", cmd, cmd->tgt_dev);
if (cmd->cmd_naca)
goto out_unlock_aca_active;
else {
spin_unlock_irqrestore(&order_data->sn_lock, flags);
scst_set_cmd_error_status(cmd, SAM_STAT_BUSY);
goto out_bypass_aca;
}
}
}
}
cmd->cmd_aca_allowed = 1;
spin_unlock_irqrestore(&order_data->sn_lock, flags);
} else if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_ACA)) {
TRACE_MGMT_DBG("Refusing ACA cmd %p, because there's no ACA, "
"tgt_dev %p", cmd, cmd->tgt_dev);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_invalid_message));
goto out_abnormal;
}
if (!cmd->set_sn_on_restart_cmd) {
if (!cmd->tgtt->multithreaded_init_done)
@@ -5052,20 +5201,28 @@ static int __scst_init_cmd(struct scst_cmd *cmd)
}
} else if (res < 0) {
TRACE_DBG("Finishing cmd %p", cmd);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_lun_not_supported));
scst_set_cmd_abnormal_done_state(cmd);
} else
goto out;
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_lun_not_supported));
goto out_abnormal;
} /* else goto out; */
out:
TRACE_EXIT_RES(res);
return res;
out_busy:
out_busy_bypass_aca:
scst_set_busy(cmd);
out_bypass_aca:
cmd->cmd_aca_allowed = 1; /* for check in scst_pre_xmit_response2() */
out_abnormal:
scst_set_cmd_abnormal_done_state(cmd);
goto out;
out_unlock_aca_active:
spin_unlock_irqrestore(&order_data->sn_lock, flags);
scst_set_cmd_error_status(cmd, SAM_STAT_ACA_ACTIVE);
goto out_bypass_aca;
}
/* Called under scst_init_lock and IRQs disabled */
@@ -6376,8 +6533,25 @@ static int scst_abort_task_set(struct scst_mgmt_cmd *mcmd)
__scst_abort_task_set(mcmd, tgt_dev);
if (mcmd->fn == SCST_PR_ABORT_ALL) {
struct scst_cmd *orig_pr_cmd = mcmd->origin_pr_cmd;
struct scst_pr_abort_all_pending_mgmt_cmds_counter *pr_cnt =
mcmd->origin_pr_cmd->pr_abort_counter;
orig_pr_cmd->pr_abort_counter;
if (tgt_dev->curr_order_data->aca_tgt_dev == (unsigned long)mcmd->mcmd_tgt_dev) {
/* PR cmd is clearing the commands received on the faulted I_T nexus */
if (orig_pr_cmd->cur_order_data->aca_tgt_dev == (unsigned long)orig_pr_cmd->tgt_dev) {
/* PR cmd received on the faulted I_T nexus */
if (orig_pr_cmd->queue_type == SCST_CMD_QUEUE_ACA)
scst_clear_aca(tgt_dev,
(tgt_dev != orig_pr_cmd->tgt_dev));
} else {
/* PR cmd received on a non-faulted I_T nexus */
if (orig_pr_cmd->queue_type != SCST_CMD_QUEUE_ACA)
scst_clear_aca(tgt_dev,
(tgt_dev != orig_pr_cmd->tgt_dev));
}
}
if (atomic_dec_and_test(&pr_cnt->pr_aborting_cnt))
complete_all(&pr_cnt->pr_aborting_cmpl);
}
@@ -6842,6 +7016,16 @@ static int scst_abort_all_nexus_loss_sess(struct scst_mgmt_cmd *mcmd,
"ABORT ALL SESS or UNREG SESS",
(mcmd->fn == SCST_UNREG_SESS_TM));
}
if (nexus_loss_unreg_sess) {
/*
* We need at first abort all affected commands and
* only then release them as part of clearing ACA
*/
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
scst_clear_aca(tgt_dev,
(tgt_dev != mcmd->mcmd_tgt_dev));
}
}
}
rcu_read_unlock();
@@ -6916,6 +7100,16 @@ static int scst_abort_all_nexus_loss_tgt(struct scst_mgmt_cmd *mcmd,
tm_dbg_task_mgmt(tgt_dev->dev, "NEXUS LOSS or "
"ABORT ALL", 0);
}
if (nexus_loss) {
/*
* We need at first abort all affected commands and
* only then release them as part of clearing ACA
*/
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
scst_clear_aca(tgt_dev,
(tgt_dev != mcmd->mcmd_tgt_dev));
}
}
}
}
rcu_read_unlock();
@@ -6973,6 +7167,118 @@ static int scst_abort_task(struct scst_mgmt_cmd *mcmd)
return res;
}
/* sn_lock supposed to be held and IRQs off */
static void __scst_clear_aca(struct scst_tgt_dev *tgt_dev,
struct scst_mgmt_cmd *mcmd, bool other_ini)
{
struct scst_order_data *order_data = tgt_dev->curr_order_data;
struct scst_cmd *aca_cmd;
TRACE_ENTRY();
TRACE_MGMT_DBG("Clearing ACA for tgt_dev %p (lun %lld)",
tgt_dev, (unsigned long long)tgt_dev->lun);
aca_cmd = order_data->aca_cmd;
if (aca_cmd != NULL) {
unsigned long flags;
TRACE_MGMT_DBG("Aborting pending ACA cmd %p", aca_cmd);
spin_lock_irqsave(&aca_cmd->sess->sess_list_lock, flags);
scst_abort_cmd(aca_cmd, mcmd, other_ini, (mcmd != NULL));
spin_unlock_irqrestore(&aca_cmd->sess->sess_list_lock, flags);
}
order_data->aca_tgt_dev = 0;
order_data->aca_cmd = NULL;
TRACE_EXIT();
return;
}
/* No locks or dev_lock, or scst_mutex */
void scst_clear_aca(struct scst_tgt_dev *tgt_dev, bool other_ini)
{
struct scst_order_data *order_data = tgt_dev->curr_order_data;
TRACE_ENTRY();
spin_lock_irq(&order_data->sn_lock);
if (order_data->aca_tgt_dev == 0) {
TRACE_DBG("No ACA (tgt_dev %p)", tgt_dev);
EXTRACHECKS_BUG_ON(order_data->aca_cmd != NULL);
goto out_unlock;
}
__scst_clear_aca(tgt_dev, NULL, other_ini);
spin_unlock_irq(&order_data->sn_lock);
scst_make_deferred_commands_active(order_data);
out:
TRACE_EXIT();
return;
out_unlock:
spin_unlock_irq(&order_data->sn_lock);
goto out;
}
/* No locks */
static int scst_clear_aca_mcmd(struct scst_mgmt_cmd *mcmd)
{
int res;
struct scst_tgt_dev *mcmd_tgt_dev = mcmd->mcmd_tgt_dev;
struct scst_order_data *order_data = mcmd_tgt_dev->curr_order_data;
unsigned long aca_tgt_dev;
TRACE_ENTRY();
TRACE(TRACE_MGMT, "CLEAR ACA (dev %s, lun=%lld, mcmd %p, tgt_dev %p)",
mcmd_tgt_dev->dev->virt_name,
(long long unsigned int)mcmd_tgt_dev->lun, mcmd, mcmd_tgt_dev);
spin_lock_irq(&order_data->sn_lock);
aca_tgt_dev = order_data->aca_tgt_dev;
if (aca_tgt_dev == 0) {
TRACE(TRACE_MGMT, "CLEAR ACA while there's no ACA (mcmd %p)", mcmd);
goto out_unlock_done;
}
if ((unsigned long)mcmd_tgt_dev != aca_tgt_dev) {
TRACE(TRACE_MGMT, "CLEAR ACA from not initiated ACA I_T nexus "
"(mcmd %p, mcmd_tgt_dev %p, aca_tgt_dev %ld)", mcmd,
mcmd_tgt_dev, aca_tgt_dev);
goto out_unlock_reject;
}
__scst_clear_aca(mcmd_tgt_dev, mcmd, false);
spin_unlock_irq(&order_data->sn_lock);
scst_make_deferred_commands_active(order_data);
scst_unblock_aborted_cmds(mcmd_tgt_dev->sess->tgt, mcmd_tgt_dev->sess,
mcmd_tgt_dev->dev, false);
out_state:
res = scst_set_mcmd_next_state(mcmd);
TRACE_EXIT_RES(res);
return res;
out_unlock_reject:
mcmd->status = SCST_MGMT_STATUS_REJECTED;
out_unlock_done:
spin_unlock_irq(&order_data->sn_lock);
goto out_state;
}
/* Returns 0 if the command processing should be continued, <0 otherwise */
static int scst_mgmt_cmd_exec(struct scst_mgmt_cmd *mcmd)
{
@@ -7023,8 +7329,7 @@ static int scst_mgmt_cmd_exec(struct scst_mgmt_cmd *mcmd)
break;
case SCST_CLEAR_ACA:
/* Nothing to do (yet) */
scst_mgmt_cmd_set_status(mcmd, SCST_MGMT_STATUS_FN_NOT_SUPPORTED);
res = scst_clear_aca_mcmd(mcmd);
goto out_done;
default:
+7 -7
View File
@@ -809,7 +809,7 @@ void *main_loop(void *arg)
pl.events = POLLIN;
cmd.preply = 0;
multi.multi_cmd.preplies = (uint64_t)&multi.replies[0];
multi.multi_cmd.preplies = (uintptr_t)&multi.replies[0];
multi.multi_cmd.replies_cnt = 0;
multi.multi_cmd.cmds_cnt = MULTI_CMDS_CNT;
@@ -829,7 +829,7 @@ void *main_loop(void *arg)
if (use_multi) {
TRACE_DBG("preplies %p (first: %p), replies_cnt %d, "
"replies_done %d, cmds_cnt %d", (void *)multi.multi_cmd.preplies,
"replies_done %d, cmds_cnt %d", (void *)(uintptr_t)multi.multi_cmd.preplies,
&multi.replies[0], multi.multi_cmd.replies_cnt,
multi.multi_cmd.replies_done, multi.multi_cmd.cmds_cnt);
res = ioctl(scst_usr_fd, SCST_USER_REPLY_AND_GET_MULTI, &multi.multi_cmd);
@@ -842,7 +842,7 @@ void *main_loop(void *arg)
case EBUSY:
TRACE_MGMT_DBG("SCST_USER returned %d (%s)", res, strerror(res));
cmd.preply = 0;
multi.multi_cmd.preplies = (uint64_t)&multi.replies[0];
multi.multi_cmd.preplies = (uintptr_t)&multi.replies[0];
multi.multi_cmd.replies_cnt = 0;
multi.multi_cmd.cmds_cnt = MULTI_CMDS_CNT;
case EINTR:
@@ -850,7 +850,7 @@ void *main_loop(void *arg)
case EAGAIN:
TRACE_DBG("SCST_USER returned EAGAIN (%d)", res);
cmd.preply = 0;
multi.multi_cmd.preplies = (uint64_t)&multi.replies[0];
multi.multi_cmd.preplies = (uintptr_t)&multi.replies[0];
multi.multi_cmd.replies_cnt = 0;
multi.multi_cmd.cmds_cnt = MULTI_CMDS_CNT;
if (dev->non_blocking)
@@ -861,7 +861,7 @@ void *main_loop(void *arg)
PRINT_ERROR("SCST_USER failed: %s (%d)", strerror(res), res);
#if 1
cmd.preply = 0;
multi.multi_cmd.preplies = (uint64_t)&multi.replies[0];
multi.multi_cmd.preplies = (uintptr_t)&multi.replies[0];
multi.multi_cmd.replies_cnt = 0;
multi.multi_cmd.cmds_cnt = MULTI_CMDS_CNT;
continue;
@@ -900,13 +900,13 @@ again_poll:
if (multi.multi_cmd.replies_done < multi.multi_cmd.replies_cnt) {
TRACE_MGMT_DBG("replies_done %d < replies_cnt %d (dev %s)",
multi.multi_cmd.replies_done, multi.multi_cmd.replies_cnt, dev->name);
multi.multi_cmd.preplies = (uint64_t)&multi.replies[multi.multi_cmd.replies_done];
multi.multi_cmd.preplies = (uintptr_t)&multi.replies[multi.multi_cmd.replies_done];
multi.multi_cmd.replies_cnt = multi.multi_cmd.replies_cnt - multi.multi_cmd.replies_done;
multi.multi_cmd.cmds_cnt = MULTI_CMDS_CNT;
continue;
}
TRACE_DBG("cmds_cnt %d", multi.multi_cmd.cmds_cnt);
multi.multi_cmd.preplies = (uint64_t)&multi.replies[0];
multi.multi_cmd.preplies = (uintptr_t)&multi.replies[0];
for (i = 0, j = 0; i < multi.multi_cmd.cmds_cnt; i++, j++) {
vcmd.cmd = &multi.cmds[i];
vcmd.reply = &multi.replies[j];