AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/08/01 07:44 flow patch-triage
0m Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch introduces sparse annotations (e.g., __must_hold, __acquires, __releases, __guarded_by) and CONTEXT_ANALYSIS := y to Makefiles in the block layer to enable static context analysis. It also refactors some locking logic (like extracting __loop_change_fd and __loop_configure in loop.c, and using guard()/scoped_guard() in null_blk/zoned.c) to make the locking behavior unconditional and verifiable by the static analyzer. There are no functional changes to the execution flow or logic of the kernel.",
  "WorthFuzzing": false
}

1/1 2026/08/01 07:44 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 27615096d419701f4321b1b70aa03a0b54bb802e\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Sat Aug 1 07:44:24 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/drivers/block/Makefile b/drivers/block/Makefile\nindex 2d8096eb8cdf8..e17f6381b7982 100644\n--- a/drivers/block/Makefile\n+++ b/drivers/block/Makefile\n@@ -6,6 +6,8 @@\n # Rewritten to use lists instead of if-statements.\n # \n \n+CONTEXT_ANALYSIS := y\n+\n # needed for trace events\n ccflags-y\t\t\t\t+= -I$(src)\n \ndiff --git a/drivers/block/aoe/Makefile b/drivers/block/aoe/Makefile\nindex b7545ce2f1b0f..27bff6359a56e 100644\n--- a/drivers/block/aoe/Makefile\n+++ b/drivers/block/aoe/Makefile\n@@ -3,5 +3,7 @@\n # Makefile for ATA over Ethernet\n #\n \n+CONTEXT_ANALYSIS := y\n+\n obj-$(CONFIG_ATA_OVER_ETH)\t+= aoe.o\n aoe-y := aoeblk.o aoechr.o aoecmd.o aoedev.o aoemain.o aoenet.o\ndiff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c\nindex a4744a30a8af4..54c57b9f88942 100644\n--- a/drivers/block/aoe/aoecmd.c\n+++ b/drivers/block/aoe/aoecmd.c\n@@ -1193,6 +1193,7 @@ noskb:\t\tif (buf)\n  */\n static int\n ktio(int id)\n+\t__must_hold(\u0026iocq[id].lock)\n {\n \tstruct frame *f;\n \tstruct list_head *pos;\ndiff --git a/drivers/block/loop.c b/drivers/block/loop.c\nindex 1faecef330092..e2ac19de11f42 100644\n--- a/drivers/block/loop.c\n+++ b/drivers/block/loop.c\n@@ -90,33 +90,32 @@ struct loop_cmd {\n #define LOOP_IDLE_WORKER_TIMEOUT (60 * HZ)\n #define LOOP_DEFAULT_HW_Q_DEPTH 128\n \n-static DEFINE_IDR(loop_index_idr);\n static DEFINE_MUTEX(loop_ctl_mutex);\n+static __guarded_by(\u0026loop_ctl_mutex) DEFINE_IDR(loop_index_idr);\n static DEFINE_MUTEX(loop_validate_mutex);\n \n /**\n  * loop_global_lock_killable() - take locks for safe loop_validate_file() test\n  *\n  * @lo: struct loop_device\n- * @global: true if @lo is about to bind another \"struct loop_device\", false otherwise\n  *\n  * Returns 0 on success, -EINTR otherwise.\n  *\n- * Since loop_validate_file() traverses on other \"struct loop_device\" if\n- * is_loop_device() is true, we need a global lock for serializing concurrent\n+ * Since loop_validate_file() traverses on other \"struct loop_device\", we need a\n+ * global lock for serializing concurrent\n  * loop_configure()/loop_change_fd()/__loop_clr_fd() calls.\n  */\n-static int loop_global_lock_killable(struct loop_device *lo, bool global)\n+static int loop_global_lock_killable(struct loop_device *lo)\n+\t__cond_acquires(0, \u0026loop_validate_mutex)\n+\t__cond_acquires(0, \u0026lo-\u003elo_mutex)\n {\n \tint err;\n \n-\tif (global) {\n-\t\terr = mutex_lock_killable(\u0026loop_validate_mutex);\n-\t\tif (err)\n-\t\t\treturn err;\n-\t}\n+\terr = mutex_lock_killable(\u0026loop_validate_mutex);\n+\tif (err)\n+\t\treturn err;\n \terr = mutex_lock_killable(\u0026lo-\u003elo_mutex);\n-\tif (err \u0026\u0026 global)\n+\tif (err)\n \t\tmutex_unlock(\u0026loop_validate_mutex);\n \treturn err;\n }\n@@ -125,13 +124,13 @@ static int loop_global_lock_killable(struct loop_device *lo, bool global)\n  * loop_global_unlock() - release locks taken by loop_global_lock_killable()\n  *\n  * @lo: struct loop_device\n- * @global: true if @lo was about to bind another \"struct loop_device\", false otherwise\n  */\n-static void loop_global_unlock(struct loop_device *lo, bool global)\n+static void loop_global_unlock(struct loop_device *lo)\n+\t__releases(\u0026lo-\u003elo_mutex)\n+\t__releases(\u0026loop_validate_mutex)\n {\n \tmutex_unlock(\u0026lo-\u003elo_mutex);\n-\tif (global)\n-\t\tmutex_unlock(\u0026loop_validate_mutex);\n+\tmutex_unlock(\u0026loop_validate_mutex);\n }\n \n static int max_part;\n@@ -523,6 +522,50 @@ static int loop_check_backing_file(struct file *file)\n \treturn 0;\n }\n \n+static int __loop_change_fd(struct loop_device *lo, struct block_device *bdev,\n+\t\t\t    struct file *file, struct file **old_file,\n+\t\t\t    bool *partscan)\n+\t__must_hold(\u0026lo-\u003elo_mutex)\n+{\n+\tunsigned int memflags;\n+\tint error;\n+\n+\tif (lo-\u003elo_state != Lo_bound)\n+\t\treturn -ENXIO;\n+\n+\t/* the loop device has to be read-only */\n+\tif (!(lo-\u003elo_flags \u0026 LO_FLAGS_READ_ONLY))\n+\t\treturn -EINVAL;\n+\n+\terror = loop_validate_file(file, bdev);\n+\tif (error)\n+\t\treturn error;\n+\n+\t*old_file = lo-\u003elo_backing_file;\n+\n+\t/* size of the new backing store needs to be the same */\n+\tif (lo_calculate_size(lo, file) != lo_calculate_size(lo, *old_file))\n+\t\treturn -EINVAL;\n+\n+\t/*\n+\t * We might switch to direct I/O mode for the loop device, write back\n+\t * all dirty data the page cache now that so that the individual I/O\n+\t * operations don't have to do that.\n+\t */\n+\tvfs_fsync(file, 0);\n+\n+\t/* and ... switch */\n+\tdisk_force_media_change(lo-\u003elo_disk);\n+\tmemflags = blk_mq_freeze_queue(lo-\u003elo_queue);\n+\tmapping_set_gfp_mask((*old_file)-\u003ef_mapping, lo-\u003eold_gfp_mask);\n+\tloop_assign_backing_file(lo, file);\n+\tloop_update_dio(lo);\n+\tblk_mq_unfreeze_queue(lo-\u003elo_queue, memflags);\n+\t*partscan = lo-\u003elo_flags \u0026 LO_FLAGS_PARTSCAN;\n+\n+\treturn 0;\n+}\n+\n /*\n  * loop_change_fd switched the backing store of a loopback device to\n  * a new file. This is useful for operating system installers to free up\n@@ -536,7 +579,6 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,\n {\n \tstruct file *file = fget(arg);\n \tstruct file *old_file;\n-\tunsigned int memflags;\n \tint error;\n \tbool partscan;\n \tbool is_loop;\n@@ -554,46 +596,21 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,\n \tdev_set_uevent_suppress(disk_to_dev(lo-\u003elo_disk), 1);\n \n \tis_loop = is_loop_device(file);\n-\terror = loop_global_lock_killable(lo, is_loop);\n+\tif (is_loop) {\n+\t\terror = loop_global_lock_killable(lo);\n+\t\tif (error)\n+\t\t\tgoto out_putf;\n+\t\terror = __loop_change_fd(lo, bdev, file, \u0026old_file, \u0026partscan);\n+\t\tloop_global_unlock(lo);\n+\t} else {\n+\t\terror = mutex_lock_killable(\u0026lo-\u003elo_mutex);\n+\t\tif (error)\n+\t\t\tgoto out_putf;\n+\t\terror = __loop_change_fd(lo, bdev, file, \u0026old_file, \u0026partscan);\n+\t\tmutex_unlock(\u0026lo-\u003elo_mutex);\n+\t}\n \tif (error)\n \t\tgoto out_putf;\n-\terror = -ENXIO;\n-\tif (lo-\u003elo_state != Lo_bound)\n-\t\tgoto out_err;\n-\n-\t/* the loop device has to be read-only */\n-\terror = -EINVAL;\n-\tif (!(lo-\u003elo_flags \u0026 LO_FLAGS_READ_ONLY))\n-\t\tgoto out_err;\n-\n-\terror = loop_validate_file(file, bdev);\n-\tif (error)\n-\t\tgoto out_err;\n-\n-\told_file = lo-\u003elo_backing_file;\n-\n-\terror = -EINVAL;\n-\n-\t/* size of the new backing store needs to be the same */\n-\tif (lo_calculate_size(lo, file) != lo_calculate_size(lo, old_file))\n-\t\tgoto out_err;\n-\n-\t/*\n-\t * We might switch to direct I/O mode for the loop device, write back\n-\t * all dirty data the page cache now that so that the individual I/O\n-\t * operations don't have to do that.\n-\t */\n-\tvfs_fsync(file, 0);\n-\n-\t/* and ... switch */\n-\tdisk_force_media_change(lo-\u003elo_disk);\n-\tmemflags = blk_mq_freeze_queue(lo-\u003elo_queue);\n-\tmapping_set_gfp_mask(old_file-\u003ef_mapping, lo-\u003eold_gfp_mask);\n-\tloop_assign_backing_file(lo, file);\n-\tloop_update_dio(lo);\n-\tblk_mq_unfreeze_queue(lo-\u003elo_queue, memflags);\n-\tpartscan = lo-\u003elo_flags \u0026 LO_FLAGS_PARTSCAN;\n-\tloop_global_unlock(lo, is_loop);\n \n \t/*\n \t * Flush loop_validate_file() before fput(), for l-\u003elo_backing_file\n@@ -618,8 +635,6 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,\n \tkobject_uevent(\u0026disk_to_dev(lo-\u003elo_disk)-\u003ekobj, KOBJ_CHANGE);\n \treturn error;\n \n-out_err:\n-\tloop_global_unlock(lo, is_loop);\n out_putf:\n \tfput(file);\n \tdev_set_uevent_suppress(disk_to_dev(lo-\u003elo_disk), 0);\n@@ -974,61 +989,29 @@ static void loop_update_limits(struct loop_device *lo, struct queue_limits *lim,\n \t\tlim-\u003ediscard_granularity = 0;\n }\n \n-static int loop_configure(struct loop_device *lo, blk_mode_t mode,\n-\t\t\t  struct block_device *bdev,\n-\t\t\t  const struct loop_config *config)\n+static int __loop_configure(struct loop_device *lo, blk_mode_t mode,\n+\t\t\t    struct block_device *bdev,\n+\t\t\t    const struct loop_config *config, struct file *file,\n+\t\t\t    bool *partscan)\n+\t__must_hold(\u0026lo-\u003elo_mutex)\n {\n-\tstruct file *file = fget(config-\u003efd);\n \tstruct queue_limits lim;\n-\tint error;\n \tloff_t size;\n-\tbool partscan;\n-\tbool is_loop;\n-\n-\tif (!file)\n-\t\treturn -EBADF;\n-\n-\terror = loop_check_backing_file(file);\n-\tif (error) {\n-\t\tfput(file);\n-\t\treturn error;\n-\t}\n-\n-\tis_loop = is_loop_device(file);\n-\n-\t/* This is safe, since we have a reference from open(). */\n-\t__module_get(THIS_MODULE);\n-\n-\t/*\n-\t * If we don't hold exclusive handle for the device, upgrade to it\n-\t * here to avoid changing device under exclusive owner.\n-\t */\n-\tif (!(mode \u0026 BLK_OPEN_EXCL)) {\n-\t\terror = bd_prepare_to_claim(bdev, loop_configure, NULL);\n-\t\tif (error)\n-\t\t\tgoto out_putf;\n-\t}\n-\n-\terror = loop_global_lock_killable(lo, is_loop);\n-\tif (error)\n-\t\tgoto out_bdev;\n+\tint error;\n \n-\terror = -EBUSY;\n \tif (lo-\u003elo_state != Lo_unbound)\n-\t\tgoto out_unlock;\n+\t\treturn -EBUSY;\n \n \terror = loop_validate_file(file, bdev);\n \tif (error)\n-\t\tgoto out_unlock;\n+\t\treturn error;\n \n-\tif ((config-\u003einfo.lo_flags \u0026 ~LOOP_CONFIGURE_SETTABLE_FLAGS) != 0) {\n-\t\terror = -EINVAL;\n-\t\tgoto out_unlock;\n-\t}\n+\tif ((config-\u003einfo.lo_flags \u0026 ~LOOP_CONFIGURE_SETTABLE_FLAGS) != 0)\n+\t\treturn -EINVAL;\n \n \terror = loop_set_status_from_info(lo, \u0026config-\u003einfo);\n \tif (error)\n-\t\tgoto out_unlock;\n+\t\treturn error;\n \tlo-\u003elo_flags = config-\u003einfo.lo_flags;\n \n \tif (!(file-\u003ef_mode \u0026 FMODE_WRITE) || !(mode \u0026 BLK_OPEN_WRITE) ||\n@@ -1039,10 +1022,8 @@ static int loop_configure(struct loop_device *lo, blk_mode_t mode,\n \t\tlo-\u003eworkqueue = alloc_workqueue(\"loop%d\",\n \t\t\t\t\t\tWQ_UNBOUND | WQ_FREEZABLE,\n \t\t\t\t\t\t0, lo-\u003elo_number);\n-\t\tif (!lo-\u003eworkqueue) {\n-\t\t\terror = -ENOMEM;\n-\t\t\tgoto out_unlock;\n-\t\t}\n+\t\tif (!lo-\u003eworkqueue)\n+\t\t\treturn -ENOMEM;\n \t}\n \n \t/* suppress uevents while reconfiguring the device */\n@@ -1059,7 +1040,7 @@ static int loop_configure(struct loop_device *lo, blk_mode_t mode,\n \t/* No need to freeze the queue as the device isn't bound yet. */\n \terror = queue_limits_commit_update(lo-\u003elo_queue, \u0026lim);\n \tif (error)\n-\t\tgoto out_unlock;\n+\t\treturn error;\n \n \t/*\n \t * We might switch to direct I/O mode for the loop device, write back\n@@ -1080,14 +1061,66 @@ static int loop_configure(struct loop_device *lo, blk_mode_t mode,\n \tWRITE_ONCE(lo-\u003elo_state, Lo_bound);\n \tif (part_shift)\n \t\tlo-\u003elo_flags |= LO_FLAGS_PARTSCAN;\n-\tpartscan = lo-\u003elo_flags \u0026 LO_FLAGS_PARTSCAN;\n-\tif (partscan)\n+\t*partscan = lo-\u003elo_flags \u0026 LO_FLAGS_PARTSCAN;\n+\tif (*partscan)\n \t\tclear_bit(GD_SUPPRESS_PART_SCAN, \u0026lo-\u003elo_disk-\u003estate);\n \n \tdev_set_uevent_suppress(disk_to_dev(lo-\u003elo_disk), 0);\n \tkobject_uevent(\u0026disk_to_dev(lo-\u003elo_disk)-\u003ekobj, KOBJ_CHANGE);\n \n-\tloop_global_unlock(lo, is_loop);\n+\treturn 0;\n+}\n+\n+static int loop_configure(struct loop_device *lo, blk_mode_t mode,\n+\t\t\t  struct block_device *bdev,\n+\t\t\t  const struct loop_config *config)\n+{\n+\tstruct file *file = fget(config-\u003efd);\n+\tint error;\n+\tbool partscan;\n+\tbool is_loop;\n+\n+\tif (!file)\n+\t\treturn -EBADF;\n+\n+\terror = loop_check_backing_file(file);\n+\tif (error) {\n+\t\tfput(file);\n+\t\treturn error;\n+\t}\n+\n+\tis_loop = is_loop_device(file);\n+\n+\t/* This is safe, since we have a reference from open(). */\n+\t__module_get(THIS_MODULE);\n+\n+\t/*\n+\t * If we don't hold exclusive handle for the device, upgrade to it\n+\t * here to avoid changing device under exclusive owner.\n+\t */\n+\tif (!(mode \u0026 BLK_OPEN_EXCL)) {\n+\t\terror = bd_prepare_to_claim(bdev, loop_configure, NULL);\n+\t\tif (error)\n+\t\t\tgoto out_putf;\n+\t}\n+\n+\tif (is_loop) {\n+\t\terror = loop_global_lock_killable(lo);\n+\t\tif (error)\n+\t\t\tgoto out_bdev;\n+\t\terror = __loop_configure(lo, mode, bdev, config, file,\n+\t\t\t\t\t \u0026partscan);\n+\t\tloop_global_unlock(lo);\n+\t} else {\n+\t\terror = mutex_lock_killable(\u0026lo-\u003elo_mutex);\n+\t\tif (error)\n+\t\t\tgoto out_bdev;\n+\t\terror = __loop_configure(lo, mode, bdev, config, file,\n+\t\t\t\t\t \u0026partscan);\n+\t\tmutex_unlock(\u0026lo-\u003elo_mutex);\n+\t}\n+\tif (error)\n+\t\tgoto out_bdev;\n \tif (partscan)\n \t\tloop_reread_partitions(lo);\n \n@@ -1096,8 +1129,6 @@ static int loop_configure(struct loop_device *lo, blk_mode_t mode,\n \n \treturn 0;\n \n-out_unlock:\n-\tloop_global_unlock(lo, is_loop);\n out_bdev:\n \tif (!(mode \u0026 BLK_OPEN_EXCL))\n \t\tbd_abort_claiming(bdev, loop_configure);\n@@ -1194,11 +1225,11 @@ static int loop_clr_fd(struct loop_device *lo)\n \t * which loop_configure()/loop_change_fd() found via fget() was this\n \t * loop device.\n \t */\n-\terr = loop_global_lock_killable(lo, true);\n+\terr = loop_global_lock_killable(lo);\n \tif (err)\n \t\treturn err;\n \tif (lo-\u003elo_state != Lo_bound) {\n-\t\tloop_global_unlock(lo, true);\n+\t\tloop_global_unlock(lo);\n \t\treturn -ENXIO;\n \t}\n \t/*\n@@ -1210,7 +1241,7 @@ static int loop_clr_fd(struct loop_device *lo)\n \tlo-\u003elo_flags |= LO_FLAGS_AUTOCLEAR;\n \tif (disk_openers(lo-\u003elo_disk) == 1)\n \t\tWRITE_ONCE(lo-\u003elo_state, Lo_rundown);\n-\tloop_global_unlock(lo, true);\n+\tloop_global_unlock(lo);\n \n \treturn 0;\n }\n@@ -2302,6 +2333,7 @@ static void __exit loop_exit(void)\n \t * module unloading is requested). If this is not a clean unloading,\n \t * we have no means to avoid kernel crash.\n \t */\n+\t__assume_ctx_lock(\u0026loop_ctl_mutex);\n \tidr_for_each_entry(\u0026loop_index_idr, lo, id)\n \t\tloop_remove(lo);\n \ndiff --git a/drivers/block/mtip32xx/Makefile b/drivers/block/mtip32xx/Makefile\nindex bff32b5d3c192..233961fdb41b9 100644\n--- a/drivers/block/mtip32xx/Makefile\n+++ b/drivers/block/mtip32xx/Makefile\n@@ -3,4 +3,6 @@\n # Makefile for  Block device driver for Micron PCIe SSD\n #\n \n+CONTEXT_ANALYSIS := y\n+\n obj-$(CONFIG_BLK_DEV_PCIESSD_MTIP32XX) += mtip32xx.o\ndiff --git a/drivers/block/nbd.c b/drivers/block/nbd.c\nindex 8f10762e90ef7..751449d362b03 100644\n--- a/drivers/block/nbd.c\n+++ b/drivers/block/nbd.c\n@@ -49,8 +49,8 @@\n #define CREATE_TRACE_POINTS\n #include \u003ctrace/events/nbd.h\u003e\n \n-static DEFINE_IDR(nbd_index_idr);\n static DEFINE_MUTEX(nbd_index_mutex);\n+static __guarded_by(\u0026nbd_index_mutex) DEFINE_IDR(nbd_index_idr);\n static struct workqueue_struct *nbd_del_wq;\n static int nbd_total_devices = 0;\n \n@@ -1506,6 +1506,7 @@ static void nbd_config_put(struct nbd_device *nbd)\n }\n \n static int nbd_start_device(struct nbd_device *nbd)\n+\t__must_hold(\u0026nbd-\u003econfig_lock)\n {\n \tstruct nbd_config *config = nbd-\u003econfig;\n \tint num_connections = config-\u003enum_connections;\n@@ -1578,6 +1579,7 @@ static int nbd_start_device(struct nbd_device *nbd)\n }\n \n static int nbd_start_device_ioctl(struct nbd_device *nbd)\n+\t__must_hold(\u0026nbd-\u003econfig_lock)\n {\n \tstruct nbd_config *config = nbd-\u003econfig;\n \tint ret;\n@@ -1629,6 +1631,7 @@ static void nbd_set_cmd_timeout(struct nbd_device *nbd, u64 timeout)\n /* Must be called with config_lock held */\n static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,\n \t\t       unsigned int cmd, unsigned long arg)\n+\t__must_hold(\u0026nbd-\u003econfig_lock)\n {\n \tstruct nbd_config *config = nbd-\u003econfig;\n \tloff_t bytesize;\n@@ -2773,7 +2776,11 @@ static void __exit nbd_cleanup(void)\n \t/* Also wait for nbd_dev_remove_work() completes */\n \tdestroy_workqueue(nbd_del_wq);\n \n-\tidr_destroy(\u0026nbd_index_idr);\n+\t{\n+\t\t__assume_ctx_lock(\u0026nbd_index_mutex);\n+\t\tidr_destroy(\u0026nbd_index_idr);\n+\t}\n+\n \tunregister_blkdev(NBD_MAJOR, \"nbd\");\n }\n \ndiff --git a/drivers/block/null_blk/Makefile b/drivers/block/null_blk/Makefile\nindex 84c36e512ab89..282b0d51a4779 100644\n--- a/drivers/block/null_blk/Makefile\n+++ b/drivers/block/null_blk/Makefile\n@@ -1,5 +1,7 @@\n # SPDX-License-Identifier: GPL-2.0\n \n+CONTEXT_ANALYSIS := y\n+\n # needed for trace events\n ccflags-y\t\t\t+= -I$(src)\n \ndiff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c\nindex f8c0fd57e041a..baffc6c61178f 100644\n--- a/drivers/block/null_blk/main.c\n+++ b/drivers/block/null_blk/main.c\n@@ -1038,6 +1038,7 @@ static struct nullb_page *null_insert_page(struct nullb *nullb,\n }\n \n static int null_flush_cache_page(struct nullb *nullb, struct nullb_page *c_page)\n+\t__must_hold(\u0026nullb-\u003elock)\n {\n \tint i;\n \tunsigned int offset;\n@@ -1087,6 +1088,7 @@ static int null_flush_cache_page(struct nullb *nullb, struct nullb_page *c_page)\n }\n \n static int null_make_cache_space(struct nullb *nullb, unsigned long n)\n+\t__must_hold(\u0026nullb-\u003elock)\n {\n \tint i, err, nr_pages;\n \tstruct nullb_page *c_pages[FREE_BATCH];\n@@ -1141,6 +1143,7 @@ static int null_make_cache_space(struct nullb *nullb, unsigned long n)\n \n static blk_status_t copy_to_nullb(struct nullb *nullb, void *source,\n \t\t\t\t  loff_t pos, size_t n, bool is_fua)\n+\t__must_hold(\u0026nullb-\u003elock)\n {\n \tsize_t temp, count = 0;\n \tstruct nullb_page *t_page;\n@@ -1242,6 +1245,7 @@ static blk_status_t null_handle_flush(struct nullb *nullb)\n static blk_status_t null_transfer(struct nullb *nullb, struct page *page,\n \tunsigned int len, unsigned int off, bool is_write, loff_t pos,\n \tbool is_fua)\n+\t__must_hold(\u0026nullb-\u003elock)\n {\n \tstruct nullb_device *dev = nullb-\u003edev;\n \tblk_status_t err = BLK_STS_OK;\ndiff --git a/drivers/block/null_blk/zoned.c b/drivers/block/null_blk/zoned.c\nindex 384bdce6a9b7f..dbae748c90ba9 100644\n--- a/drivers/block/null_blk/zoned.c\n+++ b/drivers/block/null_blk/zoned.c\n@@ -30,23 +30,26 @@ static inline void null_init_zone_lock(struct nullb_device *dev,\n \t\tmutex_init(\u0026zone-\u003emutex);\n }\n \n-static inline void null_lock_zone(struct nullb_device *dev,\n-\t\t\t\t  struct nullb_zone *zone)\n-{\n-\tif (!dev-\u003ememory_backed)\n-\t\tspin_lock_irq(\u0026zone-\u003espinlock);\n-\telse\n-\t\tmutex_lock(\u0026zone-\u003emutex);\n-}\n-\n-static inline void null_unlock_zone(struct nullb_device *dev,\n-\t\t\t\t    struct nullb_zone *zone)\n-{\n-\tif (!dev-\u003ememory_backed)\n-\t\tspin_unlock_irq(\u0026zone-\u003espinlock);\n-\telse\n-\t\tmutex_unlock(\u0026zone-\u003emutex);\n-}\n+struct nullb_dev_and_zone {\n+\tstruct nullb_device *dev;\n+\tstruct nullb_zone *zone;\n+};\n+\n+DEFINE_CLASS(null_zone, struct nullb_dev_and_zone, ({\n+\t\t     if (!_T.dev-\u003ememory_backed)\n+\t\t\t     spin_unlock_irq(\u0026_T.zone-\u003espinlock);\n+\t\t     else\n+\t\t\t     mutex_unlock(\u0026_T.zone-\u003emutex);\n+\t     }), ({\n+\t\t     if (!dev-\u003ememory_backed)\n+\t\t\t     spin_lock_irq(\u0026zone-\u003espinlock);\n+\t\t     else\n+\t\t\t     mutex_lock(\u0026zone-\u003emutex);\n+\t\t     (struct nullb_dev_and_zone){ dev, zone };\n+\t     }),\n+\t     struct nullb_device *dev, struct nullb_zone *zone)\n+\n+DEFINE_CLASS_IS_UNCONDITIONAL(null_zone)\n \n int null_init_zoned_dev(struct nullb_device *dev,\n \t\t\tstruct queue_limits *lim)\n@@ -216,14 +219,14 @@ int null_report_zones(struct gendisk *disk, sector_t sector,\n \t\t * So use a local copy to avoid corruption of the device zone\n \t\t * array.\n \t\t */\n-\t\tnull_lock_zone(dev, zone);\n-\t\tblkz.start = zone-\u003estart;\n-\t\tblkz.len = zone-\u003elen;\n-\t\tblkz.wp = zone-\u003ewp;\n-\t\tblkz.type = zone-\u003etype;\n-\t\tblkz.cond = zone-\u003econd;\n-\t\tblkz.capacity = zone-\u003ecapacity;\n-\t\tnull_unlock_zone(dev, zone);\n+\t\tscoped_guard(null_zone, dev, zone) {\n+\t\t\tblkz.start = zone-\u003estart;\n+\t\t\tblkz.len = zone-\u003elen;\n+\t\t\tblkz.wp = zone-\u003ewp;\n+\t\t\tblkz.type = zone-\u003etype;\n+\t\t\tblkz.cond = zone-\u003econd;\n+\t\t\tblkz.capacity = zone-\u003ecapacity;\n+\t\t}\n \n \t\terror = disk_report_zone(disk, \u0026blkz, i, args);\n \t\tif (error)\n@@ -364,7 +367,7 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,\n \t\treturn null_process_cmd(cmd, REQ_OP_WRITE, sector, nr_sectors);\n \t}\n \n-\tnull_lock_zone(dev, zone);\n+\tguard(null_zone)(dev, zone);\n \n \t/*\n \t * Regular writes must be at the write pointer position. Zone append\n@@ -376,19 +379,15 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,\n \t */\n \tif (append) {\n \t\tif (WARN_ON_ONCE(!dev-\u003ezone_append_max_sectors) ||\n-\t\t    zone-\u003ewp == NULL_ZONE_INVALID_WP) {\n-\t\t\tret = BLK_STS_IOERR;\n-\t\t\tgoto unlock_zone;\n-\t\t}\n+\t\t    zone-\u003ewp == NULL_ZONE_INVALID_WP)\n+\t\t\treturn BLK_STS_IOERR;\n \t\tsector = zone-\u003ewp;\n \t\tblk_mq_rq_from_pdu(cmd)-\u003e__sector = sector;\n \t}\n \n \tif (sector != zone-\u003ewp ||\n-\t    zone-\u003ewp + nr_sectors \u003e zone-\u003estart + zone-\u003ecapacity) {\n-\t\tret = BLK_STS_IOERR;\n-\t\tgoto unlock_zone;\n-\t}\n+\t    zone-\u003ewp + nr_sectors \u003e zone-\u003estart + zone-\u003ecapacity)\n+\t\treturn BLK_STS_IOERR;\n \n \tif (zone-\u003econd == BLK_ZONE_COND_CLOSED ||\n \t    zone-\u003econd == BLK_ZONE_COND_EMPTY) {\n@@ -398,7 +397,7 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,\n \t\t\tret = null_check_zone_resources(dev, zone);\n \t\t\tif (ret != BLK_STS_OK) {\n \t\t\t\tspin_unlock(\u0026dev-\u003ezone_res_lock);\n-\t\t\t\tgoto unlock_zone;\n+\t\t\t\treturn ret;\n \t\t\t}\n \t\t\tif (zone-\u003econd == BLK_ZONE_COND_CLOSED) {\n \t\t\t\tdev-\u003enr_zones_closed--;\n@@ -415,17 +414,15 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,\n \n \tif (dev-\u003ebadblocks.shift != -1) {\n \t\tbadblocks_ret = null_handle_badblocks(cmd, sector, \u0026nr_sectors);\n-\t\tif (badblocks_ret != BLK_STS_OK \u0026\u0026 !nr_sectors) {\n-\t\t\tret = badblocks_ret;\n-\t\t\tgoto unlock_zone;\n-\t\t}\n+\t\tif (badblocks_ret != BLK_STS_OK \u0026\u0026 !nr_sectors)\n+\t\t\treturn badblocks_ret;\n \t}\n \n \tif (dev-\u003ememory_backed) {\n \t\tret = null_handle_memory_backed(cmd, REQ_OP_WRITE, sector,\n \t\t\t\t\t\tnr_sectors);\n \t\tif (ret != BLK_STS_OK)\n-\t\t\tgoto unlock_zone;\n+\t\t\treturn ret;\n \t}\n \n \tzone-\u003ewp += nr_sectors;\n@@ -441,12 +438,7 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,\n \t\tzone-\u003econd = BLK_ZONE_COND_FULL;\n \t}\n \n-\tret = badblocks_ret;\n-\n-unlock_zone:\n-\tnull_unlock_zone(dev, zone);\n-\n-\treturn ret;\n+\treturn badblocks_ret;\n }\n \n static blk_status_t null_open_zone(struct nullb_device *dev,\n@@ -655,14 +647,14 @@ static blk_status_t null_zone_mgmt(struct nullb_cmd *cmd, enum req_op op,\n \tif (op == REQ_OP_ZONE_RESET_ALL) {\n \t\tfor (i = dev-\u003ezone_nr_conv; i \u003c dev-\u003enr_zones; i++) {\n \t\t\tzone = \u0026dev-\u003ezones[i];\n-\t\t\tnull_lock_zone(dev, zone);\n-\t\t\tif (zone-\u003econd != BLK_ZONE_COND_EMPTY \u0026\u0026\n-\t\t\t    zone-\u003econd != BLK_ZONE_COND_READONLY \u0026\u0026\n-\t\t\t    zone-\u003econd != BLK_ZONE_COND_OFFLINE) {\n-\t\t\t\tnull_reset_zone(dev, zone);\n-\t\t\t\ttrace_nullb_zone_op(cmd, i, zone-\u003econd);\n+\t\t\tscoped_guard(null_zone, dev, zone) {\n+\t\t\t\tif (zone-\u003econd != BLK_ZONE_COND_EMPTY \u0026\u0026\n+\t\t\t\t    zone-\u003econd != BLK_ZONE_COND_READONLY \u0026\u0026\n+\t\t\t\t    zone-\u003econd != BLK_ZONE_COND_OFFLINE) {\n+\t\t\t\t\tnull_reset_zone(dev, zone);\n+\t\t\t\t\ttrace_nullb_zone_op(cmd, i, zone-\u003econd);\n+\t\t\t\t}\n \t\t\t}\n-\t\t\tnull_unlock_zone(dev, zone);\n \t\t}\n \t\treturn BLK_STS_OK;\n \t}\n@@ -670,13 +662,11 @@ static blk_status_t null_zone_mgmt(struct nullb_cmd *cmd, enum req_op op,\n \tzone_no = null_zone_no(dev, sector);\n \tzone = \u0026dev-\u003ezones[zone_no];\n \n-\tnull_lock_zone(dev, zone);\n+\tguard(null_zone)(dev, zone);\n \n \tif (zone-\u003econd == BLK_ZONE_COND_READONLY ||\n-\t    zone-\u003econd == BLK_ZONE_COND_OFFLINE) {\n-\t\tret = BLK_STS_IOERR;\n-\t\tgoto unlock;\n-\t}\n+\t    zone-\u003econd == BLK_ZONE_COND_OFFLINE)\n+\t\treturn BLK_STS_IOERR;\n \n \tswitch (op) {\n \tcase REQ_OP_ZONE_RESET:\n@@ -699,9 +689,6 @@ static blk_status_t null_zone_mgmt(struct nullb_cmd *cmd, enum req_op op,\n \tif (ret == BLK_STS_OK)\n \t\ttrace_nullb_zone_op(cmd, zone_no, zone-\u003econd);\n \n-unlock:\n-\tnull_unlock_zone(dev, zone);\n-\n \treturn ret;\n }\n \n@@ -710,7 +697,6 @@ blk_status_t null_process_zoned_cmd(struct nullb_cmd *cmd, enum req_op op,\n {\n \tstruct nullb_device *dev;\n \tstruct nullb_zone *zone;\n-\tblk_status_t sts;\n \n \tswitch (op) {\n \tcase REQ_OP_WRITE:\n@@ -729,10 +715,8 @@ blk_status_t null_process_zoned_cmd(struct nullb_cmd *cmd, enum req_op op,\n \t\tif (zone-\u003econd == BLK_ZONE_COND_OFFLINE)\n \t\t\treturn BLK_STS_IOERR;\n \n-\t\tnull_lock_zone(dev, zone);\n-\t\tsts = null_process_cmd(cmd, op, sector, nr_sectors);\n-\t\tnull_unlock_zone(dev, zone);\n-\t\treturn sts;\n+\t\tscoped_guard(null_zone, dev, zone)\n+\t\t\treturn null_process_cmd(cmd, op, sector, nr_sectors);\n \t}\n }\n \n@@ -746,7 +730,7 @@ static void null_set_zone_cond(struct nullb_device *dev,\n \t\t\t cond != BLK_ZONE_COND_OFFLINE))\n \t\treturn;\n \n-\tnull_lock_zone(dev, zone);\n+\tguard(null_zone)(dev, zone);\n \n \t/*\n \t * If the read-only condition is requested again to zones already in\n@@ -767,8 +751,6 @@ static void null_set_zone_cond(struct nullb_device *dev,\n \t\tzone-\u003econd = cond;\n \t\tzone-\u003ewp = NULL_ZONE_INVALID_WP;\n \t}\n-\n-\tnull_unlock_zone(dev, zone);\n }\n \n /*\ndiff --git a/drivers/block/rbd.c b/drivers/block/rbd.c\nindex 1f1c2810f6ee3..f0f7a94e3e3e3 100644\n--- a/drivers/block/rbd.c\n+++ b/drivers/block/rbd.c\n@@ -4183,6 +4183,7 @@ static void rbd_acquire_lock(struct work_struct *work)\n }\n \n static bool rbd_quiesce_lock(struct rbd_device *rbd_dev)\n+\t__must_hold(\u0026rbd_dev-\u003elock_rwsem)\n {\n \tdout(\"%s rbd_dev %p\\n\", __func__, rbd_dev);\n \tlockdep_assert_held_write(\u0026rbd_dev-\u003elock_rwsem);\n@@ -4227,6 +4228,7 @@ static void __rbd_release_lock(struct rbd_device *rbd_dev)\n  * lock_rwsem must be held for write\n  */\n static void rbd_release_lock(struct rbd_device *rbd_dev)\n+\t__must_hold(\u0026rbd_dev-\u003elock_rwsem)\n {\n \tif (!rbd_quiesce_lock(rbd_dev))\n \t\treturn;\n@@ -4583,6 +4585,7 @@ static void rbd_unregister_watch(struct rbd_device *rbd_dev)\n  * lock_rwsem must be held for write\n  */\n static void rbd_reacquire_lock(struct rbd_device *rbd_dev)\n+\t__must_hold(\u0026rbd_dev-\u003elock_rwsem)\n {\n \tstruct ceph_osd_client *osdc = \u0026rbd_dev-\u003erbd_client-\u003eclient-\u003eosdc;\n \tchar cookie[32];\n@@ -6780,6 +6783,7 @@ static void rbd_dev_device_release(struct rbd_device *rbd_dev)\n  * upon return.\n  */\n static int rbd_dev_device_setup(struct rbd_device *rbd_dev)\n+\t__releases(\u0026rbd_dev-\u003eheader_rwsem)\n {\n \tint ret;\n \n@@ -6881,6 +6885,7 @@ static void rbd_dev_image_release(struct rbd_device *rbd_dev)\n  * with @depth == 0.\n  */\n static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)\n+\t__context_unsafe(conditional locking on @depth)\n {\n \tbool need_watch = !rbd_is_ro(rbd_dev);\n \tint ret;\n@@ -7134,6 +7139,9 @@ static ssize_t do_rbd_add(const char *buf, size_t count)\n \tif (rc \u003c 0)\n \t\tgoto err_out_rbd_dev;\n \n+\t/* Acquired by rbd_dev_image_probe(rbd_dev, 0) */\n+\t__acquire(\u0026rbd_dev-\u003eheader_rwsem);\n+\n \tif (rbd_dev-\u003eopts-\u003ealloc_size \u003e rbd_dev-\u003elayout.object_size) {\n \t\trbd_warn(rbd_dev, \"alloc_size adjusted to %u\",\n \t\t\t rbd_dev-\u003elayout.object_size);\ndiff --git a/drivers/block/rnbd/Makefile b/drivers/block/rnbd/Makefile\nindex 208e5f8654975..42c2cccdb53d3 100644\n--- a/drivers/block/rnbd/Makefile\n+++ b/drivers/block/rnbd/Makefile\n@@ -1,5 +1,7 @@\n # SPDX-License-Identifier: GPL-2.0-or-later\n \n+CONTEXT_ANALYSIS := y\n+\n ccflags-y := -I$(srctree)/drivers/infiniband/ulp/rtrs\n \n rnbd-client-y := rnbd-clt.o \\\ndiff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c\nindex 2a22f9dc1f2f1..b18b50efd0940 100644\n--- a/drivers/block/ublk_drv.c\n+++ b/drivers/block/ublk_drv.c\n@@ -373,11 +373,13 @@ static inline bool ublk_support_batch_io(const struct ublk_queue *ubq)\n }\n \n static inline void ublk_io_lock(struct ublk_io *io)\n+\t__acquires(\u0026io-\u003elock)\n {\n \tspin_lock(\u0026io-\u003elock);\n }\n \n static inline void ublk_io_unlock(struct ublk_io *io)\n+\t__releases(\u0026io-\u003elock)\n {\n \tspin_unlock(\u0026io-\u003elock);\n }\n@@ -3262,6 +3264,7 @@ static int ublk_check_fetch_buf(const struct ublk_device *ub, __u64 buf_addr)\n \n static int __ublk_fetch(struct io_uring_cmd *cmd, struct ublk_device *ub,\n \t\t\tstruct ublk_io *io, u16 q_id)\n+\t__must_hold(\u0026ub-\u003emutex)\n {\n \t/* UBLK_IO_FETCH_REQ is only allowed before dev is setup */\n \tif (ublk_dev_ready(ub))\n@@ -3689,6 +3692,7 @@ static void ublk_batch_revert_prep_cmd(struct ublk_batch_io_iter *iter,\n static int ublk_batch_prep_io(struct ublk_queue *ubq,\n \t\t\t      const struct ublk_batch_io_data *data,\n \t\t\t      const struct ublk_elem_header *elem)\n+\t__must_hold(\u0026data-\u003eub-\u003emutex)\n {\n \tstruct ublk_io *io = \u0026ubq-\u003eios[elem-\u003etag];\n \tconst struct ublk_batch_io *uc = \u0026data-\u003eheader;\n@@ -4422,6 +4426,7 @@ static bool ublk_validate_user_pid(struct ublk_device *ub, pid_t ublksrv_pid)\n  * UNPREP, daemon death), so re-check it under the mutex and wait again.\n  */\n static int ublk_wait_dev_ready_and_lock(struct ublk_device *ub)\n+\t__cond_acquires(0, \u0026ub-\u003emutex)\n {\n \twhile (true) {\n \t\tif (wait_var_event_interruptible(\u0026ub-\u003enr_queue_ready,\n@@ -5323,6 +5328,7 @@ static int ublk_char_dev_permission(struct ublk_device *ub,\n  * already holds ub-\u003emutex when calling del_gendisk() which freezes the queue.\n */\n static unsigned int ublk_lock_buf_tree(struct ublk_device *ub)\n+\t__acquires(\u0026ub-\u003emutex)\n {\n \tunsigned int memflags = 0;\n \n@@ -5334,6 +5340,7 @@ static unsigned int ublk_lock_buf_tree(struct ublk_device *ub)\n }\n \n static void ublk_unlock_buf_tree(struct ublk_device *ub, unsigned int memflags)\n+\t__releases(\u0026ub-\u003emutex)\n {\n \tif (ub-\u003eub_disk)\n \t\tblk_mq_unfreeze_queue(ub-\u003eub_disk-\u003equeue, memflags);\ndiff --git a/drivers/block/xen-blkback/Makefile b/drivers/block/xen-blkback/Makefile\nindex b0ea5ab5b9a15..864ef423226cf 100644\n--- a/drivers/block/xen-blkback/Makefile\n+++ b/drivers/block/xen-blkback/Makefile\n@@ -1,4 +1,7 @@\n # SPDX-License-Identifier: GPL-2.0-only\n+\n+CONTEXT_ANALYSIS := y\n+\n obj-$(CONFIG_XEN_BLKDEV_BACKEND) := xen-blkback.o\n \n xen-blkback-y\t:= blkback.o xenbus.o\ndiff --git a/drivers/block/zram/Makefile b/drivers/block/zram/Makefile\nindex 0fdefd576691b..a5663ab016532 100644\n--- a/drivers/block/zram/Makefile\n+++ b/drivers/block/zram/Makefile\n@@ -1,5 +1,7 @@\n # SPDX-License-Identifier: GPL-2.0-only\n \n+CONTEXT_ANALYSIS := y\n+\n zram-y\t:=\tzcomp.o zram_drv.o\n \n zram-$(CONFIG_ZRAM_BACKEND_LZO)\t\t+= backend_lzorle.o backend_lzo.o\ndiff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c\nindex 974c4691887e6..155dbeacab1b4 100644\n--- a/drivers/block/zram/zcomp.c\n+++ b/drivers/block/zram/zcomp.c\n@@ -112,7 +112,8 @@ ssize_t zcomp_available_show(const char *comp, char *buf, ssize_t at)\n \treturn at;\n }\n \n-struct zcomp_strm *zcomp_stream_get(struct zcomp *comp)\n+struct zcomp_strm *__zcomp_stream_get(struct zcomp *comp)\n+\t__context_unsafe(uses raw_cpu_ptr())\n {\n \tfor (;;) {\n \t\tstruct zcomp_strm *zstrm = raw_cpu_ptr(comp-\u003estream);\ndiff --git a/drivers/block/zram/zcomp.h b/drivers/block/zram/zcomp.h\nindex 81a0f3f6ff487..afe0c1bf348d8 100644\n--- a/drivers/block/zram/zcomp.h\n+++ b/drivers/block/zram/zcomp.h\n@@ -85,8 +85,10 @@ const char *zcomp_lookup_backend_name(const char *comp);\n struct zcomp *zcomp_create(const char *alg, struct zcomp_params *params);\n void zcomp_destroy(struct zcomp *comp);\n \n-struct zcomp_strm *zcomp_stream_get(struct zcomp *comp);\n-void zcomp_stream_put(struct zcomp_strm *zstrm);\n+#define zcomp_stream_get(...) __acquire_ret(__zcomp_stream_get(__VA_ARGS__), \u0026__ret-\u003elock)\n+struct zcomp_strm *__zcomp_stream_get(struct zcomp *comp);\n+void zcomp_stream_put(struct zcomp_strm *zstrm)\n+\t__releases(\u0026zstrm-\u003elock);\n \n int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,\n \t\t   const void *src, unsigned int *dst_len);\n"
}

