mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-18 11:11:27 +00:00
scst: Make pr path configurable
Make the path of the file in which persistent reservation information is stored configurable via sysfs. Signed-off-by: Bart Van Assche <bvanassche@acm.org> with some improvements and fixes git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@5510 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -1043,6 +1043,12 @@ Each vdisk_fileio's device has the following attributes in
|
||||
|
||||
- size_mb - contains size of this virtual device in MB.
|
||||
|
||||
- pr_file_name - Full path of the file or block device in which to store
|
||||
persistent reservation information. The default value for this attribute is
|
||||
/var/lib/scst/pr/${device_name}. Writing a new value into this sysfs
|
||||
attribute is only allowed if the device is not exported. Modifying this
|
||||
sysfs attribute causes the persistent reservation state to be reloaded.
|
||||
|
||||
- t10_dev_id - contains and allows to set T10 vendor specific
|
||||
identifier for Device Identification VPD page (0x83) of INQUIRY data.
|
||||
By default VDISK handler always generates t10_dev_id for every new
|
||||
|
||||
@@ -2533,6 +2533,9 @@ struct scst_device {
|
||||
/* True if persist through power loss is activated. */
|
||||
unsigned short pr_aptpl:1;
|
||||
|
||||
/* Whether or not pr_file_name has been modified via sysfs. */
|
||||
unsigned int pr_file_name_is_set:1;
|
||||
|
||||
/* Persistent reservation type */
|
||||
uint8_t pr_type;
|
||||
|
||||
@@ -2562,7 +2565,10 @@ struct scst_device {
|
||||
|
||||
struct scst_order_data dev_order_data;
|
||||
|
||||
/* Persist through power loss files */
|
||||
/*
|
||||
* Where to save persistent reservation information. Protected by
|
||||
* dev_pr_mutex.
|
||||
*/
|
||||
char *pr_file_name;
|
||||
char *pr_file_name1;
|
||||
|
||||
@@ -4700,7 +4706,10 @@ struct scst_sysfs_work_item {
|
||||
};
|
||||
struct {
|
||||
struct scst_device *dev;
|
||||
int new_threads_num;
|
||||
union {
|
||||
int new_threads_num;
|
||||
bool default_val;
|
||||
};
|
||||
enum scst_dev_type_threads_pool_type new_threads_pool_type;
|
||||
};
|
||||
struct scst_session *sess;
|
||||
@@ -4743,6 +4752,9 @@ int scst_scsi_exec_async(struct scst_cmd *cmd, void *data,
|
||||
void (*done)(void *data, char *sense, int result, int resid));
|
||||
#endif
|
||||
|
||||
int scst_get_file_mode(const char *path);
|
||||
bool scst_parent_dir_exists(const char *path);
|
||||
|
||||
struct scst_data_descriptor {
|
||||
uint64_t sdd_lba;
|
||||
uint64_t sdd_blocks;
|
||||
|
||||
@@ -3759,6 +3759,17 @@ void scst_free_device(struct scst_device *dev)
|
||||
return;
|
||||
}
|
||||
|
||||
bool scst_device_is_exported(struct scst_device *dev)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
|
||||
lockdep_assert_held(&scst_mutex);
|
||||
#endif
|
||||
|
||||
WARN_ON_ONCE(!dev->dev_tgt_dev_list.next);
|
||||
|
||||
return !list_empty(&dev->dev_tgt_dev_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* scst_init_mem_lim - initialize memory limits structure
|
||||
*
|
||||
@@ -10143,6 +10154,55 @@ int scst_read_file_transactional(const char *name, const char *name1,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scst_read_file_transactional);
|
||||
|
||||
/*
|
||||
* Return the file mode if @path exists or an error code if opening @path via
|
||||
* filp_open() in read-only mode failed.
|
||||
*/
|
||||
int scst_get_file_mode(const char *path)
|
||||
{
|
||||
struct file *file;
|
||||
int res;
|
||||
|
||||
file = filp_open(path, O_RDONLY, 0400);
|
||||
if (IS_ERR(file)) {
|
||||
res = PTR_ERR(file);
|
||||
goto out;
|
||||
}
|
||||
res = file->f_dentry->d_inode->i_mode;
|
||||
filp_close(file, NULL);
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(scst_get_file_mode);
|
||||
|
||||
/*
|
||||
* Return true if either @path does not contain a slash or if the directory
|
||||
* specified in @path exists.
|
||||
*/
|
||||
bool scst_parent_dir_exists(const char *path)
|
||||
{
|
||||
const char *last_slash = strrchr(path, '/');
|
||||
const char *dir;
|
||||
int dir_mode;
|
||||
bool res = true;
|
||||
|
||||
if (last_slash && last_slash > path) {
|
||||
dir = kasprintf(GFP_KERNEL, "%.*s", (int)(last_slash - path),
|
||||
path);
|
||||
if (dir) {
|
||||
dir_mode = scst_get_file_mode(dir);
|
||||
kfree(dir);
|
||||
res = dir_mode >= 0 && S_ISDIR(dir_mode);
|
||||
} else {
|
||||
res = false;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(scst_parent_dir_exists);
|
||||
|
||||
static void __init scst_scsi_op_list_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -1198,13 +1198,13 @@ out:
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
out_del_unlocked:
|
||||
mutex_lock(&scst_mutex);
|
||||
list_del(&dev->dev_list_entry);
|
||||
list_del_init(&dev->dev_list_entry);
|
||||
mutex_unlock(&scst_mutex);
|
||||
scst_free_device(dev);
|
||||
goto out;
|
||||
#else
|
||||
out_del_locked:
|
||||
list_del(&dev->dev_list_entry);
|
||||
list_del_init(&dev->dev_list_entry);
|
||||
#endif
|
||||
|
||||
out_free_dev:
|
||||
@@ -1266,7 +1266,7 @@ static void scst_unregister_device(struct scsi_device *scsidp)
|
||||
|
||||
dev->dev_unregistering = 1;
|
||||
|
||||
list_del(&dev->dev_list_entry);
|
||||
list_del_init(&dev->dev_list_entry);
|
||||
|
||||
scst_dg_dev_remove_by_dev(dev);
|
||||
|
||||
@@ -1418,6 +1418,11 @@ int scst_register_virtual_device(struct scst_dev_type *dev_handler,
|
||||
scst_virt_dev_last_id = 1;
|
||||
}
|
||||
|
||||
res = scst_pr_set_file_name(dev, NULL, "%s/%s", SCST_PR_DIR,
|
||||
dev->virt_name);
|
||||
if (res != 0)
|
||||
goto out_free_dev;
|
||||
|
||||
res = scst_pr_init_dev(dev);
|
||||
if (res != 0)
|
||||
goto out_free_dev;
|
||||
@@ -1516,7 +1521,7 @@ void scst_unregister_virtual_device(int id)
|
||||
|
||||
dev->dev_unregistering = 1;
|
||||
|
||||
list_del(&dev->dev_list_entry);
|
||||
list_del_init(&dev->dev_list_entry);
|
||||
|
||||
scst_pr_clear_dev(dev);
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#endif
|
||||
#include <linux/vmalloc.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
|
||||
#include <linux/mount.h>
|
||||
@@ -74,6 +75,19 @@
|
||||
#define isblank(c) ((c) == ' ' || (c) == '\t')
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && defined(CONFIG_LOCKDEP)
|
||||
#define scst_assert_pr_mutex_held(dev) \
|
||||
do { \
|
||||
if (dev->dev_list_entry.next && \
|
||||
!list_empty(&dev->dev_list_entry)) \
|
||||
lockdep_assert_held(&dev->dev_pr_mutex); \
|
||||
} while (0);
|
||||
#else
|
||||
static inline void scst_assert_pr_mutex_held(struct scst_device *dev)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int tid_size(const uint8_t *tid)
|
||||
{
|
||||
sBUG_ON(tid == NULL);
|
||||
@@ -174,6 +188,8 @@ out_error:
|
||||
static inline void scst_pr_set_holder(struct scst_device *dev,
|
||||
struct scst_dev_registrant *holder, uint8_t scope, uint8_t type)
|
||||
{
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
dev->pr_is_set = 1;
|
||||
dev->pr_scope = scope;
|
||||
dev->pr_type = type;
|
||||
@@ -190,6 +206,8 @@ static bool scst_pr_is_holder(struct scst_device *dev,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
if (!dev->pr_is_set)
|
||||
goto out;
|
||||
|
||||
@@ -209,6 +227,8 @@ out:
|
||||
/* Must be called under dev_pr_mutex */
|
||||
void scst_pr_dump_prs(struct scst_device *dev, bool force)
|
||||
{
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
if (!force) {
|
||||
#if defined(CONFIG_SCST_DEBUG)
|
||||
if ((trace_flag & TRACE_PRES) == 0)
|
||||
@@ -265,6 +285,8 @@ static void scst_pr_find_registrants_list_all(struct scst_device *dev,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
TRACE_PR("Finding all registered records for device '%s' "
|
||||
"with exclude reg key %016llx",
|
||||
dev->virt_name, be64_to_cpu(exclude_reg->key));
|
||||
@@ -291,6 +313,8 @@ static void scst_pr_find_registrants_list_key(struct scst_device *dev,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
TRACE_PR("Finding registrants for device '%s' with key %016llx",
|
||||
dev->virt_name, be64_to_cpu(key));
|
||||
|
||||
@@ -320,6 +344,8 @@ static struct scst_dev_registrant *scst_pr_find_reg(
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
list_for_each_entry(reg, &dev->dev_registrants_list,
|
||||
dev_registrants_list_entry) {
|
||||
if ((reg->rel_tgt_id == rel_tgt_id) &&
|
||||
@@ -338,6 +364,8 @@ static void scst_pr_clear_reservation(struct scst_device *dev)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
WARN_ON(!dev->pr_is_set);
|
||||
|
||||
dev->pr_is_set = 0;
|
||||
@@ -355,6 +383,8 @@ static void scst_pr_clear_holder(struct scst_device *dev)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
WARN_ON(!dev->pr_is_set);
|
||||
|
||||
if (dev->pr_type == TYPE_WRITE_EXCLUSIVE_ALL_REG ||
|
||||
@@ -382,6 +412,8 @@ static struct scst_dev_registrant *scst_pr_add_registrant(
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
sBUG_ON(dev == NULL);
|
||||
sBUG_ON(transport_id == NULL);
|
||||
|
||||
@@ -465,6 +497,8 @@ static void scst_pr_remove_registrant(struct scst_device *dev,
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
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, be64_to_cpu(reg->key),
|
||||
@@ -485,6 +519,18 @@ static void scst_pr_remove_registrant(struct scst_device *dev,
|
||||
return;
|
||||
}
|
||||
|
||||
static void scst_pr_remove_registrants(struct scst_device *dev)
|
||||
{
|
||||
struct scst_dev_registrant *reg, *tmp_reg;
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
list_for_each_entry_safe(reg, tmp_reg, &dev->dev_registrants_list,
|
||||
dev_registrants_list_entry) {
|
||||
scst_pr_remove_registrant(dev, reg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Must be called under dev_pr_mutex */
|
||||
static void scst_pr_send_ua_reg(struct scst_device *dev,
|
||||
struct scst_dev_registrant *reg,
|
||||
@@ -494,6 +540,8 @@ static void scst_pr_send_ua_reg(struct scst_device *dev,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
scst_set_sense(ua, sizeof(ua), dev->d_sense, key, asc, ascq);
|
||||
|
||||
TRACE_PR("Queueing UA [%x %x %x]: registrant %s/%d (%p), tgt_dev %p, "
|
||||
@@ -517,6 +565,8 @@ static void scst_pr_send_ua_all(struct scst_device *dev,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
list_for_each_entry(reg, &dev->dev_registrants_list,
|
||||
dev_registrants_list_entry) {
|
||||
if (reg != exclude_reg)
|
||||
@@ -537,6 +587,8 @@ static void scst_pr_abort_reg(struct scst_device *dev,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
if (reg->tgt_dev == NULL) {
|
||||
TRACE_PR("Registrant %s/%d (%p, key 0x%016llx) has no session",
|
||||
debug_transport_id_to_initiator_name(reg->transport_id),
|
||||
@@ -612,6 +664,10 @@ static int scst_pr_do_load_device_file(struct scst_device *dev,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
scst_pr_remove_registrants(dev);
|
||||
|
||||
old_fs = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
|
||||
@@ -767,10 +823,12 @@ out:
|
||||
|
||||
static int scst_pr_load_device_file(struct scst_device *dev)
|
||||
{
|
||||
int res;
|
||||
int res, rc;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
if (dev->pr_file_name == NULL || dev->pr_file_name1 == NULL) {
|
||||
PRINT_ERROR("Invalid file paths for '%s'", dev->virt_name);
|
||||
res = -EINVAL;
|
||||
@@ -779,12 +837,20 @@ static int scst_pr_load_device_file(struct scst_device *dev)
|
||||
|
||||
res = scst_pr_do_load_device_file(dev, dev->pr_file_name);
|
||||
if (res == 0)
|
||||
goto out;
|
||||
goto out_dump;
|
||||
else if (res == -ENOMEM)
|
||||
goto out;
|
||||
|
||||
res = scst_pr_do_load_device_file(dev, dev->pr_file_name1);
|
||||
rc = res;
|
||||
|
||||
res = scst_pr_do_load_device_file(dev, dev->pr_file_name1);
|
||||
if (res != 0) {
|
||||
if (res == -ENOENT)
|
||||
res = rc;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out_dump:
|
||||
scst_pr_dump_prs(dev, false);
|
||||
|
||||
out:
|
||||
@@ -799,6 +865,8 @@ static void scst_pr_remove_device_files(struct scst_tgt_dev *tgt_dev)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
res = dev->pr_file_name ? scst_remove_file(dev->pr_file_name) : -ENOENT;
|
||||
res = dev->pr_file_name1 ? scst_remove_file(dev->pr_file_name1) : -ENOENT;
|
||||
|
||||
@@ -821,6 +889,8 @@ void scst_pr_sync_device_file(struct scst_tgt_dev *tgt_dev, struct scst_cmd *cmd
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
if ((dev->pr_aptpl == 0) || list_empty(&dev->dev_registrants_list)) {
|
||||
scst_pr_remove_device_files(tgt_dev);
|
||||
goto out;
|
||||
@@ -1003,107 +1073,107 @@ write_error_close:
|
||||
goto out_set_fs;
|
||||
}
|
||||
|
||||
static int scst_pr_check_pr_path(void)
|
||||
#endif /* CONFIG_SCST_PROC */
|
||||
|
||||
/**
|
||||
* scst_pr_set_file_name - set name of file in which to save PR information
|
||||
* @dev: SCST device.
|
||||
* @prev: If not NULL, the current path will be stored in *@prev. It is the
|
||||
* responsibility of the caller to invoke kfree(*@prev) at an
|
||||
* appropriate time.
|
||||
* @fmt: Full path of the file in which to save PR info.
|
||||
*
|
||||
* This function must be called either while @dev is not on the device list
|
||||
* or with scst_mutex held.
|
||||
*/
|
||||
int scst_pr_set_file_name(struct scst_device *dev, char **prev,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
int res;
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
|
||||
struct nameidata nd;
|
||||
#else
|
||||
struct path path;
|
||||
#endif
|
||||
va_list args;
|
||||
char *pr_file_name = NULL, *bkp = NULL;
|
||||
int file_mode, res = -EINVAL;
|
||||
|
||||
mm_segment_t old_fs = get_fs();
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
TRACE_ENTRY();
|
||||
sBUG_ON(!fmt);
|
||||
|
||||
set_fs(KERNEL_DS);
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
|
||||
res = path_lookup(SCST_PR_DIR, 0, &nd);
|
||||
if (res == 0)
|
||||
scst_path_put(&nd);
|
||||
#else
|
||||
res = kern_path(SCST_PR_DIR, 0, &path);
|
||||
if (res == 0)
|
||||
path_put(&path);
|
||||
#endif
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Unable to find %s (err %d), you should create "
|
||||
"this directory manually or reinstall SCST",
|
||||
SCST_PR_DIR, res);
|
||||
goto out_setfs;
|
||||
res = -ENOMEM;
|
||||
va_start(args, fmt);
|
||||
pr_file_name = kvasprintf(GFP_KERNEL, fmt, args);
|
||||
va_end(args);
|
||||
if (!pr_file_name) {
|
||||
PRINT_ERROR("Unable to kvasprintf() new PR file name");
|
||||
goto out;
|
||||
}
|
||||
|
||||
out_setfs:
|
||||
set_fs(old_fs);
|
||||
res = -EINVAL;
|
||||
if (pr_file_name[0] != '/') {
|
||||
PRINT_ERROR("PR file name must be absolute!");
|
||||
goto out;
|
||||
}
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
file_mode = scst_get_file_mode(pr_file_name);
|
||||
if (file_mode >= 0 && !S_ISREG(file_mode) && !S_ISBLK(file_mode)) {
|
||||
PRINT_ERROR("PR file name must be file or block device!");
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = -ENOENT;
|
||||
if (!scst_parent_dir_exists(pr_file_name)) {
|
||||
PRINT_ERROR("PR file name parent directory doesn't exist");
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = -ENOMEM;
|
||||
bkp = kasprintf(GFP_KERNEL, "%s.1", pr_file_name);
|
||||
if (!bkp) {
|
||||
PRINT_ERROR("Unable to kasprintf() backup PR file name");
|
||||
goto out;
|
||||
}
|
||||
if (prev) {
|
||||
*prev = dev->pr_file_name;
|
||||
dev->pr_file_name = pr_file_name;
|
||||
pr_file_name = NULL;
|
||||
} else
|
||||
swap(dev->pr_file_name, pr_file_name);
|
||||
swap(dev->pr_file_name1, bkp);
|
||||
res = 0;
|
||||
|
||||
out:
|
||||
kfree(pr_file_name);
|
||||
kfree(bkp);
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SCST_PROC */
|
||||
|
||||
/* Called under scst_mutex */
|
||||
/* Must be called under dev_pr_mutex or before dev is on the device list. */
|
||||
int scst_pr_init_dev(struct scst_device *dev)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev->pr_file_name = kasprintf(GFP_KERNEL, "%s/%s", SCST_PR_DIR,
|
||||
dev->virt_name);
|
||||
if (dev->pr_file_name == NULL) {
|
||||
PRINT_ERROR("Allocation of device '%s' file path failed",
|
||||
dev->virt_name);
|
||||
res = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
dev->pr_file_name1 = kasprintf(GFP_KERNEL, "%s/%s.1", SCST_PR_DIR,
|
||||
dev->virt_name);
|
||||
if (dev->pr_file_name1 == NULL) {
|
||||
PRINT_ERROR("Allocation of device '%s' backup file path failed",
|
||||
dev->virt_name);
|
||||
res = -ENOMEM;
|
||||
goto out_free_name;
|
||||
}
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
sBUG_ON(!dev->pr_file_name || !dev->pr_file_name1);
|
||||
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
res = scst_pr_check_pr_path();
|
||||
if (res == 0) {
|
||||
res = scst_pr_load_device_file(dev);
|
||||
if (res == -ENOENT)
|
||||
res = 0;
|
||||
}
|
||||
res = scst_pr_load_device_file(dev);
|
||||
if (res == -ENOENT)
|
||||
res = 0;
|
||||
#endif
|
||||
|
||||
if (res != 0)
|
||||
goto out_free_name1;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
out_free_name1:
|
||||
kfree(dev->pr_file_name1);
|
||||
dev->pr_file_name1 = NULL;
|
||||
|
||||
out_free_name:
|
||||
kfree(dev->pr_file_name);
|
||||
dev->pr_file_name = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Called under scst_mutex */
|
||||
void scst_pr_clear_dev(struct scst_device *dev)
|
||||
{
|
||||
struct scst_dev_registrant *reg, *tmp_reg;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
list_for_each_entry_safe(reg, tmp_reg, &dev->dev_registrants_list,
|
||||
dev_registrants_list_entry) {
|
||||
scst_pr_remove_registrant(dev, reg);
|
||||
}
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
scst_pr_remove_registrants(dev);
|
||||
|
||||
kfree(dev->pr_file_name);
|
||||
kfree(dev->pr_file_name1);
|
||||
@@ -1198,6 +1268,8 @@ static int scst_pr_register_with_spec_i_pt(struct scst_cmd *cmd,
|
||||
struct scst_dev_registrant *reg;
|
||||
uint8_t *transport_id;
|
||||
|
||||
scst_assert_pr_mutex_held(cmd->dev);
|
||||
|
||||
action_key = get_unaligned((__be64 *)&buffer[8]);
|
||||
|
||||
ext_size = get_unaligned_be32(&buffer[24]);
|
||||
@@ -1315,6 +1387,8 @@ static void scst_pr_unregister(struct scst_device *dev,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
TRACE_PR("Unregistering key %0llx", reg->key);
|
||||
|
||||
is_holder = scst_pr_is_holder(dev, reg);
|
||||
@@ -1346,6 +1420,8 @@ static void scst_pr_unregister_all_tg_pt(struct scst_device *dev,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
/*
|
||||
* We can't use scst_mutex here since the caller already holds
|
||||
* dev_pr_mutex.
|
||||
@@ -1388,6 +1464,8 @@ static int scst_pr_register_on_tgt_id(struct scst_cmd *cmd,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(cmd->dev);
|
||||
|
||||
TRACE_PR("rel_tgt_id %d, spec_i_pt %d", rel_tgt_id, spec_i_pt);
|
||||
|
||||
if (spec_i_pt) {
|
||||
@@ -1433,6 +1511,8 @@ static int scst_pr_register_all_tg_pt(struct scst_cmd *cmd, uint8_t *buffer,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(cmd->dev);
|
||||
|
||||
/*
|
||||
* We can't use scst_mutex here because the caller already holds
|
||||
* dev_pr_mutex.
|
||||
@@ -1478,6 +1558,8 @@ static int __scst_pr_register(struct scst_cmd *cmd, uint8_t *buffer,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(cmd->dev);
|
||||
|
||||
if (all_tg_pt) {
|
||||
res = scst_pr_register_all_tg_pt(cmd, buffer, buffer_size,
|
||||
spec_i_pt, &rollback_list);
|
||||
@@ -1524,6 +1606,8 @@ void scst_pr_register(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(cmd->dev);
|
||||
|
||||
aptpl = buffer[20] & 0x01;
|
||||
spec_i_pt = (buffer[20] >> 3) & 0x01;
|
||||
all_tg_pt = (buffer[20] >> 2) & 0x01;
|
||||
@@ -1618,6 +1702,8 @@ void scst_pr_register_and_ignore(struct scst_cmd *cmd, uint8_t *buffer,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(cmd->dev);
|
||||
|
||||
aptpl = buffer[20] & 0x01;
|
||||
all_tg_pt = (buffer[20] >> 2) & 0x01;
|
||||
action_key = get_unaligned((__be64 *)&buffer[8]);
|
||||
@@ -1696,6 +1782,8 @@ void scst_pr_register_and_move(struct scst_cmd *cmd, uint8_t *buffer,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(cmd->dev);
|
||||
|
||||
aptpl = buffer[17] & 0x01;
|
||||
key = get_unaligned((__be64 *)&buffer[0]);
|
||||
action_key = get_unaligned((__be64 *)&buffer[8]);
|
||||
@@ -1839,6 +1927,8 @@ void scst_pr_reserve(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
key = get_unaligned((__be64 *)&buffer[0]);
|
||||
scope = cmd->cdb[2] >> 4;
|
||||
type = cmd->cdb[2] & 0x0f;
|
||||
@@ -1926,6 +2016,8 @@ void scst_pr_release(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
key = get_unaligned((__be64 *)&buffer[0]);
|
||||
scope = cmd->cdb[2] >> 4;
|
||||
type = cmd->cdb[2] & 0x0f;
|
||||
@@ -2001,6 +2093,8 @@ void scst_pr_clear(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
key = get_unaligned((__be64 *)&buffer[0]);
|
||||
|
||||
if (buffer_size != 24) {
|
||||
@@ -2211,6 +2305,8 @@ void scst_pr_preempt(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(cmd->dev);
|
||||
|
||||
scst_pr_do_preempt(cmd, buffer, buffer_size, false);
|
||||
|
||||
TRACE_EXIT();
|
||||
@@ -2248,6 +2344,8 @@ void scst_pr_preempt_and_abort(struct scst_cmd *cmd, uint8_t *buffer,
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(cmd->dev);
|
||||
|
||||
cmd->pr_abort_counter = kzalloc(sizeof(*cmd->pr_abort_counter),
|
||||
GFP_KERNEL);
|
||||
if (cmd->pr_abort_counter == NULL) {
|
||||
@@ -2424,6 +2522,8 @@ void scst_pr_read_keys(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
if (buffer_size < 8) {
|
||||
TRACE_PR("buffer_size too small: %d. expected >= 8 "
|
||||
"(buffer %p)", buffer_size, buffer);
|
||||
@@ -2475,6 +2575,8 @@ void scst_pr_read_reservation(struct scst_cmd *cmd, uint8_t *buffer,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
if (buffer_size < 8) {
|
||||
TRACE_PR("buffer_size too small: %d. expected >= 8 "
|
||||
"(buffer %p)", buffer_size, buffer);
|
||||
@@ -2538,6 +2640,8 @@ void scst_pr_report_caps(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(dev);
|
||||
|
||||
if (buffer_size < 8) {
|
||||
TRACE_PR("buffer_size too small: %d. expected >= 8 "
|
||||
"(buffer %p)", buffer_size, buffer);
|
||||
@@ -2577,6 +2681,8 @@ void scst_pr_read_full_status(struct scst_cmd *cmd, uint8_t *buffer,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_assert_pr_mutex_held(cmd->dev);
|
||||
|
||||
if (buffer_size < 8)
|
||||
goto skip;
|
||||
|
||||
|
||||
@@ -89,6 +89,9 @@ static inline void scst_pr_write_unlock(struct scst_device *dev)
|
||||
mutex_unlock(&dev->dev_pr_mutex);
|
||||
}
|
||||
|
||||
int scst_pr_set_file_name(struct scst_device *dev, char **prev,
|
||||
const char *fmt, ...) __printf(3, 4);
|
||||
|
||||
int scst_pr_init_dev(struct scst_device *dev);
|
||||
void scst_pr_clear_dev(struct scst_device *dev);
|
||||
|
||||
|
||||
@@ -335,6 +335,7 @@ void scst_free_tgt(struct scst_tgt *tgt);
|
||||
|
||||
int scst_alloc_device(gfp_t gfp_mask, struct scst_device **out_dev);
|
||||
void scst_free_device(struct scst_device *dev);
|
||||
bool scst_device_is_exported(struct scst_device *dev);
|
||||
|
||||
struct scst_acg *scst_alloc_add_acg(struct scst_tgt *tgt,
|
||||
const char *acg_name, bool tgt_acg);
|
||||
|
||||
@@ -2756,6 +2756,135 @@ static ssize_t scst_dev_sysfs_type_show(struct kobject *kobj,
|
||||
static struct kobj_attribute dev_type_attr =
|
||||
__ATTR(type, S_IRUGO, scst_dev_sysfs_type_show, NULL);
|
||||
|
||||
static ssize_t scst_dev_sysfs_pr_file_name_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct scst_device *dev;
|
||||
int res;
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_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" :
|
||||
"");
|
||||
mutex_unlock(&dev->dev_pr_mutex);
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
scst_dev_sysfs_pr_file_name_process_store(struct scst_sysfs_work_item *work)
|
||||
{
|
||||
struct scst_device *dev = work->dev;
|
||||
char *pr_file_name = work->buf, *prev = NULL;
|
||||
int res;
|
||||
|
||||
res = mutex_lock_interruptible(&scst_mutex);
|
||||
if (res != 0)
|
||||
goto out;
|
||||
|
||||
res = -EBUSY;
|
||||
if (scst_device_is_exported(dev)) {
|
||||
PRINT_ERROR("%s: not changing pr_file_name because the device"
|
||||
" has already been exported", dev->virt_name);
|
||||
goto unlock_scst;
|
||||
}
|
||||
|
||||
res = mutex_lock_interruptible(&dev->dev_pr_mutex);
|
||||
if (res)
|
||||
goto unlock_scst;
|
||||
|
||||
if (strcmp(dev->pr_file_name, pr_file_name) == 0)
|
||||
goto unlock_dev_pr;
|
||||
|
||||
res = scst_pr_set_file_name(dev, &prev, "%s", pr_file_name);
|
||||
if (res != 0)
|
||||
goto unlock_dev_pr;
|
||||
|
||||
res = scst_pr_init_dev(dev);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("%s: loading PR from %s failed (%d) - restoring %s",
|
||||
dev->virt_name, dev->pr_file_name, res,
|
||||
prev ? : "");
|
||||
scst_pr_set_file_name(dev, NULL, "%s", prev);
|
||||
scst_pr_init_dev(dev);
|
||||
goto unlock_dev_pr;
|
||||
}
|
||||
|
||||
dev->pr_file_name_is_set = !work->default_val;
|
||||
|
||||
unlock_dev_pr:
|
||||
mutex_unlock(&dev->dev_pr_mutex);
|
||||
|
||||
unlock_scst:
|
||||
mutex_unlock(&scst_mutex);
|
||||
|
||||
out:
|
||||
kobject_put(&dev->dev_kobj);
|
||||
kfree(prev);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t scst_dev_sysfs_pr_file_name_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct scst_sysfs_work_item *work;
|
||||
struct scst_device *dev;
|
||||
char *pr_file_name, *p;
|
||||
int res = -ENOMEM;
|
||||
bool def = false;
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
|
||||
pr_file_name = kasprintf(GFP_KERNEL, "%.*s", (int)count, buf);
|
||||
if (!pr_file_name) {
|
||||
PRINT_ERROR("Unable to kasprintf() PR file name");
|
||||
goto out;
|
||||
}
|
||||
p = pr_file_name;
|
||||
strsep(&p, "\n"); /* strip trailing whitespace */
|
||||
if (pr_file_name[0] == '\0') {
|
||||
kfree(pr_file_name);
|
||||
pr_file_name = kasprintf(GFP_KERNEL, "%s/%s", SCST_PR_DIR,
|
||||
dev->virt_name);
|
||||
if (!pr_file_name) {
|
||||
PRINT_ERROR("Unable to kasprintf() PR file name");
|
||||
goto out;
|
||||
}
|
||||
def = true;
|
||||
}
|
||||
|
||||
res = scst_alloc_sysfs_work(scst_dev_sysfs_pr_file_name_process_store,
|
||||
false, &work);
|
||||
if (res != 0)
|
||||
goto out;
|
||||
kobject_get(&dev->dev_kobj);
|
||||
work->dev = dev;
|
||||
work->default_val = def;
|
||||
swap(work->buf, pr_file_name);
|
||||
|
||||
res = scst_sysfs_queue_wait_work(work);
|
||||
if (res == 0)
|
||||
res = count;
|
||||
|
||||
out:
|
||||
kfree(pr_file_name);
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct kobj_attribute dev_pr_file_name_attr =
|
||||
__ATTR(pr_file_name, S_IWUSR|S_IRUGO,
|
||||
scst_dev_sysfs_pr_file_name_show,
|
||||
scst_dev_sysfs_pr_file_name_store);
|
||||
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
|
||||
static ssize_t scst_dev_sysfs_dump_prs(struct kobject *kobj,
|
||||
@@ -3205,6 +3334,15 @@ int scst_dev_sysfs_create(struct scst_device *dev)
|
||||
dev->virt_name);
|
||||
goto out_del;
|
||||
}
|
||||
} else {
|
||||
res = sysfs_create_file(&dev->dev_kobj,
|
||||
&dev_pr_file_name_attr.attr);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Can't create attr %s for dev %s",
|
||||
dev_pr_file_name_attr.attr.name,
|
||||
dev->virt_name);
|
||||
goto out_del;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
|
||||
Reference in New Issue
Block a user