Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Sergey Senozhatsky and committed by
Linus Torvalds
6566d1a3 f405c445

+141 -6
+24
Documentation/ABI/testing/sysfs-class-zram
··· 1 + What: /sys/class/zram-control/ 2 + Date: August 2015 3 + KernelVersion: 4.2 4 + Contact: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> 5 + Description: 6 + The zram-control/ class sub-directory belongs to zram 7 + device class 8 + 9 + What: /sys/class/zram-control/hot_add 10 + Date: August 2015 11 + KernelVersion: 4.2 12 + Contact: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> 13 + Description: 14 + RO attribute. Read operation will cause zram to add a new 15 + device and return its device id back to user (so one can 16 + use /dev/zram<id>), or error code. 17 + 18 + What: /sys/class/zram-control/hot_remove 19 + Date: August 2015 20 + KernelVersion: 4.2 21 + Contact: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> 22 + Description: 23 + WO attribute. Remove a specific /dev/zramX device, where X 24 + is a device_id provided by user.
+20 -3
Documentation/blockdev/zram.txt
··· 99 99 mkfs.ext4 /dev/zram1 100 100 mount /dev/zram1 /tmp 101 101 102 - 7) Stats: 102 + 7) Add/remove zram devices 103 + 104 + zram provides a control interface, which enables dynamic (on-demand) device 105 + addition and removal. 106 + 107 + In order to add a new /dev/zramX device, perform read operation on hot_add 108 + attribute. This will return either new device's device id (meaning that you 109 + can use /dev/zram<id>) or error code. 110 + 111 + Example: 112 + cat /sys/class/zram-control/hot_add 113 + 1 114 + 115 + To remove the existing /dev/zramX device (where X is a device id) 116 + execute 117 + echo X > /sys/class/zram-control/hot_remove 118 + 119 + 8) Stats: 103 120 Per-device statistics are exported as various nodes under /sys/block/zram<id>/ 104 121 105 122 A brief description of exported device attritbutes. For more details please ··· 191 174 zero_pages 192 175 num_migrated 193 176 194 - 8) Deactivate: 177 + 9) Deactivate: 195 178 swapoff /dev/zram0 196 179 umount /dev/zram1 197 180 198 - 9) Reset: 181 + 10) Reset: 199 182 Write any positive value to 'reset' sysfs node 200 183 echo 1 > /sys/block/zram0/reset 201 184 echo 1 > /sys/block/zram1/reset
+97 -3
drivers/block/zram/zram_drv.c
··· 29 29 #include <linux/vmalloc.h> 30 30 #include <linux/err.h> 31 31 #include <linux/idr.h> 32 + #include <linux/sysfs.h> 32 33 33 34 #include "zram_drv.h" 34 35 35 36 static DEFINE_IDR(zram_index_idr); 37 + /* idr index must be protected */ 38 + static DEFINE_MUTEX(zram_index_mutex); 39 + 36 40 static int zram_major; 37 41 static const char *default_compressor = "lzo"; 38 42 ··· 1277 1273 return ret; 1278 1274 } 1279 1275 1280 - static void zram_remove(struct zram *zram) 1276 + static int zram_remove(struct zram *zram) 1281 1277 { 1282 - pr_info("Removed device: %s\n", zram->disk->disk_name); 1278 + struct block_device *bdev; 1279 + 1280 + bdev = bdget_disk(zram->disk, 0); 1281 + if (!bdev) 1282 + return -ENOMEM; 1283 + 1284 + mutex_lock(&bdev->bd_mutex); 1285 + if (bdev->bd_openers || zram->claim) { 1286 + mutex_unlock(&bdev->bd_mutex); 1287 + bdput(bdev); 1288 + return -EBUSY; 1289 + } 1290 + 1291 + zram->claim = true; 1292 + mutex_unlock(&bdev->bd_mutex); 1293 + 1283 1294 /* 1284 1295 * Remove sysfs first, so no one will perform a disksize 1285 - * store while we destroy the devices 1296 + * store while we destroy the devices. This also helps during 1297 + * hot_remove -- zram_reset_device() is the last holder of 1298 + * ->init_lock, no later/concurrent disksize_store() or any 1299 + * other sysfs handlers are possible. 1286 1300 */ 1287 1301 sysfs_remove_group(&disk_to_dev(zram->disk)->kobj, 1288 1302 &zram_disk_attr_group); 1289 1303 1304 + /* Make sure all the pending I/O are finished */ 1305 + fsync_bdev(bdev); 1290 1306 zram_reset_device(zram); 1307 + bdput(bdev); 1308 + 1309 + pr_info("Removed device: %s\n", zram->disk->disk_name); 1310 + 1291 1311 idr_remove(&zram_index_idr, zram->disk->first_minor); 1292 1312 blk_cleanup_queue(zram->disk->queue); 1293 1313 del_gendisk(zram->disk); 1294 1314 put_disk(zram->disk); 1295 1315 kfree(zram); 1316 + return 0; 1296 1317 } 1318 + 1319 + /* zram-control sysfs attributes */ 1320 + static ssize_t hot_add_show(struct class *class, 1321 + struct class_attribute *attr, 1322 + char *buf) 1323 + { 1324 + int ret; 1325 + 1326 + mutex_lock(&zram_index_mutex); 1327 + ret = zram_add(); 1328 + mutex_unlock(&zram_index_mutex); 1329 + 1330 + if (ret < 0) 1331 + return ret; 1332 + return scnprintf(buf, PAGE_SIZE, "%d\n", ret); 1333 + } 1334 + 1335 + static ssize_t hot_remove_store(struct class *class, 1336 + struct class_attribute *attr, 1337 + const char *buf, 1338 + size_t count) 1339 + { 1340 + struct zram *zram; 1341 + int ret, dev_id; 1342 + 1343 + /* dev_id is gendisk->first_minor, which is `int' */ 1344 + ret = kstrtoint(buf, 10, &dev_id); 1345 + if (ret) 1346 + return ret; 1347 + if (dev_id < 0) 1348 + return -EINVAL; 1349 + 1350 + mutex_lock(&zram_index_mutex); 1351 + 1352 + zram = idr_find(&zram_index_idr, dev_id); 1353 + if (zram) 1354 + ret = zram_remove(zram); 1355 + else 1356 + ret = -ENODEV; 1357 + 1358 + mutex_unlock(&zram_index_mutex); 1359 + return ret ? ret : count; 1360 + } 1361 + 1362 + static struct class_attribute zram_control_class_attrs[] = { 1363 + __ATTR_RO(hot_add), 1364 + __ATTR_WO(hot_remove), 1365 + __ATTR_NULL, 1366 + }; 1367 + 1368 + static struct class zram_control_class = { 1369 + .name = "zram-control", 1370 + .owner = THIS_MODULE, 1371 + .class_attrs = zram_control_class_attrs, 1372 + }; 1297 1373 1298 1374 static int zram_remove_cb(int id, void *ptr, void *data) 1299 1375 { ··· 1383 1299 1384 1300 static void destroy_devices(void) 1385 1301 { 1302 + class_unregister(&zram_control_class); 1386 1303 idr_for_each(&zram_index_idr, &zram_remove_cb, NULL); 1387 1304 idr_destroy(&zram_index_idr); 1388 1305 unregister_blkdev(zram_major, "zram"); ··· 1393 1308 { 1394 1309 int ret; 1395 1310 1311 + ret = class_register(&zram_control_class); 1312 + if (ret) { 1313 + pr_warn("Unable to register zram-control class\n"); 1314 + return ret; 1315 + } 1316 + 1396 1317 zram_major = register_blkdev(0, "zram"); 1397 1318 if (zram_major <= 0) { 1398 1319 pr_warn("Unable to get major number\n"); 1320 + class_unregister(&zram_control_class); 1399 1321 return -EBUSY; 1400 1322 } 1401 1323 1402 1324 while (num_devices != 0) { 1325 + mutex_lock(&zram_index_mutex); 1403 1326 ret = zram_add(); 1327 + mutex_unlock(&zram_index_mutex); 1404 1328 if (ret < 0) 1405 1329 goto out_error; 1406 1330 num_devices--;