diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 024402438bd1..ab064c84b092 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -1553,68 +1553,70 @@ static void zram_debugfs_destroy(void) debugfs_remove_recursive(zram_debugfs_root); } -static ssize_t read_block_state(struct file *file, char __user *buf, - size_t count, loff_t *ppos) +static void *zram_block_state_start(struct seq_file *seq, loff_t *pos) { - char *kbuf; - unsigned long index; - ssize_t written = 0; - struct zram *zram = file->private_data; + struct zram *zram = seq->private; unsigned long nr_pages; - kbuf = kvmalloc(count, GFP_KERNEL); - if (!kbuf) - return -ENOMEM; - - guard(rwsem_read)(&zram->dev_lock); - if (!init_done(zram)) { - kvfree(kbuf); - return -EINVAL; - } + down_read(&zram->dev_lock); + if (!init_done(zram)) + return ERR_PTR(-EINVAL); nr_pages = zram->disksize >> PAGE_SHIFT; + if (*pos >= nr_pages) + return NULL; - for (index = *ppos; index < nr_pages; index++) { - int copied; - - slot_lock(zram, index); - if (!slot_allocated(zram, index)) - goto next; - - copied = snprintf(kbuf + written, count, - "%12lu %12u.%06d %c%c%c%c%c%c\n", - index, zram->table[index].attr.ac_time, 0, - test_slot_flag(zram, index, ZRAM_SAME) ? 's' : '.', - test_slot_flag(zram, index, ZRAM_WB) ? 'w' : '.', - test_slot_flag(zram, index, ZRAM_HUGE) ? 'h' : '.', - test_slot_flag(zram, index, ZRAM_IDLE) ? 'i' : '.', - get_slot_comp_priority(zram, index) ? 'r' : '.', - test_slot_flag(zram, index, - ZRAM_INCOMPRESSIBLE) ? 'n' : '.'); - - if (count <= copied) { - slot_unlock(zram, index); - break; - } - written += copied; - count -= copied; -next: - slot_unlock(zram, index); - *ppos += 1; - } - - if (copy_to_user(buf, kbuf, written)) - written = -EFAULT; - kvfree(kbuf); - - return written; + return pos; } -static const struct file_operations proc_zram_block_state_op = { - .open = simple_open, - .read = read_block_state, - .llseek = default_llseek, +static void *zram_block_state_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct zram *zram = seq->private; + unsigned long nr_pages = zram->disksize >> PAGE_SHIFT; + + ++*pos; + if (*pos >= nr_pages) + return NULL; + + return pos; +} + +static void zram_block_state_stop(struct seq_file *seq, void *v) +{ + struct zram *zram = seq->private; + + up_read(&zram->dev_lock); +} + +static int zram_block_state_show(struct seq_file *seq, void *v) +{ + struct zram *zram = seq->private; + unsigned long index = *(loff_t *)v; + + slot_lock(zram, index); + if (slot_allocated(zram, index)) { + seq_printf(seq, "%12lu %12u.%06d %c%c%c%c%c%c\n", + index, zram->table[index].attr.ac_time, 0, + test_slot_flag(zram, index, ZRAM_SAME) ? 's' : '.', + test_slot_flag(zram, index, ZRAM_WB) ? 'w' : '.', + test_slot_flag(zram, index, ZRAM_HUGE) ? 'h' : '.', + test_slot_flag(zram, index, ZRAM_IDLE) ? 'i' : '.', + get_slot_comp_priority(zram, index) ? 'r' : '.', + test_slot_flag(zram, index, + ZRAM_INCOMPRESSIBLE) ? 'n' : '.'); + } + slot_unlock(zram, index); + + return 0; +} + +static const struct seq_operations zram_block_state_sops = { + .start = zram_block_state_start, + .next = zram_block_state_next, + .stop = zram_block_state_stop, + .show = zram_block_state_show, }; +DEFINE_SEQ_ATTRIBUTE(zram_block_state); static void zram_debugfs_register(struct zram *zram) { @@ -1624,7 +1626,7 @@ static void zram_debugfs_register(struct zram *zram) zram->debugfs_dir = debugfs_create_dir(zram->disk->disk_name, zram_debugfs_root); debugfs_create_file("block_state", 0400, zram->debugfs_dir, - zram, &proc_zram_block_state_op); + zram, &zram_block_state_fops); } static void zram_debugfs_unregister(struct zram *zram)