Commit 6d2cf6f2 authored by Bart Van Assche's avatar Bart Van Assche Committed by Jens Axboe

genhd: Annotate all part and part_tbl pointer dereferences

Annotate gendisk.part_tbl and disk_part_tbl.part dereferences with
rcu_dereference_protected(). This patch does not change the behavior
of the modified code but ensures that sparse does not complain about
disk->part_tbl manipulations nor about part_tbl->part accesses.
Additionally, improve documentation of the locking requirements of
the modified functions.
Signed-off-by: default avatarBart Van Assche <bart.vanassche@sandisk.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Jan Kara <jack@suse.cz>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent f8465933
...@@ -1127,12 +1127,13 @@ static const struct attribute_group *disk_attr_groups[] = { ...@@ -1127,12 +1127,13 @@ static const struct attribute_group *disk_attr_groups[] = {
* original ptbl is freed using RCU callback. * original ptbl is freed using RCU callback.
* *
* LOCKING: * LOCKING:
* Matching bd_mutx locked. * Matching bd_mutex locked or the caller is the only user of @disk.
*/ */
static void disk_replace_part_tbl(struct gendisk *disk, static void disk_replace_part_tbl(struct gendisk *disk,
struct disk_part_tbl *new_ptbl) struct disk_part_tbl *new_ptbl)
{ {
struct disk_part_tbl *old_ptbl = disk->part_tbl; struct disk_part_tbl *old_ptbl =
rcu_dereference_protected(disk->part_tbl, 1);
rcu_assign_pointer(disk->part_tbl, new_ptbl); rcu_assign_pointer(disk->part_tbl, new_ptbl);
...@@ -1151,14 +1152,16 @@ static void disk_replace_part_tbl(struct gendisk *disk, ...@@ -1151,14 +1152,16 @@ static void disk_replace_part_tbl(struct gendisk *disk,
* uses RCU to allow unlocked dereferencing for stats and other stuff. * uses RCU to allow unlocked dereferencing for stats and other stuff.
* *
* LOCKING: * LOCKING:
* Matching bd_mutex locked, might sleep. * Matching bd_mutex locked or the caller is the only user of @disk.
* Might sleep.
* *
* RETURNS: * RETURNS:
* 0 on success, -errno on failure. * 0 on success, -errno on failure.
*/ */
int disk_expand_part_tbl(struct gendisk *disk, int partno) int disk_expand_part_tbl(struct gendisk *disk, int partno)
{ {
struct disk_part_tbl *old_ptbl = disk->part_tbl; struct disk_part_tbl *old_ptbl =
rcu_dereference_protected(disk->part_tbl, 1);
struct disk_part_tbl *new_ptbl; struct disk_part_tbl *new_ptbl;
int len = old_ptbl ? old_ptbl->len : 0; int len = old_ptbl ? old_ptbl->len : 0;
int i, target; int i, target;
...@@ -1352,6 +1355,7 @@ EXPORT_SYMBOL(alloc_disk); ...@@ -1352,6 +1355,7 @@ EXPORT_SYMBOL(alloc_disk);
struct gendisk *alloc_disk_node(int minors, int node_id) struct gendisk *alloc_disk_node(int minors, int node_id)
{ {
struct gendisk *disk; struct gendisk *disk;
struct disk_part_tbl *ptbl;
disk = kzalloc_node(sizeof(struct gendisk), GFP_KERNEL, node_id); disk = kzalloc_node(sizeof(struct gendisk), GFP_KERNEL, node_id);
if (disk) { if (disk) {
...@@ -1365,7 +1369,8 @@ struct gendisk *alloc_disk_node(int minors, int node_id) ...@@ -1365,7 +1369,8 @@ struct gendisk *alloc_disk_node(int minors, int node_id)
kfree(disk); kfree(disk);
return NULL; return NULL;
} }
disk->part_tbl->part[0] = &disk->part0; ptbl = rcu_dereference_protected(disk->part_tbl, 1);
rcu_assign_pointer(ptbl->part[0], &disk->part0);
/* /*
* set_capacity() and get_capacity() currently don't use * set_capacity() and get_capacity() currently don't use
......
...@@ -252,15 +252,20 @@ void __delete_partition(struct percpu_ref *ref) ...@@ -252,15 +252,20 @@ void __delete_partition(struct percpu_ref *ref)
call_rcu(&part->rcu_head, delete_partition_rcu_cb); call_rcu(&part->rcu_head, delete_partition_rcu_cb);
} }
/*
* Must be called either with bd_mutex held, before a disk can be opened or
* after all disk users are gone.
*/
void delete_partition(struct gendisk *disk, int partno) void delete_partition(struct gendisk *disk, int partno)
{ {
struct disk_part_tbl *ptbl = disk->part_tbl; struct disk_part_tbl *ptbl =
rcu_dereference_protected(disk->part_tbl, 1);
struct hd_struct *part; struct hd_struct *part;
if (partno >= ptbl->len) if (partno >= ptbl->len)
return; return;
part = ptbl->part[partno]; part = rcu_dereference_protected(ptbl->part[partno], 1);
if (!part) if (!part)
return; return;
...@@ -280,6 +285,10 @@ static ssize_t whole_disk_show(struct device *dev, ...@@ -280,6 +285,10 @@ static ssize_t whole_disk_show(struct device *dev,
static DEVICE_ATTR(whole_disk, S_IRUSR | S_IRGRP | S_IROTH, static DEVICE_ATTR(whole_disk, S_IRUSR | S_IRGRP | S_IROTH,
whole_disk_show, NULL); whole_disk_show, NULL);
/*
* Must be called either with bd_mutex held, before a disk can be opened or
* after all disk users are gone.
*/
struct hd_struct *add_partition(struct gendisk *disk, int partno, struct hd_struct *add_partition(struct gendisk *disk, int partno,
sector_t start, sector_t len, int flags, sector_t start, sector_t len, int flags,
struct partition_meta_info *info) struct partition_meta_info *info)
...@@ -295,7 +304,7 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno, ...@@ -295,7 +304,7 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
err = disk_expand_part_tbl(disk, partno); err = disk_expand_part_tbl(disk, partno);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
ptbl = disk->part_tbl; ptbl = rcu_dereference_protected(disk->part_tbl, 1);
if (ptbl->part[partno]) if (ptbl->part[partno])
return ERR_PTR(-EBUSY); return ERR_PTR(-EBUSY);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment