You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'ida-4.19' of git://git.infradead.org/users/willy/linux-dax
Pull IDA updates from Matthew Wilcox:
"A better IDA API:
id = ida_alloc(ida, GFP_xxx);
ida_free(ida, id);
rather than the cumbersome ida_simple_get(), ida_simple_remove().
The new IDA API is similar to ida_simple_get() but better named. The
internal restructuring of the IDA code removes the bitmap
preallocation nonsense.
I hope the net -200 lines of code is convincing"
* 'ida-4.19' of git://git.infradead.org/users/willy/linux-dax: (29 commits)
ida: Change ida_get_new_above to return the id
ida: Remove old API
test_ida: check_ida_destroy and check_ida_alloc
test_ida: Convert check_ida_conv to new API
test_ida: Move ida_check_max
test_ida: Move ida_check_leaf
idr-test: Convert ida_check_nomem to new API
ida: Start new test_ida module
target/iscsi: Allocate session IDs from an IDA
iscsi target: fix session creation failure handling
drm/vmwgfx: Convert to new IDA API
dmaengine: Convert to new IDA API
ppc: Convert vas ID allocation to new IDA API
media: Convert entity ID allocation to new IDA API
ppc: Convert mmu context allocation to new IDA API
Convert net_namespace to new IDA API
cb710: Convert to new IDA API
rsxx: Convert to new IDA API
osd: Convert to new IDA API
sd: Convert to new IDA API
...
This commit is contained in:
@@ -26,48 +26,16 @@
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/pgalloc.h>
|
||||
|
||||
static DEFINE_SPINLOCK(mmu_context_lock);
|
||||
static DEFINE_IDA(mmu_context_ida);
|
||||
|
||||
static int alloc_context_id(int min_id, int max_id)
|
||||
{
|
||||
int index, err;
|
||||
|
||||
again:
|
||||
if (!ida_pre_get(&mmu_context_ida, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock(&mmu_context_lock);
|
||||
err = ida_get_new_above(&mmu_context_ida, min_id, &index);
|
||||
spin_unlock(&mmu_context_lock);
|
||||
|
||||
if (err == -EAGAIN)
|
||||
goto again;
|
||||
else if (err)
|
||||
return err;
|
||||
|
||||
if (index > max_id) {
|
||||
spin_lock(&mmu_context_lock);
|
||||
ida_remove(&mmu_context_ida, index);
|
||||
spin_unlock(&mmu_context_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return index;
|
||||
return ida_alloc_range(&mmu_context_ida, min_id, max_id, GFP_KERNEL);
|
||||
}
|
||||
|
||||
void hash__reserve_context_id(int id)
|
||||
{
|
||||
int rc, result = 0;
|
||||
|
||||
do {
|
||||
if (!ida_pre_get(&mmu_context_ida, GFP_KERNEL))
|
||||
break;
|
||||
|
||||
spin_lock(&mmu_context_lock);
|
||||
rc = ida_get_new_above(&mmu_context_ida, id, &result);
|
||||
spin_unlock(&mmu_context_lock);
|
||||
} while (rc == -EAGAIN);
|
||||
int result = ida_alloc_range(&mmu_context_ida, id, id, GFP_KERNEL);
|
||||
|
||||
WARN(result != id, "mmu: Failed to reserve context id %d (rc %d)\n", id, result);
|
||||
}
|
||||
@@ -172,9 +140,7 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
|
||||
|
||||
void __destroy_context(int context_id)
|
||||
{
|
||||
spin_lock(&mmu_context_lock);
|
||||
ida_remove(&mmu_context_ida, context_id);
|
||||
spin_unlock(&mmu_context_lock);
|
||||
ida_free(&mmu_context_ida, context_id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__destroy_context);
|
||||
|
||||
@@ -182,13 +148,11 @@ static void destroy_contexts(mm_context_t *ctx)
|
||||
{
|
||||
int index, context_id;
|
||||
|
||||
spin_lock(&mmu_context_lock);
|
||||
for (index = 0; index < ARRAY_SIZE(ctx->extended_id); index++) {
|
||||
context_id = ctx->extended_id[index];
|
||||
if (context_id)
|
||||
ida_remove(&mmu_context_ida, context_id);
|
||||
ida_free(&mmu_context_ida, context_id);
|
||||
}
|
||||
spin_unlock(&mmu_context_lock);
|
||||
}
|
||||
|
||||
static void pte_frag_destroy(void *pte_frag)
|
||||
|
||||
@@ -515,35 +515,17 @@ int init_winctx_regs(struct vas_window *window, struct vas_winctx *winctx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(vas_ida_lock);
|
||||
|
||||
static void vas_release_window_id(struct ida *ida, int winid)
|
||||
{
|
||||
spin_lock(&vas_ida_lock);
|
||||
ida_remove(ida, winid);
|
||||
spin_unlock(&vas_ida_lock);
|
||||
ida_free(ida, winid);
|
||||
}
|
||||
|
||||
static int vas_assign_window_id(struct ida *ida)
|
||||
{
|
||||
int rc, winid;
|
||||
int winid = ida_alloc_max(ida, VAS_WINDOWS_PER_CHIP - 1, GFP_KERNEL);
|
||||
|
||||
do {
|
||||
rc = ida_pre_get(ida, GFP_KERNEL);
|
||||
if (!rc)
|
||||
return -EAGAIN;
|
||||
|
||||
spin_lock(&vas_ida_lock);
|
||||
rc = ida_get_new(ida, &winid);
|
||||
spin_unlock(&vas_ida_lock);
|
||||
} while (rc == -EAGAIN);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (winid > VAS_WINDOWS_PER_CHIP) {
|
||||
pr_err("Too many (%d) open windows\n", winid);
|
||||
vas_release_window_id(ida, winid);
|
||||
if (winid == -ENOSPC) {
|
||||
pr_err("Too many (%d) open windows\n", VAS_WINDOWS_PER_CHIP);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,6 @@ static struct dentry *dfs_device_status;
|
||||
|
||||
static u32 cpu_use[NR_CPUS];
|
||||
|
||||
static DEFINE_SPINLOCK(rssd_index_lock);
|
||||
static DEFINE_IDA(rssd_index_ida);
|
||||
|
||||
static int mtip_block_initialize(struct driver_data *dd);
|
||||
@@ -3767,20 +3766,10 @@ static int mtip_block_initialize(struct driver_data *dd)
|
||||
goto alloc_disk_error;
|
||||
}
|
||||
|
||||
/* Generate the disk name, implemented same as in sd.c */
|
||||
do {
|
||||
if (!ida_pre_get(&rssd_index_ida, GFP_KERNEL)) {
|
||||
rv = -ENOMEM;
|
||||
goto ida_get_error;
|
||||
}
|
||||
|
||||
spin_lock(&rssd_index_lock);
|
||||
rv = ida_get_new(&rssd_index_ida, &index);
|
||||
spin_unlock(&rssd_index_lock);
|
||||
} while (rv == -EAGAIN);
|
||||
|
||||
if (rv)
|
||||
rv = ida_alloc(&rssd_index_ida, GFP_KERNEL);
|
||||
if (rv < 0)
|
||||
goto ida_get_error;
|
||||
index = rv;
|
||||
|
||||
rv = rssd_disk_name_format("rssd",
|
||||
index,
|
||||
@@ -3922,9 +3911,7 @@ block_queue_alloc_init_error:
|
||||
block_queue_alloc_tag_error:
|
||||
mtip_hw_debugfs_exit(dd);
|
||||
disk_index_error:
|
||||
spin_lock(&rssd_index_lock);
|
||||
ida_remove(&rssd_index_ida, index);
|
||||
spin_unlock(&rssd_index_lock);
|
||||
ida_free(&rssd_index_ida, index);
|
||||
|
||||
ida_get_error:
|
||||
put_disk(dd->disk);
|
||||
@@ -4012,9 +3999,7 @@ static int mtip_block_remove(struct driver_data *dd)
|
||||
}
|
||||
dd->disk = NULL;
|
||||
|
||||
spin_lock(&rssd_index_lock);
|
||||
ida_remove(&rssd_index_ida, dd->index);
|
||||
spin_unlock(&rssd_index_lock);
|
||||
ida_free(&rssd_index_ida, dd->index);
|
||||
|
||||
/* De-initialize the protocol layer. */
|
||||
mtip_hw_exit(dd);
|
||||
@@ -4054,9 +4039,7 @@ static int mtip_block_shutdown(struct driver_data *dd)
|
||||
dd->queue = NULL;
|
||||
}
|
||||
|
||||
spin_lock(&rssd_index_lock);
|
||||
ida_remove(&rssd_index_ida, dd->index);
|
||||
spin_unlock(&rssd_index_lock);
|
||||
ida_free(&rssd_index_ida, dd->index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,6 @@ MODULE_PARM_DESC(sync_start, "On by Default: Driver load will not complete "
|
||||
"until the card startup has completed.");
|
||||
|
||||
static DEFINE_IDA(rsxx_disk_ida);
|
||||
static DEFINE_SPINLOCK(rsxx_ida_lock);
|
||||
|
||||
/* --------------------Debugfs Setup ------------------- */
|
||||
|
||||
@@ -771,19 +770,10 @@ static int rsxx_pci_probe(struct pci_dev *dev,
|
||||
card->dev = dev;
|
||||
pci_set_drvdata(dev, card);
|
||||
|
||||
do {
|
||||
if (!ida_pre_get(&rsxx_disk_ida, GFP_KERNEL)) {
|
||||
st = -ENOMEM;
|
||||
goto failed_ida_get;
|
||||
}
|
||||
|
||||
spin_lock(&rsxx_ida_lock);
|
||||
st = ida_get_new(&rsxx_disk_ida, &card->disk_id);
|
||||
spin_unlock(&rsxx_ida_lock);
|
||||
} while (st == -EAGAIN);
|
||||
|
||||
if (st)
|
||||
st = ida_alloc(&rsxx_disk_ida, GFP_KERNEL);
|
||||
if (st < 0)
|
||||
goto failed_ida_get;
|
||||
card->disk_id = st;
|
||||
|
||||
st = pci_enable_device(dev);
|
||||
if (st)
|
||||
@@ -985,9 +975,7 @@ failed_request_regions:
|
||||
failed_dma_mask:
|
||||
pci_disable_device(dev);
|
||||
failed_enable:
|
||||
spin_lock(&rsxx_ida_lock);
|
||||
ida_remove(&rsxx_disk_ida, card->disk_id);
|
||||
spin_unlock(&rsxx_ida_lock);
|
||||
ida_free(&rsxx_disk_ida, card->disk_id);
|
||||
failed_ida_get:
|
||||
kfree(card);
|
||||
|
||||
@@ -1050,6 +1038,7 @@ static void rsxx_pci_remove(struct pci_dev *dev)
|
||||
pci_disable_device(dev);
|
||||
pci_release_regions(dev);
|
||||
|
||||
ida_free(&rsxx_disk_ida, card->disk_id);
|
||||
kfree(card);
|
||||
}
|
||||
|
||||
|
||||
+7
-16
@@ -161,9 +161,7 @@ static void chan_dev_release(struct device *dev)
|
||||
|
||||
chan_dev = container_of(dev, typeof(*chan_dev), device);
|
||||
if (atomic_dec_and_test(chan_dev->idr_ref)) {
|
||||
mutex_lock(&dma_list_mutex);
|
||||
ida_remove(&dma_ida, chan_dev->dev_id);
|
||||
mutex_unlock(&dma_list_mutex);
|
||||
ida_free(&dma_ida, chan_dev->dev_id);
|
||||
kfree(chan_dev->idr_ref);
|
||||
}
|
||||
kfree(chan_dev);
|
||||
@@ -898,17 +896,12 @@ static bool device_has_all_tx_types(struct dma_device *device)
|
||||
|
||||
static int get_dma_id(struct dma_device *device)
|
||||
{
|
||||
int rc;
|
||||
int rc = ida_alloc(&dma_ida, GFP_KERNEL);
|
||||
|
||||
do {
|
||||
if (!ida_pre_get(&dma_ida, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
mutex_lock(&dma_list_mutex);
|
||||
rc = ida_get_new(&dma_ida, &device->dev_id);
|
||||
mutex_unlock(&dma_list_mutex);
|
||||
} while (rc == -EAGAIN);
|
||||
|
||||
return rc;
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
device->dev_id = rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1092,9 +1085,7 @@ int dma_async_device_register(struct dma_device *device)
|
||||
err_out:
|
||||
/* if we never registered a channel just release the idr */
|
||||
if (atomic_read(idr_ref) == 0) {
|
||||
mutex_lock(&dma_list_mutex);
|
||||
ida_remove(&dma_ida, device->dev_id);
|
||||
mutex_unlock(&dma_list_mutex);
|
||||
ida_free(&dma_ida, device->dev_id);
|
||||
kfree(idr_ref);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -51,51 +51,34 @@ static int vmw_gmrid_man_get_node(struct ttm_mem_type_manager *man,
|
||||
{
|
||||
struct vmwgfx_gmrid_man *gman =
|
||||
(struct vmwgfx_gmrid_man *)man->priv;
|
||||
int ret = 0;
|
||||
int id;
|
||||
|
||||
mem->mm_node = NULL;
|
||||
|
||||
id = ida_alloc_max(&gman->gmr_ida, gman->max_gmr_ids - 1, GFP_KERNEL);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
spin_lock(&gman->lock);
|
||||
|
||||
if (gman->max_gmr_pages > 0) {
|
||||
gman->used_gmr_pages += bo->num_pages;
|
||||
if (unlikely(gman->used_gmr_pages > gman->max_gmr_pages))
|
||||
goto out_err_locked;
|
||||
goto nospace;
|
||||
}
|
||||
|
||||
do {
|
||||
spin_unlock(&gman->lock);
|
||||
if (unlikely(ida_pre_get(&gman->gmr_ida, GFP_KERNEL) == 0)) {
|
||||
ret = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
spin_lock(&gman->lock);
|
||||
|
||||
ret = ida_get_new(&gman->gmr_ida, &id);
|
||||
if (unlikely(ret == 0 && id >= gman->max_gmr_ids)) {
|
||||
ida_remove(&gman->gmr_ida, id);
|
||||
ret = 0;
|
||||
goto out_err_locked;
|
||||
}
|
||||
} while (ret == -EAGAIN);
|
||||
|
||||
if (likely(ret == 0)) {
|
||||
mem->mm_node = gman;
|
||||
mem->start = id;
|
||||
mem->num_pages = bo->num_pages;
|
||||
} else
|
||||
goto out_err_locked;
|
||||
mem->mm_node = gman;
|
||||
mem->start = id;
|
||||
mem->num_pages = bo->num_pages;
|
||||
|
||||
spin_unlock(&gman->lock);
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
spin_lock(&gman->lock);
|
||||
out_err_locked:
|
||||
nospace:
|
||||
gman->used_gmr_pages -= bo->num_pages;
|
||||
spin_unlock(&gman->lock);
|
||||
return ret;
|
||||
ida_free(&gman->gmr_ida, id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man,
|
||||
@@ -105,8 +88,8 @@ static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man,
|
||||
(struct vmwgfx_gmrid_man *)man->priv;
|
||||
|
||||
if (mem->mm_node) {
|
||||
ida_free(&gman->gmr_ida, mem->start);
|
||||
spin_lock(&gman->lock);
|
||||
ida_remove(&gman->gmr_ida, mem->start);
|
||||
gman->used_gmr_pages -= mem->num_pages;
|
||||
spin_unlock(&gman->lock);
|
||||
mem->mm_node = NULL;
|
||||
|
||||
@@ -585,18 +585,12 @@ int __must_check media_device_register_entity(struct media_device *mdev,
|
||||
entity->num_links = 0;
|
||||
entity->num_backlinks = 0;
|
||||
|
||||
if (!ida_pre_get(&mdev->entity_internal_idx, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
ret = ida_alloc_min(&mdev->entity_internal_idx, 1, GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
entity->internal_idx = ret;
|
||||
|
||||
mutex_lock(&mdev->graph_mutex);
|
||||
|
||||
ret = ida_get_new_above(&mdev->entity_internal_idx, 1,
|
||||
&entity->internal_idx);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&mdev->graph_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mdev->entity_internal_idx_max =
|
||||
max(mdev->entity_internal_idx_max, entity->internal_idx);
|
||||
|
||||
@@ -642,7 +636,7 @@ static void __media_device_unregister_entity(struct media_entity *entity)
|
||||
struct media_interface *intf;
|
||||
unsigned int i;
|
||||
|
||||
ida_simple_remove(&mdev->entity_internal_idx, entity->internal_idx);
|
||||
ida_free(&mdev->entity_internal_idx, entity->internal_idx);
|
||||
|
||||
/* Remove all interface links pointing to this entity */
|
||||
list_for_each_entry(intf, &mdev->interfaces, graph_obj.list) {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <linux/gfp.h>
|
||||
|
||||
static DEFINE_IDA(cb710_ida);
|
||||
static DEFINE_SPINLOCK(cb710_ida_lock);
|
||||
|
||||
void cb710_pci_update_config_reg(struct pci_dev *pdev,
|
||||
int reg, uint32_t mask, uint32_t xor)
|
||||
@@ -205,7 +204,6 @@ static int cb710_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
struct cb710_chip *chip;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
int err;
|
||||
int n = 0;
|
||||
@@ -256,18 +254,10 @@ static int cb710_probe(struct pci_dev *pdev,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
do {
|
||||
if (!ida_pre_get(&cb710_ida, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_irqsave(&cb710_ida_lock, flags);
|
||||
err = ida_get_new(&cb710_ida, &chip->platform_id);
|
||||
spin_unlock_irqrestore(&cb710_ida_lock, flags);
|
||||
|
||||
if (err && err != -EAGAIN)
|
||||
return err;
|
||||
} while (err);
|
||||
|
||||
err = ida_alloc(&cb710_ida, GFP_KERNEL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
chip->platform_id = err;
|
||||
|
||||
dev_info(&pdev->dev, "id %d, IO 0x%p, IRQ %d\n",
|
||||
chip->platform_id, chip->iobase, pdev->irq);
|
||||
@@ -308,7 +298,6 @@ unreg_mmc:
|
||||
static void cb710_remove_one(struct pci_dev *pdev)
|
||||
{
|
||||
struct cb710_chip *chip = pci_get_drvdata(pdev);
|
||||
unsigned long flags;
|
||||
|
||||
cb710_unregister_slot(chip, CB710_SLOT_SM);
|
||||
cb710_unregister_slot(chip, CB710_SLOT_MS);
|
||||
@@ -317,9 +306,7 @@ static void cb710_remove_one(struct pci_dev *pdev)
|
||||
BUG_ON(atomic_read(&chip->slot_refs_count) != 0);
|
||||
#endif
|
||||
|
||||
spin_lock_irqsave(&cb710_ida_lock, flags);
|
||||
ida_remove(&cb710_ida, chip->platform_id);
|
||||
spin_unlock_irqrestore(&cb710_ida_lock, flags);
|
||||
ida_free(&cb710_ida, chip->platform_id);
|
||||
}
|
||||
|
||||
static const struct pci_device_id cb710_pci_tbl[] = {
|
||||
|
||||
@@ -423,19 +423,11 @@ static int osd_probe(struct device *dev)
|
||||
if (scsi_device->type != TYPE_OSD)
|
||||
return -ENODEV;
|
||||
|
||||
do {
|
||||
if (!ida_pre_get(&osd_minor_ida, GFP_KERNEL))
|
||||
return -ENODEV;
|
||||
|
||||
error = ida_get_new(&osd_minor_ida, &minor);
|
||||
} while (error == -EAGAIN);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
if (minor >= SCSI_OSD_MAX_MINOR) {
|
||||
error = -EBUSY;
|
||||
goto err_retract_minor;
|
||||
}
|
||||
minor = ida_alloc_max(&osd_minor_ida, SCSI_OSD_MAX_MINOR, GFP_KERNEL);
|
||||
if (minor == -ENOSPC)
|
||||
return -EBUSY;
|
||||
if (minor < 0)
|
||||
return -ENODEV;
|
||||
|
||||
error = -ENOMEM;
|
||||
oud = kzalloc(sizeof(*oud), GFP_KERNEL);
|
||||
@@ -499,7 +491,7 @@ static int osd_probe(struct device *dev)
|
||||
err_free_osd:
|
||||
put_device(&oud->class_dev);
|
||||
err_retract_minor:
|
||||
ida_remove(&osd_minor_ida, minor);
|
||||
ida_free(&osd_minor_ida, minor);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -514,7 +506,7 @@ static int osd_remove(struct device *dev)
|
||||
}
|
||||
|
||||
cdev_device_del(&oud->cdev, &oud->class_dev);
|
||||
ida_remove(&osd_minor_ida, oud->minor);
|
||||
ida_free(&osd_minor_ida, oud->minor);
|
||||
put_device(&oud->class_dev);
|
||||
|
||||
return 0;
|
||||
|
||||
+4
-17
@@ -123,7 +123,6 @@ static void scsi_disk_release(struct device *cdev);
|
||||
static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
|
||||
static void sd_print_result(const struct scsi_disk *, const char *, int);
|
||||
|
||||
static DEFINE_SPINLOCK(sd_index_lock);
|
||||
static DEFINE_IDA(sd_index_ida);
|
||||
|
||||
/* This semaphore is used to mediate the 0->1 reference get in the
|
||||
@@ -3340,16 +3339,8 @@ static int sd_probe(struct device *dev)
|
||||
if (!gd)
|
||||
goto out_free;
|
||||
|
||||
do {
|
||||
if (!ida_pre_get(&sd_index_ida, GFP_KERNEL))
|
||||
goto out_put;
|
||||
|
||||
spin_lock(&sd_index_lock);
|
||||
error = ida_get_new(&sd_index_ida, &index);
|
||||
spin_unlock(&sd_index_lock);
|
||||
} while (error == -EAGAIN);
|
||||
|
||||
if (error) {
|
||||
index = ida_alloc(&sd_index_ida, GFP_KERNEL);
|
||||
if (index < 0) {
|
||||
sdev_printk(KERN_WARNING, sdp, "sd_probe: memory exhausted.\n");
|
||||
goto out_put;
|
||||
}
|
||||
@@ -3393,9 +3384,7 @@ static int sd_probe(struct device *dev)
|
||||
return 0;
|
||||
|
||||
out_free_index:
|
||||
spin_lock(&sd_index_lock);
|
||||
ida_remove(&sd_index_ida, index);
|
||||
spin_unlock(&sd_index_lock);
|
||||
ida_free(&sd_index_ida, index);
|
||||
out_put:
|
||||
put_disk(gd);
|
||||
out_free:
|
||||
@@ -3460,9 +3449,7 @@ static void scsi_disk_release(struct device *dev)
|
||||
struct scsi_disk *sdkp = to_scsi_disk(dev);
|
||||
struct gendisk *disk = sdkp->disk;
|
||||
|
||||
spin_lock(&sd_index_lock);
|
||||
ida_remove(&sd_index_ida, sdkp->index);
|
||||
spin_unlock(&sd_index_lock);
|
||||
ida_free(&sd_index_ida, sdkp->index);
|
||||
|
||||
disk->private_data = NULL;
|
||||
put_disk(disk);
|
||||
|
||||
@@ -57,9 +57,8 @@ static DEFINE_SPINLOCK(tiqn_lock);
|
||||
static DEFINE_MUTEX(np_lock);
|
||||
|
||||
static struct idr tiqn_idr;
|
||||
struct idr sess_idr;
|
||||
DEFINE_IDA(sess_ida);
|
||||
struct mutex auth_id_lock;
|
||||
spinlock_t sess_idr_lock;
|
||||
|
||||
struct iscsit_global *iscsit_global;
|
||||
|
||||
@@ -700,9 +699,7 @@ static int __init iscsi_target_init_module(void)
|
||||
|
||||
spin_lock_init(&iscsit_global->ts_bitmap_lock);
|
||||
mutex_init(&auth_id_lock);
|
||||
spin_lock_init(&sess_idr_lock);
|
||||
idr_init(&tiqn_idr);
|
||||
idr_init(&sess_idr);
|
||||
|
||||
ret = target_register_template(&iscsi_ops);
|
||||
if (ret)
|
||||
@@ -4375,10 +4372,7 @@ int iscsit_close_session(struct iscsi_session *sess)
|
||||
pr_debug("Decremented number of active iSCSI Sessions on"
|
||||
" iSCSI TPG: %hu to %u\n", tpg->tpgt, tpg->nsessions);
|
||||
|
||||
spin_lock(&sess_idr_lock);
|
||||
idr_remove(&sess_idr, sess->session_index);
|
||||
spin_unlock(&sess_idr_lock);
|
||||
|
||||
ida_free(&sess_ida, sess->session_index);
|
||||
kfree(sess->sess_ops);
|
||||
sess->sess_ops = NULL;
|
||||
spin_unlock_bh(&se_tpg->session_lock);
|
||||
|
||||
@@ -55,9 +55,7 @@ extern struct kmem_cache *lio_ooo_cache;
|
||||
extern struct kmem_cache *lio_qr_cache;
|
||||
extern struct kmem_cache *lio_r2t_cache;
|
||||
|
||||
extern struct idr sess_idr;
|
||||
extern struct ida sess_ida;
|
||||
extern struct mutex auth_id_lock;
|
||||
extern spinlock_t sess_idr_lock;
|
||||
|
||||
|
||||
#endif /*** ISCSI_TARGET_H ***/
|
||||
|
||||
@@ -336,22 +336,15 @@ static int iscsi_login_zero_tsih_s1(
|
||||
timer_setup(&sess->time2retain_timer,
|
||||
iscsit_handle_time2retain_timeout, 0);
|
||||
|
||||
idr_preload(GFP_KERNEL);
|
||||
spin_lock_bh(&sess_idr_lock);
|
||||
ret = idr_alloc(&sess_idr, NULL, 0, 0, GFP_NOWAIT);
|
||||
if (ret >= 0)
|
||||
sess->session_index = ret;
|
||||
spin_unlock_bh(&sess_idr_lock);
|
||||
idr_preload_end();
|
||||
|
||||
ret = ida_alloc(&sess_ida, GFP_KERNEL);
|
||||
if (ret < 0) {
|
||||
pr_err("idr_alloc() for sess_idr failed\n");
|
||||
pr_err("Session ID allocation failed %d\n", ret);
|
||||
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
|
||||
ISCSI_LOGIN_STATUS_NO_RESOURCES);
|
||||
kfree(sess);
|
||||
return -ENOMEM;
|
||||
goto free_sess;
|
||||
}
|
||||
|
||||
sess->session_index = ret;
|
||||
sess->creation_time = get_jiffies_64();
|
||||
/*
|
||||
* The FFP CmdSN window values will be allocated from the TPG's
|
||||
@@ -365,20 +358,26 @@ static int iscsi_login_zero_tsih_s1(
|
||||
ISCSI_LOGIN_STATUS_NO_RESOURCES);
|
||||
pr_err("Unable to allocate memory for"
|
||||
" struct iscsi_sess_ops.\n");
|
||||
kfree(sess);
|
||||
return -ENOMEM;
|
||||
goto free_id;
|
||||
}
|
||||
|
||||
sess->se_sess = transport_alloc_session(TARGET_PROT_NORMAL);
|
||||
if (IS_ERR(sess->se_sess)) {
|
||||
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
|
||||
ISCSI_LOGIN_STATUS_NO_RESOURCES);
|
||||
kfree(sess->sess_ops);
|
||||
kfree(sess);
|
||||
return -ENOMEM;
|
||||
goto free_ops;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free_ops:
|
||||
kfree(sess->sess_ops);
|
||||
free_id:
|
||||
ida_free(&sess_ida, sess->session_index);
|
||||
free_sess:
|
||||
kfree(sess);
|
||||
conn->sess = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int iscsi_login_zero_tsih_s2(
|
||||
@@ -1161,13 +1160,9 @@ void iscsi_target_login_sess_out(struct iscsi_conn *conn,
|
||||
ISCSI_LOGIN_STATUS_INIT_ERR);
|
||||
if (!zero_tsih || !conn->sess)
|
||||
goto old_sess_out;
|
||||
if (conn->sess->se_sess)
|
||||
transport_free_session(conn->sess->se_sess);
|
||||
if (conn->sess->session_index != 0) {
|
||||
spin_lock_bh(&sess_idr_lock);
|
||||
idr_remove(&sess_idr, conn->sess->session_index);
|
||||
spin_unlock_bh(&sess_idr_lock);
|
||||
}
|
||||
|
||||
transport_free_session(conn->sess->se_sess);
|
||||
ida_free(&sess_ida, conn->sess->session_index);
|
||||
kfree(conn->sess->sess_ops);
|
||||
kfree(conn->sess);
|
||||
conn->sess = NULL;
|
||||
|
||||
+12
-33
@@ -46,7 +46,7 @@ static int pty_limit = NR_UNIX98_PTY_DEFAULT;
|
||||
static int pty_reserve = NR_UNIX98_PTY_RESERVE;
|
||||
static int pty_limit_min;
|
||||
static int pty_limit_max = INT_MAX;
|
||||
static int pty_count;
|
||||
static atomic_t pty_count = ATOMIC_INIT(0);
|
||||
|
||||
static struct ctl_table pty_table[] = {
|
||||
{
|
||||
@@ -93,8 +93,6 @@ static struct ctl_table pty_root_table[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(allocated_ptys_lock);
|
||||
|
||||
struct pts_mount_opts {
|
||||
int setuid;
|
||||
int setgid;
|
||||
@@ -533,44 +531,25 @@ static struct file_system_type devpts_fs_type = {
|
||||
|
||||
int devpts_new_index(struct pts_fs_info *fsi)
|
||||
{
|
||||
int index;
|
||||
int ida_ret;
|
||||
int index = -ENOSPC;
|
||||
|
||||
retry:
|
||||
if (!ida_pre_get(&fsi->allocated_ptys, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
if (atomic_inc_return(&pty_count) >= (pty_limit -
|
||||
(fsi->mount_opts.reserve ? 0 : pty_reserve)))
|
||||
goto out;
|
||||
|
||||
mutex_lock(&allocated_ptys_lock);
|
||||
if (pty_count >= (pty_limit -
|
||||
(fsi->mount_opts.reserve ? 0 : pty_reserve))) {
|
||||
mutex_unlock(&allocated_ptys_lock);
|
||||
return -ENOSPC;
|
||||
}
|
||||
index = ida_alloc_max(&fsi->allocated_ptys, fsi->mount_opts.max - 1,
|
||||
GFP_KERNEL);
|
||||
|
||||
ida_ret = ida_get_new(&fsi->allocated_ptys, &index);
|
||||
if (ida_ret < 0) {
|
||||
mutex_unlock(&allocated_ptys_lock);
|
||||
if (ida_ret == -EAGAIN)
|
||||
goto retry;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (index >= fsi->mount_opts.max) {
|
||||
ida_remove(&fsi->allocated_ptys, index);
|
||||
mutex_unlock(&allocated_ptys_lock);
|
||||
return -ENOSPC;
|
||||
}
|
||||
pty_count++;
|
||||
mutex_unlock(&allocated_ptys_lock);
|
||||
out:
|
||||
if (index < 0)
|
||||
atomic_dec(&pty_count);
|
||||
return index;
|
||||
}
|
||||
|
||||
void devpts_kill_index(struct pts_fs_info *fsi, int idx)
|
||||
{
|
||||
mutex_lock(&allocated_ptys_lock);
|
||||
ida_remove(&fsi->allocated_ptys, idx);
|
||||
pty_count--;
|
||||
mutex_unlock(&allocated_ptys_lock);
|
||||
ida_free(&fsi->allocated_ptys, idx);
|
||||
atomic_dec(&pty_count);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+12
-38
@@ -61,9 +61,6 @@ __setup("mphash_entries=", set_mphash_entries);
|
||||
static u64 event;
|
||||
static DEFINE_IDA(mnt_id_ida);
|
||||
static DEFINE_IDA(mnt_group_ida);
|
||||
static DEFINE_SPINLOCK(mnt_id_lock);
|
||||
static int mnt_id_start = 0;
|
||||
static int mnt_group_start = 1;
|
||||
|
||||
static struct hlist_head *mount_hashtable __read_mostly;
|
||||
static struct hlist_head *mountpoint_hashtable __read_mostly;
|
||||
@@ -101,50 +98,30 @@ static inline struct hlist_head *mp_hash(struct dentry *dentry)
|
||||
|
||||
static int mnt_alloc_id(struct mount *mnt)
|
||||
{
|
||||
int res;
|
||||
int res = ida_alloc(&mnt_id_ida, GFP_KERNEL);
|
||||
|
||||
retry:
|
||||
ida_pre_get(&mnt_id_ida, GFP_KERNEL);
|
||||
spin_lock(&mnt_id_lock);
|
||||
res = ida_get_new_above(&mnt_id_ida, mnt_id_start, &mnt->mnt_id);
|
||||
if (!res)
|
||||
mnt_id_start = mnt->mnt_id + 1;
|
||||
spin_unlock(&mnt_id_lock);
|
||||
if (res == -EAGAIN)
|
||||
goto retry;
|
||||
|
||||
return res;
|
||||
if (res < 0)
|
||||
return res;
|
||||
mnt->mnt_id = res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mnt_free_id(struct mount *mnt)
|
||||
{
|
||||
int id = mnt->mnt_id;
|
||||
spin_lock(&mnt_id_lock);
|
||||
ida_remove(&mnt_id_ida, id);
|
||||
if (mnt_id_start > id)
|
||||
mnt_id_start = id;
|
||||
spin_unlock(&mnt_id_lock);
|
||||
ida_free(&mnt_id_ida, mnt->mnt_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a new peer group ID
|
||||
*
|
||||
* mnt_group_ida is protected by namespace_sem
|
||||
*/
|
||||
static int mnt_alloc_group_id(struct mount *mnt)
|
||||
{
|
||||
int res;
|
||||
int res = ida_alloc_min(&mnt_group_ida, 1, GFP_KERNEL);
|
||||
|
||||
if (!ida_pre_get(&mnt_group_ida, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
res = ida_get_new_above(&mnt_group_ida,
|
||||
mnt_group_start,
|
||||
&mnt->mnt_group_id);
|
||||
if (!res)
|
||||
mnt_group_start = mnt->mnt_group_id + 1;
|
||||
|
||||
return res;
|
||||
if (res < 0)
|
||||
return res;
|
||||
mnt->mnt_group_id = res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -152,10 +129,7 @@ static int mnt_alloc_group_id(struct mount *mnt)
|
||||
*/
|
||||
void mnt_release_group_id(struct mount *mnt)
|
||||
{
|
||||
int id = mnt->mnt_group_id;
|
||||
ida_remove(&mnt_group_ida, id);
|
||||
if (mnt_group_start > id)
|
||||
mnt_group_start = id;
|
||||
ida_free(&mnt_group_ida, mnt->mnt_group_id);
|
||||
mnt->mnt_group_id = 0;
|
||||
}
|
||||
|
||||
|
||||
+23
-42
@@ -981,58 +981,42 @@ void emergency_thaw_all(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Unnamed block devices are dummy devices used by virtual
|
||||
* filesystems which don't use real block-devices. -- jrs
|
||||
*/
|
||||
|
||||
static DEFINE_IDA(unnamed_dev_ida);
|
||||
static DEFINE_SPINLOCK(unnamed_dev_lock);/* protects the above */
|
||||
/* Many userspace utilities consider an FSID of 0 invalid.
|
||||
* Always return at least 1 from get_anon_bdev.
|
||||
*/
|
||||
static int unnamed_dev_start = 1;
|
||||
|
||||
/**
|
||||
* get_anon_bdev - Allocate a block device for filesystems which don't have one.
|
||||
* @p: Pointer to a dev_t.
|
||||
*
|
||||
* Filesystems which don't use real block devices can call this function
|
||||
* to allocate a virtual block device.
|
||||
*
|
||||
* Context: Any context. Frequently called while holding sb_lock.
|
||||
* Return: 0 on success, -EMFILE if there are no anonymous bdevs left
|
||||
* or -ENOMEM if memory allocation failed.
|
||||
*/
|
||||
int get_anon_bdev(dev_t *p)
|
||||
{
|
||||
int dev;
|
||||
int error;
|
||||
|
||||
retry:
|
||||
if (ida_pre_get(&unnamed_dev_ida, GFP_ATOMIC) == 0)
|
||||
return -ENOMEM;
|
||||
spin_lock(&unnamed_dev_lock);
|
||||
error = ida_get_new_above(&unnamed_dev_ida, unnamed_dev_start, &dev);
|
||||
if (!error)
|
||||
unnamed_dev_start = dev + 1;
|
||||
spin_unlock(&unnamed_dev_lock);
|
||||
if (error == -EAGAIN)
|
||||
/* We raced and lost with another CPU. */
|
||||
goto retry;
|
||||
else if (error)
|
||||
return -EAGAIN;
|
||||
/*
|
||||
* Many userspace utilities consider an FSID of 0 invalid.
|
||||
* Always return at least 1 from get_anon_bdev.
|
||||
*/
|
||||
dev = ida_alloc_range(&unnamed_dev_ida, 1, (1 << MINORBITS) - 1,
|
||||
GFP_ATOMIC);
|
||||
if (dev == -ENOSPC)
|
||||
dev = -EMFILE;
|
||||
if (dev < 0)
|
||||
return dev;
|
||||
|
||||
if (dev >= (1 << MINORBITS)) {
|
||||
spin_lock(&unnamed_dev_lock);
|
||||
ida_remove(&unnamed_dev_ida, dev);
|
||||
if (unnamed_dev_start > dev)
|
||||
unnamed_dev_start = dev;
|
||||
spin_unlock(&unnamed_dev_lock);
|
||||
return -EMFILE;
|
||||
}
|
||||
*p = MKDEV(0, dev & MINORMASK);
|
||||
*p = MKDEV(0, dev);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(get_anon_bdev);
|
||||
|
||||
void free_anon_bdev(dev_t dev)
|
||||
{
|
||||
int slot = MINOR(dev);
|
||||
spin_lock(&unnamed_dev_lock);
|
||||
ida_remove(&unnamed_dev_ida, slot);
|
||||
if (slot < unnamed_dev_start)
|
||||
unnamed_dev_start = slot;
|
||||
spin_unlock(&unnamed_dev_lock);
|
||||
ida_free(&unnamed_dev_ida, MINOR(dev));
|
||||
}
|
||||
EXPORT_SYMBOL(free_anon_bdev);
|
||||
|
||||
@@ -1040,7 +1024,6 @@ int set_anon_super(struct super_block *s, void *data)
|
||||
{
|
||||
return get_anon_bdev(&s->s_dev);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(set_anon_super);
|
||||
|
||||
void kill_anon_super(struct super_block *sb)
|
||||
@@ -1049,7 +1032,6 @@ void kill_anon_super(struct super_block *sb)
|
||||
generic_shutdown_super(sb);
|
||||
free_anon_bdev(dev);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(kill_anon_super);
|
||||
|
||||
void kill_litter_super(struct super_block *sb)
|
||||
@@ -1058,7 +1040,6 @@ void kill_litter_super(struct super_block *sb)
|
||||
d_genocide(sb->s_root);
|
||||
kill_anon_super(sb);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(kill_litter_super);
|
||||
|
||||
static int ns_test_super(struct super_block *sb, void *data)
|
||||
|
||||
+57
-17
@@ -236,34 +236,74 @@ struct ida {
|
||||
}
|
||||
#define DEFINE_IDA(name) struct ida name = IDA_INIT(name)
|
||||
|
||||
int ida_pre_get(struct ida *ida, gfp_t gfp_mask);
|
||||
int ida_get_new_above(struct ida *ida, int starting_id, int *p_id);
|
||||
void ida_remove(struct ida *ida, int id);
|
||||
int ida_alloc_range(struct ida *, unsigned int min, unsigned int max, gfp_t);
|
||||
void ida_free(struct ida *, unsigned int id);
|
||||
void ida_destroy(struct ida *ida);
|
||||
|
||||
int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end,
|
||||
gfp_t gfp_mask);
|
||||
void ida_simple_remove(struct ida *ida, unsigned int id);
|
||||
/**
|
||||
* ida_alloc() - Allocate an unused ID.
|
||||
* @ida: IDA handle.
|
||||
* @gfp: Memory allocation flags.
|
||||
*
|
||||
* Allocate an ID between 0 and %INT_MAX, inclusive.
|
||||
*
|
||||
* Context: Any context.
|
||||
* Return: The allocated ID, or %-ENOMEM if memory could not be allocated,
|
||||
* or %-ENOSPC if there are no free IDs.
|
||||
*/
|
||||
static inline int ida_alloc(struct ida *ida, gfp_t gfp)
|
||||
{
|
||||
return ida_alloc_range(ida, 0, ~0, gfp);
|
||||
}
|
||||
|
||||
/**
|
||||
* ida_alloc_min() - Allocate an unused ID.
|
||||
* @ida: IDA handle.
|
||||
* @min: Lowest ID to allocate.
|
||||
* @gfp: Memory allocation flags.
|
||||
*
|
||||
* Allocate an ID between @min and %INT_MAX, inclusive.
|
||||
*
|
||||
* Context: Any context.
|
||||
* Return: The allocated ID, or %-ENOMEM if memory could not be allocated,
|
||||
* or %-ENOSPC if there are no free IDs.
|
||||
*/
|
||||
static inline int ida_alloc_min(struct ida *ida, unsigned int min, gfp_t gfp)
|
||||
{
|
||||
return ida_alloc_range(ida, min, ~0, gfp);
|
||||
}
|
||||
|
||||
/**
|
||||
* ida_alloc_max() - Allocate an unused ID.
|
||||
* @ida: IDA handle.
|
||||
* @max: Highest ID to allocate.
|
||||
* @gfp: Memory allocation flags.
|
||||
*
|
||||
* Allocate an ID between 0 and @max, inclusive.
|
||||
*
|
||||
* Context: Any context.
|
||||
* Return: The allocated ID, or %-ENOMEM if memory could not be allocated,
|
||||
* or %-ENOSPC if there are no free IDs.
|
||||
*/
|
||||
static inline int ida_alloc_max(struct ida *ida, unsigned int max, gfp_t gfp)
|
||||
{
|
||||
return ida_alloc_range(ida, 0, max, gfp);
|
||||
}
|
||||
|
||||
static inline void ida_init(struct ida *ida)
|
||||
{
|
||||
INIT_RADIX_TREE(&ida->ida_rt, IDR_RT_MARKER | GFP_NOWAIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* ida_get_new - allocate new ID
|
||||
* @ida: idr handle
|
||||
* @p_id: pointer to the allocated handle
|
||||
*
|
||||
* Simple wrapper around ida_get_new_above() w/ @starting_id of zero.
|
||||
*/
|
||||
static inline int ida_get_new(struct ida *ida, int *p_id)
|
||||
{
|
||||
return ida_get_new_above(ida, 0, p_id);
|
||||
}
|
||||
#define ida_simple_get(ida, start, end, gfp) \
|
||||
ida_alloc_range(ida, start, (end) - 1, gfp)
|
||||
#define ida_simple_remove(ida, id) ida_free(ida, id)
|
||||
|
||||
static inline bool ida_is_empty(const struct ida *ida)
|
||||
{
|
||||
return radix_tree_empty(&ida->ida_rt);
|
||||
}
|
||||
|
||||
/* in lib/radix-tree.c */
|
||||
int ida_pre_get(struct ida *ida, gfp_t gfp_mask);
|
||||
#endif /* __IDR_H__ */
|
||||
|
||||
@@ -1833,6 +1833,9 @@ config TEST_HASH
|
||||
This is intended to help people writing architecture-specific
|
||||
optimized versions. If unsure, say N.
|
||||
|
||||
config TEST_IDA
|
||||
tristate "Perform selftest on IDA functions"
|
||||
|
||||
config TEST_PARMAN
|
||||
tristate "Perform selftest on priority array manager"
|
||||
depends on PARMAN
|
||||
|
||||
@@ -50,6 +50,7 @@ obj-$(CONFIG_TEST_BPF) += test_bpf.o
|
||||
obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o
|
||||
obj-$(CONFIG_TEST_SYSCTL) += test_sysctl.o
|
||||
obj-$(CONFIG_TEST_HASH) += test_hash.o test_siphash.o
|
||||
obj-$(CONFIG_TEST_IDA) += test_ida.o
|
||||
obj-$(CONFIG_TEST_KASAN) += test_kasan.o
|
||||
CFLAGS_test_kasan.o += -fno-builtin
|
||||
obj-$(CONFIG_TEST_UBSAN) += test_ubsan.o
|
||||
|
||||
@@ -317,18 +317,12 @@ EXPORT_SYMBOL(idr_replace);
|
||||
* bit per ID, and so is more space efficient than an IDR. To use an IDA,
|
||||
* define it using DEFINE_IDA() (or embed a &struct ida in a data structure,
|
||||
* then initialise it using ida_init()). To allocate a new ID, call
|
||||
* ida_simple_get(). To free an ID, call ida_simple_remove().
|
||||
* ida_alloc(), ida_alloc_min(), ida_alloc_max() or ida_alloc_range().
|
||||
* To free an ID, call ida_free().
|
||||
*
|
||||
* If you have more complex locking requirements, use a loop around
|
||||
* ida_pre_get() and ida_get_new() to allocate a new ID. Then use
|
||||
* ida_remove() to free an ID. You must make sure that ida_get_new() and
|
||||
* ida_remove() cannot be called at the same time as each other for the
|
||||
* same IDA.
|
||||
*
|
||||
* You can also use ida_get_new_above() if you need an ID to be allocated
|
||||
* above a particular number. ida_destroy() can be used to dispose of an
|
||||
* IDA without needing to free the individual IDs in it. You can use
|
||||
* ida_is_empty() to find out whether the IDA has any IDs currently allocated.
|
||||
* ida_destroy() can be used to dispose of an IDA without needing to
|
||||
* free the individual IDs in it. You can use ida_is_empty() to find
|
||||
* out whether the IDA has any IDs currently allocated.
|
||||
*
|
||||
* IDs are currently limited to the range [0-INT_MAX]. If this is an awkward
|
||||
* limitation, it should be quite straightforward to raise the maximum.
|
||||
@@ -369,25 +363,7 @@ EXPORT_SYMBOL(idr_replace);
|
||||
|
||||
#define IDA_MAX (0x80000000U / IDA_BITMAP_BITS - 1)
|
||||
|
||||
/**
|
||||
* ida_get_new_above - allocate new ID above or equal to a start id
|
||||
* @ida: ida handle
|
||||
* @start: id to start search at
|
||||
* @id: pointer to the allocated handle
|
||||
*
|
||||
* Allocate new ID above or equal to @start. It should be called
|
||||
* with any required locks to ensure that concurrent calls to
|
||||
* ida_get_new_above() / ida_get_new() / ida_remove() are not allowed.
|
||||
* Consider using ida_simple_get() if you do not have complex locking
|
||||
* requirements.
|
||||
*
|
||||
* If memory is required, it will return %-EAGAIN, you should unlock
|
||||
* and go back to the ida_pre_get() call. If the ida is full, it will
|
||||
* return %-ENOSPC. On success, it will return 0.
|
||||
*
|
||||
* @id returns a value in the range @start ... %0x7fffffff.
|
||||
*/
|
||||
int ida_get_new_above(struct ida *ida, int start, int *id)
|
||||
static int ida_get_new_above(struct ida *ida, int start)
|
||||
{
|
||||
struct radix_tree_root *root = &ida->ida_rt;
|
||||
void __rcu **slot;
|
||||
@@ -426,8 +402,8 @@ int ida_get_new_above(struct ida *ida, int start, int *id)
|
||||
if (ebit < BITS_PER_LONG) {
|
||||
tmp |= 1UL << ebit;
|
||||
rcu_assign_pointer(*slot, (void *)tmp);
|
||||
*id = new + ebit - RADIX_TREE_EXCEPTIONAL_SHIFT;
|
||||
return 0;
|
||||
return new + ebit -
|
||||
RADIX_TREE_EXCEPTIONAL_SHIFT;
|
||||
}
|
||||
bitmap = this_cpu_xchg(ida_bitmap, NULL);
|
||||
if (!bitmap)
|
||||
@@ -458,8 +434,7 @@ int ida_get_new_above(struct ida *ida, int start, int *id)
|
||||
RADIX_TREE_EXCEPTIONAL_ENTRY);
|
||||
radix_tree_iter_replace(root, &iter, slot,
|
||||
bitmap);
|
||||
*id = new;
|
||||
return 0;
|
||||
return new;
|
||||
}
|
||||
bitmap = this_cpu_xchg(ida_bitmap, NULL);
|
||||
if (!bitmap)
|
||||
@@ -468,20 +443,11 @@ int ida_get_new_above(struct ida *ida, int start, int *id)
|
||||
radix_tree_iter_replace(root, &iter, slot, bitmap);
|
||||
}
|
||||
|
||||
*id = new;
|
||||
return 0;
|
||||
return new;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ida_get_new_above);
|
||||
|
||||
/**
|
||||
* ida_remove - Free the given ID
|
||||
* @ida: ida handle
|
||||
* @id: ID to free
|
||||
*
|
||||
* This function should not be called at the same time as ida_get_new_above().
|
||||
*/
|
||||
void ida_remove(struct ida *ida, int id)
|
||||
static void ida_remove(struct ida *ida, int id)
|
||||
{
|
||||
unsigned long index = id / IDA_BITMAP_BITS;
|
||||
unsigned offset = id % IDA_BITMAP_BITS;
|
||||
@@ -518,99 +484,90 @@ void ida_remove(struct ida *ida, int id)
|
||||
}
|
||||
return;
|
||||
err:
|
||||
WARN(1, "ida_remove called for id=%d which is not allocated.\n", id);
|
||||
WARN(1, "ida_free called for id=%d which is not allocated.\n", id);
|
||||
}
|
||||
EXPORT_SYMBOL(ida_remove);
|
||||
|
||||
/**
|
||||
* ida_destroy - Free the contents of an ida
|
||||
* @ida: ida handle
|
||||
* ida_destroy() - Free all IDs.
|
||||
* @ida: IDA handle.
|
||||
*
|
||||
* Calling this function releases all resources associated with an IDA. When
|
||||
* this call returns, the IDA is empty and can be reused or freed. The caller
|
||||
* should not allow ida_remove() or ida_get_new_above() to be called at the
|
||||
* same time.
|
||||
* Calling this function frees all IDs and releases all resources used
|
||||
* by an IDA. When this call returns, the IDA is empty and can be reused
|
||||
* or freed. If the IDA is already empty, there is no need to call this
|
||||
* function.
|
||||
*
|
||||
* Context: Any context.
|
||||
*/
|
||||
void ida_destroy(struct ida *ida)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct radix_tree_iter iter;
|
||||
void __rcu **slot;
|
||||
|
||||
xa_lock_irqsave(&ida->ida_rt, flags);
|
||||
radix_tree_for_each_slot(slot, &ida->ida_rt, &iter, 0) {
|
||||
struct ida_bitmap *bitmap = rcu_dereference_raw(*slot);
|
||||
if (!radix_tree_exception(bitmap))
|
||||
kfree(bitmap);
|
||||
radix_tree_iter_delete(&ida->ida_rt, &iter, slot);
|
||||
}
|
||||
xa_unlock_irqrestore(&ida->ida_rt, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(ida_destroy);
|
||||
|
||||
/**
|
||||
* ida_simple_get - get a new id.
|
||||
* @ida: the (initialized) ida.
|
||||
* @start: the minimum id (inclusive, < 0x8000000)
|
||||
* @end: the maximum id (exclusive, < 0x8000000 or 0)
|
||||
* @gfp_mask: memory allocation flags
|
||||
* ida_alloc_range() - Allocate an unused ID.
|
||||
* @ida: IDA handle.
|
||||
* @min: Lowest ID to allocate.
|
||||
* @max: Highest ID to allocate.
|
||||
* @gfp: Memory allocation flags.
|
||||
*
|
||||
* Allocates an id in the range start <= id < end, or returns -ENOSPC.
|
||||
* On memory allocation failure, returns -ENOMEM.
|
||||
* Allocate an ID between @min and @max, inclusive. The allocated ID will
|
||||
* not exceed %INT_MAX, even if @max is larger.
|
||||
*
|
||||
* Compared to ida_get_new_above() this function does its own locking, and
|
||||
* should be used unless there are special requirements.
|
||||
*
|
||||
* Use ida_simple_remove() to get rid of an id.
|
||||
* Context: Any context.
|
||||
* Return: The allocated ID, or %-ENOMEM if memory could not be allocated,
|
||||
* or %-ENOSPC if there are no free IDs.
|
||||
*/
|
||||
int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end,
|
||||
gfp_t gfp_mask)
|
||||
int ida_alloc_range(struct ida *ida, unsigned int min, unsigned int max,
|
||||
gfp_t gfp)
|
||||
{
|
||||
int ret, id;
|
||||
unsigned int max;
|
||||
int id = 0;
|
||||
unsigned long flags;
|
||||
|
||||
BUG_ON((int)start < 0);
|
||||
BUG_ON((int)end < 0);
|
||||
if ((int)min < 0)
|
||||
return -ENOSPC;
|
||||
|
||||
if (end == 0)
|
||||
max = 0x80000000;
|
||||
else {
|
||||
BUG_ON(end < start);
|
||||
max = end - 1;
|
||||
}
|
||||
if ((int)max < 0)
|
||||
max = INT_MAX;
|
||||
|
||||
again:
|
||||
if (!ida_pre_get(ida, gfp_mask))
|
||||
return -ENOMEM;
|
||||
|
||||
xa_lock_irqsave(&ida->ida_rt, flags);
|
||||
ret = ida_get_new_above(ida, start, &id);
|
||||
if (!ret) {
|
||||
if (id > max) {
|
||||
ida_remove(ida, id);
|
||||
ret = -ENOSPC;
|
||||
} else {
|
||||
ret = id;
|
||||
}
|
||||
id = ida_get_new_above(ida, min);
|
||||
if (id > (int)max) {
|
||||
ida_remove(ida, id);
|
||||
id = -ENOSPC;
|
||||
}
|
||||
xa_unlock_irqrestore(&ida->ida_rt, flags);
|
||||
|
||||
if (unlikely(ret == -EAGAIN))
|
||||
if (unlikely(id == -EAGAIN)) {
|
||||
if (!ida_pre_get(ida, gfp))
|
||||
return -ENOMEM;
|
||||
goto again;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return id;
|
||||
}
|
||||
EXPORT_SYMBOL(ida_simple_get);
|
||||
EXPORT_SYMBOL(ida_alloc_range);
|
||||
|
||||
/**
|
||||
* ida_simple_remove - remove an allocated id.
|
||||
* @ida: the (initialized) ida.
|
||||
* @id: the id returned by ida_simple_get.
|
||||
* ida_free() - Release an allocated ID.
|
||||
* @ida: IDA handle.
|
||||
* @id: Previously allocated ID.
|
||||
*
|
||||
* Use to release an id allocated with ida_simple_get().
|
||||
*
|
||||
* Compared to ida_remove() this function does its own locking, and should be
|
||||
* used unless there are special requirements.
|
||||
* Context: Any context.
|
||||
*/
|
||||
void ida_simple_remove(struct ida *ida, unsigned int id)
|
||||
void ida_free(struct ida *ida, unsigned int id)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
@@ -619,4 +576,4 @@ void ida_simple_remove(struct ida *ida, unsigned int id)
|
||||
ida_remove(ida, id);
|
||||
xa_unlock_irqrestore(&ida->ida_rt, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(ida_simple_remove);
|
||||
EXPORT_SYMBOL(ida_free);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user