From f161d4b44d7cc1dc66b53365215227db356378b1 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Wed, 11 Feb 2015 18:34:40 -0800 Subject: [PATCH] target: Fix PR_APTPL_BUF_LEN buffer size limitation This patch addresses the original PR_APTPL_BUF_LEN = 8k limitiation for write-out of PR APTPL metadata that Martin has recently been running into. It changes core_scsi3_update_and_write_aptpl() to use vzalloc'ed memory instead of kzalloc, and increases the default hardcoded length to 256k. It also adds logic in core_scsi3_update_and_write_aptpl() to double the original length upon core_scsi3_update_aptpl_buf() failure, and retries until the vzalloc'ed buffer is large enough to accommodate the outgoing APTPL metadata. Reported-by: Martin Svec Cc: stable@vger.kernel.org Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_pr.c | 25 +++++++++++++------------ include/target/target_core_base.h | 2 +- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index d56f2aaba9af..67fb3bf240cd 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -1862,8 +1862,8 @@ static int core_scsi3_update_aptpl_buf( } if ((len + strlen(tmp) >= pr_aptpl_buf_len)) { - pr_err("Unable to update renaming" - " APTPL metadata\n"); + pr_err("Unable to update renaming APTPL metadata," + " reallocating larger buffer\n"); ret = -EMSGSIZE; goto out; } @@ -1880,8 +1880,8 @@ static int core_scsi3_update_aptpl_buf( lun->lun_sep->sep_rtpi, lun->unpacked_lun, reg_count); if ((len + strlen(tmp) >= pr_aptpl_buf_len)) { - pr_err("Unable to update renaming" - " APTPL metadata\n"); + pr_err("Unable to update renaming APTPL metadata," + " reallocating larger buffer\n"); ret = -EMSGSIZE; goto out; } @@ -1944,7 +1944,7 @@ static int __core_scsi3_write_aptpl_to_file( static sense_reason_t core_scsi3_update_and_write_aptpl(struct se_device *dev, bool aptpl) { unsigned char *buf; - int rc; + int rc, len = PR_APTPL_BUF_LEN; if (!aptpl) { char *null_buf = "No Registrations or Reservations\n"; @@ -1958,25 +1958,26 @@ static sense_reason_t core_scsi3_update_and_write_aptpl(struct se_device *dev, b return 0; } - - buf = kzalloc(PR_APTPL_BUF_LEN, GFP_KERNEL); +retry: + buf = vzalloc(len); if (!buf) return TCM_OUT_OF_RESOURCES; - rc = core_scsi3_update_aptpl_buf(dev, buf, PR_APTPL_BUF_LEN); + rc = core_scsi3_update_aptpl_buf(dev, buf, len); if (rc < 0) { - kfree(buf); - return TCM_OUT_OF_RESOURCES; + vfree(buf); + len *= 2; + goto retry; } rc = __core_scsi3_write_aptpl_to_file(dev, buf); if (rc != 0) { pr_err("SPC-3 PR: Could not update APTPL\n"); - kfree(buf); + vfree(buf); return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } dev->t10_pr.pr_aptpl_active = 1; - kfree(buf); + vfree(buf); pr_debug("SPC-3 PR: Set APTPL Bit Activated\n"); return 0; } diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 397fb635766a..eec07656eb03 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -409,7 +409,7 @@ struct t10_reservation { /* Activate Persistence across Target Power Loss enabled * for SCSI device */ int pr_aptpl_active; -#define PR_APTPL_BUF_LEN 8192 +#define PR_APTPL_BUF_LEN 262144 u32 pr_generation; spinlock_t registration_lock; spinlock_t aptpl_reg_lock;