[Devel] [PATCH VZ9 2/3] block/blk-cbt: allow multiple cbts in a single queue
Andrey Zhadchenko
andrey.zhadchenko at virtuozzo.com
Wed Jan 22 14:05:25 MSK 2025
On 1/22/25 11:51, Pavel Tikhomirov wrote:
>> +static struct cbt_info *blk_cbt_find(struct request_queue *q, __u8
>> *name)
>> +{
>> + struct cbt_info *cbt;
>> +
>> + list_for_each_entry(cbt, &q->cbt_list, list)
>> + if (!memcmp(name, cbt->name, CBT_NAME_LENGTH))
>> + return cbt;
>> +
>> + return NULL;
>> +}
>> +
>> static int blk_cbt_snap_create(struct request_queue *q, __u8 *name,
>> struct blk_user_cbt_snap_create __user *arg)
>> {
>> @@ -382,8 +397,7 @@ static int blk_cbt_snap_create(struct
>> request_queue *q, __u8 *name,
>> return -EFAULT;
>> mutex_lock(&cbt_mutex);
>> - cbt = q->cbt;
>> -
>> + cbt = blk_cbt_find(q, name);
>> if (!cbt) {
>> mutex_unlock(&cbt_mutex);
>> return -ENOENT;
>> @@ -392,11 +406,6 @@ static int blk_cbt_snap_create(struct
>> request_queue *q, __u8 *name,
>> BUG_ON(!cbt->map);
>> BUG_ON(!cbt->block_max);
>> - if (!name || memcmp(name, cbt->name, sizeof(cbt->name))) {
>> - mutex_unlock(&cbt_mutex);
>> - return -EINVAL;
>> - }
>> -
>> if (cbt->snp_map) {
>> mutex_unlock(&cbt_mutex);
>> return -EBUSY;
> ...
>> @@ -667,35 +665,46 @@ static void cbt_release_callback(struct rcu_head
>> *head)
>> kfree(cbt);
>> }
>> -void blk_cbt_release(struct request_queue *q)
>> +static void blk_cbt_del(struct cbt_info *cbt)
>> {
>> - struct cbt_info *cbt;
>> - int in_use = 0;
>> unsigned long flags;
>> + int in_use;
>> - cbt = q->cbt;
>> - if (!cbt)
>> - return;
>> spin_lock_irqsave(&cbt->lock, flags);
>> set_bit(CBT_DEAD, &cbt->flags);
>> - rcu_assign_pointer(q->cbt, NULL);
>> + list_del_rcu(&cbt->list);
>> in_use = cbt->count;
>> spin_unlock_irqrestore(&cbt->lock, flags);
>> if (!in_use)
>> call_rcu(&cbt->rcu, &cbt_release_callback);
>> }
>
> Why we don't take rcu_read_lock around list iteration in blk_cbt_find?
> If we don't take rcu_read_lock there, the cbt returned from blk_cbt_find
> can be already freed.
rcu is not taken on a path where mutex is held. cbt_mutex makes user
operations exclusive, so there won't be any race. Maybe I should add a
comment then?
>
> I see other places of _rcu walk without rcu_read_lock, e.g.:
> cbt_page_alloc (!in_rcu) case, blk_cbt_update_size.
>
> Also list can be broken probably if blk_cbt_del runs concurrently with
> itself (blk_cbt_release vs cbt_ioc_stop). I think the whole loop in
> blk_cbt_release should be protected against concurrent cbt_ioc_stop
> (that may be true as blk_cbt_release probably runs at the very end).
>
I don't think blk_cbt_release can be run concurrently win any of blk_cbt
functions, because they are operation on a file descriptor. I am sure
that kernel won't call blk_cbt_release() when some fd still refers to
the device
More information about the Devel
mailing list