diff options
author | Sergey Senozhatsky <sergey.senozhatsky@gmail.com> | 2015-06-25 18:00:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-25 20:00:36 -0400 |
commit | 6566d1a32bf725a4fa9119f16270505451ad01ac (patch) | |
tree | c2faa0b705f3da2d0cb10f520127f41df17e7148 /drivers/block | |
parent | f405c445a4866caa43101c231721123805a23bbf (diff) |
zram: add dynamic device add/remove functionality
We currently don't support on-demand device creation. The one and only
way to have N zram devices is to specify num_devices module parameter
(default value: 1). IOW if, for some reason, at some point, user wants
to have N + 1 devies he/she must umount all the existing devices, unload
the module, load the module passing num_devices equals to N + 1. And do
this again, if needed.
This patch introduces zram control sysfs class, which has two sysfs
attrs:
- hot_add -- add a new zram device
- hot_remove -- remove a specific (device_id) zram device
hot_add sysfs attr is read-only and has only automatic device id
assignment mode (as requested by Minchan Kim). read operation performed
on this attr creates a new zram device and returns back its device_id or
error status.
Usage example:
# add a new specific zram device
cat /sys/class/zram-control/hot_add
2
# remove a specific zram device
echo 4 > /sys/class/zram-control/hot_remove
Returning zram_add() error code back to user (-ENOMEM in this case)
cat /sys/class/zram-control/hot_add
cat: /sys/class/zram-control/hot_add: Cannot allocate memory
NOTE, there might be users who already depend on the fact that at least
zram0 device gets always created by zram_init(). Preserve this behavior.
[minchan@kernel.org: use zram->claim to avoid lockdep splat]
Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Cc: Minchan Kim <minchan@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/zram/zram_drv.c | 100 |
1 files changed, 97 insertions, 3 deletions
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 6a3b36d5bad6..830f0eb501fa 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c | |||
@@ -29,10 +29,14 @@ | |||
29 | #include <linux/vmalloc.h> | 29 | #include <linux/vmalloc.h> |
30 | #include <linux/err.h> | 30 | #include <linux/err.h> |
31 | #include <linux/idr.h> | 31 | #include <linux/idr.h> |
32 | #include <linux/sysfs.h> | ||
32 | 33 | ||
33 | #include "zram_drv.h" | 34 | #include "zram_drv.h" |
34 | 35 | ||
35 | static DEFINE_IDR(zram_index_idr); | 36 | static DEFINE_IDR(zram_index_idr); |
37 | /* idr index must be protected */ | ||
38 | static DEFINE_MUTEX(zram_index_mutex); | ||
39 | |||
36 | static int zram_major; | 40 | static int zram_major; |
37 | static const char *default_compressor = "lzo"; | 41 | static const char *default_compressor = "lzo"; |
38 | 42 | ||
@@ -1273,24 +1277,104 @@ out_free_dev: | |||
1273 | return ret; | 1277 | return ret; |
1274 | } | 1278 | } |
1275 | 1279 | ||
1276 | static void zram_remove(struct zram *zram) | 1280 | static int zram_remove(struct zram *zram) |
1277 | { | 1281 | { |
1278 | pr_info("Removed device: %s\n", zram->disk->disk_name); | 1282 | struct block_device *bdev; |
1283 | |||
1284 | bdev = bdget_disk(zram->disk, 0); | ||
1285 | if (!bdev) | ||
1286 | return -ENOMEM; | ||
1287 | |||
1288 | mutex_lock(&bdev->bd_mutex); | ||
1289 | if (bdev->bd_openers || zram->claim) { | ||
1290 | mutex_unlock(&bdev->bd_mutex); | ||
1291 | bdput(bdev); | ||
1292 | return -EBUSY; | ||
1293 | } | ||
1294 | |||
1295 | zram->claim = true; | ||
1296 | mutex_unlock(&bdev->bd_mutex); | ||
1297 | |||
1279 | /* | 1298 | /* |
1280 | * Remove sysfs first, so no one will perform a disksize | 1299 | * Remove sysfs first, so no one will perform a disksize |
1281 | * store while we destroy the devices | 1300 | * store while we destroy the devices. This also helps during |
1301 | * hot_remove -- zram_reset_device() is the last holder of | ||
1302 | * ->init_lock, no later/concurrent disksize_store() or any | ||
1303 | * other sysfs handlers are possible. | ||
1282 | */ | 1304 | */ |
1283 | sysfs_remove_group(&disk_to_dev(zram->disk)->kobj, | 1305 | sysfs_remove_group(&disk_to_dev(zram->disk)->kobj, |
1284 | &zram_disk_attr_group); | 1306 | &zram_disk_attr_group); |
1285 | 1307 | ||
1308 | /* Make sure all the pending I/O are finished */ | ||
1309 | fsync_bdev(bdev); | ||
1286 | zram_reset_device(zram); | 1310 | zram_reset_device(zram); |
1311 | bdput(bdev); | ||
1312 | |||
1313 | pr_info("Removed device: %s\n", zram->disk->disk_name); | ||
1314 | |||
1287 | idr_remove(&zram_index_idr, zram->disk->first_minor); | 1315 | idr_remove(&zram_index_idr, zram->disk->first_minor); |
1288 | blk_cleanup_queue(zram->disk->queue); | 1316 | blk_cleanup_queue(zram->disk->queue); |
1289 | del_gendisk(zram->disk); | 1317 | del_gendisk(zram->disk); |
1290 | put_disk(zram->disk); | 1318 | put_disk(zram->disk); |
1291 | kfree(zram); | 1319 | kfree(zram); |
1320 | return 0; | ||
1321 | } | ||
1322 | |||
1323 | /* zram-control sysfs attributes */ | ||
1324 | static ssize_t hot_add_show(struct class *class, | ||
1325 | struct class_attribute *attr, | ||
1326 | char *buf) | ||
1327 | { | ||
1328 | int ret; | ||
1329 | |||
1330 | mutex_lock(&zram_index_mutex); | ||
1331 | ret = zram_add(); | ||
1332 | mutex_unlock(&zram_index_mutex); | ||
1333 | |||
1334 | if (ret < 0) | ||
1335 | return ret; | ||
1336 | return scnprintf(buf, PAGE_SIZE, "%d\n", ret); | ||
1337 | } | ||
1338 | |||
1339 | static ssize_t hot_remove_store(struct class *class, | ||
1340 | struct class_attribute *attr, | ||
1341 | const char *buf, | ||
1342 | size_t count) | ||
1343 | { | ||
1344 | struct zram *zram; | ||
1345 | int ret, dev_id; | ||
1346 | |||
1347 | /* dev_id is gendisk->first_minor, which is `int' */ | ||
1348 | ret = kstrtoint(buf, 10, &dev_id); | ||
1349 | if (ret) | ||
1350 | return ret; | ||
1351 | if (dev_id < 0) | ||
1352 | return -EINVAL; | ||
1353 | |||
1354 | mutex_lock(&zram_index_mutex); | ||
1355 | |||
1356 | zram = idr_find(&zram_index_idr, dev_id); | ||
1357 | if (zram) | ||
1358 | ret = zram_remove(zram); | ||
1359 | else | ||
1360 | ret = -ENODEV; | ||
1361 | |||
1362 | mutex_unlock(&zram_index_mutex); | ||
1363 | return ret ? ret : count; | ||
1292 | } | 1364 | } |
1293 | 1365 | ||
1366 | static struct class_attribute zram_control_class_attrs[] = { | ||
1367 | __ATTR_RO(hot_add), | ||
1368 | __ATTR_WO(hot_remove), | ||
1369 | __ATTR_NULL, | ||
1370 | }; | ||
1371 | |||
1372 | static struct class zram_control_class = { | ||
1373 | .name = "zram-control", | ||
1374 | .owner = THIS_MODULE, | ||
1375 | .class_attrs = zram_control_class_attrs, | ||
1376 | }; | ||
1377 | |||
1294 | static int zram_remove_cb(int id, void *ptr, void *data) | 1378 | static int zram_remove_cb(int id, void *ptr, void *data) |
1295 | { | 1379 | { |
1296 | zram_remove(ptr); | 1380 | zram_remove(ptr); |
@@ -1299,6 +1383,7 @@ static int zram_remove_cb(int id, void *ptr, void *data) | |||
1299 | 1383 | ||
1300 | static void destroy_devices(void) | 1384 | static void destroy_devices(void) |
1301 | { | 1385 | { |
1386 | class_unregister(&zram_control_class); | ||
1302 | idr_for_each(&zram_index_idr, &zram_remove_cb, NULL); | 1387 | idr_for_each(&zram_index_idr, &zram_remove_cb, NULL); |
1303 | idr_destroy(&zram_index_idr); | 1388 | idr_destroy(&zram_index_idr); |
1304 | unregister_blkdev(zram_major, "zram"); | 1389 | unregister_blkdev(zram_major, "zram"); |
@@ -1308,14 +1393,23 @@ static int __init zram_init(void) | |||
1308 | { | 1393 | { |
1309 | int ret; | 1394 | int ret; |
1310 | 1395 | ||
1396 | ret = class_register(&zram_control_class); | ||
1397 | if (ret) { | ||
1398 | pr_warn("Unable to register zram-control class\n"); | ||
1399 | return ret; | ||
1400 | } | ||
1401 | |||
1311 | zram_major = register_blkdev(0, "zram"); | 1402 | zram_major = register_blkdev(0, "zram"); |
1312 | if (zram_major <= 0) { | 1403 | if (zram_major <= 0) { |
1313 | pr_warn("Unable to get major number\n"); | 1404 | pr_warn("Unable to get major number\n"); |
1405 | class_unregister(&zram_control_class); | ||
1314 | return -EBUSY; | 1406 | return -EBUSY; |
1315 | } | 1407 | } |
1316 | 1408 | ||
1317 | while (num_devices != 0) { | 1409 | while (num_devices != 0) { |
1410 | mutex_lock(&zram_index_mutex); | ||
1318 | ret = zram_add(); | 1411 | ret = zram_add(); |
1412 | mutex_unlock(&zram_index_mutex); | ||
1319 | if (ret < 0) | 1413 | if (ret < 0) |
1320 | goto out_error; | 1414 | goto out_error; |
1321 | num_devices--; | 1415 | num_devices--; |