loop: properly declare rotational flag of underlying device

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The loop driver has always declared the rotational flag of its device as
rotational, even when the device of the mapped file is nonrotational,
as is the case with SSDs or on tmpfs. This can confuse filesystem tools
which are SSD-aware; in my case I frequently forget to tell mkfs.btrfs
that my loop device on tmpfs is nonrotational, and that I really don't
need any automatic metadata redundancy.

The attached patch fixes this by introspecting the rotational flag of the
mapped file's underlying block device, if it exists. If the mapped file's
filesystem has no associated block device - as is the case on e.g. tmpfs -
we assume nonrotational storage. If there is a better way to identify such
non-devices I'd love to hear them.

On previous submission (~2 years ago I think) Jens commented that this
"changes the default". Tat's precisely the point: the default of declaring
rotational behaviour unconditionally is more likely to be wrong than
the other way around. To the best of my knowledge there are no byte-
addressable but physically rotating media without associated block device.
<insert STT-RAM joke here>

This is fresh against 4.16-rc4 and has been in production since 4.9,
with some minor changes to accommodate initialization order in 4.14.

Please consider for 4.17.

Signed-off-by: Holger Hoffstätte <holger@xxxxxxxxxxxxxxxxxxxxxx>

cheers,
Holger

diff -rup linux-4.16-rc4/drivers/block/loop.c linux-4.16-rc4-loop/drivers/block/loop.c
--- linux-4.16-rc4/drivers/block/loop.c	2018-03-04 23:54:11.000000000 +0100
+++ linux-4.16-rc4-loop/drivers/block/loop.c	2018-03-05 00:41:48.013602156 +0100
@@ -829,6 +829,24 @@ static void loop_config_discard(struct l
 	queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
 }
 
+static void loop_update_rotational(struct loop_device *lo)
+{
+	struct file *file = lo->lo_backing_file;
+	struct inode *file_inode = file->f_mapping->host;
+	struct block_device *file_bdev = file_inode->i_sb->s_bdev;
+	struct request_queue *q = lo->lo_queue;
+	bool nonrot = true;
+
+	/* not all filesystems (e.g. tmpfs) have a sb->s_bdev */
+	if (file_bdev)
+		nonrot = blk_queue_nonrot(bdev_get_queue(file_bdev));
+
+	if (nonrot)
+		queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q);
+	else
+		queue_flag_clear_unlocked(QUEUE_FLAG_NONROT, q);
+}
+
 static void loop_unprepare_queue(struct loop_device *lo)
 {
 	kthread_flush_worker(&lo->worker);
@@ -929,6 +947,7 @@ static int loop_set_fd(struct loop_devic
 	loop_update_dio(lo);
 	set_capacity(lo->lo_disk, size);
 	bd_set_size(bdev, size << 9);
+	loop_update_rotational(lo);
 	loop_sysfs_init(lo);
 	/* let user-space know about the new size */
 	kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE);



[Index of Archives]     [Linux RAID]     [Linux SCSI]     [Linux ATA RAID]     [IDE]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Device Mapper]

  Powered by Linux