2/1 2026/08/01 07:44 agent patch-evaluator
0m Model:
best-expensive

Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch introduces sparse annotations (e.g., __must_hold, __acquires, __releases, __guarded_by) and CONTEXT_ANALYSIS := y to Makefiles in the block layer to enable static context analysis. It also refactors some locking logic (like extracting __loop_change_fd and __loop_configure in loop.c, and using guard()/scoped_guard() in null_blk/zoned.c) to make the locking behavior unconditional and verifiable by the static analyzer. There are no functional changes to the execution flow or logic of the kernel.",
  "WorthFuzzing": false
}

Instruction:
You are an expert Linux kernel maintainer.
Your job is to review a provided patch series and determine
if it makes functional changes to the kernel that should be fuzzed.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively
use your code access tools to examine the actual source code and confirm any assumptions.

Return WorthFuzzing=false if the patch only contains:
- Modifications to Documentation/, Kconfig files, or code comments.
- Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints.
- Changes to numeric constants or macros that do not functionally alter execution flow.
- Code paths that are impossible to reach in virtualized environments like GCE or QEMU,
  even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim).
- Code in vendor-specific PCIe switch, SmartNIC, or GPU drivers (e.g., mlxsw, pds_core, qed,
  ionic, amdgpu) that require physical PCIe hardware cards not emulated in standard QEMU.
