diff options
Diffstat (limited to 'drivers/block/loop.c')
| -rw-r--r-- | drivers/block/loop.c | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/drivers/block/loop.c b/drivers/block/loop.c index a10c8c9b6b78..de3083b0a4f5 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 | ||
| @@ -738,6 +739,103 @@ static inline int is_loop_device(struct file *file) | |||
| 738 | return i && S_ISBLK(i->i_mode) && MAJOR(i->i_rdev) == LOOP_MAJOR; | 739 | return i && S_ISBLK(i->i_mode) && MAJOR(i->i_rdev) == LOOP_MAJOR; |
| 739 | } | 740 | } |
| 740 | 741 | ||
| 742 | /* loop sysfs attributes */ | ||
| 743 | |||
| 744 | static ssize_t loop_attr_show(struct device *dev, char *page, | ||
| 745 | ssize_t (*callback)(struct loop_device *, char *)) | ||
| 746 | { | ||
| 747 | struct loop_device *l, *lo = NULL; | ||
| 748 | |||
| 749 | mutex_lock(&loop_devices_mutex); | ||
| 750 | list_for_each_entry(l, &loop_devices, lo_list) | ||
| 751 | if (disk_to_dev(l->lo_disk) == dev) { | ||
| 752 | lo = l; | ||
| 753 | break; | ||
| 754 | } | ||
| 755 | mutex_unlock(&loop_devices_mutex); | ||
| 756 | |||
| 757 | return lo ? callback(lo, page) : -EIO; | ||
| 758 | } | ||
| 759 | |||
| 760 | #define LOOP_ATTR_RO(_name) \ | ||
| 761 | static ssize_t loop_attr_##_name##_show(struct loop_device *, char *); \ | ||
| 762 | static ssize_t loop_attr_do_show_##_name(struct device *d, \ | ||
| 763 | struct device_attribute *attr, char *b) \ | ||
| 764 | { \ | ||
| 765 | return loop_attr_show(d, b, loop_attr_##_name##_show); \ | ||
| 766 | } \ | ||
| 767 | static struct device_attribute loop_attr_##_name = \ | ||
| 768 | __ATTR(_name, S_IRUGO, loop_attr_do_show_##_name, NULL); | ||
| 769 | |||
| 770 | static ssize_t loop_attr_backing_file_show(struct loop_device *lo, char *buf) | ||
| 771 | { | ||
| 772 | ssize_t ret; | ||
| 773 | char *p = NULL; | ||
| 774 | |||
| 775 | mutex_lock(&lo->lo_ctl_mutex); | ||
| 776 | if (lo->lo_backing_file) | ||
| 777 | p = d_path(&lo->lo_backing_file->f_path, buf, PAGE_SIZE - 1); | ||
| 778 | mutex_unlock(&lo->lo_ctl_mutex); | ||
| 779 | |||
| 780 | if (IS_ERR_OR_NULL(p)) | ||
| 781 | ret = PTR_ERR(p); | ||
| 782 | else { | ||
| 783 | ret = strlen(p); | ||
| 784 | memmove(buf, p, ret); | ||
| 785 | buf[ret++] = '\n'; | ||
| 786 | buf[ret] = 0; | ||
| 787 | } | ||
| 788 | |||
| 789 | return ret; | ||
| 790 | } | ||
| 791 | |||
| 792 | static ssize_t loop_attr_offset_show(struct loop_device *lo, char *buf) | ||
| 793 | { | ||
| 794 | return sprintf(buf, "%llu\n", (unsigned long long)lo->lo_offset); | ||
| 795 | } | ||
| 796 | |||
| 797 | static ssize_t loop_attr_sizelimit_show(struct loop_device *lo, char *buf) | ||
| 798 | { | ||
| 799 | return sprintf(buf, "%llu\n", (unsigned long long)lo->lo_sizelimit); | ||
| 800 | } | ||
| 801 | |||
| 802 | static ssize_t loop_attr_autoclear_show(struct loop_device *lo, char *buf) | ||
| 803 | { | ||
| 804 | int autoclear = (lo->lo_flags & LO_FLAGS_AUTOCLEAR); | ||
| 805 | |||
| 806 | return sprintf(buf, "%s\n", autoclear ? "1" : "0"); | ||
| 807 | } | ||
| 808 | |||
| 809 | LOOP_ATTR_RO(backing_file); | ||
| 810 | LOOP_ATTR_RO(offset); | ||
| 811 | LOOP_ATTR_RO(sizelimit); | ||
| 812 | LOOP_ATTR_RO(autoclear); | ||
| 813 | |||
| 814 | static struct attribute *loop_attrs[] = { | ||
| 815 | &loop_attr_backing_file.attr, | ||
| 816 | &loop_attr_offset.attr, | ||
| 817 | &loop_attr_sizelimit.attr, | ||
| 818 | &loop_attr_autoclear.attr, | ||
| 819 | NULL, | ||
| 820 | }; | ||
| 821 | |||
| 822 | static struct attribute_group loop_attribute_group = { | ||
| 823 | .name = "loop", | ||
| 824 | .attrs= loop_attrs, | ||
| 825 | }; | ||
| 826 | |||
| 827 | static int loop_sysfs_init(struct loop_device *lo) | ||
| 828 | { | ||
| 829 | return sysfs_create_group(&disk_to_dev(lo->lo_disk)->kobj, | ||
| 830 | &loop_attribute_group); | ||
| 831 | } | ||
| 832 | |||
| 833 | static void loop_sysfs_exit(struct loop_device *lo) | ||
| 834 | { | ||
| 835 | sysfs_remove_group(&disk_to_dev(lo->lo_disk)->kobj, | ||
| 836 | &loop_attribute_group); | ||
| 837 | } | ||
| 838 | |||
| 741 | static int loop_set_fd(struct loop_device *lo, fmode_t mode, | 839 | static int loop_set_fd(struct loop_device *lo, fmode_t mode, |
| 742 | struct block_device *bdev, unsigned int arg) | 840 | struct block_device *bdev, unsigned int arg) |
| 743 | { | 841 | { |
| @@ -837,6 +935,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, | |||
| 837 | 935 | ||
| 838 | set_capacity(lo->lo_disk, size); | 936 | set_capacity(lo->lo_disk, size); |
| 839 | bd_set_size(bdev, size << 9); | 937 | bd_set_size(bdev, size << 9); |
| 938 | loop_sysfs_init(lo); | ||
| 840 | /* let user-space know about the new size */ | 939 | /* let user-space know about the new size */ |
| 841 | kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE); | 940 | kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE); |
| 842 | 941 | ||
| @@ -855,6 +954,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, | |||
| 855 | return 0; | 954 | return 0; |
| 856 | 955 | ||
| 857 | out_clr: | 956 | out_clr: |
| 957 | loop_sysfs_exit(lo); | ||
| 858 | lo->lo_thread = NULL; | 958 | lo->lo_thread = NULL; |
| 859 | lo->lo_device = NULL; | 959 | lo->lo_device = NULL; |
| 860 | lo->lo_backing_file = NULL; | 960 | lo->lo_backing_file = NULL; |
| @@ -951,6 +1051,7 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) | |||
| 951 | set_capacity(lo->lo_disk, 0); | 1051 | set_capacity(lo->lo_disk, 0); |
| 952 | if (bdev) { | 1052 | if (bdev) { |
| 953 | bd_set_size(bdev, 0); | 1053 | bd_set_size(bdev, 0); |
| 1054 | loop_sysfs_exit(lo); | ||
| 954 | /* let user-space know about this change */ | 1055 | /* let user-space know about this change */ |
| 955 | kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE); | 1056 | kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE); |
| 956 | } | 1057 | } |
