mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-21 06:36:27 +00:00
Merge branch 'svn-trunk'
This commit is contained in:
@@ -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-; \
|
||||
} && \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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"
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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).
|
||||
*************************************************************/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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! */
|
||||
}
|
||||
|
||||
|
||||
@@ -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! */
|
||||
}
|
||||
|
||||
|
||||
@@ -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! */
|
||||
}
|
||||
|
||||
|
||||
@@ -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! */
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user