aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/loop.c
diff options
context:
space:
mode:
authorMilan Broz <mbroz@redhat.com>2010-08-23 09:16:00 -0400
committerJens Axboe <jaxboe@fusionio.com>2010-08-23 09:18:10 -0400
commitee86273062cbb310665fe49e1f1937d2cf85b0b9 (patch)
treecca87f85feafedb52bcc0687b6daa6b15895b199 /drivers/block/loop.c
parent9ee47476d6734c9deb9ae9ab05d963302f6b6150 (diff)
loop: add some basic read-only sysfs attributes
Create /sys/block/loopX/loop directory and provide these attributes: - backing_file - autoclear - offset - sizelimit This loop directory is present only if loop device is configured. To be used in util-linux-ng (and possibly elsewhere like udev rules) where code need to get loop attributes from kernel (and not store duplicate info in userspace). Moreover loop ioctls are not even able to provide full backing file info because of buffer limits. Signed-off-by: Milan Broz <mbroz@redhat.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
Diffstat (limited to 'drivers/block/loop.c')
-rw-r--r--drivers/block/loop.c101
1 files changed, 101 insertions, 0 deletions
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index f3c636d23718..dc552308668e 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -74,6 +74,7 @@
74#include <linux/highmem.h> 74#include <linux/highmem.h>
75#include <linux/kthread.h> 75#include <linux/kthread.h>
76#include <linux/splice.h> 76#include <linux/splice.h>
77#include <linux/sysfs.h>
77 78
78#include <asm/uaccess.h> 79#include <asm/uaccess.h>
79 80
@@ -737,6 +738,103 @@ static inline int is_loop_device(struct file *file)
737 return i && S_ISBLK(i->i_mode) && MAJOR(i->i_rdev) == LOOP_MAJOR; 738 return i && S_ISBLK(i->i_mode) && MAJOR(i->i_rdev) == LOOP_MAJOR;
738} 739}
739 740
741/* loop sysfs attributes */
742
743static ssize_t loop_attr_show(struct device *dev, char *page,
744 ssize_t (*callback)(struct loop_device *, char *))
745{
746 struct loop_device *l, *lo = NULL;
747
748 mutex_lock(&loop_devices_mutex);
749 list_for_each_entry(l, &loop_devices, lo_list)
750 if (disk_to_dev(l->lo_disk) == dev) {
751 lo = l;
752 break;
753 }
754 mutex_unlock(&loop_devices_mutex);
755
756 return lo ? callback(lo, page) : -EIO;
757}
758
759#define LOOP_ATTR_RO(_name) \
760static ssize_t loop_attr_##_name##_show(struct loop_device *, char *); \
761static ssize_t loop_attr_do_show_##_name(struct device *d, \
762 struct device_attribute *attr, char *b) \
763{ \
764 return loop_attr_show(d, b, loop_attr_##_name##_show); \
765} \
766static struct device_attribute loop_attr_##_name = \
767 __ATTR(_name, S_IRUGO, loop_attr_do_show_##_name, NULL);
768
769static ssize_t loop_attr_backing_file_show(struct loop_device *lo, char *buf)
770{
771 ssize_t ret;
772 char *p = NULL;
773
774 mutex_lock(&lo->lo_ctl_mutex);
775 if (lo->lo_backing_file)
776 p = d_path(&lo->lo_backing_file->f_path, buf, PAGE_SIZE - 1);
777 mutex_unlock(&lo->lo_ctl_mutex);
778
779 if (IS_ERR_OR_NULL(p))
780 ret = PTR_ERR(p);
781 else {
782 ret = strlen(p);
783 memmove(buf, p, ret);
784 buf[ret++] = '\n';
785 buf[ret] = 0;
786 }
787
788 return ret;
789}
790
791static ssize_t loop_attr_offset_show(struct loop_device *lo, char *buf)
792{
793 return sprintf(buf, "%llu\n", (unsigned long long)lo->lo_offset);
794}
795
796static ssize_t loop_attr_sizelimit_show(struct loop_device *lo, char *buf)
797{
798 return sprintf(buf, "%llu\n", (unsigned long long)lo->lo_sizelimit);
799}
800
801static ssize_t loop_attr_autoclear_show(struct loop_device *lo, char *buf)
802{
803 int autoclear = (lo->lo_flags & LO_FLAGS_AUTOCLEAR);
804
805 return sprintf(buf, "%s\n", autoclear ? "1" : "0");
806}
807
808LOOP_ATTR_RO(backing_file);
809LOOP_ATTR_RO(offset);
810LOOP_ATTR_RO(sizelimit);
811LOOP_ATTR_RO(autoclear);
812
813static struct attribute *loop_attrs[] = {
814 &loop_attr_backing_file.attr,
815 &loop_attr_offset.attr,
816 &loop_attr_sizelimit.attr,
817 &loop_attr_autoclear.attr,
818 NULL,
819};
820
821static struct attribute_group loop_attribute_group = {
822 .name = "loop",
823 .attrs= loop_attrs,
824};
825
826static int loop_sysfs_init(struct loop_device *lo)
827{
828 return sysfs_create_group(&disk_to_dev(lo->lo_disk)->kobj,
829 &loop_attribute_group);
830}
831
832static void loop_sysfs_exit(struct loop_device *lo)
833{
834 sysfs_remove_group(&disk_to_dev(lo->lo_disk)->kobj,
835 &loop_attribute_group);
836}
837
740static int loop_set_fd(struct loop_device *lo, fmode_t mode, 838static int loop_set_fd(struct loop_device *lo, fmode_t mode,
741 struct block_device *bdev, unsigned int arg) 839 struct block_device *bdev, unsigned int arg)
742{ 840{
@@ -836,6 +934,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
836 934
837 set_capacity(lo->lo_disk, size); 935 set_capacity(lo->lo_disk, size);
838 bd_set_size(bdev, size << 9); 936 bd_set_size(bdev, size << 9);
937 loop_sysfs_init(lo);
839 /* let user-space know about the new size */ 938 /* let user-space know about the new size */
840 kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE); 939 kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE);
841 940
@@ -854,6 +953,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
854 return 0; 953 return 0;
855 954
856out_clr: 955out_clr:
956 loop_sysfs_exit(lo);
857 lo->lo_thread = NULL; 957 lo->lo_thread = NULL;
858 lo->lo_device = NULL; 958 lo->lo_device = NULL;
859 lo->lo_backing_file = NULL; 959 lo->lo_backing_file = NULL;
@@ -950,6 +1050,7 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
950 set_capacity(lo->lo_disk, 0); 1050 set_capacity(lo->lo_disk, 0);
951 if (bdev) { 1051 if (bdev) {
952 bd_set_size(bdev, 0); 1052 bd_set_size(bdev, 0);
1053 loop_sysfs_exit(lo);
953 /* let user-space know about this change */ 1054 /* let user-space know about this change */
954 kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE); 1055 kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE);
955 } 1056 }