diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-block | 13 | ||||
-rw-r--r-- | block/genhd.c | 71 | ||||
-rw-r--r-- | include/linux/genhd.h | 4 |
3 files changed, 88 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-block b/Documentation/ABI/testing/sysfs-block index c1eb41cb9876..2b5d56127fce 100644 --- a/Documentation/ABI/testing/sysfs-block +++ b/Documentation/ABI/testing/sysfs-block | |||
@@ -206,3 +206,16 @@ Description: | |||
206 | when a discarded area is read the discard_zeroes_data | 206 | when a discarded area is read the discard_zeroes_data |
207 | parameter will be set to one. Otherwise it will be 0 and | 207 | parameter will be set to one. Otherwise it will be 0 and |
208 | the result of reading a discarded area is undefined. | 208 | the result of reading a discarded area is undefined. |
209 | What: /sys/block/<disk>/alias | ||
210 | Date: Aug 2011 | ||
211 | Contact: Nao Nishijima <nao.nishijima.xt@hitachi.com> | ||
212 | Description: | ||
213 | A raw device name of a disk does not always point a same disk | ||
214 | each boot-up time. Therefore, users have to use persistent | ||
215 | device names, which udev creates when the kernel finds a disk, | ||
216 | instead of raw device name. However, kernel doesn't show those | ||
217 | persistent names on its messages (e.g. dmesg). | ||
218 | This file can store an alias of the disk and it would be | ||
219 | appeared in kernel messages if it is set. A disk can have an | ||
220 | alias which length is up to 255bytes. Users can use alphabets, | ||
221 | numbers, "-" and "_" in alias name. This file is writeonce. | ||
diff --git a/block/genhd.c b/block/genhd.c index e2f67902dd02..94855a9717de 100644 --- a/block/genhd.c +++ b/block/genhd.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/mutex.h> | 19 | #include <linux/mutex.h> |
20 | #include <linux/idr.h> | 20 | #include <linux/idr.h> |
21 | #include <linux/log2.h> | 21 | #include <linux/log2.h> |
22 | #include <linux/ctype.h> | ||
22 | 23 | ||
23 | #include "blk.h" | 24 | #include "blk.h" |
24 | 25 | ||
@@ -909,6 +910,74 @@ static int __init genhd_device_init(void) | |||
909 | 910 | ||
910 | subsys_initcall(genhd_device_init); | 911 | subsys_initcall(genhd_device_init); |
911 | 912 | ||
913 | static ssize_t alias_show(struct device *dev, | ||
914 | struct device_attribute *attr, char *buf) | ||
915 | { | ||
916 | struct gendisk *disk = dev_to_disk(dev); | ||
917 | ssize_t ret = 0; | ||
918 | |||
919 | if (disk->alias) | ||
920 | ret = snprintf(buf, ALIAS_LEN, "%s\n", disk->alias); | ||
921 | return ret; | ||
922 | } | ||
923 | |||
924 | static ssize_t alias_store(struct device *dev, struct device_attribute *attr, | ||
925 | const char *buf, size_t count) | ||
926 | { | ||
927 | struct gendisk *disk = dev_to_disk(dev); | ||
928 | char *alias; | ||
929 | char *envp[] = { NULL, NULL }; | ||
930 | unsigned char c; | ||
931 | int i; | ||
932 | ssize_t ret = count; | ||
933 | |||
934 | if (!count) | ||
935 | return -EINVAL; | ||
936 | |||
937 | if (count >= ALIAS_LEN) { | ||
938 | printk(KERN_ERR "alias: alias is too long\n"); | ||
939 | return -EINVAL; | ||
940 | } | ||
941 | |||
942 | /* Validation check */ | ||
943 | for (i = 0; i < count; i++) { | ||
944 | c = buf[i]; | ||
945 | if (i == count - 1 && c == '\n') | ||
946 | break; | ||
947 | if (!isalnum(c) && c != '_' && c != '-') { | ||
948 | printk(KERN_ERR "alias: invalid alias\n"); | ||
949 | return -EINVAL; | ||
950 | } | ||
951 | } | ||
952 | |||
953 | if (disk->alias) { | ||
954 | printk(KERN_INFO "alias: %s is already assigned (%s)\n", | ||
955 | disk->disk_name, disk->alias); | ||
956 | return -EINVAL; | ||
957 | } | ||
958 | |||
959 | alias = kasprintf(GFP_KERNEL, "%s", buf); | ||
960 | if (!alias) | ||
961 | return -ENOMEM; | ||
962 | |||
963 | if (alias[count - 1] == '\n') | ||
964 | alias[count - 1] = '\0'; | ||
965 | |||
966 | envp[0] = kasprintf(GFP_KERNEL, "ALIAS=%s", alias); | ||
967 | if (!envp[0]) { | ||
968 | kfree(alias); | ||
969 | return -ENOMEM; | ||
970 | } | ||
971 | |||
972 | disk->alias = alias; | ||
973 | printk(KERN_INFO "alias: assigned %s to %s\n", alias, disk->disk_name); | ||
974 | |||
975 | kobject_uevent_env(&dev->kobj, KOBJ_ADD, envp); | ||
976 | |||
977 | kfree(envp[0]); | ||
978 | return ret; | ||
979 | } | ||
980 | |||
912 | static ssize_t disk_range_show(struct device *dev, | 981 | static ssize_t disk_range_show(struct device *dev, |
913 | struct device_attribute *attr, char *buf) | 982 | struct device_attribute *attr, char *buf) |
914 | { | 983 | { |
@@ -968,6 +1037,7 @@ static ssize_t disk_discard_alignment_show(struct device *dev, | |||
968 | return sprintf(buf, "%d\n", queue_discard_alignment(disk->queue)); | 1037 | return sprintf(buf, "%d\n", queue_discard_alignment(disk->queue)); |
969 | } | 1038 | } |
970 | 1039 | ||
1040 | static DEVICE_ATTR(alias, S_IRUGO|S_IWUSR, alias_show, alias_store); | ||
971 | static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); | 1041 | static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); |
972 | static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL); | 1042 | static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL); |
973 | static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL); | 1043 | static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL); |
@@ -990,6 +1060,7 @@ static struct device_attribute dev_attr_fail_timeout = | |||
990 | #endif | 1060 | #endif |
991 | 1061 | ||
992 | static struct attribute *disk_attrs[] = { | 1062 | static struct attribute *disk_attrs[] = { |
1063 | &dev_attr_alias.attr, | ||
993 | &dev_attr_range.attr, | 1064 | &dev_attr_range.attr, |
994 | &dev_attr_ext_range.attr, | 1065 | &dev_attr_ext_range.attr, |
995 | &dev_attr_removable.attr, | 1066 | &dev_attr_removable.attr, |
diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 02fa4697a0e5..6957350e122f 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h | |||
@@ -21,6 +21,8 @@ | |||
21 | #define dev_to_part(device) container_of((device), struct hd_struct, __dev) | 21 | #define dev_to_part(device) container_of((device), struct hd_struct, __dev) |
22 | #define disk_to_dev(disk) (&(disk)->part0.__dev) | 22 | #define disk_to_dev(disk) (&(disk)->part0.__dev) |
23 | #define part_to_dev(part) (&((part)->__dev)) | 23 | #define part_to_dev(part) (&((part)->__dev)) |
24 | #define alias_name(disk) ((disk)->alias ? (disk)->alias : \ | ||
25 | (disk)->disk_name) | ||
24 | 26 | ||
25 | extern struct device_type part_type; | 27 | extern struct device_type part_type; |
26 | extern struct kobject *block_depr; | 28 | extern struct kobject *block_depr; |
@@ -58,6 +60,7 @@ enum { | |||
58 | 60 | ||
59 | #define DISK_MAX_PARTS 256 | 61 | #define DISK_MAX_PARTS 256 |
60 | #define DISK_NAME_LEN 32 | 62 | #define DISK_NAME_LEN 32 |
63 | #define ALIAS_LEN 256 | ||
61 | 64 | ||
62 | #include <linux/major.h> | 65 | #include <linux/major.h> |
63 | #include <linux/device.h> | 66 | #include <linux/device.h> |
@@ -162,6 +165,7 @@ struct gendisk { | |||
162 | * disks that can't be partitioned. */ | 165 | * disks that can't be partitioned. */ |
163 | 166 | ||
164 | char disk_name[DISK_NAME_LEN]; /* name of major driver */ | 167 | char disk_name[DISK_NAME_LEN]; /* name of major driver */ |
168 | char *alias; /* alias name of disk */ | ||
165 | char *(*devnode)(struct gendisk *gd, mode_t *mode); | 169 | char *(*devnode)(struct gendisk *gd, mode_t *mode); |
166 | 170 | ||
167 | unsigned int events; /* supported events */ | 171 | unsigned int events; /* supported events */ |