Skip to content

Commit e9c787e

Browse files
Christoph Hellwigaxboe
authored andcommitted
scsi: allocate scsi_cmnd structures as part of struct request
Rely on the new block layer functionality to allocate additional driver specific data behind struct request instead of implementing it in SCSI itѕelf. Signed-off-by: Christoph Hellwig <hch@lst.de> Acked-by: Martin K. Petersen <martin.petersen@oracle.com> Reviewed-by: Hannes Reinecke <hare@suse.com> Signed-off-by: Jens Axboe <axboe@fb.com>
1 parent d48777a commit e9c787e

File tree

6 files changed

+95
-394
lines changed

6 files changed

+95
-394
lines changed

drivers/scsi/hosts.c

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -230,19 +230,6 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
230230
}
231231
}
232232

233-
/*
234-
* Note that we allocate the freelist even for the MQ case for now,
235-
* as we need a command set aside for scsi_reset_provider. Having
236-
* the full host freelist and one command available for that is a
237-
* little heavy-handed, but avoids introducing a special allocator
238-
* just for this. Eventually the structure of scsi_reset_provider
239-
* will need a major overhaul.
240-
*/
241-
error = scsi_setup_command_freelist(shost);
242-
if (error)
243-
goto out_destroy_tags;
244-
245-
246233
if (!shost->shost_gendev.parent)
247234
shost->shost_gendev.parent = dev ? dev : &platform_bus;
248235
if (!dma_dev)
@@ -262,7 +249,7 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
262249

263250
error = device_add(&shost->shost_gendev);
264251
if (error)
265-
goto out_destroy_freelist;
252+
goto out_disable_runtime_pm;
266253

267254
scsi_host_set_state(shost, SHOST_RUNNING);
268255
get_device(shost->shost_gendev.parent);
@@ -312,13 +299,11 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
312299
device_del(&shost->shost_dev);
313300
out_del_gendev:
314301
device_del(&shost->shost_gendev);
315-
out_destroy_freelist:
302+
out_disable_runtime_pm:
316303
device_disable_async_suspend(&shost->shost_gendev);
317304
pm_runtime_disable(&shost->shost_gendev);
318305
pm_runtime_set_suspended(&shost->shost_gendev);
319306
pm_runtime_put_noidle(&shost->shost_gendev);
320-
scsi_destroy_command_freelist(shost);
321-
out_destroy_tags:
322307
if (shost_use_blk_mq(shost))
323308
scsi_mq_destroy_tags(shost);
324309
fail:
@@ -359,7 +344,6 @@ static void scsi_host_dev_release(struct device *dev)
359344
kfree(dev_name(&shost->shost_dev));
360345
}
361346