- Driver .remove, .shutdown, or pci_unregister_driver teardown callbacks (e.g., igb_remove)
  that are executed only during PCI hot-unplug or sysfs driver unbind operations.

If it modifies reachable core kernel logic, drivers, or architectures, use your code search
tools to verify the code can be executed, then return WorthFuzzing=true.

When returning WorthFuzzing=true, you MUST ALSO:
1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols.
   Avoid listing generic hot-path functions to prevent skewed test distributions.
   Prefer non-static, non-inlined API entrypoint functions over internal static helper functions
   (which are inlined by the compiler and do not have distinct symbol addresses).
2. Identify any specific CONFIG_ options required to properly test this new/modified feature.
   Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions.
   Also check "depends on" lines in Kconfig to include any non-standard parent subsystem configs
   needed for Kbuild to compile the code statically into vmlinux. List them in the EnableConfigs
   output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
For your convenience, here is the diff of the changes:
commit 27615096d419701f4321b1b70aa03a0b54bb802e
Author: syz-cluster <triage@syzkaller.com>
Date:   Sat Aug 1 07:44:24 2026 +0000

    syz-cluster: applied patch under review

diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 2d8096eb8cdf8..e17f6381b7982 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -6,6 +6,8 @@
 # Rewritten to use lists instead of if-statements.
 # 
 
