From 6dd3fb9c93513bc6a75a35a6303bb1c70ea37cd1 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Fri, 28 May 2010 16:30:11 +0000 Subject: [PATCH] Now it is possible to dump PRs states in the log using proc/sysfs interfaces + some cleanups git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1721 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- iscsi-scst/README | 2 +- iscsi-scst/README_in-tree | 2 +- scst/README | 12 +++-- scst/README_in-tree | 3 ++ scst/include/scst_debug.h | 7 ++- scst/src/scst_debug.c | 4 -- scst/src/scst_pres.c | 96 ++++++++++++++++++++++----------------- scst/src/scst_pres.h | 6 +++ scst/src/scst_proc.c | 35 ++++++++++++++ scst/src/scst_sysfs.c | 26 +++++++++++ 10 files changed, 137 insertions(+), 56 deletions(-) diff --git a/iscsi-scst/README b/iscsi-scst/README index d7ab60dd2..eb75dbbd3 100644 --- a/iscsi-scst/README +++ b/iscsi-scst/README @@ -309,7 +309,7 @@ echo 1 >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/enabled echo 1 >/sys/kernel/scst_tgt/targets/iscsi/enabled Below is another sample script, which configures 1 real local SCSI disk -0:0:1:0 one target iqn.2006-10.net.vlnb:tgt with all default parameters: +0:0:1:0 and one target iqn.2006-10.net.vlnb:tgt with all default parameters: #!/bin/bash diff --git a/iscsi-scst/README_in-tree b/iscsi-scst/README_in-tree index 68f1a0a23..ca5ef7a12 100644 --- a/iscsi-scst/README_in-tree +++ b/iscsi-scst/README_in-tree @@ -206,7 +206,7 @@ echo 1 >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/enabled echo 1 >/sys/kernel/scst_tgt/targets/iscsi/enabled Below is another sample script, which configures 1 real local SCSI disk -0:0:1:0 one target iqn.2006-10.net.vlnb:tgt with all default parameters: +0:0:1:0 and one target iqn.2006-10.net.vlnb:tgt with all default parameters: #!/bin/bash diff --git a/scst/README b/scst/README index fa24664ed..f16c1847f 100644 --- a/scst/README +++ b/scst/README @@ -374,10 +374,11 @@ entries. - "version" file, which shows version of SCST - "trace_level" file, which allows to read and set trace (logging) level - for SCST. See /proc/scsi_tgt/help file for list of commands and - trace levels. If you want to enable logging options, which produce a - lot of events, like "debug", to not loose logged events you should - also: + for SCST. Also this file allows to dump persistent reservations + information about some device in the log file. See + /proc/scsi_tgt/help file for list of commands and trace levels. If + you want to enable logging options, which produce a lot of events, + like "debug", to not loose logged events you should also: * Increase in .config of your kernel CONFIG_LOG_BUF_SHIFT variable to much bigger value, then recompile it. For example, value 25 @@ -645,6 +646,9 @@ Standard SCST dev handlers have at least the following common entries: sessions from all initiators will share the same per-device pool of threads. Valid only if threads_num attribute >0. + - dump_prs - allows to dump persistent reservations information in the + kernel log. + - type - SCSI type of this device See below for more information about other entries of this subdirectory diff --git a/scst/README_in-tree b/scst/README_in-tree index 5e4c0bf00..71c8e667d 100644 --- a/scst/README_in-tree +++ b/scst/README_in-tree @@ -325,6 +325,9 @@ Standard SCST dev handlers have at least the following common entries: sessions from all initiators will share the same per-device pool of threads. Valid only if threads_num attribute >0. + - dump_prs - allows to dump persistent reservations information in the + kernel log. + - type - SCSI type of this device See below for more information about other entries of this subdirectory diff --git a/scst/include/scst_debug.h b/scst/include/scst_debug.h index c509481b8..af00a7328 100644 --- a/scst/include/scst_debug.h +++ b/scst/include/scst_debug.h @@ -140,9 +140,10 @@ * on the logging system in case of a lot of logging. */ -extern int debug_print_prefix(unsigned long trace_flag, +int debug_print_prefix(unsigned long trace_flag, const char *prefix, const char *func, int line); -extern void debug_print_buffer(const void *data, int len); +void debug_print_buffer(const void *data, int len); +const char *debug_transport_id_to_initiator_name(const uint8_t *transport_id); #define TRACE(trace, format, args...) \ do { \ @@ -207,8 +208,6 @@ do { \ TRACE_DBG_FLAG(TRACE_MGMT_DEBUG|TRACE_SPECIAL, args) #define TRACE_PR(args...) TRACE_DBG_FLAG(TRACE_PRES, args) -const char *debug_transport_id_to_initiator_name(const uint8_t *transport_id); - #define TRACE_BUFFER(message, buff, len) \ do { \ if (trace_flag & TRACE_BUFF) { \ diff --git a/scst/src/scst_debug.c b/scst/src/scst_debug.c index 4cd08455a..c6e8bbefb 100644 --- a/scst/src/scst_debug.c +++ b/scst/src/scst_debug.c @@ -137,8 +137,6 @@ void debug_print_buffer(const void *data, int len) } EXPORT_SYMBOL(debug_print_buffer); -#ifdef CONFIG_SCST_DEBUG - /* * This function converts transport_id in a string form into internal per-CPU * static buffer. This buffer isn't anyhow protected, because it's acceptable @@ -226,6 +224,4 @@ const char *debug_transport_id_to_initiator_name(const uint8_t *transport_id) #undef SIZEOF_NAME_BUF } -#endif /* CONFIG_SCST_DEBUG */ - #endif /* CONFIG_SCST_DEBUG || CONFIG_SCST_TRACING */ diff --git a/scst/src/scst_pres.c b/scst/src/scst_pres.c index 526ff894b..637c7c780 100644 --- a/scst/src/scst_pres.c +++ b/scst/src/scst_pres.c @@ -195,19 +195,28 @@ out: return res; } +#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) + /* Must be called under dev_pr_mutex */ -static void scst_pr_dump_prs(struct scst_device *dev) +void scst_pr_dump_prs(struct scst_device *dev, bool force) { - TRACE_PR("Persistent reservations for device %s:", dev->virt_name); + if (!force) { +#if defined(CONFIG_SCST_DEBUG) + if ((trace_flag & TRACE_PRES) == 0) +#endif + goto out; + } + + PRINT_INFO("Persistent reservations for device %s:", dev->virt_name); if (list_empty(&dev->dev_registrants_list)) - TRACE_PR("%s", " No registrants"); + PRINT_INFO("%s", " No registrants"); else { struct scst_dev_registrant *reg; int i = 0; list_for_each_entry(reg, &dev->dev_registrants_list, dev_registrants_list_entry) { - TRACE_PR(" [%d] registrant %s/%d, key '%016llx' " + PRINT_INFO(" [%d] registrant %s/%d, key %016llx " "(reg %p, tgt_dev %p)", i++, debug_transport_id_to_initiator_name( reg->transport_id), @@ -218,22 +227,25 @@ static void scst_pr_dump_prs(struct scst_device *dev) if (dev->pr_is_set) { struct scst_dev_registrant *holder = dev->pr_holder; if (holder != NULL) - TRACE_PR("Reservation holder is %s/%d (key '%016llx', " + PRINT_INFO("Reservation holder is %s/%d (key %016llx, " "scope %x, type %x, reg %p, tgt_dev %p)", debug_transport_id_to_initiator_name( holder->transport_id), holder->rel_tgt_id, holder->key, dev->pr_scope, dev->pr_type, holder, holder->tgt_dev); else - TRACE_PR("All registrants are reservation holders " + PRINT_INFO("All registrants are reservation holders " "(scope %x, type %x)", dev->pr_scope, dev->pr_type); } else - TRACE_PR("%s", "Not reserved"); + PRINT_INFO("%s", "Not reserved"); +out: return; } +#endif /* defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) */ + /* dev_pr_mutex must be locked */ static void scst_pr_find_registrants_list_all(struct scst_device *dev, struct scst_dev_registrant *exclude_reg, struct list_head *list) @@ -243,14 +255,14 @@ static void scst_pr_find_registrants_list_all(struct scst_device *dev, TRACE_ENTRY(); TRACE_PR("Finding all registered records for device '%s' " - "with exclude reg key '%016llx'", + "with exclude reg key %016llx", dev->virt_name, exclude_reg->key); list_for_each_entry(reg, &dev->dev_registrants_list, dev_registrants_list_entry) { if (reg == exclude_reg) continue; - TRACE_PR("Adding registrant %s/%d (%p) to find list (key '%016llx')", + TRACE_PR("Adding registrant %s/%d (%p) to find list (key %016llx)", debug_transport_id_to_initiator_name(reg->transport_id), reg->rel_tgt_id, reg, reg->key); list_add_tail(®->aux_list_entry, list); @@ -268,14 +280,14 @@ static void scst_pr_find_registrants_list_key(struct scst_device *dev, TRACE_ENTRY(); - TRACE_PR("Finding registrants for device '%s' with key '%016llx'", + TRACE_PR("Finding registrants for device '%s' with key %016llx", dev->virt_name, key); list_for_each_entry(reg, &dev->dev_registrants_list, dev_registrants_list_entry) { if (reg->key == key) { TRACE_PR("Adding registrant %s/%d (%p) to the find " - "list (key '%016llx')", + "list (key %016llx)", debug_transport_id_to_initiator_name( reg->transport_id), reg->rel_tgt_id, reg->tgt_dev, key); @@ -443,7 +455,7 @@ static void scst_pr_remove_registrant(struct scst_device *dev, { TRACE_ENTRY(); - TRACE_PR("Removing registrant %s/%d (reg %p, tgt_dev %p, key '%016llx', " + TRACE_PR("Removing registrant %s/%d (reg %p, tgt_dev %p, key %016llx, " "dev %s)", debug_transport_id_to_initiator_name(reg->transport_id), reg->rel_tgt_id, reg, reg->tgt_dev, reg->key, dev->virt_name); @@ -474,7 +486,7 @@ static void scst_pr_send_ua_reg(struct scst_device *dev, scst_set_sense(ua, sizeof(ua), dev->d_sense, key, asc, ascq); TRACE_PR("Queuing UA [%x %x %x]: registrant %s/%d (%p), tgt_dev %p, " - "key '%016llx'", ua[2], ua[12], ua[13], + "key %016llx", ua[2], ua[12], ua[13], debug_transport_id_to_initiator_name(reg->transport_id), reg->rel_tgt_id, reg, reg->tgt_dev, reg->key); @@ -515,7 +527,7 @@ static void scst_pr_abort_reg(struct scst_device *dev, TRACE_ENTRY(); if (reg->tgt_dev == NULL) { - TRACE_PR("Registrant %s/%d (%p, key '0x%016llx') has no session", + TRACE_PR("Registrant %s/%d (%p, key 0x%016llx) has no session", debug_transport_id_to_initiator_name(reg->transport_id), reg->rel_tgt_id, reg, reg->key); goto out; @@ -523,7 +535,7 @@ static void scst_pr_abort_reg(struct scst_device *dev, sess = reg->tgt_dev->sess; - TRACE_PR("Aborting %d commands for %s/%d (reg %p, key '0x%016llx', " + TRACE_PR("Aborting %d commands for %s/%d (reg %p, key 0x%016llx, " "tgt_dev %p, sess %p)", atomic_read(®->tgt_dev->tgt_dev_cmd_count), debug_transport_id_to_initiator_name(reg->transport_id), @@ -781,7 +793,7 @@ static int scst_pr_load_device_file(struct scst_device *dev) res = scst_pr_do_load_device_file(dev, dev->pr_file_name1); - scst_pr_dump_prs(dev); + scst_pr_dump_prs(dev, false); out: TRACE_EXIT_RES(res); @@ -1395,7 +1407,7 @@ static void scst_pr_unregister(struct scst_device *dev, TRACE_ENTRY(); - TRACE_PR("Unregistering key '%0llx'", reg->key); + TRACE_PR("Unregistering key %0llx", reg->key); is_holder = scst_pr_is_holder(dev, reg); pr_type = dev->pr_type; @@ -1461,7 +1473,7 @@ void scst_pr_register(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size) reg = tgt_dev->registrant; - TRACE_PR("Register: initiator %s/%d (%p), key '%0llx', action_key '%0llx' " + TRACE_PR("Register: initiator %s/%d (%p), key %0llx, action_key %0llx " "(tgt_dev %p)", debug_transport_id_to_initiator_name(sess->transport_id), sess->tgt->rel_tgt_id, reg, key, action_key, tgt_dev); @@ -1502,7 +1514,7 @@ void scst_pr_register(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size) } else { if (reg->key != key) { TRACE_PR("tgt_dev %p already registered - reservation " - "key ('%0llx') mismatch", tgt_dev, reg->key); + "key %0llx mismatch", tgt_dev, reg->key); scst_set_cmd_error_status(cmd, SAM_STAT_RESERVATION_CONFLICT); goto out; @@ -1523,7 +1535,7 @@ void scst_pr_register(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size) dev->pr_aptpl = aptpl; - scst_pr_dump_prs(dev); + scst_pr_dump_prs(dev, false); out: list_for_each_entry(reg, &rollback_list, aux_list_entry) { @@ -1589,7 +1601,7 @@ void scst_pr_register_and_ignore(struct scst_cmd *cmd, uint8_t *buffer, reg = tgt_dev->registrant; TRACE_PR("Register and ignore: initiator %s/%d (%p), action_key " - "'%016llx' (tgt_dev %p)", + "%016llx (tgt_dev %p)", debug_transport_id_to_initiator_name(sess->transport_id), sess->tgt->rel_tgt_id, reg, action_key, tgt_dev); @@ -1617,7 +1629,7 @@ void scst_pr_register_and_ignore(struct scst_cmd *cmd, uint8_t *buffer, dev->pr_aptpl = aptpl; - scst_pr_dump_prs(dev); + scst_pr_dump_prs(dev, false); out: TRACE_EXIT(); @@ -1753,7 +1765,7 @@ void scst_pr_register_and_move(struct scst_cmd *cmd, uint8_t *buffer, } TRACE_PR("Register and move: from initiator %s/%d (%p, tgt_dev %p) to " - "initiator %s/%d (%p, tgt_dev %p), key '%016llx' (unreg %d)", + "initiator %s/%d (%p, tgt_dev %p), key %016llx (unreg %d)", debug_transport_id_to_initiator_name(reg->transport_id), reg->rel_tgt_id, reg, reg->tgt_dev, debug_transport_id_to_initiator_name(transport_id_move), @@ -1770,7 +1782,7 @@ void scst_pr_register_and_move(struct scst_cmd *cmd, uint8_t *buffer, dev->pr_aptpl = aptpl; - scst_pr_dump_prs(dev); + scst_pr_dump_prs(dev, false); out: TRACE_EXIT(); @@ -1815,7 +1827,7 @@ void scst_pr_reserve(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size) reg = tgt_dev->registrant; - TRACE_PR("Reserve: initiator %s/%d (%p), key '%016llx', scope %d, " + TRACE_PR("Reserve: initiator %s/%d (%p), key %016llx, scope %d, " "type %d (tgt_dev %p)", debug_transport_id_to_initiator_name(cmd->sess->transport_id), cmd->sess->tgt->rel_tgt_id, reg, key, scope, type, tgt_dev); @@ -1855,7 +1867,7 @@ void scst_pr_reserve(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size) } } - scst_pr_dump_prs(dev); + scst_pr_dump_prs(dev, false); out: TRACE_EXIT(); @@ -1892,7 +1904,7 @@ void scst_pr_release(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size) reg = tgt_dev->registrant; - TRACE_PR("Release: initiator %s/%d (%p), key '%016llx', scope %d, type " + TRACE_PR("Release: initiator %s/%d (%p), key %016llx, scope %d, type " "%d (tgt_dev %p)", debug_transport_id_to_initiator_name( cmd->sess->transport_id), cmd->sess->tgt->rel_tgt_id, reg, key, scope, type, tgt_dev); @@ -1931,7 +1943,7 @@ void scst_pr_release(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size) SCST_LOAD_SENSE(scst_sense_reservation_released)); } - scst_pr_dump_prs(dev); + scst_pr_dump_prs(dev, false); out: TRACE_EXIT(); @@ -1962,7 +1974,7 @@ void scst_pr_clear(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size) reg = tgt_dev->registrant; - TRACE_PR("Clear: initiator %s/%d (%p), key '%016llx' (tgt_dev %p)", + TRACE_PR("Clear: initiator %s/%d (%p), key %016llx (tgt_dev %p)", debug_transport_id_to_initiator_name(cmd->sess->transport_id), cmd->sess->tgt->rel_tgt_id, reg, key, tgt_dev); @@ -1984,7 +1996,7 @@ void scst_pr_clear(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size) dev->pr_generation++; - scst_pr_dump_prs(dev); + scst_pr_dump_prs(dev, false); out: TRACE_EXIT(); @@ -2024,8 +2036,8 @@ static void scst_pr_do_preempt(struct scst_cmd *cmd, uint8_t *buffer, reg = tgt_dev->registrant; - TRACE_PR("Preempt%s: initiator %s/%d (%p), key '%016llx', action_key " - "'%016llx', scope %x type %x (tgt_dev %p)", + TRACE_PR("Preempt%s: initiator %s/%d (%p), key %016llx, action_key " + "%016llx, scope %x type %x (tgt_dev %p)", abort ? " and abort" : "", debug_transport_id_to_initiator_name(cmd->sess->transport_id), cmd->sess->tgt->rel_tgt_id, reg, key, action_key, scope, type, @@ -2143,14 +2155,14 @@ static void scst_pr_do_preempt(struct scst_cmd *cmd, uint8_t *buffer, done: dev->pr_generation++; - scst_pr_dump_prs(dev); + scst_pr_dump_prs(dev, false); out: TRACE_EXIT(); return; out_error: - TRACE_PR("Invalid key '%016llx'", action_key); + TRACE_PR("Invalid key %016llx", action_key); scst_set_cmd_error_status(cmd, SAM_STAT_RESERVATION_CONFLICT); goto out; } @@ -2238,8 +2250,8 @@ bool scst_pr_crh_case(struct scst_cmd *cmd) TRACE_ENTRY(); - TRACE_DBG("Test if there is a CRH case for command '%s' (0x%x) from " - "'%s'", cmd->op_name, cmd->cdb[0], cmd->sess->initiator_name); + TRACE_DBG("Test if there is a CRH case for command %s (0x%x) from " + "%s", cmd->op_name, cmd->cdb[0], cmd->sess->initiator_name); if (!dev->pr_is_set) { TRACE_PR("%s", "PR not set"); @@ -2274,11 +2286,11 @@ bool scst_pr_crh_case(struct scst_cmd *cmd) } if (!allowed) - TRACE_PR("Command '%s' (0x%x) from '%s' rejected due " - "to not CRH reservation", cmd->op_name, cmd->cdb[0], + TRACE_PR("Command %s (0x%x) from %s rejected due to not CRH " + "reservation", cmd->op_name, cmd->cdb[0], cmd->sess->initiator_name); else - TRACE_DBG("Command %s (0x%x) from '%s' is allowed to execute " + TRACE_DBG("Command %s (0x%x) from %s is allowed to execute " "due to CRH", cmd->op_name, cmd->cdb[0], cmd->sess->initiator_name); @@ -2302,7 +2314,7 @@ bool scst_pr_is_cmd_allowed(struct scst_cmd *cmd) unlock = scst_pr_read_lock(dev); - TRACE_DBG("Testing if command '%s' (0x%x) from '%s' allowed to execute", + TRACE_DBG("Testing if command %s (0x%x) from %s allowed to execute", cmd->op_name, cmd->cdb[0], cmd->sess->initiator_name); /* Recheck, because it can change while we were waiting for the lock */ @@ -2352,11 +2364,11 @@ bool scst_pr_is_cmd_allowed(struct scst_cmd *cmd) } if (!allowed) - TRACE_PR("Command '%s' (0x%x) from '%s' rejected due " + TRACE_PR("Command %s (0x%x) from %s rejected due " "to PR", cmd->op_name, cmd->cdb[0], cmd->sess->initiator_name); else - TRACE_DBG("Command %s (0x%x) from '%s' is allowed to execute", + TRACE_DBG("Command %s (0x%x) from %s is allowed to execute", cmd->op_name, cmd->cdb[0], cmd->sess->initiator_name); out_unlock: diff --git a/scst/src/scst_pres.h b/scst/src/scst_pres.h index 547251fcd..d0952c5ac 100644 --- a/scst/src/scst_pres.h +++ b/scst/src/scst_pres.h @@ -165,4 +165,10 @@ void scst_pr_read_full_status(struct scst_cmd *cmd, uint8_t *buffer, void scst_pr_sync_device_file(struct scst_tgt_dev *tgt_dev, struct scst_cmd *cmd); #endif +#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) +void scst_pr_dump_prs(struct scst_device *dev, bool force); +#else +static inline void scst_pr_dump_prs(struct scst_device *dev, bool force) {} +#endif + #endif /* SCST_PRES_H_ */ diff --git a/scst/src/scst_proc.c b/scst/src/scst_proc.c index 1e178ee2f..816691222 100644 --- a/scst/src/scst_proc.c +++ b/scst/src/scst_proc.c @@ -33,6 +33,7 @@ #include "scst.h" #include "scst_priv.h" #include "scst_mem.h" +#include "scst_pres.h" static int scst_proc_init_groups(void); static void scst_proc_cleanup_groups(void); @@ -87,6 +88,7 @@ static struct scst_proc_data scst_dev_handler_proc_data; #define SCST_PROC_ACTION_ADD_GROUP 11 #define SCST_PROC_ACTION_DEL_GROUP 12 #define SCST_PROC_ACTION_RENAME_GROUP 13 +#define SCST_PROC_ACTION_DUMP_PRS 14 static struct proc_dir_entry *scst_proc_scsi_tgt; static struct proc_dir_entry *scst_proc_groups_root; @@ -161,6 +163,7 @@ static char *scst_proc_help_string = " mgmt, minor, mgmt_dbg]\n" " Additionally for /proc/scsi_tgt/trace_level there are these TOKENs\n" " [scsi_serializing, retry, recv_bot, send_bot, recv_top, send_top]\n" +" echo \"dump_prs dev_name\" >/proc/scsi_tgt/trace_level\n" #endif ; @@ -301,6 +304,9 @@ int scst_proc_log_entry_write(struct file *file, const char __user *buf, } else if (!strncasecmp("value ", p, 6)) { p += 6; action = SCST_PROC_ACTION_VALUE; + } else if (!strncasecmp("dump_prs ", p, 9)) { + p += 9; + action = SCST_PROC_ACTION_DUMP_PRS; } else { if (p[strlen(p) - 1] == '\n') p[strlen(p) - 1] = '\0'; @@ -358,6 +364,35 @@ int scst_proc_log_entry_write(struct file *file, const char __user *buf, p++; level = simple_strtoul(p, NULL, 0); break; + case SCST_PROC_ACTION_DUMP_PRS: + { + struct scst_device *dev; + + while (isspace(*p) && *p != '\0') + p++; + e = p; + while (!isspace(*e) && *e != '\0') + e++; + *e = '\0'; + + if (mutex_lock_interruptible(&scst_mutex) != 0) { + res = -EINTR; + goto out_free; + } + + list_for_each_entry(dev, &scst_dev_list, dev_list_entry) { + if (strcmp(dev->virt_name, p) == 0) { + scst_pr_dump_prs(dev, true); + goto out_up; + } + } + + PRINT_ERROR("Device %s not found", p); + res = -ENOENT; +out_up: + mutex_unlock(&scst_mutex); + goto out_free; + } } oldlevel = *log_level; diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index 9086de38e..1769a2956 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -27,6 +27,7 @@ #include "scst.h" #include "scst_priv.h" #include "scst_mem.h" +#include "scst_pres.h" static DECLARE_COMPLETION(scst_sysfs_root_release_completion); @@ -827,6 +828,28 @@ static ssize_t scst_device_sysfs_type_show(struct kobject *kobj, static struct kobj_attribute device_type_attr = __ATTR(type, S_IRUGO, scst_device_sysfs_type_show, NULL); +#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) + +static ssize_t scst_device_sysfs_dump_prs(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + struct scst_device *dev; + + TRACE_ENTRY(); + + dev = container_of(kobj, struct scst_device, dev_kobj); + + scst_pr_dump_prs(dev, true); + + TRACE_EXIT_RES(count); + return count; +} + +static struct kobj_attribute device_dump_prs_attr = + __ATTR(dump_prs, S_IWUSR, NULL, scst_device_sysfs_dump_prs); + +#endif /* defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) */ + static ssize_t scst_device_sysfs_threads_num_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -1015,6 +1038,9 @@ static struct kobj_attribute device_threads_pool_type_attr = static struct attribute *scst_device_attrs[] = { &device_type_attr.attr, +#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) + &device_dump_prs_attr.attr, +#endif &device_threads_num_attr.attr, &device_threads_pool_type_attr.attr, NULL,