362-
scsi_destroy_command_freelist(shost);
363347
if (shost_use_blk_mq(shost)) {
364348
if (shost->tag_set.tags)
365349
scsi_mq_destroy_tags(shost);

drivers/scsi/scsi.c

Lines changed: 0 additions & 319 deletions
Original file line numberDiff line numberDiff line change
@@ -98,163 +98,6 @@ EXPORT_SYMBOL(scsi_sd_probe_domain);
9898
ASYNC_DOMAIN_EXCLUSIVE(scsi_sd_pm_domain);
9999
EXPORT_SYMBOL(scsi_sd_pm_domain);
100100

101-
struct scsi_host_cmd_pool {
102-
struct kmem_cache *cmd_slab;
103-
unsigned int users;
104-
char *cmd_name;
105-
};
106-
107-
static struct scsi_host_cmd_pool scsi_cmd_pool = {
108-
.cmd_name = "scsi_cmd_cache",
109-
};
110-
111-
static DEFINE_MUTEX(host_cmd_pool_mutex);
112-
113-
/**
114-
* scsi_host_free_command - internal function to release a command
115-
* @shost: host to free the command for
116-
* @cmd: command to release
117-
*
118-
* the command must previously have been allocated by
119-
* scsi_host_alloc_command.
120-
*/
121-
static void
122-
scsi_host_free_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
123-
{
124-
struct scsi_host_cmd_pool *pool = shost->cmd_pool;
125-
126-
if (cmd->prot_sdb)
127-
kmem_cache_free(scsi_sdb_cache, cmd->prot_sdb);
128-
scsi_free_sense_buffer(shost, cmd->sense_buffer);
129-
kmem_cache_free(pool->cmd_slab, cmd);
130-
}
131-
132-
/**
133-
* scsi_host_alloc_command - internal function to allocate command
134-
* @shost: SCSI host whose pool to allocate from
135-
* @gfp_mask: mask for the allocation
136-
*
137-
* Returns a fully allocated command with sense buffer and protection
138-
* data buffer (where applicable) or NULL on failure
139-
*/
140-
static struct scsi_cmnd *
141-
scsi_host_alloc_command(struct Scsi_Host *shost, gfp_t gfp_mask)
142-
{
143-
struct scsi_host_cmd_pool *pool = shost->cmd_pool;
144-
struct scsi_cmnd *cmd;
145-
146-
cmd = kmem_cache_zalloc(pool->cmd_slab, gfp_mask);
147-
if (!cmd)
148-
goto fail;
149-
150-
cmd->sense_buffer = scsi_alloc_sense_buffer(shost, gfp_mask,
151-
NUMA_NO_NODE);
152-
if (!cmd->sense_buffer)
153-
goto fail_free_cmd;
154-
155-
if (scsi_host_get_prot(shost) >= SHOST_DIX_TYPE0_PROTECTION) {
156-
cmd->prot_sdb = kmem_cache_zalloc(scsi_sdb_cache, gfp_mask);
157-
if (!cmd->prot_sdb)
158-
goto fail_free_sense;
159-
}
160-
161-
return cmd;
162-
163-
fail_free_sense:
164-
scsi_free_sense_buffer(shost, cmd->sense_buffer);
165-
fail_free_cmd:
166-
kmem_cache_free(pool->cmd_slab, cmd);
167-
fail:
168-
return NULL;
169-
}
170-
171-
/**
172-
* __scsi_get_command - Allocate a struct scsi_cmnd
173-
* @shost: host to transmit command
174-
* @gfp_mask: allocation mask
175-
*
176-
* Description: allocate a struct scsi_cmd from host's slab, recycling from the
177-
* host's free_list if necessary.
178-
*/
179-
static struct scsi_cmnd *
180-
__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
181-
{
182-
struct scsi_cmnd *cmd = scsi_host_alloc_command(shost, gfp_mask);
183-
184-
if (unlikely(!cmd)) {
185-
unsigned long flags;
186-
187-
spin_lock_irqsave(&shost->free_list_lock, flags);
188-
if (likely(!list_empty(&shost->free_list))) {
189-
cmd = list_entry(shost->free_list.next,
190-
struct scsi_cmnd, list);
191-
list_del_init(&cmd->list);
192-
}
193-
spin_unlock_irqrestore(&shost->free_list_lock, flags);
194-
195-
if (cmd) {
196-
void *buf, *prot;
197-
198-
buf = cmd->sense_buffer;
199-
prot = cmd->prot_sdb;
200-
201-
memset(cmd, 0, sizeof(*cmd));
202-
203-
cmd->sense_buffer = buf;
204-
cmd->prot_sdb = prot;
205-
}
206-
}
207-
208-
return cmd;
209-
}
210-
211-
/**
212-
* scsi_get_command - Allocate and setup a scsi command block
213-
* @dev: parent scsi device
214-
* @gfp_mask: allocator flags
215-
*
216-
* Returns: The allocated scsi command structure.
217-
*/
218-
struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
219-
{
220-
struct scsi_cmnd *cmd = __scsi_get_command(dev->host, gfp_mask);
221-
unsigned long flags;
222-
223-
if (unlikely(cmd == NULL))
224-
return NULL;
225-
226-
cmd->device = dev;
227-
INIT_LIST_HEAD(&cmd->list);
228-
INIT_DELAYED_WORK(&cmd->abort_work, scmd_eh_abort_handler);
229-
spin_lock_irqsave(&dev->list_lock, flags);
230-
list_add_tail(&cmd->list, &dev->cmd_list);
231-
spin_unlock_irqrestore(&dev->list_lock, flags);
232-
cmd->jiffies_at_alloc = jiffies;
233-
return cmd;
234-
}
235-
236-
/**
237-
* __scsi_put_command - Free a struct scsi_cmnd
238-
* @shost: dev->host
239-
* @cmd: Command to free
240-
*/
241-
static void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
242-
{
243-
unsigned long flags;
244-
245-
if (unlikely(list_empty(&shost->free_list))) {
246-
spin_lock_irqsave(&shost->free_list_lock, flags);
247-
if (list_empty(&shost->free_list)) {
248-
list_add(&cmd->list, &shost->free_list);
249-
cmd = NULL;
250-
}
251-
spin_unlock_irqrestore(&shost->free_list_lock, flags);
252-
}
253-
254-
if (likely(cmd != NULL))
255-
scsi_host_free_command(shost, cmd);
256-
}
257-
258101
/**
259102
* scsi_put_command - Free a scsi command block
260103
* @cmd: command block to free
@@ -274,168 +117,6 @@ void scsi_put_command(struct scsi_cmnd *cmd)
274117
spin_unlock_irqrestore(&cmd->device->list_lock, flags);
275118

276119
BUG_ON(delayed_work_pending(&cmd->abort_work));
277-
278-
__scsi_put_command(cmd->device->host, cmd);
279-
}
280-
281-
static struct scsi_host_cmd_pool *
282-
scsi_find_host_cmd_pool(struct Scsi_Host *shost)
283-
{
284-
if (shost->hostt->cmd_size)
285-
return shost->hostt->cmd_pool;
286-
return &scsi_cmd_pool;
287-
}
288-
289-
static void
290-
scsi_free_host_cmd_pool(struct scsi_host_cmd_pool *pool)
291-
{
292-
kfree(pool->cmd_name);
293-
kfree(pool);
294-
}
295-
296-
static struct scsi_host_cmd_pool *
297-
scsi_alloc_host_cmd_pool(struct Scsi_Host *shost)
298-
{
299-
struct scsi_host_template *hostt = shost->hostt;
300-
struct scsi_host_cmd_pool *pool;
301-
302-
pool = kzalloc(sizeof(*pool), GFP_KERNEL);
303-
if (!pool)
304-
return NULL;
305-
306-
pool->cmd_name = kasprintf(GFP_KERNEL, "%s_cmd", hostt->proc_name);
307-
if (!pool->cmd_name) {
308-
scsi_free_host_cmd_pool(pool);
309-
return NULL;
310-
}
311-
312-
if (hostt->cmd_size)
313-
hostt->cmd_pool = pool;
314-
315-
return pool;
316-
}
317-
318-
static struct scsi_host_cmd_pool *
319-
scsi_get_host_cmd_pool(struct Scsi_Host *shost)
320-
{
321-
struct scsi_host_template *hostt = shost->hostt;
322-
struct scsi_host_cmd_pool *retval = NULL, *pool;
323-
size_t cmd_size = sizeof(struct scsi_cmnd) + hostt->cmd_size;
324-
325-
/*
326-
* Select a command slab for this host and create it if not
327-
* yet existent.
328-
*/
329-
mutex_lock(&host_cmd_pool_mutex);
330-
pool = scsi_find_host_cmd_pool(shost);
331-
if (!pool) {
332-
pool = scsi_alloc_host_cmd_pool(shost);
333-
if (!pool)
334-
goto out;
335-
}
336-
337-
if (!pool->users) {
338-
pool->cmd_slab = kmem_cache_create(pool->cmd_name, cmd_size, 0,
339-
SLAB_HWCACHE_ALIGN, NULL);
340-
if (!pool->cmd_slab)
341-
goto out_free_pool;
342-
}
343-
344-
pool->users++;
345-
retval = pool;
346-
out:
347-
mutex_unlock(&host_cmd_pool_mutex);
348-
return retval;
349-
350-
out_free_pool:
351-
if (hostt->cmd_size) {
352-
scsi_free_host_cmd_pool(pool);
353-
hostt->cmd_pool = NULL;
354-
}
355-
goto out;
356-
}
357-
358-
static void scsi_put_host_cmd_pool(struct Scsi_Host *shost)
359-
{
360-
struct scsi_host_template *hostt = shost->hostt;
361-
struct scsi_host_cmd_pool *pool;
362-
363-
mutex_lock(&host_cmd_pool_mutex);
364-
pool = scsi_find_host_cmd_pool(shost);
365-
366-
/*
367-
* This may happen if a driver has a mismatched get and put
368-
* of the command pool; the driver should be implicated in
369-
* the stack trace
370-
*/
371-
BUG_ON(pool->users == 0);
372-
373-
if (!--pool->users) {
374-
kmem_cache_destroy(pool->cmd_slab);
375-
if (hostt->cmd_size) {
376-
scsi_free_host_cmd_pool(pool);
377-
hostt->cmd_pool = NULL;
378-
}
379-
}
380-
mutex_unlock(&host_cmd_pool_mutex);
381-
}
382-
383-
/**
384-
* scsi_setup_command_freelist - Setup the command freelist for a scsi host.
385-
* @shost: host to allocate the freelist for.
386-
*
387-
* Description: The command freelist protects against system-wide out of memory
388-
* deadlock by preallocating one SCSI command structure for each host, so the
389-
* system can always write to a swap file on a device associated with that host.
390-
*
391-
* Returns: Nothing.
392-
*/
393-
int scsi_setup_command_freelist(struct Scsi_Host *shost)
394-
{
395-
struct scsi_cmnd *cmd;
396-
397-
spin_lock_init(&shost->free_list_lock);
398-
INIT_LIST_HEAD(&shost->free_list);
399-
400-
shost->cmd_pool = scsi_get_host_cmd_pool(shost);
401-
if (!shost->cmd_pool)
402-
return -ENOMEM;
403-
404-
/*
405-
* Get one backup command for this host.
406-
*/
407-
cmd = scsi_host_alloc_command(shost, GFP_KERNEL);
408-
if (!cmd) {
409-
scsi_put_host_cmd_pool(shost);
410-
shost->cmd_pool = NULL;
411-
return -ENOMEM;
412-
}
413-
list_add(&cmd->list, &shost->free_list);
414-
return 0;
415-
}
416-
417-
/**
418-
* scsi_destroy_command_freelist - Release the command freelist for a scsi host.
419-
* @shost: host whose freelist is going to be destroyed
420-
*/
421-
void scsi_destroy_command_freelist(struct Scsi_Host *shost)
422-
{
423-
/*
424-
* If cmd_pool is NULL the free list was not initialized, so
425-
* do not attempt to release resources.
426-
*/
427-
if (!shost->cmd_pool)
428-
return;
429-
430-
while (!list_empty(&shost->free_list)) {
431-
struct scsi_cmnd *cmd;
432-
433-
cmd = list_entry(shost->free_list.next, struct scsi_cmnd, list);
434-
list_del_init(&cmd->list);
435-
scsi_host_free_command(shost, cmd);
436-
}
437-
shost->cmd_pool = NULL;
438-
scsi_put_host_cmd_pool(shost);
439120
}
440121

441122
#ifdef CONFIG_SCSI_LOGGING

0 commit comments

Comments
 (0)