Skip to content

Commit a33df75

Browse files
Christoph Hellwigaxboe
authored andcommitted
block: use an xarray for disk->part_tbl
Now that no fast path lookups in the partition table are left, there is no point in micro-optimizing the data structure for it. Just use a bog standard xarray. Signed-off-by: Christoph Hellwig <hch@lst.de> Acked-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 0470dd9 commit a33df75

File tree

5 files changed

+22
-193
lines changed

5 files changed

+22
-193
lines changed

block/blk-settings.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -865,7 +865,7 @@ void blk_queue_set_zoned(struct gendisk *disk, enum blk_zoned_model model)
865865
* we do nothing special as far as the block layer is concerned.
866866
*/
867867
if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) ||
868-
disk_has_partitions(disk))
868+
!xa_empty(&disk->part_tbl))
869869
model = BLK_ZONED_NONE;
870870
break;
871871
case BLK_ZONED_NONE:

block/blk.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,6 @@ int bdev_add_partition(struct block_device *bdev, int partno,
345345
int bdev_del_partition(struct block_device *bdev, int partno);
346346
int bdev_resize_partition(struct block_device *bdev, int partno,
347347
sector_t start, sector_t length);
348-
int disk_expand_part_tbl(struct gendisk *disk, int target);
349348

350349
int bio_add_hw_page(struct request_queue *q, struct bio *bio,
351350
struct page *page, unsigned int len, unsigned int offset,

block/genhd.c

Lines changed: 12 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -161,15 +161,6 @@ static void part_in_flight_rw(struct block_device *part,
161161
inflight[1] = 0;
162162
}
163163

164-
static struct block_device *__disk_get_part(struct gendisk *disk, int partno)
165-
{
166-
struct disk_part_tbl *ptbl = rcu_dereference(disk->part_tbl);
167-
168-
if (unlikely(partno < 0 || partno >= ptbl->len))
169-
return NULL;
170-
return rcu_dereference(ptbl->part[partno]);
171-
}
172-
173164
/**
174165
* disk_part_iter_init - initialize partition iterator
175166
* @piter: iterator to initialize
@@ -204,41 +195,26 @@ void disk_part_iter_init(struct disk_part_iter *piter, struct gendisk *disk,
204195
*/
205196
struct block_device *disk_part_iter_next(struct disk_part_iter *piter)
206197
{
207-
struct disk_part_tbl *ptbl;
198+
struct block_device *part;
199+
unsigned long idx;
208200

209201
/* put the last partition */
210202
disk_part_iter_exit(piter);
211203

212-
/* get part_tbl */
213204
rcu_read_lock();
214-
ptbl = rcu_dereference(piter->disk->part_tbl);
215-
216-
/* iterate to the next partition */
217-
for (; piter->idx != ptbl->len; piter->idx += 1) {
218-
struct block_device *part;
219-
220-
part = rcu_dereference(ptbl->part[piter->idx]);
221-
if (!part)
222-
continue;
223-
piter->part = bdgrab(part);
224-
if (!piter->part)
225-
continue;
205+
xa_for_each_start(&piter->disk->part_tbl, idx, part, piter->idx) {
226206
if (!bdev_nr_sectors(part) &&
227207
!(piter->flags & DISK_PITER_INCL_EMPTY) &&
228208
!(piter->flags & DISK_PITER_INCL_EMPTY_PART0 &&
229-
piter->idx == 0)) {
230-
bdput(piter->part);
231-
piter->part = NULL;
209+
piter->idx == 0))
232210
continue;
233-
}
234211

235212
piter->part = bdgrab(part);
236213
if (!piter->part)
237214
continue;
238-
piter->idx += 1;
215+
piter->idx = idx + 1;
239216
break;
240217
}
241-
242218
rcu_read_unlock();
243219

244220
return piter->part;
@@ -260,42 +236,6 @@ void disk_part_iter_exit(struct disk_part_iter *piter)
260236
piter->part = NULL;
261237
}
262238

263-
/**
264-
* disk_has_partitions
265-
* @disk: gendisk of interest
266-
*
267-
* Walk through the partition table and check if valid partition exists.
268-
*
269-
* CONTEXT:
270-
* Don't care.
271-
*
272-
* RETURNS:
273-
* True if the gendisk has at least one valid non-zero size partition.
274-
* Otherwise false.
275-
*/
276-
bool disk_has_partitions(struct gendisk *disk)
277-
{
278-
struct disk_part_tbl *ptbl;
279-
int i;
280-
bool ret = false;
281-
282-
rcu_read_lock();
283-
ptbl = rcu_dereference(disk->part_tbl);
284-
285-
/* Iterate partitions skipping the whole device at index 0 */
286-
for (i = 1; i < ptbl->len; i++) {
287-
if (rcu_dereference(ptbl->part[i])) {
288-
ret = true;
289-
break;
290-
}
291-
}
292-
293-
rcu_read_unlock();
294-
295-
return ret;
296-
}
297-
EXPORT_SYMBOL_GPL(disk_has_partitions);
298-
299239
/*
300240
* Can be deleted altogether. Later.
301241
*
@@ -858,7 +798,7 @@ struct block_device *bdget_disk(struct gendisk *disk, int partno)
858798
struct block_device *bdev = NULL;
859799

860800
rcu_read_lock();
861-
bdev = __disk_get_part(disk, partno);
801+
bdev = xa_load(&disk->part_tbl, partno);
862802
if (bdev && !bdgrab(bdev))
863803
bdev = NULL;
864804
rcu_read_unlock();
@@ -1248,83 +1188,6 @@ static const struct attribute_group *disk_attr_groups[] = {
12481188
NULL
12491189
};
12501190

1251-
/**
1252-
* disk_replace_part_tbl - replace disk->part_tbl in RCU-safe way
1253-
* @disk: disk to replace part_tbl for
1254-
* @new_ptbl: new part_tbl to install
1255-
*
1256-
* Replace disk->part_tbl with @new_ptbl in RCU-safe way. The
1257-
* original ptbl is freed using RCU callback.
1258-
*
1259-
* LOCKING:
1260-
* Matching bd_mutex locked or the caller is the only user of @disk.
1261-
*/
1262-
static void disk_replace_part_tbl(struct gendisk *disk,
1263-
struct disk_part_tbl *new_ptbl)
1264-
{
1265-
struct disk_part_tbl *old_ptbl =
1266-
rcu_dereference_protected(disk->part_tbl, 1);
1267-
1268-
rcu_assign_pointer(disk->part_tbl, new_ptbl);
1269-
1270-
if (old_ptbl) {
1271-
rcu_assign_pointer(old_ptbl->last_lookup, NULL);
1272-
kfree_rcu(old_ptbl, rcu_head);
1273-
}
1274-
}
1275-
1276-
/**
1277-
* disk_expand_part_tbl - expand disk->part_tbl
1278-
* @disk: disk to expand part_tbl for
1279-
* @partno: expand such that this partno can fit in
1280-
*
1281-
* Expand disk->part_tbl such that @partno can fit in. disk->part_tbl
1282-
* uses RCU to allow unlocked dereferencing for stats and other stuff.
1283-
*
1284-
* LOCKING:
1285-
* Matching bd_mutex locked or the caller is the only user of @disk.
1286-
* Might sleep.
1287-
*
1288-
* RETURNS:
1289-
* 0 on success, -errno on failure.
1290-
*/
1291-
int disk_expand_part_tbl(struct gendisk *disk, int partno)
1292-
{
1293-
struct disk_part_tbl *old_ptbl =
1294-
rcu_dereference_protected(disk->part_tbl, 1);
1295-
struct disk_part_tbl *new_ptbl;
1296-
int len = old_ptbl ? old_ptbl->len : 0;
1297-
int i, target;
1298-
1299-
/*
1300-
* check for int overflow, since we can get here from blkpg_ioctl()
1301-
* with a user passed 'partno'.
1302-
*/
1303-
target = partno + 1;
1304-
if (target < 0)
1305-
return -EINVAL;
1306-
1307-
/* disk_max_parts() is zero during initialization, ignore if so */
1308-
if (disk_max_parts(disk) && target > disk_max_parts(disk))
1309-
return -EINVAL;
1310-
1311-
if (target <= len)
1312-
return 0;
1313-
1314-
new_ptbl = kzalloc_node(struct_size(new_ptbl, part, target), GFP_KERNEL,
1315-
disk->node_id);
1316-
if (!new_ptbl)
1317-
return -ENOMEM;
1318-
1319-
new_ptbl->len = target;
1320-
1321-
for (i = 0; i < len; i++)
1322-
rcu_assign_pointer(new_ptbl->part[i], old_ptbl->part[i]);
1323-
1324-
disk_replace_part_tbl(disk, new_ptbl);
1325-
return 0;
1326-
}
1327-
13281191
/**
13291192
* disk_release - releases all allocated resources of the gendisk
13301193
* @dev: the device representing this disk
@@ -1348,7 +1211,7 @@ static void disk_release(struct device *dev)
13481211
blk_free_devt(dev->devt);
13491212
disk_release_events(disk);
13501213
kfree(disk->random);
1351-
disk_replace_part_tbl(disk, NULL);
1214+
xa_destroy(&disk->part_tbl);
13521215
bdput(disk->part0);
13531216
if (disk->queue)
13541217
blk_put_queue(disk->queue);
@@ -1501,7 +1364,6 @@ dev_t blk_lookup_devt(const char *name, int partno)
15011364
struct gendisk *__alloc_disk_node(int minors, int node_id)
15021365
{
15031366
struct gendisk *disk;
1504-
struct disk_part_tbl *ptbl;
15051367

15061368
if (minors > DISK_MAX_PARTS) {
15071369
printk(KERN_ERR
@@ -1519,11 +1381,9 @@ struct gendisk *__alloc_disk_node(int minors, int node_id)
15191381
goto out_free_disk;
15201382

15211383
disk->node_id = node_id;
1522-
if (disk_expand_part_tbl(disk, 0))
1523-
goto out_bdput;
1524-
1525-
ptbl = rcu_dereference_protected(disk->part_tbl, 1);
1526-
rcu_assign_pointer(ptbl->part[0], disk->part0);
1384+
xa_init(&disk->part_tbl);
1385+
if (xa_insert(&disk->part_tbl, 0, disk->part0, GFP_KERNEL))
1386+
goto out_destroy_part_tbl;
15271387

15281388
disk->minors = minors;
15291389
rand_initialize_disk(disk);
@@ -1532,7 +1392,8 @@ struct gendisk *__alloc_disk_node(int minors, int node_id)
15321392
device_initialize(disk_to_dev(disk));
15331393
return disk;
15341394

1535-
out_bdput:
1395+
out_destroy_part_tbl:
1396+
xa_destroy(&disk->part_tbl);
15361397
bdput(disk->part0);
15371398
out_free_disk:
15381399
kfree(disk);

block/partitions/core.c

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -287,13 +287,7 @@ struct device_type part_type = {
287287
*/
288288
void delete_partition(struct block_device *part)
289289
{
290-
struct gendisk *disk = part->bd_disk;
291-
struct disk_part_tbl *ptbl =
292-
rcu_dereference_protected(disk->part_tbl, 1);
293-
294-
rcu_assign_pointer(ptbl->part[part->bd_partno], NULL);
295-
rcu_assign_pointer(ptbl->last_lookup, NULL);
296-
290+
xa_erase(&part->bd_disk->part_tbl, part->bd_partno);
297291
kobject_put(part->bd_holder_dir);
298292
device_del(&part->bd_device);
299293

@@ -325,7 +319,6 @@ static struct block_device *add_partition(struct gendisk *disk, int partno,
325319
struct device *ddev = disk_to_dev(disk);
326320
struct device *pdev;
327321
struct block_device *bdev;
328-
struct disk_part_tbl *ptbl;
329322
const char *dname;
330323
int err;
331324

@@ -347,12 +340,7 @@ static struct block_device *add_partition(struct gendisk *disk, int partno,
347340
break;
348341
}
349342

350-
err = disk_expand_part_tbl(disk, partno);
351-
if (err)
352-
return ERR_PTR(err);
353-
ptbl = rcu_dereference_protected(disk->part_tbl, 1);
354-
355-
if (ptbl->part[partno])
343+
if (xa_load(&disk->part_tbl, partno))
356344
return ERR_PTR(-EBUSY);
357345

358346
bdev = bdev_alloc(disk, partno);
@@ -405,8 +393,10 @@ static struct block_device *add_partition(struct gendisk *disk, int partno,
405393
}
406394

407395
/* everything is up and running, commence */
396+
err = xa_insert(&disk->part_tbl, partno, bdev, GFP_KERNEL);
397+
if (err)
398+
goto out_del;
408399
bdev_add(bdev, devt);
409-
rcu_assign_pointer(ptbl->part[partno], bdev);
410400

411401
/* suppress uevent if the disk suppresses it */
412402
if (!dev_get_uevent_suppress(ddev))
@@ -612,7 +602,7 @@ static bool blk_add_partition(struct gendisk *disk, struct block_device *bdev,
612602
int blk_add_partitions(struct gendisk *disk, struct block_device *bdev)
613603
{
614604
struct parsed_partitions *state;
615-
int ret = -EAGAIN, p, highest;
605+
int ret = -EAGAIN, p;
616606

617607
if (!disk_part_scan_enabled(disk))
618608
return 0;
@@ -660,15 +650,6 @@ int blk_add_partitions(struct gendisk *disk, struct block_device *bdev)
660650
/* tell userspace that the media / partition table may have changed */
661651
kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE);
662652

663-
/*
664-
* Detect the highest partition number and preallocate disk->part_tbl.
665-
* This is an optimization and not strictly necessary.
666-
*/
667-
for (p = 1, highest = 0; p < state->limit; p++)
668-
if (state->parts[p].size)
669-
highest = p;
670-
disk_expand_part_tbl(disk, highest);
671-
672653
for (p = 1; p < state->limit; p++)
673654
if (!blk_add_partition(disk, bdev, state, p))
674655
goto out_free_state;

include/linux/genhd.h

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ extern struct class block_class;
3232
#include <linux/string.h>
3333
#include <linux/fs.h>
3434
#include <linux/workqueue.h>
35+
#include <linux/xarray.h>
3536

3637
#define PARTITION_META_INFO_VOLNAMELTH 64
3738
/*
@@ -116,13 +117,6 @@ enum {
116117
DISK_EVENT_FLAG_UEVENT = 1 << 1,
117118
};
118119

119-
struct disk_part_tbl {
120-
struct rcu_head rcu_head;
121-
int len;
122-
struct block_device __rcu *last_lookup;
123-
struct block_device __rcu *part[];
124-
};
125-
126120
struct disk_events;
127121
struct badblocks;
128122

@@ -148,12 +142,7 @@ struct gendisk {
148142
unsigned short events; /* supported events */
149143
unsigned short event_flags; /* flags related to event processing */
150144

151-
/* Array of pointers to partitions indexed by partno.
152-
* Protected with matching bdev lock but stat and other
153-
* non-critical accesses use RCU. Always access through
154-
* helpers.
155-
*/
156-
struct disk_part_tbl __rcu *part_tbl;
145+
struct xarray part_tbl;
157146
struct block_device *part0;
158147

159148
const struct block_device_operations *fops;
@@ -225,15 +214,14 @@ void disk_uevent(struct gendisk *disk, enum kobject_action action);
225214
struct disk_part_iter {
226215
struct gendisk *disk;
227216
struct block_device *part;
228-
int idx;
217+
unsigned long idx;
229218
unsigned int flags;
230219
};
231220

232221
extern void disk_part_iter_init(struct disk_part_iter *piter,
233222
struct gendisk *disk, unsigned int flags);
234223
struct block_device *disk_part_iter_next(struct disk_part_iter *piter);
235224
extern void disk_part_iter_exit(struct disk_part_iter *piter);
236-
extern bool disk_has_partitions(struct gendisk *disk);
237225

238226
/* block/genhd.c */
239227
extern void device_add_disk(struct device *parent, struct gendisk *disk,

0 commit comments

Comments
 (0)