public inbox for linux-block@vger.kernel.org
 help / color / mirror / Atom feed
* [bug report] blk-iocost: don't release 'ioc->lock' while updating params
@ 2022-10-26 14:14 Dan Carpenter
  2022-10-27  1:20 ` Yu Kuai
  0 siblings, 1 reply; 2+ messages in thread
From: Dan Carpenter @ 2022-10-26 14:14 UTC (permalink / raw)
  To: yukuai3; +Cc: linux-block

Hello Yu Kuai,

The patch 2c0647988433: "blk-iocost: don't release 'ioc->lock' while
updating params" from Oct 12, 2022, leads to the following Smatch
static checker warnings:

block/blk-iocost.c:3211 ioc_qos_write() warn: sleeping in atomic context
block/blk-iocost.c:3240 ioc_qos_write() warn: sleeping in atomic context
block/blk-iocost.c:3407 ioc_cost_model_write() warn: sleeping in atomic context

block/blk-iocost.c
    3168 static ssize_t ioc_qos_write(struct kernfs_open_file *of, char *input,
    3169                              size_t nbytes, loff_t off)
    3170 {
    3171         struct block_device *bdev;
    3172         struct gendisk *disk;
    3173         struct ioc *ioc;
    3174         u32 qos[NR_QOS_PARAMS];
    3175         bool enable, user;
    3176         char *p;
    3177         int ret;
    3178 
    3179         bdev = blkcg_conf_open_bdev(&input);
    3180         if (IS_ERR(bdev))
    3181                 return PTR_ERR(bdev);
    3182 
    3183         disk = bdev->bd_disk;
    3184         ioc = q_to_ioc(disk->queue);
    3185         if (!ioc) {
    3186                 ret = blk_iocost_init(disk);
    3187                 if (ret)
    3188                         goto err;
    3189                 ioc = q_to_ioc(disk->queue);
    3190         }
    3191 
    3192         blk_mq_freeze_queue(disk->queue);
    3193         blk_mq_quiesce_queue(disk->queue);
    3194 
    3195         spin_lock_irq(&ioc->lock);

Preempt disabled.

    3196         memcpy(qos, ioc->params.qos, sizeof(qos));
    3197         enable = ioc->enabled;
    3198         user = ioc->user_qos_params;
    3199 
    3200         while ((p = strsep(&input, " \t\n"))) {
    3201                 substring_t args[MAX_OPT_ARGS];
    3202                 char buf[32];
    3203                 int tok;
    3204                 s64 v;
    3205 
    3206                 if (!*p)
    3207                         continue;
    3208 
    3209                 switch (match_token(p, qos_ctrl_tokens, args)) {
    3210                 case QOS_ENABLE:
--> 3211                         match_u64(&args[0], &v);
                                 ^^^^^^^^^^^^^^^^^^^^^^^^
match functions do sleeping allocations.

    3212                         enable = v;
    3213                         continue;
    3214                 case QOS_CTRL:
    3215                         match_strlcpy(buf, &args[0], sizeof(buf));
    3216                         if (!strcmp(buf, "auto"))
    3217                                 user = false;
    3218                         else if (!strcmp(buf, "user"))
    3219                                 user = true;
    3220                         else
    3221                                 goto einval;
    3222                         continue;
    3223                 }
    3224 
    3225                 tok = match_token(p, qos_tokens, args);
    3226                 switch (tok) {
    3227                 case QOS_RPPM:
    3228                 case QOS_WPPM:
    3229                         if (match_strlcpy(buf, &args[0], sizeof(buf)) >=
    3230                             sizeof(buf))
    3231                                 goto einval;
    3232                         if (cgroup_parse_float(buf, 2, &v))
    3233                                 goto einval;
    3234                         if (v < 0 || v > 10000)
    3235                                 goto einval;
    3236                         qos[tok] = v * 100;
    3237                         break;
    3238                 case QOS_RLAT:
    3239                 case QOS_WLAT:
    3240                         if (match_u64(&args[0], &v))
    3241                                 goto einval;
    3242                         qos[tok] = v;
    3243                         break;
    3244                 case QOS_MIN:
    3245                 case QOS_MAX:
    3246                         if (match_strlcpy(buf, &args[0], sizeof(buf)) >=
    3247                             sizeof(buf))
    3248                                 goto einval;
    3249                         if (cgroup_parse_float(buf, 2, &v))
    3250                                 goto einval;
    3251                         if (v < 0)
    3252                                 goto einval;
    3253                         qos[tok] = clamp_t(s64, v * 100,
    3254                                            VRATE_MIN_PPM, VRATE_MAX_PPM);
    3255                         break;
    3256                 default:
    3257                         goto einval;
    3258                 }
    3259                 user = true;
    3260         }
    3261 
    3262         if (qos[QOS_MIN] > qos[QOS_MAX])
    3263                 goto einval;
    3264 
    3265         if (enable) {
    3266                 blk_stat_enable_accounting(disk->queue);
    3267                 blk_queue_flag_set(QUEUE_FLAG_RQ_ALLOC_TIME, disk->queue);
    3268                 ioc->enabled = true;
    3269                 wbt_disable_default(disk->queue);
    3270         } else {
    3271                 blk_queue_flag_clear(QUEUE_FLAG_RQ_ALLOC_TIME, disk->queue);
    3272                 ioc->enabled = false;
    3273                 wbt_enable_default(disk->queue);
    3274         }
    3275 
    3276         if (user) {
    3277                 memcpy(ioc->params.qos, qos, sizeof(qos));
    3278                 ioc->user_qos_params = true;
    3279         } else {
    3280                 ioc->user_qos_params = false;
    3281         }
    3282 
    3283         ioc_refresh_params(ioc, true);
    3284         spin_unlock_irq(&ioc->lock);
    3285 
    3286         blk_mq_unquiesce_queue(disk->queue);
    3287         blk_mq_unfreeze_queue(disk->queue);
    3288 
    3289         blkdev_put_no_open(bdev);
    3290         return nbytes;
    3291 einval:
    3292         spin_unlock_irq(&ioc->lock);
    3293 
    3294         blk_mq_unquiesce_queue(disk->queue);
    3295         blk_mq_unfreeze_queue(disk->queue);
    3296 
    3297         ret = -EINVAL;
    3298 err:
    3299         blkdev_put_no_open(bdev);
    3300         return ret;
    3301 }

regards,
dan carpenter

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [bug report] blk-iocost: don't release 'ioc->lock' while updating params
  2022-10-26 14:14 [bug report] blk-iocost: don't release 'ioc->lock' while updating params Dan Carpenter
@ 2022-10-27  1:20 ` Yu Kuai
  0 siblings, 0 replies; 2+ messages in thread