+CONTEXT_ANALYSIS := y
+
 # needed for trace events
 ccflags-y				+= -I$(src)
 
diff --git a/drivers/block/aoe/Makefile b/drivers/block/aoe/Makefile
index b7545ce2f1b0f..27bff6359a56e 100644
--- a/drivers/block/aoe/Makefile
+++ b/drivers/block/aoe/Makefile
@@ -3,5 +3,7 @@
 # Makefile for ATA over Ethernet
 #
 
+CONTEXT_ANALYSIS := y
+
 obj-$(CONFIG_ATA_OVER_ETH)	+= aoe.o
 aoe-y := aoeblk.o aoechr.o aoecmd.o aoedev.o aoemain.o aoenet.o
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index a4744a30a8af4..54c57b9f88942 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -1193,6 +1193,7 @@ noskb:		if (buf)
  */
 static int
 ktio(int id)
+	__must_hold(&iocq[id].lock)
 {
 	struct frame *f;
 	struct list_head *pos;
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 1faecef330092..e2ac19de11f42 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -90,33 +90,32 @@ struct loop_cmd {
 #define LOOP_IDLE_WORKER_TIMEOUT (60 * HZ)
 #define LOOP_DEFAULT_HW_Q_DEPTH 128
 
-static DEFINE_IDR(loop_index_idr);
 static DEFINE_MUTEX(loop_ctl_mutex);
+static __guarded_by(&loop_ctl_mutex) DEFINE_IDR(loop_index_idr);
 static DEFINE_MUTEX(loop_validate_mutex);
 
 /**
  * loop_global_lock_killable() - take locks for safe loop_validate_file() test
  *
  * @lo: struct loop_device
- * @global: true if @lo is about to bind another "struct loop_device", false otherwise
  *
  * Returns 0 on success, -EINTR otherwise.
  *
- * Since loop_validate_file() traverses on other "struct loop_device" if
- * is_loop_device() is true, we need a global lock for serializing concurrent
+ * Since loop_validate_file() traverses on other "struct loop_device", we need a
+ * global lock for serializing concurrent
  * loop_configure()/loop_change_fd()/__loop_clr_fd() calls.
  */
-static int loop_global_lock_killable(struct loop_device *lo, bool global)
+static int loop_global_lock_killable(struct loop_device *lo)
+	__cond_acquires(0, &loop_validate_mutex)
+	__cond_acquires(0, &lo->lo_mutex)
 {
 	int err;
 
-	if (global) {
-		err = mutex_lock_killable(&loop_validate_mutex);
-		if (err)
-			return err;
-	}
+	err = mutex_lock_killable(&loop_validate_mutex);
+	if (err)
+		return err;
 	err = mutex_lock_killable(&lo->lo_mutex);
-	if (err && global)
+	if (err)
 		mutex_unlock(&loop_validate_mutex);
 	return err;
 }
@@ -125,13 +124,13 @@ static int loop_global_lock_killable(struct loop_device *lo, bool global)
  * loop_global_unlock() - release locks taken by loop_global_lock_killable()
  *
  * @lo: struct loop_device
- * @global: true if @lo was about to bind another "struct loop_device", false otherwise
  */
-static void loop_global_unlock(struct loop_device *lo, bool global)
+static void loop_global_unlock(struct loop_device *lo)
+	__releases(&lo->lo_mutex)
+	__releases(&loop_validate_mutex)
 {
 	mutex_unlock(&lo->lo_mutex);
-	if (global)
-		mutex_unlock(&loop_validate_mutex);
+	mutex_unlock(&loop_validate_mutex);
 }
 
 static int max_part;
@@ -523,6 +522,50 @@ static int loop_check_backing_file(struct file *file)
 	return 0;
 }
 
+static int __loop_change_fd(struct loop_device *lo, struct block_device *bdev,
+			    struct file *file, struct file **old_file,
+			    bool *partscan)
+	__must_hold(&lo->lo_mutex)
+{
+	unsigned int memflags;
+	int error;
+
+	if (lo->lo_state != Lo_bound)
+		return -ENXIO;
+
+	/* the loop device has to be read-only */
+	if (!(lo->lo_flags & LO_FLAGS_READ_ONLY))
+		return -EINVAL;
+
+	error = loop_validate_file(file, bdev);
+	if (error)
+		return error;
+
+	*old_file = lo->lo_backing_file;
+
+	/* size of the new backing store needs to be the same */
+	if (lo_calculate_size(lo, file) != lo_calculate_size(lo, *old_file))
+		return -EINVAL;
+
+	/*
+	 * We might switch to direct I/O mode for the loop device, write back
+	 * all dirty data the page cache now that so that the individual I/O
+	 * operations don't have to do that.
+	 */
+	vfs_fsync(file, 0);
+
+	/* and ... switch */
+	disk_force_media_change(lo->lo_disk);
+	memflags = blk_mq_freeze_queue(lo->lo_queue);
+	mapping_set_gfp_mask((*old_file)->f_mapping, lo->old_gfp_mask);
+	loop_assign_backing_file(lo, file);
+	loop_update_dio(lo);
+	blk_mq_unfreeze_queue(lo->lo_queue, memflags);
+	*partscan = lo->lo_flags & LO_FLAGS_PARTSCAN;
+
+	return 0;
+}
+
 /*
  * loop_change_fd switched the backing store of a loopback device to
  * a new file. This is useful for operating system installers to free up
@@ -536,7 +579,6 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
 {
 	struct file *file = fget(arg);
 	struct file *old_file;
-	unsigned int memflags;
 	int error;
 	bool partscan;
 	bool is_loop;
@@ -554,46 +596,21 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
 	dev_set_uevent_suppress(disk_to_dev(lo->lo_disk), 1);
 
 	is_loop = is_loop_device(file);
-	error = loop_global_lock_killable(lo, is_loop);
+	if (is_loop) {
+		error = loop_global_lock_killable(lo);
+		if (error)
+			goto out_putf;
+		error = __loop_change_fd(lo, bdev, file, &old_file, &partscan);
+		loop_global_unlock(lo);
+	} else {
+		error = mutex_lock_killable(&lo->lo_mutex);
+		if (error)
+			goto out_putf;
+		error = __loop_change_fd(lo, bdev, file, &old_file, &partscan);
+		mutex_unlock(&lo->lo_mutex);
+	}
 	if (error)
 		goto out_putf;
-	error = -ENXIO;
-	if (lo->lo_state != Lo_bound)
-		goto out_err;
-
-	/* the loop device has to be read-only */
-	error = -EINVAL;
-	if (!(lo->lo_flags & LO_FLAGS_READ_ONLY))
-		goto out_err;
-
-	error = loop_validate_file(file, bdev);
-	if (error)
-		goto out_err;
-
-	old_file = lo->lo_backing_file;
-
-	error = -EINVAL;
-
-	/* size of the new backing store needs to be the same */
-	if (lo_calculate_size(lo, file) != lo_calculate_size(lo, old_file))
-		goto out_err;
-
-	/*
-	 * We might switch to direct I/O mode for the loop device, write back
-	 * all dirty data the page cache now that so that the individual I/O
-	 * operations don't have to do that.
-	 */
-	vfs_fsync(file, 0);
-
-	/* and ... switch */
-	disk_force_media_change(lo->lo_disk);
-	memflags = blk_mq_freeze_queue(lo->lo_queue);
-	mapping_set_gfp_mask(old_file->f_mapping, lo->old_gfp_mask);
-	loop_assign_backing_file(lo, file);
-	loop_update_dio(lo);
-	blk_mq_unfreeze_queue(lo->lo_queue, memflags);
-	partscan = lo->lo_flags & LO_FLAGS_PARTSCAN;
-	loop_global_unlock(lo, is_loop);
 
 	/*
 	 * Flush loop_validate_file() before fput(), for l->lo_backing_file
@@ -618,8 +635,6 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
 	kobject_uevent(&disk_to_dev(lo->lo_disk)->kobj, KOBJ_CHANGE);
 	return error;
 
-out_err:
-	loop_global_unlock(lo, is_loop);
 out_putf:
 	fput(file);
 	dev_set_uevent_suppress(disk_to_dev(lo->lo_disk), 0);
@@ -974,61 +989,29 @@ static void loop_update_limits(struct loop_device *lo, struct queue_limits *lim,
 		lim->discard_granularity = 0;
 }
 
-static int loop_configure(struct loop_device *lo, blk_mode_t mode,
-			  struct block_device *bdev,
-			  const struct loop_config *config)
+static int __loop_configure(struct loop_device *lo, blk_mode_t mode,
+			    struct block_device *bdev,
+			    const struct loop_config *config, struct file *file,
+			    bool *partscan)
+	__must_hold(&lo->lo_mutex)
 {
-	struct file *file = fget(config->fd);
 	struct queue_limits lim;
-	int error;
 	loff_t size;
-	bool partscan;
-	bool is_loop;
-
-	if (!file)
-		return -EBADF;
-
-	error = loop_check_backing_file(file);
-	if (error) {
-		fput(file);
-		return error;
-	}
-
-	is_loop = is_loop_device(file);
-
-	/* This is safe, since we have a reference from open(). */
-	__module_get(THIS_MODULE);
-
-	/*
-	 * If we don't hold exclusive handle for the device, upgrade to it
-	 * here to avoid changing device under exclusive owner.
-	 */
-	if (!(mode & BLK_OPEN_EXCL)) {
-		error = bd_prepare_to_claim(bdev, loop_configure, NULL);
-		if (error)
-			goto out_putf;
-	}
-
-	error = loop_global_lock_killable(lo, is_loop);
-	if (error)
-		goto out_bdev;
+	int error;
 
-	error = -EBUSY;
 	if (lo->lo_state != Lo_unbound)
-		goto out_unlock;
+		return -EBUSY;
 
 	error = loop_validate_file(file, bdev);
 	if (error)
-		goto out_unlock;
+		return error;
 
-	if ((config->info.lo_flags & ~LOOP_CONFIGURE_SETTABLE_FLAGS) != 0) {
-		error = -EINVAL;
-		goto out_unlock;
-	}
+	if ((config->info.lo_flags & ~LOOP_CONFIGURE_SETTABLE_FLAGS) != 0)
+		return -EINVAL;
 
 	error = loop_set_status_from_info(lo, &config->info);
 	if (error)
-		goto out_unlock;
+		return error;
 	lo->lo_flags = config->info.lo_flags;
 
 	if (!(file->f_mode & FMODE_WRITE) || !(mode & BLK_OPEN_WRITE) ||
@@ -1039,10 +1022,8 @@ static int loop_configure(struct loop_device *lo, blk_mode_t mode,
 		lo->workqueue = alloc_workqueue("loop%d",
 						WQ_UNBOUND | WQ_FREEZABLE,
 						0, lo->lo_number);
-		if (!lo->workqueue) {
-			error = -ENOMEM;
-			goto out_unlock;
-		}
+		if (!lo->workqueue)
+			return -ENOMEM;
 	}
 
 	/* suppress uevents while reconfiguring the device */
@@ -1059,7 +1040,7 @@ static int loop_configure(struct loop_device *lo, blk_mode_t mode,
 	/* No need to freeze the queue as the device isn't bound yet. */
 	error = queue_limits_commit_update(lo->lo_queue, &lim);
 	if (error)
-		goto out_unlock;
+		return error;
 
 	/*
 	 * We might switch to direct I/O mode for the loop device, write back
@@ -1080,14 +1061,66 @@ static int loop_configure(struct loop_device *lo, blk_mode_t mode,
 	WRITE_ONCE(lo->lo_state, Lo_bound);
 	if (part_shift)
 		lo->lo_flags |= LO_FLAGS_PARTSCAN;
-	partscan = lo->lo_flags & LO_FLAGS_PARTSCAN;
-	if (partscan)
+	*partscan = lo->lo_flags & LO_FLAGS_PARTSCAN;
+	if (*partscan)
 		clear_bit(GD_SUPPRESS_PART_SCAN, &lo->lo_disk->state);
 
 	dev_set_uevent_suppress(disk_to_dev(lo->lo_disk), 0);
 	kobject_uevent(&disk_to_dev(lo->lo_disk)->kobj, KOBJ_CHANGE);
 
-	loop_global_unlock(lo, is_loop);
+	return 0;
+}
+
+static int loop_configure(struct loop_device *lo, blk_mode_t mode,
+			  struct block_device *bdev,
+			  const struct loop_config *config)
+{
+	struct file *file = fget(config->fd);
+	int error;
+	bool partscan;
+	bool is_loop;
+
+	if (!file)
+		return -EBADF;
+
+	error = loop_check_backing_file(file);
+	if (error) {
+		fput(file);
+		return error;
+	}
+
+	is_loop = is_loop_device(file);
+
+	/* This is safe, since we have a reference from open(). */
+	__module_get(THIS_MODULE);
+
+	/*
+	 * If we don't hold exclusive handle for the device, upgrade to it
+	 * here to avoid changing device under exclusive owner.
+	 */
+	if (!(mode & BLK_OPEN_EXCL)) {
+		error = bd_prepare_to_claim(bdev, loop_configure, NULL);
+		if (error)
+			goto out_putf;
+	}
+
+	if (is_loop) {
+		error = loop_global_lock_killable(lo);
+		if (error)
+			goto out_bdev;
+		error = __loop_configure(lo, mode, bdev, config, file,
+					 &partscan);
+		loop_global_unlock(lo);
+	} else {
+		error = mutex_lock_killable(&lo->lo_mutex);
+		if (error)
+			goto out_bdev;
+		error = __loop_configure(lo, mode, bdev, config, file,
+					 &partscan);
+		mutex_unlock(&lo->lo_mutex);
+	}
+	if (error)
+		goto out_bdev;
 	if (partscan)
 		loop_reread_partitions(lo);
 
@@ -1096,8 +1129,6 @@ static int loop_configure(struct loop_device *lo, blk_mode_t mode,
 
 	return 0;
 
-out_unlock:
-	loop_global_unlock(lo, is_loop);
 out_bdev:
 	if (!(mode & BLK_OPEN_EXCL))
 		bd_abort_claiming(bdev, loop_configure);
@@ -1194,11 +1225,11 @@ static int loop_clr_fd(struct loop_device *lo)
 	 * which loop_configure()/loop_change_fd() found via fget() was this
 	 * loop device.
 	 */
-	err = loop_global_lock_killable(lo, true);
+	err = loop_global_lock_killable(lo);
 	if (err)
 		return err;
 	if (lo->lo_state != Lo_bound) {
-		loop_global_unlock(lo, true);
+		loop_global_unlock(lo);
 		return -ENXIO;
 	}
 	/*
@@ -1210,7 +1241,7 @@ static int loop_clr_fd(struct loop_device *lo)
 	lo->lo_flags |= LO_FLAGS_AUTOCLEAR;
 	if (disk_openers(lo->lo_disk) == 1)
 		WRITE_ONCE(lo->lo_state, Lo_rundown);
-	loop_global_unlock(lo, true);
+	loop_global_unlock(lo);
 
 	return 0;
 }
@@ -2302,6 +2333,7 @@ static void __exit loop_exit(void)
 	 * module unloading is requested). If this is not a clean unloading,
 	 * we have no means to avoid kernel crash.
 	 */
+	__assume_ctx_lock(&loop_ctl_mutex);
 	idr_for_each_entry(&loop_index_idr, lo, id)
 		loop_remove(lo);
 
diff --git a/drivers/block/mtip32xx/Makefile b/drivers/block/mtip32xx/Makefile
index bff32b5d3c192..233961fdb41b9 100644
--- a/drivers/block/mtip32xx/Makefile
+++ b/drivers/block/mtip32xx/Makefile
@@ -3,4 +3,6 @@
 # Makefile for  Block device driver for Micron PCIe SSD
 #
 
+CONTEXT_ANALYSIS := y
+
 obj-$(CONFIG_BLK_DEV_PCIESSD_MTIP32XX) += mtip32xx.o
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 8f10762e90ef7..751449d362b03 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -49,8 +49,8 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/nbd.h>
 
-static DEFINE_IDR(nbd_index_idr);
 static DEFINE_MUTEX(nbd_index_mutex);
+static __guarded_by(&nbd_index_mutex) DEFINE_IDR(nbd_index_idr);
 static struct workqueue_struct *nbd_del_wq;
 static int nbd_total_devices = 0;
 
@@ -1506,6 +1506,7 @@ static void nbd_config_put(struct nbd_device *nbd)
 }
 
 static int nbd_start_device(struct nbd_device *nbd)
+	__must_hold(&nbd->config_lock)
 {
 	struct nbd_config *config = nbd->config;
 	int num_connections = config->num_connections;
@@ -1578,6 +1579,7 @@ static int nbd_start_device(struct nbd_device *nbd)
 }
 
 static int nbd_start_device_ioctl(struct nbd_device *nbd)
+	__must_hold(&nbd->config_lock)
 {
 	struct nbd_config *config = nbd->config;
 	int ret;
@@ -1629,6 +1631,7 @@ static void nbd_set_cmd_timeout(struct nbd_device *nbd, u64 timeout)
 /* Must be called with config_lock held */
 static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
 		       unsigned int cmd, unsigned long arg)
+	__must_hold(&nbd->config_lock)
 {
 	struct nbd_config *config = nbd->config;
 	loff_t bytesize;
@@ -2773,7 +2776,11 @@ static void __exit nbd_cleanup(void)
 	/* Also wait for nbd_dev_remove_work() completes */
 	destroy_workqueue(nbd_del_wq);
 
-	idr_destroy(&nbd_index_idr);
+	{
+		__assume_ctx_lock(&nbd_index_mutex);
+		idr_destroy(&nbd_index_idr);
+	}
+
 	unregister_blkdev(NBD_MAJOR, "nbd");
 }
 
diff --git a/drivers/block/null_blk/Makefile b/drivers/block/null_blk/Makefile
index 84c36e512ab89..282b0d51a4779 100644
--- a/drivers/block/null_blk/Makefile
+++ b/drivers/block/null_blk/Makefile
@@ -1,5 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
+CONTEXT_ANALYSIS := y
+
 # needed for trace events
 ccflags-y			+= -I$(src)
 
diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c
index f8c0fd57e041a..baffc6c61178f 100644
--- a/drivers/block/null_blk/main.c
+++ b/drivers/block/null_blk/main.c
@@ -1038,6 +1038,7 @@ static struct nullb_page *null_insert_page(struct nullb *nullb,
 }
 
 static int null_flush_cache_page(struct nullb *nullb, struct nullb_page *c_page)
+	__must_hold(&nullb->lock)
 {
 	int i;
 	unsigned int offset;
@@ -1087,6 +1088,7 @@ static int null_flush_cache_page(struct nullb *nullb, struct nullb_page *c_page)
 }
 
 static int null_make_cache_space(struct nullb *nullb, unsigned long n)
+	__must_hold(&nullb->lock)
 {
 	int i, err, nr_pages;
 	struct nullb_page *c_pages[FREE_BATCH];
@@ -1141,6 +1143,7 @@ static int null_make_cache_space(struct nullb *nullb, unsigned long n)
 
 static blk_status_t copy_to_nullb(struct nullb *nullb, void *source,
 				  loff_t pos, size_t n, bool is_fua)
+	__must_hold(&nullb->lock)
 {
 	size_t temp, count = 0;
 	struct nullb_page *t_page;
@@ -1242,6 +1245,7 @@ static blk_status_t null_handle_flush(struct nullb *nullb)
 static blk_status_t null_transfer(struct nullb *nullb, struct page *page,
 	unsigned int len, unsigned int off, bool is_write, loff_t pos,
 	bool is_fua)
+	__must_hold(&nullb->lock)
 {
 	struct nullb_device *dev = nullb->dev;
 	blk_status_t err = BLK_STS_OK;
diff --git a/drivers/block/null_blk/zoned.c b/drivers/block/null_blk/zoned.c
index 384bdce6a9b7f..dbae748c90ba9 100644
--- a/drivers/block/null_blk/zoned.c
+++ b/drivers/block/null_blk/zoned.c
@@ -30,23 +30,26 @@ static inline void null_init_zone_lock(struct nullb_device *dev,
 		mutex_init(&zone->mutex);
 }
 
-static inline void null_lock_zone(struct nullb_device *dev,
-				  struct nullb_zone *zone)
-{
-	if (!dev->memory_backed)
-		spin_lock_irq(&zone->spinlock);
-	else
-		mutex_lock(&zone->mutex);
-}
-
-static inline void null_unlock_zone(struct nullb_device *dev,
-				    struct nullb_zone *zone)
-{
-	if (!dev->memory_backed)
-		spin_unlock_irq(&zone->spinlock);
-	else
-		mutex_unlock(&zone->mutex);
-}
+struct nullb_dev_and_zone {
+	struct nullb_device *dev;
+	struct nullb_zone *zone;
+};
+
+DEFINE_CLASS(null_zone, struct nullb_dev_and_zone, ({
+		     if (!_T.dev->memory_backed)
+			     spin_unlock_irq(&_T.zone->spinlock);
+		     else
+			     mutex_unlock(&_T.zone->mutex);
+	     }), ({
+		     if (!dev->memory_backed)
+			     spin_lock_irq(&zone->spinlock);
+		     else
+			     mutex_lock(&zone->mutex);
+		     (struct nullb_dev_and_zone){ dev, zone };
+	     }),
+	     struct nullb_device *dev, struct nullb_zone *zone)
+
+DEFINE_CLASS_IS_UNCONDITIONAL(null_zone)
 
 int null_init_zoned_dev(struct nullb_device *dev,
 			struct queue_limits *lim)
@@ -216,14 +219,14 @@ int null_report_zones(struct gendisk *disk, sector_t sector,
 		 * So use a local copy to avoid corruption of the device zone
 		 * array.
 		 */
-		null_lock_zone(dev, zone);
-		blkz.start = zone->start;
-		blkz.len = zone->len;
-		blkz.wp = zone->wp;
-		blkz.type = zone->type;
-		blkz.cond = zone->cond;
-		blkz.capacity = zone->capacity;
-		null_unlock_zone(dev, zone);
+		scoped_guard(null_zone, dev, zone) {
+			blkz.start = zone->start;
+			blkz.len = zone->len;
+			blkz.wp = zone->wp;
+			blkz.type = zone->type;
+			blkz.cond = zone->cond;
+			blkz.capacity = zone->capacity;
+		}
 
 		error = disk_report_zone(disk, &blkz, i, args);
 		if (error)
@@ -364,7 +367,7 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
 		return null_process_cmd(cmd, REQ_OP_WRITE, sector, nr_sectors);
 	}
 
-	null_lock_zone(dev, zone);
+	guard(null_zone)(dev, zone);
 
 	/*
 	 * Regular writes must be at the write pointer position. Zone append
@@ -376,19 +379,15 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
 	 */
 	if (append) {
 		if (WARN_ON_ONCE(!dev->zone_append_max_sectors) ||
-		    zone->wp == NULL_ZONE_INVALID_WP) {
-			ret = BLK_STS_IOERR;
-			goto unlock_zone;
-		}
+		    zone->wp == NULL_ZONE_INVALID_WP)
+			return BLK_STS_IOERR;
 		sector = zone->wp;
 		blk_mq_rq_from_pdu(cmd)->__sector = sector;
 	}
 
 	if (sector != zone->wp ||
-	    zone->wp + nr_sectors > zone->start + zone->capacity) {
-		ret = BLK_STS_IOERR;
-		goto unlock_zone;
-	}
+	    zone->wp + nr_sectors > zone->start + zone->capacity)
+		return BLK_STS_IOERR;
 
 	if (zone->cond == BLK_ZONE_COND_CLOSED ||
 	    zone->cond == BLK_ZONE_COND_EMPTY) {
@@ -398,7 +397,7 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
 			ret = null_check_zone_resources(dev, zone);
 			if (ret != BLK_STS_OK) {
 				spin_unlock(&dev->zone_res_lock);
-				goto unlock_zone;
+				return ret;
 			}
 			if (zone->cond == BLK_ZONE_COND_CLOSED) {
 				dev->nr_zones_closed--;
@@ -415,17 +414,15 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
 
 	if (dev->badblocks.shift != -1) {
 		badblocks_ret = null_handle_badblocks(cmd, sector, &nr_sectors);
-		if (badblocks_ret != BLK_STS_OK && !nr_sectors) {
-			ret = badblocks_ret;
-			goto unlock_zone;
-		}
+		if (badblocks_ret != BLK_STS_OK && !nr_sectors)
+			return badblocks_ret;
 	}
 
 	if (dev->memory_backed) {
 		ret = null_handle_memory_backed(cmd, REQ_OP_WRITE, sector,
 						nr_sectors);
 		if (ret != BLK_STS_OK)
-			goto unlock_zone;
+			return ret;
 	}
 
 	zone->wp += nr_sectors;
@@ -441,12 +438,7 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
 		zone->cond = BLK_ZONE_COND_FULL;
 	}
 
-	ret = badblocks_ret;
-
-unlock_zone:
-	null_unlock_zone(dev, zone);
-
-	return ret;
+	return badblocks_ret;
 }
 
 static blk_status_t null_open_zone(struct nullb_device *dev,
@@ -655,14 +647,14 @@ static blk_status_t null_zone_mgmt(struct nullb_cmd *cmd, enum req_op op,
 	if (op == REQ_OP_ZONE_RESET_ALL) {
 		for (i = dev->zone_nr_conv; i < dev->nr_zones; i++) {
 			zone = &dev->zones[i];
-			null_lock_zone(dev, zone);
-			if (zone->cond != BLK_ZONE_COND_EMPTY &&
-			    zone->cond != BLK_ZONE_COND_READONLY &&
-			    zone->cond != BLK_ZONE_COND_OFFLINE) {
-				null_reset_zone(dev, zone);
-				trace_nullb_zone_op(cmd, i, zone->cond);
+			scoped_guard(null_zone, dev, zone) {
+				if (zone->cond != BLK_ZONE_COND_EMPTY &&
+				    zone->cond != BLK_ZONE_COND_READONLY &&
+				    zone->cond != BLK_ZONE_COND_OFFLINE) {
+					null_reset_zone(dev, zone);
+					trace_nullb_zone_op(cmd, i, zone->cond);
+				}
 			}
-			null_unlock_zone(dev, zone);
 		}
 		return BLK_STS_OK;
 	}
@@ -670,13 +662,11 @@ static blk_status_t null_zone_mgmt(struct nullb_cmd *cmd, enum req_op op,
 	zone_no = null_zone_no(dev, sector);
 	zone = &dev->zones[zone_no];
 
-	null_lock_zone(dev, zone);
+	guard(null_zone)(dev, zone);
 
 	if (zone->cond == BLK_ZONE_COND_READONLY ||
-	    zone->cond == BLK_ZONE_COND_OFFLINE) {
-		ret = BLK_STS_IOERR;
-		goto unlock;
-	}
+	    zone->cond == BLK_ZONE_COND_OFFLINE)
+		return BLK_STS_IOERR;
 
 	switch (op) {
 	case REQ_OP_ZONE_RESET:
@@ -699,9 +689,6 @@ static blk_status_t null_zone_mgmt(struct nullb_cmd *cmd, enum req_op op,
 	if (ret == BLK_STS_OK)
 		trace_nullb_zone_op(cmd, zone_no, zone->cond);
 
-unlock:
-	null_unlock_zone(dev, zone);
-
 	return ret;
 }
 
@@ -710,7 +697,6 @@ blk_status_t null_process_zoned_cmd(struct nullb_cmd *cmd, enum req_op op,
 {
 	struct nullb_device *dev;
 	struct nullb_zone *zone;
-	blk_status_t sts;
 
 	switch (op) {
 	case REQ_OP_WRITE:
@@ -729,10 +715,8 @@ blk_status_t null_process_zoned_cmd(struct nullb_cmd *cmd, enum req_op op,
 		if (zone->cond == BLK_ZONE_COND_OFFLINE)
 			return BLK_STS_IOERR;
 
-		null_lock_zone(dev, zone);
-		sts = null_process_cmd(cmd, op, sector, nr_sectors);
-		null_unlock_zone(dev, zone);
-		return sts;
+		scoped_guard(null_zone, dev, zone)
+			return null_process_cmd(cmd, op, sector, nr_sectors);
 	}
 }
 
@@ -746,7 +730,7 @@ static void null_set_zone_cond(struct nullb_device *dev,
 			 cond != BLK_ZONE_COND_OFFLINE))
 		return;
 
-	null_lock_zone(dev, zone);
+	guard(null_zone)(dev, zone);
 
 	/*
 	 * If the read-only condition is requested again to zones already in
@@ -767,8 +751,6 @@ static void null_set_zone_cond(struct nullb_device *dev,
 		zone->cond = cond;
 		zone->wp = NULL_ZONE_INVALID_WP;
 	}
-
-	null_unlock_zone(dev, zone);
 }
 
 /*
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 1f1c2810f6ee3..f0f7a94e3e3e3 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -4183,6 +4183,7 @@ static void rbd_acquire_lock(struct work_struct *work)
 }
 
 static bool rbd_quiesce_lock(struct rbd_device *rbd_dev)
+	__must_hold(&rbd_dev->lock_rwsem)
 {
 	dout("%s rbd_dev %p\n", __func__, rbd_dev);
 	lockdep_assert_held_write(&rbd_dev->lock_rwsem);
@@ -4227,6 +4228,7 @@ static void __rbd_release_lock(struct rbd_device *rbd_dev)
  * lock_rwsem must be held for write
  */
 static void rbd_release_lock(struct rbd_device *rbd_dev)
+	__must_hold(&rbd_dev->lock_rwsem)
 {
 	if (!rbd_quiesce_lock(rbd_dev))
 		return;
@@ -4583,6 +4585,7 @@ static void rbd_unregister_watch(struct rbd_device *rbd_dev)
  * lock_rwsem must be held for write
  */
 static void rbd_reacquire_lock(struct rbd_device *rbd_dev)
+	__must_hold(&rbd_dev->lock_rwsem)
 {
 	struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
 	char cookie[32];
@@ -6780,6 +6783,7 @@ static void rbd_dev_device_release(struct rbd_device *rbd_dev)
  * upon return.
  */
 static int rbd_dev_device_setup(struct rbd_device *rbd_dev)
+	__releases(&rbd_dev->header_rwsem)
 {
 	int ret;
 
@@ -6881,6 +6885,7 @@ static void rbd_dev_image_release(struct rbd_device *rbd_dev)
  * with @depth == 0.
  */
 static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
+	__context_unsafe(conditional locking on @depth)
 {
 	bool need_watch = !rbd_is_ro(rbd_dev);
 	int ret;
@@ -7134,6 +7139,9 @@ static ssize_t do_rbd_add(const char *buf, size_t count)
 	if (rc < 0)
 		goto err_out_rbd_dev;
 
+	/* Acquired by rbd_dev_image_probe(rbd_dev, 0) */
+	__acquire(&rbd_dev->header_rwsem);
+
 	if (rbd_dev->opts->alloc_size > rbd_dev->layout.object_size) {
 		rbd_warn(rbd_dev, "alloc_size adjusted to %u",
 			 rbd_dev->layout.object_size);
diff --git a/drivers/block/rnbd/Makefile b/drivers/block/rnbd/Makefile
index 208e5f8654975..42c2cccdb53d3 100644
--- a/drivers/block/rnbd/Makefile
+++ b/drivers/block/rnbd/Makefile
@@ -1,5 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-or-later
 
+CONTEXT_ANALYSIS := y
+
 ccflags-y := -I$(srctree)/drivers/infiniband/ulp/rtrs
 
 rnbd-client-y := rnbd-clt.o \
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 2a22f9dc1f2f1..b18b50efd0940 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -373,11 +373,13 @@ static inline bool ublk_support_batch_io(const struct ublk_queue *ubq)
 }
 
 static inline void ublk_io_lock(struct ublk_io *io)
+	__acquires(&io->lock)
 {
 	spin_lock(&io->lock);
 }
 
 static inline void ublk_io_unlock(struct ublk_io *io)
+	__releases(&io->lock)
 {
 	spin_unlock(&io->lock);
 }
@@ -3262,6 +3264,7 @@ static int ublk_check_fetch_buf(const struct ublk_device *ub, __u64 buf_addr)
 
 static int __ublk_fetch(struct io_uring_cmd *cmd, struct ublk_device *ub,
 			struct ublk_io *io, u16 q_id)
+	__must_hold(&ub->mutex)
 {
 	/* UBLK_IO_FETCH_REQ is only allowed before dev is setup */
 	if (ublk_dev_ready(ub))
@@ -3689,6 +3692,7 @@ static void ublk_batch_revert_prep_cmd(struct ublk_batch_io_iter *iter,
 static int ublk_batch_prep_io(struct ublk_queue *ubq,
 			      const struct ublk_batch_io_data *data,
 			      const struct ublk_elem_header *elem)
+	__must_hold(&data->ub->mutex)
 {
 	struct ublk_io *io = &ubq->ios[elem->tag];
 	const struct ublk_batch_io *uc = &data->header;
@@ -4422,6 +4426,7 @@ static bool ublk_validate_user_pid(struct ublk_device *ub, pid_t ublksrv_pid)
  * UNPREP, daemon death), so re-check it under the mutex and wait again.
  */
 static int ublk_wait_dev_ready_and_lock(struct ublk_device *ub)
+	__cond_acquires(0, &ub->mutex)
 {
 	while (true) {
 		if (wait_var_event_interruptible(&ub->nr_queue_ready,
@@ -5323,6 +5328,7 @@ static int ublk_char_dev_permission(struct ublk_device *ub,
  * already holds ub->mutex when calling del_gendisk() which freezes the queue.
 */
 static unsigned int ublk_lock_buf_tree(struct ublk_device *ub)
+	__acquires(&ub->mutex)
 {
 	unsigned int memflags = 0;
 
@@ -5334,6 +5340,7 @@ static unsigned int ublk_lock_buf_tree(struct ublk_device *ub)
 }
 
 static void ublk_unlock_buf_tree(struct ublk_device *ub, unsigned int memflags)
+	__releases(&ub->mutex)
 {
 	if (ub->ub_disk)
 		blk_mq_unfreeze_queue(ub->ub_disk->queue, memflags);
diff --git a/drivers/block/xen-blkback/Makefile b/drivers/block/xen-blkback/Makefile
index b0ea5ab5b9a15..864ef423226cf 100644
--- a/drivers/block/xen-blkback/Makefile
+++ b/drivers/block/xen-blkback/Makefile
@@ -1,4 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
+
+CONTEXT_ANALYSIS := y
+
 obj-$(CONFIG_XEN_BLKDEV_BACKEND) := xen-blkback.o
 
 xen-blkback-y	:= blkback.o xenbus.o
diff --git a/drivers/block/zram/Makefile b/drivers/block/zram/Makefile
index 0fdefd576691b..a5663ab016532 100644
--- a/drivers/block/zram/Makefile
+++ b/drivers/block/zram/Makefile
@@ -1,5 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
+CONTEXT_ANALYSIS := y
+
 zram-y	:=	zcomp.o zram_drv.o
 
 zram-$(CONFIG_ZRAM_BACKEND_LZO)		+= backend_lzorle.o backend_lzo.o
diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
index 974c4691887e6..155dbeacab1b4 100644
--- a/drivers/block/zram/zcomp.c
+++ b/drivers/block/zram/zcomp.c
@@ -112,7 +112,8 @@ ssize_t zcomp_available_show(const char *comp, char *buf, ssize_t at)
 	return at;
 }
 
-struct zcomp_strm *zcomp_stream_get(struct zcomp *comp)
+struct zcomp_strm *__zcomp_stream_get(struct zcomp *comp)
+	__context_unsafe(uses raw_cpu_ptr())
 {
 	for (;;) {
 		struct zcomp_strm *zstrm = raw_cpu_ptr(comp->stream);
diff --git a/drivers/block/zram/zcomp.h b/drivers/block/zram/zcomp.h
index 81a0f3f6ff487..afe0c1bf348d8 100644
--- a/drivers/block/zram/zcomp.h
+++ b/drivers/block/zram/zcomp.h
@@ -85,8 +85,10 @@ const char *zcomp_lookup_backend_name(const char *comp);
 struct zcomp *zcomp_create(const char *alg, struct zcomp_params *params);
 void zcomp_destroy(struct zcomp *comp);
 
-struct zcomp_strm *zcomp_stream_get(struct zcomp *comp);
-void zcomp_stream_put(struct zcomp_strm *zstrm);
+#define zcomp_stream_get(...) __acquire_ret(__zcomp_stream_get(__VA_ARGS__), &__ret->lock)
+struct zcomp_strm *__zcomp_stream_get(struct zcomp *comp);
+void zcomp_stream_put(struct zcomp_strm *zstrm)
+	__releases(&zstrm->lock);
 
 int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
 		   const void *src, unsigned int *dst_len);

3/2 2026/08/01 07:44 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 14269
							output: 151
							thoughts: 2207
						

Thoughts:
**Patch Analysis: Sparse Annotations and Refactoring for Context Analysis**

Okay, so I'm looking at this patch that's adding `CONTEXT_ANALYSIS := y` to a bunch of Makefiles in `drivers/block/`, and it's also adding a *lot* of sparse annotations across several block drivers. My initial thought is, "Okay, this is probably about improving static analysis." I see stuff like `__must_hold`, `__cond_acquires`, `__releases`, `__guarded_by`, `__assume_ctx_lock`, `__context_unsafe`, `__acquire`, `__acquire_ret`. Classic sparse stuff.

Then I notice `scoped_guard` and `guard` being used in `null_blk/zoned.c`. That *could* be a functional change, but more likely it's just refactoring to use some new cleanup macros. Let's dig into that `null_blk/zoned.c` part first. Yep, looks like `null_lock_zone` and `null_unlock_zone` are replaced with `guard(null_zone)` and `scoped_guard(null_zone)`. Essentially a RAII-style lock management strategy. It's just refactoring, but I want to make sure the logic is identical.

The rest of the patch seems to be similar: Annotations, annotations, annotations, like `__must_hold(&iocq[id].lock)` in `aoecmd.c`.  I see some refactoring in `loop.c` to remove the `global` argument from `loop_global_lock_killable`.  This is likely because sparse can't handle conditional locking based on an argument, so they're making the locking unconditional and explicit.  The logic is identical, it's just that if it's "is_loop" then it's unconditionally locking both mutexes.

In `nbd.c`, it's just adding an annotation, no functional changes. Also, there is a small change in `zcomp.c` to use `__zcomp_stream_get` which is marked as `__context_unsafe(uses raw_cpu_ptr())`

So, basically, all these changes are annotations and some refactoring to keep sparse happy. *None* of them, at first glance, appear to change any functional logic in the drivers. It's all about making the locking patterns clear to the static analyzer.

Now, let me double-check. I want to be *absolutely* certain. Does that `guard` macro in `null_blk/zoned.c` *really* not change anything? Let's check `null_zone_write`. The `guard` now handles the unlock implicitly when it goes out of scope. Instead of a `goto unlock_zone`, it directly returns. Same logic.

Okay, let's look at `loop.c`. Previously, it was checking `global` to determine if we should lock. Now, in `loop_global_lock_killable` we lock both mutexes unconditionally. But, the callers `loop_change_fd` and `loop_configure` now check `is_loop`, locking the second mutex if and only if it's true. It's an identical state machine. The code is identical.

Therefore, the `WorthFuzzing` assessment is definitely false. There are no functional changes that would necessitate fuzzing. This is all about enhancing static analysis and doesn't introduce any new potential bugs at a functional level. I'll use `set-results` to return `WorthFuzzing=false`.



4/2 2026/08/01 07:44 tool set-results
0m Args:
{
  "EnableConfigs": [],
  "FocusSymbols": [],
  "Reasoning": "The patch introduces sparse annotations (e.g., __must_hold, __acquires, __releases, __guarded_by) and CONTEXT_ANALYSIS := y to Makefiles in the block layer to enable static context analysis. It also refactors some locking logic (like extracting __loop_change_fd and __loop_configure in loop.c, and using guard()/scoped_guard() in null_blk/zoned.c) to make the locking behavior unconditional and verifiable by the static analyzer. There are no functional changes to the execution flow or logic of the kernel.",
  "WorthFuzzing": false
}

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch introduces sparse annotations (e.g., __must_hold, __acquires, __releases, __guarded_by) and CONTEXT_ANALYSIS := y to Makefiles in the block layer to enable static context analysis. It also refactors some locking logic (like extracting __loop_change_fd and __loop_configure in loop.c, and using guard()/scoped_guard() in null_blk/zoned.c) to make the locking behavior unconditional and verifiable by the static analyzer. There are no functional changes to the execution flow or logic of the kernel.",
  "WorthFuzzing": false
}

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)