Commit f405c445a4866caa43101c231721123805a23bbf
Committed by
Linus Torvalds
1 parent
92ff152887
Exists in
smarct4x-processor-sdk-linux-03.00.00.04
and in
4 other branches
zram: close race by open overriding
[ Original patch from Minchan Kim <minchan@kernel.org> ] Commit ba6b17d68c8e ("zram: fix umount-reset_store-mount race condition") introduced bdev->bd_mutex to protect a race between mount and reset. At that time, we don't have dynamic zram-add/remove feature so it was okay. However, as we introduce dynamic device feature, bd_mutex became trouble. CPU 0 echo 1 > /sys/block/zram<id>/reset -> kernfs->s_active(A) -> zram:reset_store->bd_mutex(B) CPU 1 echo <id> > /sys/class/zram/zram-remove ->zram:zram_remove: bd_mutex(B) -> sysfs_remove_group -> kernfs->s_active(A) IOW, AB -> BA deadlock The reason we are holding bd_mutex for zram_remove is to prevent any incoming open /dev/zram[0-9]. Otherwise, we could remove zram others already have opened. But it causes above deadlock problem. To fix the problem, this patch overrides block_device.open and it returns -EBUSY if zram asserts he claims zram to reset so any incoming open will be failed so we don't need to hold bd_mutex for zram_remove ayn more. This patch is to prepare for zram-add/remove feature. [sergey.senozhatsky@gmail.com: simplify reset_store()] Signed-off-by: Minchan Kim <minchan@kernel.org> Acked-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 2 changed files with 38 additions and 19 deletions Side-by-side Diff
drivers/block/zram/zram_drv.c
... | ... | @@ -1070,45 +1070,60 @@ |
1070 | 1070 | struct zram *zram; |
1071 | 1071 | struct block_device *bdev; |
1072 | 1072 | |
1073 | + ret = kstrtou16(buf, 10, &do_reset); | |
1074 | + if (ret) | |
1075 | + return ret; | |
1076 | + | |
1077 | + if (!do_reset) | |
1078 | + return -EINVAL; | |
1079 | + | |
1073 | 1080 | zram = dev_to_zram(dev); |
1074 | 1081 | bdev = bdget_disk(zram->disk, 0); |
1075 | - | |
1076 | 1082 | if (!bdev) |
1077 | 1083 | return -ENOMEM; |
1078 | 1084 | |
1079 | 1085 | mutex_lock(&bdev->bd_mutex); |
1080 | - /* Do not reset an active device! */ | |
1081 | - if (bdev->bd_openers) { | |
1082 | - ret = -EBUSY; | |
1083 | - goto out; | |
1086 | + /* Do not reset an active device or claimed device */ | |
1087 | + if (bdev->bd_openers || zram->claim) { | |
1088 | + mutex_unlock(&bdev->bd_mutex); | |
1089 | + bdput(bdev); | |
1090 | + return -EBUSY; | |
1084 | 1091 | } |
1085 | 1092 | |
1086 | - ret = kstrtou16(buf, 10, &do_reset); | |
1087 | - if (ret) | |
1088 | - goto out; | |
1093 | + /* From now on, anyone can't open /dev/zram[0-9] */ | |
1094 | + zram->claim = true; | |
1095 | + mutex_unlock(&bdev->bd_mutex); | |
1089 | 1096 | |
1090 | - if (!do_reset) { | |
1091 | - ret = -EINVAL; | |
1092 | - goto out; | |
1093 | - } | |
1094 | - | |
1095 | - /* Make sure all pending I/O is finished */ | |
1097 | + /* Make sure all the pending I/O are finished */ | |
1096 | 1098 | fsync_bdev(bdev); |
1097 | 1099 | zram_reset_device(zram); |
1098 | - | |
1099 | - mutex_unlock(&bdev->bd_mutex); | |
1100 | 1100 | revalidate_disk(zram->disk); |
1101 | 1101 | bdput(bdev); |
1102 | 1102 | |
1103 | + mutex_lock(&bdev->bd_mutex); | |
1104 | + zram->claim = false; | |
1105 | + mutex_unlock(&bdev->bd_mutex); | |
1106 | + | |
1103 | 1107 | return len; |
1108 | +} | |
1104 | 1109 | |
1105 | -out: | |
1106 | - mutex_unlock(&bdev->bd_mutex); | |
1107 | - bdput(bdev); | |
1110 | +static int zram_open(struct block_device *bdev, fmode_t mode) | |
1111 | +{ | |
1112 | + int ret = 0; | |
1113 | + struct zram *zram; | |
1114 | + | |
1115 | + WARN_ON(!mutex_is_locked(&bdev->bd_mutex)); | |
1116 | + | |
1117 | + zram = bdev->bd_disk->private_data; | |
1118 | + /* zram was claimed to reset so open request fails */ | |
1119 | + if (zram->claim) | |
1120 | + ret = -EBUSY; | |
1121 | + | |
1108 | 1122 | return ret; |
1109 | 1123 | } |
1110 | 1124 | |
1111 | 1125 | static const struct block_device_operations zram_devops = { |
1126 | + .open = zram_open, | |
1112 | 1127 | .swap_slot_free_notify = zram_slot_free_notify, |
1113 | 1128 | .rw_page = zram_rw_page, |
1114 | 1129 | .owner = THIS_MODULE |
drivers/block/zram/zram_drv.h