aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew R. Ochs <mrochs@linux.vnet.ibm.com>2015-10-21 16:15:37 -0400
committerJames Bottomley <JBottomley@Odin.com>2015-10-30 04:20:00 -0400
commit17ead26f23e99ab0bb14e0876adab0ee151711f7 (patch)
treee29414217e9c7a9d700ce095e3ca2dae1aadfcec
parentb22b4037a013e9ce77cec79d95fdcdc9bece0955 (diff)
cxlflash: Fix to avoid corrupting adapter fops
The fops owned by the adapter can be corrupted in certain scenarios, opening a window where certain fops are temporarily NULLed before being reset to their proper value. This can potentially lead software to make incorrect decisions, leaving the user with the inability to function as intended. An example of this behavior can be observed when there are a number of users with a high rate of turn around (attach to LUN, perform an I/O, detach from LUN, repeat). Every so often a user is given a valid context and adapter file descriptor, but the file associated with the descriptor lacks the correct read permission bit (FMODE_CAN_READ) and thus the read system call bails before calling the valid read fop. Background: The fops is stored in the adapter structure to provide the ability to lookup the adapter structure from within the fop handler. CXL services use the file's private_data and at present, the CXL context does not have a private section. In an effort to limit areas of the cxlflash driver with code specific the superpipe function, a design choice was made to keep the details of the fops situated away from the legacy portions of the driver. This drove the behavior that the adapter fops is set at the beginning of the disk attach ioctl handler when there are no users present. The corruption that this fix remedies is due to the fact that the fops is initially defaulted to values found within a static structure. When the fops is handed down to the CXL services later in the attach path, certain services are patched. The fops structure remains correct until the user count drops to 0 and the fops is reset, triggering the process to repeat again. The user counts are tightly coupled with the creation and deletion of the user context. If multiple users perform a disk attach at the same time, when the user count is currently 0, some users can be in the middle of obtaining a file descriptor and have not yet reached the context creation code that [in addition to creating the context] increments the user count. Subsequent users coming in to perform the attach see that the user count is still 0, and reinitialize the fops, temporarily removing the patched fops. The users that are in the middle obtaining their file descriptor may then receive an invalid descriptor. The fix simply removes the user count altogether and moves the fops initialization to probe time such that it is only performed one time for the life of the adapter. In the future, if the CXL services adopt a private member for their context, that could be used to store the adapter structure reference and cxlflash could revert to a model that does not require an embedded fops. Signed-off-by: Matthew R. Ochs <mrochs@linux.vnet.ibm.com> Signed-off-by: Manoj N. Kumar <manoj@linux.vnet.ibm.com> Reviewed-by: Brian King <brking@linux.vnet.ibm.com> Reviewed-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com> Reviewed-by: Daniel Axtens <dja@axtens.net> Reviewed-by: Tomas Henzl <thenzl@redhat.com> Signed-off-by: James Bottomley <JBottomley@Odin.com>
-rw-r--r--drivers/scsi/cxlflash/common.h3
-rw-r--r--drivers/scsi/cxlflash/main.c1
-rw-r--r--drivers/scsi/cxlflash/superpipe.c11
3 files changed, 3 insertions, 12 deletions
diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h
index bbfe711826c3..c11cd193f896 100644
--- a/drivers/scsi/cxlflash/common.h
+++ b/drivers/scsi/cxlflash/common.h
@@ -21,6 +21,7 @@
21#include <scsi/scsi.h> 21#include <scsi/scsi.h>
22#include <scsi/scsi_device.h> 22#include <scsi/scsi_device.h>
23 23
24extern const struct file_operations cxlflash_cxl_fops;
24 25
25#define MAX_CONTEXT CXLFLASH_MAX_CONTEXT /* num contexts per afu */ 26#define MAX_CONTEXT CXLFLASH_MAX_CONTEXT /* num contexts per afu */
26 27
@@ -115,8 +116,6 @@ struct cxlflash_cfg {
115 struct list_head ctx_err_recovery; /* contexts w/ recovery pending */ 116 struct list_head ctx_err_recovery; /* contexts w/ recovery pending */
116 struct file_operations cxl_fops; 117 struct file_operations cxl_fops;
117 118
118 atomic_t num_user_contexts;
119
120 /* Parameters that are LUN table related */ 119 /* Parameters that are LUN table related */
121 int last_lun_index[CXLFLASH_NUM_FC_PORTS]; 120 int last_lun_index[CXLFLASH_NUM_FC_PORTS];
122 int promote_lun_index; 121 int promote_lun_index;
diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c
index 51883bef8444..3f4387957e23 100644
--- a/drivers/scsi/cxlflash/main.c
+++ b/drivers/scsi/cxlflash/main.c
@@ -2386,6 +2386,7 @@ static int cxlflash_probe(struct pci_dev *pdev,
2386 2386
2387 cfg->init_state = INIT_STATE_NONE; 2387 cfg->init_state = INIT_STATE_NONE;
2388 cfg->dev = pdev; 2388 cfg->dev = pdev;
2389 cfg->cxl_fops = cxlflash_cxl_fops;
2389 2390
2390 /* 2391 /*
2391 * The promoted LUNs move to the top of the LUN table. The rest stay 2392 * The promoted LUNs move to the top of the LUN table. The rest stay
diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c
index b5eeeff0fd0c..34acb587d730 100644
--- a/drivers/scsi/cxlflash/superpipe.c
+++ b/drivers/scsi/cxlflash/superpipe.c
@@ -712,7 +712,6 @@ static void destroy_context(struct cxlflash_cfg *cfg,
712 kfree(ctxi->rht_needs_ws); 712 kfree(ctxi->rht_needs_ws);
713 kfree(ctxi->rht_lun); 713 kfree(ctxi->rht_lun);
714 kfree(ctxi); 714 kfree(ctxi);
715 atomic_dec_if_positive(&cfg->num_user_contexts);
716} 715}
717 716
718/** 717/**
@@ -769,7 +768,6 @@ static struct ctx_info *create_context(struct cxlflash_cfg *cfg,
769 INIT_LIST_HEAD(&ctxi->luns); 768 INIT_LIST_HEAD(&ctxi->luns);
770 INIT_LIST_HEAD(&ctxi->list); /* initialize for list_empty() */ 769 INIT_LIST_HEAD(&ctxi->list); /* initialize for list_empty() */
771 770
772 atomic_inc(&cfg->num_user_contexts);
773 mutex_lock(&ctxi->mutex); 771 mutex_lock(&ctxi->mutex);
774out: 772out:
775 return ctxi; 773 return ctxi;
@@ -1164,10 +1162,7 @@ out:
1164 return rc; 1162 return rc;
1165} 1163}
1166 1164
1167/* 1165const struct file_operations cxlflash_cxl_fops = {
1168 * Local fops for adapter file descriptor
1169 */
1170static const struct file_operations cxlflash_cxl_fops = {
1171 .owner = THIS_MODULE, 1166 .owner = THIS_MODULE,
1172 .mmap = cxlflash_cxl_mmap, 1167 .mmap = cxlflash_cxl_mmap,
1173 .release = cxlflash_cxl_release, 1168 .release = cxlflash_cxl_release,
@@ -1286,10 +1281,6 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
1286 1281
1287 int fd = -1; 1282 int fd = -1;
1288 1283
1289 /* On first attach set fileops */
1290 if (atomic_read(&cfg->num_user_contexts) == 0)
1291 cfg->cxl_fops = cxlflash_cxl_fops;
1292
1293 if (attach->num_interrupts > 4) { 1284 if (attach->num_interrupts > 4) {
1294 dev_dbg(dev, "%s: Cannot support this many interrupts %llu\n", 1285 dev_dbg(dev, "%s: Cannot support this many interrupts %llu\n",
1295 __func__, attach->num_interrupts); 1286 __func__, attach->num_interrupts);