diff --git a/scst/include/scst.h b/scst/include/scst.h index bb566b720..efe2bf5ec 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -1947,14 +1947,6 @@ struct scst_cmd { /* Set if cmd is queued as hw pending */ unsigned int cmd_hw_pending:1; - /* - * Set, if for this cmd required to not have any IO or FS calls on - * memory buffers allocations, at least for READ and WRITE commands. - * Needed for cases like file systems mounted over scst_local's - * devices. - */ - unsigned noio_mem_alloc: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 @@ -2039,6 +2031,15 @@ struct scst_cmd { /* cmd's async flags */ unsigned long cmd_flags; + /* + * GFP mask with which memory on READ or WRITE data path for this cmd + * should be allocated, if the current context is not ATOMIC. Useful + * for cases like if this cmd required to not have any IO or FS calls + * on allocations, like for file systems mounted over scst_local's + * devices. + */ + gfp_t cmd_gfp_mask; + /* Keeps status of cmd's status/data delivery to remote initiator */ int delivery_status; @@ -2569,8 +2570,16 @@ struct scst_tgt_dev { struct scst_device *dev; /* to save extra dereferences */ uint64_t lun; /* to save extra dereferences */ - gfp_t gfp_mask; + /* + * Extra flags in GFP mask for data buffers allocations of this + * tgt_dev's cmds + */ + gfp_t tgt_dev_gfp_mask; + + /* SGV pool from which buffers of this tgt_dev's cmds should be allocated */ struct sgv_pool *pool; + + /* Max number of allowed in this tgt_dev SG segments */ int max_sg_cnt; /************************************************************* @@ -3545,16 +3554,13 @@ static inline void scst_cmd_set_tgt_sn(struct scst_cmd *cmd, uint32_t tgt_sn) } /* - * Get/Set functions for noio_mem_alloc + * Forbids for this cmd any IO-causing allocations. + * + * !! Must be called before scst_cmd_init_done() !! */ -static inline bool scst_cmd_get_noio_mem_alloc(struct scst_cmd *cmd) -{ - return cmd->noio_mem_alloc; -} - static inline void scst_cmd_set_noio_mem_alloc(struct scst_cmd *cmd) { - cmd->noio_mem_alloc = 1; + cmd->cmd_gfp_mask = GFP_NOIO; } /* @@ -4082,9 +4088,9 @@ int scst_get_buf_full(struct scst_cmd *cmd, uint8_t **buf); int scst_get_buf_full_sense(struct scst_cmd *cmd, uint8_t **buf); void scst_put_buf_full(struct scst_cmd *cmd, uint8_t *buf); -static inline gfp_t scst_cmd_get_gfp_flags(struct scst_cmd *cmd) +static inline gfp_t scst_cmd_get_gfp_mask(struct scst_cmd *cmd) { - return cmd->noio_mem_alloc ? GFP_NOIO : GFP_KERNEL; + return cmd->cmd_gfp_mask; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) && !defined(BACKPORT_LINUX_WORKQUEUE_TO_2_6_19) diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 5bb919a15..b96707b67 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -1034,14 +1034,12 @@ static enum compl_status_e vdisk_synchronize_cache(struct vdisk_cmd_params *p) cmd->completed = 1; cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME); - vdisk_fsync(p, loff, data_len, dev, - scst_cmd_get_gfp_flags(cmd), NULL, true); + vdisk_fsync(p, loff, data_len, dev, cmd->cmd_gfp_mask, NULL, true); /* ToDo: vdisk_fsync() error processing */ scst_cmd_put(cmd); res = RUNNING_ASYNC; } else { - vdisk_fsync(p, loff, data_len, dev, - scst_cmd_get_gfp_flags(cmd), cmd, true); + vdisk_fsync(p, loff, data_len, dev, cmd->cmd_gfp_mask, cmd, true); res = RUNNING_ASYNC; } @@ -1057,8 +1055,7 @@ static enum compl_status_e vdisk_exec_start_stop(struct vdisk_cmd_params *p) TRACE_ENTRY(); - vdisk_fsync(p, 0, virt_dev->file_size, dev, scst_cmd_get_gfp_flags(cmd), - cmd, false); + vdisk_fsync(p, 0, virt_dev->file_size, dev, cmd->cmd_gfp_mask, cmd, false); TRACE_EXIT(); return CMD_SUCCEEDED; @@ -1472,7 +1469,7 @@ static int fileio_alloc_and_parse(struct scst_cmd *cmd) TRACE_ENTRY(); - p = kmem_cache_zalloc(vdisk_cmd_param_cachep, GFP_KERNEL); + p = kmem_cache_zalloc(vdisk_cmd_param_cachep, cmd->cmd_gfp_mask); if (!p) { scst_set_busy(cmd); goto out_err; @@ -2136,7 +2133,7 @@ static int vdisk_unmap_range(struct scst_cmd *cmd, if (virt_dev->blockio) { #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27) struct inode *inode = fd->f_dentry->d_inode; - gfp_t gfp = scst_cmd_get_gfp_flags(cmd); + gfp_t gfp = cmd->cmd_gfp_mask; #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31) err = blkdev_issue_discard(inode->i_bdev, start_lba, blocks, gfp); #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) \ @@ -2373,7 +2370,7 @@ static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p) TRACE_ENTRY(); - buf = kzalloc(INQ_BUF_SZ, GFP_KERNEL); + buf = kzalloc(INQ_BUF_SZ, cmd->cmd_gfp_mask); if (buf == NULL) { scst_set_busy(cmd); goto out; @@ -2934,7 +2931,7 @@ static enum compl_status_e vdisk_exec_mode_sense(struct vdisk_cmd_params *p) TRACE_ENTRY(); - buf = kzalloc(MSENSE_BUF_SZ, GFP_KERNEL); + buf = kzalloc(MSENSE_BUF_SZ, cmd->cmd_gfp_mask); if (buf == NULL) { scst_set_busy(cmd); goto out; @@ -3651,7 +3648,7 @@ static struct iovec *vdisk_alloc_iv(struct scst_cmd *cmd, p->iv_count = 0; /* It can't be called in atomic context */ p->iv = (iv_count <= ARRAY_SIZE(p->small_iv)) ? p->small_iv : - kmalloc(sizeof(*p->iv) * iv_count, GFP_KERNEL); + kmalloc(sizeof(*p->iv) * iv_count, cmd->cmd_gfp_mask); if (p->iv == NULL) { PRINT_ERROR("Unable to allocate iv (%d)", iv_count); goto out; @@ -3924,7 +3921,7 @@ out_sync: /* O_DSYNC flag is used for WT devices */ if (p->fua) vdisk_fsync(p, loff, scst_cmd_get_data_len(cmd), cmd->dev, - scst_cmd_get_gfp_flags(cmd), cmd, false); + cmd->cmd_gfp_mask, cmd, false); out: TRACE_EXIT(); return CMD_SUCCEEDED; @@ -4027,7 +4024,7 @@ static void blockio_exec_rw(struct vdisk_cmd_params *p, bool write, bool fua) int need_new_bio; struct scst_blockio_work *blockio_work; int bios = 0; - gfp_t gfp_mask = scst_cmd_get_gfp_flags(cmd); + gfp_t gfp_mask = cmd->cmd_gfp_mask; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) struct blk_plug plug; #endif @@ -4244,7 +4241,7 @@ static int vdisk_blockio_flush(struct block_device *bdev, gfp_t gfp_mask, #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) if (async) { - struct bio *bio = bio_alloc(GFP_KERNEL, 0); + struct bio *bio = bio_alloc(gfp_mask, 0); if (bio == NULL) { res = -ENOMEM; goto out_rep; @@ -4308,7 +4305,7 @@ static enum compl_status_e fileio_exec_verify(struct vdisk_cmd_params *p) sBUG_ON(virt_dev->blockio); if (vdisk_fsync(p, loff, data_len, cmd->dev, - scst_cmd_get_gfp_flags(cmd), cmd, false) != 0) + cmd->cmd_gfp_mask, cmd, false) != 0) goto out; /* diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 14c7558ab..9cbe8c743 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -1343,7 +1343,7 @@ static inline void tm_dbg_deinit_tgt_dev(struct scst_tgt_dev *tgt_dev) {} int scst_alloc_sense(struct scst_cmd *cmd, int atomic) { int res = 0; - gfp_t gfp_mask = atomic ? GFP_ATOMIC : (GFP_KERNEL|__GFP_NOFAIL); + gfp_t gfp_mask = atomic ? GFP_ATOMIC : (cmd->cmd_gfp_mask|__GFP_NOFAIL); TRACE_ENTRY(); @@ -4482,7 +4482,7 @@ static struct scst_cmd *scst_create_prepare_internal_cmd( { struct scst_cmd *res; int rc; - gfp_t gfp_mask = scst_cmd_atomic(orig_cmd) ? GFP_ATOMIC : GFP_KERNEL; + gfp_t gfp_mask = scst_cmd_atomic(orig_cmd) ? GFP_ATOMIC : orig_cmd->cmd_gfp_mask; unsigned long flags; TRACE_ENTRY(); @@ -5318,6 +5318,7 @@ int scst_pre_init_cmd(struct scst_cmd *cmd, const uint8_t *cdb, cmd->start_time = jiffies; atomic_set(&cmd->cmd_ref, 1); cmd->cmd_threads = &scst_main_cmd_threads; + cmd->cmd_gfp_mask = GFP_KERNEL; INIT_LIST_HEAD(&cmd->mgmt_cmd_list); cmd->cdb = cmd->cdb_buf; cmd->queue_type = SCST_CMD_QUEUE_SIMPLE; @@ -5652,7 +5653,7 @@ int scst_alloc_space(struct scst_cmd *cmd) TRACE_ENTRY(); - gfp_mask = tgt_dev->gfp_mask | (atomic ? GFP_ATOMIC : GFP_KERNEL); + gfp_mask = tgt_dev->tgt_dev_gfp_mask | (atomic ? GFP_ATOMIC : cmd->cmd_gfp_mask); flags = atomic ? SGV_POOL_NO_ALLOC_ON_CACHE_MISS : 0; if (cmd->no_sgv) @@ -5933,7 +5934,7 @@ int scst_scsi_exec_async(struct scst_cmd *cmd, void *data, struct request *rq; struct scsi_io_context *sioc; int write = (cmd->data_direction & SCST_DATA_WRITE) ? WRITE : READ; - gfp_t gfp = scst_cmd_get_gfp_flags(cmd); + gfp_t gfp = cmd->cmd_gfp_mask; int cmd_len = cmd->cdb_len; sioc = kmem_cache_zalloc(scsi_io_context_cache, gfp); diff --git a/scst/src/scst_mem.c b/scst/src/scst_mem.c index 46e51185f..3b5dba47b 100644 --- a/scst/src/scst_mem.c +++ b/scst/src/scst_mem.c @@ -98,7 +98,7 @@ static inline bool sgv_pool_clustered(const struct sgv_pool *pool) void scst_sgv_pool_use_norm(struct scst_tgt_dev *tgt_dev) { - tgt_dev->gfp_mask = __GFP_NOWARN; + tgt_dev->tgt_dev_gfp_mask = __GFP_NOWARN; tgt_dev->pool = sgv_norm_pool; tgt_dev->tgt_dev_clust_pool = 0; } @@ -106,7 +106,7 @@ void scst_sgv_pool_use_norm(struct scst_tgt_dev *tgt_dev) void scst_sgv_pool_use_norm_clust(struct scst_tgt_dev *tgt_dev) { TRACE_MEM("%s", "Use clustering"); - tgt_dev->gfp_mask = __GFP_NOWARN; + tgt_dev->tgt_dev_gfp_mask = __GFP_NOWARN; tgt_dev->pool = sgv_norm_clust_pool; tgt_dev->tgt_dev_clust_pool = 1; } @@ -114,7 +114,7 @@ void scst_sgv_pool_use_norm_clust(struct scst_tgt_dev *tgt_dev) void scst_sgv_pool_use_dma(struct scst_tgt_dev *tgt_dev) { TRACE_MEM("%s", "Use ISA DMA memory"); - tgt_dev->gfp_mask = __GFP_NOWARN | GFP_DMA; + tgt_dev->tgt_dev_gfp_mask = __GFP_NOWARN | GFP_DMA; tgt_dev->pool = sgv_dma_pool; tgt_dev->tgt_dev_clust_pool = 0; } diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 7a2c2fcb7..8c447e256 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -226,7 +226,7 @@ int scst_rx_cmd_prealloced(struct scst_cmd *cmd, struct scst_session *sess, unsigned int cdb_len, bool atomic) { int res; - gfp_t gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL; + gfp_t gfp_mask = atomic ? GFP_ATOMIC : cmd->cmd_gfp_mask; TRACE_ENTRY(); @@ -273,7 +273,7 @@ struct scst_cmd *scst_rx_cmd(struct scst_session *sess, unsigned int cdb_len, bool atomic) { struct scst_cmd *cmd; - gfp_t gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL; + gfp_t gfp_mask = atomic ? GFP_ATOMIC : GFP_NOIO; TRACE_ENTRY(); @@ -2708,7 +2708,7 @@ static int scst_do_real_exec(struct scst_cmd *cmd) rc = scst_exec_req(scsi_dev, cmd->cdb, cmd->cdb_len, cmd->data_direction, cmd->sg, cmd->bufflen, cmd->sg_cnt, cmd->timeout, cmd->retries, cmd, - scst_pass_through_cmd_done, GFP_KERNEL); + scst_pass_through_cmd_done, cmd->cmd_gfp_mask); #else rc = scst_scsi_exec_async(cmd, cmd, scst_pass_through_cmd_done); #endif