From: Yu Kuai @ 2022-10-27  1:20 UTC (permalink / raw)
  To: Dan Carpenter; +Cc: linux-block, yukuai (C)

Hi, Dan!

在 2022/10/26 22:14, Dan Carpenter 写道:
> Hello Yu Kuai,
> 
> The patch 2c0647988433: "blk-iocost: don't release 'ioc->lock' while
> updating params" from Oct 12, 2022, leads to the following Smatch
> static checker warnings:
> 
> block/blk-iocost.c:3211 ioc_qos_write() warn: sleeping in atomic context
> block/blk-iocost.c:3240 ioc_qos_write() warn: sleeping in atomic context
> block/blk-iocost.c:3407 ioc_cost_model_write() warn: sleeping in atomic context
> 
> block/blk-iocost.c
>      3168 static ssize_t ioc_qos_write(struct kernfs_open_file *of, char *input,
>      3169                              size_t nbytes, loff_t off)
>      3170 {
>      3171         struct block_device *bdev;
>      3172         struct gendisk *disk;
>      3173         struct ioc *ioc;
>      3174         u32 qos[NR_QOS_PARAMS];
>      3175         bool enable, user;
>      3176         char *p;
>      3177         int ret;
>      3178
>      3179         bdev = blkcg_conf_open_bdev(&input);
>      3180         if (IS_ERR(bdev))
>      3181                 return PTR_ERR(bdev);
>      3182
>      3183         disk = bdev->bd_disk;
>      3184         ioc = q_to_ioc(disk->queue);
>      3185         if (!ioc) {
>      3186                 ret = blk_iocost_init(disk);
>      3187                 if (ret)
>      3188                         goto err;
>      3189                 ioc = q_to_ioc(disk->queue);
>      3190         }
>      3191
>      3192         blk_mq_freeze_queue(disk->queue);
>      3193         blk_mq_quiesce_queue(disk->queue);
>      3194
>      3195         spin_lock_irq(&ioc->lock);
> 
> Preempt disabled.
> 
>      3196         memcpy(qos, ioc->params.qos, sizeof(qos));
>      3197         enable = ioc->enabled;
>      3198         user = ioc->user_qos_params;
>      3199
>      3200         while ((p = strsep(&input, " \t\n"))) {
>      3201                 substring_t args[MAX_OPT_ARGS];
>      3202                 char buf[32];
>      3203                 int tok;
>      3204                 s64 v;
>      3205
>      3206                 if (!*p)
>      3207                         continue;
>      3208
>      3209                 switch (match_token(p, qos_ctrl_tokens, args)) {
>      3210                 case QOS_ENABLE:
> --> 3211                         match_u64(&args[0], &v);
>                                   ^^^^^^^^^^^^^^^^^^^^^^^^
> match functions do sleeping allocations.
Thanks for the report, I'll try to fix this soon.

Kuai
> 
>      3212                         enable = v;
>      3213                         continue;
>      3214                 case QOS_CTRL:
>      3215                         match_strlcpy(buf, &args[0], sizeof(buf));
>      3216                         if (!strcmp(buf, "auto"))
>      3217                                 user = false;
>      3218                         else if (!strcmp(buf, "user"))
>      3219                                 user = true;
>      3220                         else
>      3221                                 goto einval;
>      3222                         continue;
>      3223                 }
>      3224
>      3225                 tok = match_token(p, qos_tokens, args);
>      3226                 switch (tok) {
>      3227                 case QOS_RPPM:
>      3228                 case QOS_WPPM:
>      3229                         if (match_strlcpy(buf, &args[0], sizeof(buf)) >=
>      3230                             sizeof(buf))
>      3231                                 goto einval;
>      3232                         if (cgroup_parse_float(buf, 2, &v))
>      3233                                 goto einval;
>      3234                         if (v < 0 || v > 10000)
>      3235                                 goto einval;
>      3236                         qos[tok] = v * 100;
>      3237                         break;
>      3238                 case QOS_RLAT:
>      3239                 case QOS_WLAT:
>      3240                         if (match_u64(&args[0], &v))
>      3241                                 goto einval;
>      3242                         qos[tok] = v;
>      3243                         break;
>      3244                 case QOS_MIN:
>      3245                 case QOS_MAX:
>      3246                         if (match_strlcpy(buf, &args[0], sizeof(buf)) >=
>      3247                             sizeof(buf))
>      3248                                 goto einval;
>      3249                         if (cgroup_parse_float(buf, 2, &v))
>      3250                                 goto einval;
>      3251                         if (v < 0)
>      3252                                 goto einval;
>      3253                         qos[tok] = clamp_t(s64, v * 100,
>      3254                                            VRATE_MIN_PPM, VRATE_MAX_PPM);
>      3255                         break;
>      3256                 default:
>      3257                         goto einval;
>      3258                 }
>      3259                 user = true;
>      3260         }
>      3261
>      3262         if (qos[QOS_MIN] > qos[QOS_MAX])
>      3263                 goto einval;
>      3264
>      3265         if (enable) {
>      3266                 blk_stat_enable_accounting(disk->queue);
>      3267                 blk_queue_flag_set(QUEUE_FLAG_RQ_ALLOC_TIME, disk->queue);
>      3268                 ioc->enabled = true;
>      3269                 wbt_disable_default(disk->queue);
>      3270         } else {
>      3271                 blk_queue_flag_clear(QUEUE_FLAG_RQ_ALLOC_TIME, disk->queue);
>      3272                 ioc->enabled = false;
>      3273                 wbt_enable_default(disk->queue);
>      3274         }
>      3275
>      3276         if (user) {
>      3277                 memcpy(ioc->params.qos, qos, sizeof(qos));
>      3278                 ioc->user_qos_params = true;
>      3279         } else {
>      3280                 ioc->user_qos_params = false;
>      3281         }
>      3282
>      3283         ioc_refresh_params(ioc, true);
>      3284         spin_unlock_irq(&ioc->lock);
>      3285
>      3286         blk_mq_unquiesce_queue(disk->queue);
>      3287         blk_mq_unfreeze_queue(disk->queue);
>      3288
>      3289         blkdev_put_no_open(bdev);
>      3290         return nbytes;
>      3291 einval:
>      3292         spin_unlock_irq(&ioc->lock);
>      3293
>      3294         blk_mq_unquiesce_queue(disk->queue);
>      3295         blk_mq_unfreeze_queue(disk->queue);
>      3296
>      3297         ret = -EINVAL;
>      3298 err:
>      3299         blkdev_put_no_open(bdev);
>      3300         return ret;
>      3301 }
> 
> regards,
> dan carpenter
> 
> .
> 


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2022-10-27  1:21 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-10-26 14:14 [bug report] blk-iocost: don't release 'ioc->lock' while updating params Dan Carpenter
2022-10-27  1:20 ` Yu Kuai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox