devfs
[Top] [All Lists]

Patch: /dev/guid support

To: Linux-IA64 Mailing list <linux-ia64@xxxxxxxxxxxxx>, devfs mailing list <devfs@xxxxxxxxxxx>
Subject: Patch: /dev/guid support
From: Martin Wilck <Martin.Wilck@xxxxxxxxxxxxxxxxxxx>
Date: Wed, 30 May 2001 18:41:20 +0200 (CEST)
Sender: owner-devfs@xxxxxxxxxxx
Hello,

here is a small patch I suggest for Linux/IA64.

It makes the kernel aware of the GUIDs of hard disks and partitions and
thereby allows to e.g. mount volumes by GUID rather than
driver/bus/target/lun, so that volumes can be uniquely identified
even if the sequence of controllers or disks on a controller changes.

The patch relies heavily on devfs and the EFI/GPT code in the IA64 kernel.
It is against 2.4.4 with David's latest IA64 patch (08/05/2001).

GUIDs are only recognized on disks with an EFI GPT partition table.

The GUIDs appear as soft links in /dev/guid, like this:

$ ls -l /dev/guid
total 0
25fb7980-1dd2-1000-8b55-00d0b7c7f993 -> ../scsi/host0/bus0/target0/lun0/disc
lr-xr-xr-x    1 root     root           37 Jan  1  1970
272ca680-1dd2-1000-b7ef-00d0b7c7f993 -> ../scsi/host0/bus0/target0/lun0/part1
lr-xr-xr-x    1 root     root           37 Jan  1  1970
87821d20-f3fa-2444-96b9-7ad4423d337b -> ../scsi/host0/bus0/target0/lun0/part2
lr-xr-xr-x    1 root     root           36 Jan  1  1970
a1050a55-2b64-244a-924d-8f6b9ea01931 -> ../scsi/host1/bus0/target3/lun0/disc
lr-xr-xr-x    1 root     root           37 Jan  1  1970
e3f2fd2f-604c-614e-b135-d74f3b5f9277 -> ../scsi/host0/bus0/target0/lun0/part3
lr-xr-xr-x    1 root     root           37 Jan  1  1970
e853dbd1-6dc3-1f4d-8e23-09311b60dd9e -> ../scsi/host1/bus0/target3/lun0/part1

As you can see, there are links for the entire disks as well as the
partitions.

On my system, links are correctly deleted / replaced if a disk is
repartitioned.

Notes:
 - The most heavy change in kernel internals is the inclusion of
   a efi_guid_t* field in the hd_struct structure.

 - I have copied Matt's uuid_unparse() function to fs/partition/check.c.
   I assume it would have been better to export Matt's function and have
   it only once in the code, but I couldn't figure out in which subtree it
   would then best belong.

Any improvements/suggestions/fixes greatly appreciated.

Martin

-- 
Martin Wilck     <Martin.Wilck@xxxxxxxxxxxxxxxxxxx>
FSC EP PS DS1, Paderborn      Tel. +49 5251 8 15113



diff -ru -x *.o -x.* -x*.rej -x*~ linux-2.4.4-orig/Documentation/Configure.help 
linux-2.4.4mw/Documentation/Configure.help
--- linux-2.4.4-orig/Documentation/Configure.help       Wed May 30 20:27:55 2001
+++ linux-2.4.4mw/Documentation/Configure.help  Wed May 30 18:24:09 2001
@@ -11996,6 +11996,12 @@
   were partitioned using EFI GPT.  Presently only useful on the
   IA-64 platform.

+/dev/guid support (EXPERIMENTAL)
+CONFIG_DEVFS_GUID
+  Say Y here if you would like to access disks and partitions by
+  their Globally Unique Identifiers (GUIDs) which will appear as
+  symbolic links in /dev/guid.
+
 Ultrix partition support
 CONFIG_ULTRIX_PARTITION
   Say Y here if you would like to be able to read the hard disk
diff -ru -x *.o -x.* -x*.rej -x*~ linux-2.4.4-orig/fs/devfs/base.c 
linux-2.4.4mw/fs/devfs/base.c
--- linux-2.4.4-orig/fs/devfs/base.c    Wed May 30 20:27:55 2001
+++ linux-2.4.4mw/fs/devfs/base.c       Wed May 30 20:27:38 2001
@@ -1903,6 +1903,27 @@
     return master->slave;
 }   /*  End Function devfs_get_unregister_slave  */

+#ifdef CONFIG_DEVFS_GUID
+/**
+ *     devfs_unregister_slave - remove the slave that is unregistered when 
@master is unregistered.
+ *      Destroys the connection established by devfs_auto_unregister.
+ *
+ *     @master: The master devfs entry.
+ */
+
+void devfs_unregister_slave (devfs_handle_t master)
+{
+       devfs_handle_t slave;
+
+       if (master == NULL) return;
+
+       slave = master->slave;
+       if (slave) {
+               master->slave = NULL;
+               unregister (slave);
+       };
+}
+#endif /* CONFIG_DEVFS_GUID */

 /**
  *     devfs_get_name - Get the name for a device entry in its parent 
directory.
@@ -2103,6 +2124,9 @@
 EXPORT_SYMBOL(devfs_get_next_sibling);
 EXPORT_SYMBOL(devfs_auto_unregister);
 EXPORT_SYMBOL(devfs_get_unregister_slave);
+#ifdef CONFIG_DEVFS_GUID
+EXPORT_SYMBOL(devfs_unregister_slave);
+#endif
 EXPORT_SYMBOL(devfs_register_chrdev);
 EXPORT_SYMBOL(devfs_register_blkdev);
 EXPORT_SYMBOL(devfs_unregister_chrdev);
diff -ru -x *.o -x.* -x*.rej -x*~ linux-2.4.4-orig/fs/partitions/Config.in 
linux-2.4.4mw/fs/partitions/Config.in
--- linux-2.4.4-orig/fs/partitions/Config.in    Wed May 30 20:27:55 2001
+++ linux-2.4.4mw/fs/partitions/Config.in       Wed May 30 18:24:03 2001
@@ -25,6 +25,7 @@
       bool '    Solaris (x86) partition table support' 
CONFIG_SOLARIS_X86_PARTITION
       bool '    Unixware slices support' CONFIG_UNIXWARE_DISKLABEL
       bool '    EFI GUID Partition support' CONFIG_EFI_PARTITION
+      dep_bool '    /dev/guid support (EXPERIMENTAL)' CONFIG_DEVFS_GUID 
$CONFIG_DEVFS_FS $CONFIG_EFI_PARTITION
    fi
    bool '  SGI partition support' CONFIG_SGI_PARTITION
    bool '  Ultrix partition table support' CONFIG_ULTRIX_PARTITION
diff -ru -x *.o -x.* -x*.rej -x*~ linux-2.4.4-orig/fs/partitions/check.c 
linux-2.4.4mw/fs/partitions/check.c
--- linux-2.4.4-orig/fs/partitions/check.c      Wed May 30 20:27:55 2001
+++ linux-2.4.4mw/fs/partitions/check.c Wed May 30 19:29:55 2001
@@ -37,6 +37,18 @@
 # include "efi.h"
 #endif

+#ifdef CONFIG_DEVFS_GUID
+#define GUID_UNPARSED_LEN 36
+static void
+uuid_unparse_1(efi_guid_t *guid, char *out)
+{
+       sprintf(out, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+               guid->data1, guid->data2, guid->data3,
+               guid->data4[0], guid->data4[1], guid->data4[2], guid->data4[3],
+               guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]);
+}
+#endif
+
 extern void device_init(void);
 extern int *blk_size[];
 extern void rd_load(void);
@@ -82,6 +94,10 @@
        NULL
 };

+#ifdef CONFIG_DEVFS_GUID
+static devfs_handle_t guid_top_handle;
+#endif
+
 /*
  * disk_name() is used by partition check code and the md driver.
  * It formats the devicename of the indicated disk into
@@ -317,6 +333,101 @@
        devfs_register_partitions (hd, i, hd->sizes ? 0 : 1);
 }

+#ifdef CONFIG_DEVFS_GUID
+/*
+  devfs_register_guid: create a /dev/guid entry for a disk or partition
+                       if it has a GUID.
+
+  The /dev/guid entry will be a symlink to the "real" devfs device.
+  It is marked as "slave" of the real device,
+  to be automatically unregistered by devfs if that device is unregistered.
+
+  If the partition already had a /dev/guid entry, delete (unregister) it.
+  (If the disk was repartitioned, it's likely the old GUID entry will be 
wrong).
+
+  dev, minor:  Device for which an entry is to be created.
+
+  Prerequisites: dev->part[minor].guid must be either NULL or point
+                 to a valid kmalloc'ed GUID.
+*/
+
+static void devfs_register_guid (struct gendisk *dev, int minor)
+{
+       efi_guid_t *guid = dev->part[minor].guid;
+       devfs_handle_t guid_handle, slave,
+               real_master = dev->part[minor].de;
+       devfs_handle_t master = real_master;
+       char guid_link[GUID_UNPARSED_LEN + 1];
+       char dirname[128];
+       int pos, st;
+
+       if (!guid_top_handle)
+               guid_top_handle = devfs_mk_dir (NULL, "guid", NULL);
+
+       if (!guid || !master) return;
+
+       do {
+               slave = devfs_get_unregister_slave (master);
+               if (slave) {
+                       if (slave == master || slave == real_master) {
+                               printk (KERN_WARNING
+                                       "devfs_register_guid: infinite slave 
loop!\n");
+                               return;
+                       } else if (devfs_get_parent (slave) == guid_top_handle) 
{
+                               printk (KERN_INFO
+                                       "devfs_register_guid: unregistering 
%s\n",
+                                       devfs_get_name (slave, NULL));
+                               devfs_unregister_slave (master);
+                               slave = NULL;
+                       } else
+                               master = slave;
+               };
+       } while (slave);
+
+       uuid_unparse_1 (guid, guid_link);
+       pos = devfs_generate_path (real_master, dirname + 3,
+                                  sizeof (dirname) - 3);
+       if (pos < 0) {
+               printk (KERN_WARNING
+                       "devfs_register_guid: error generating path: %d\n",
+                       pos);
+               return;
+       };
+
+       strncpy (dirname + pos, "../", 3);
+
+       st = devfs_mk_symlink (guid_top_handle, guid_link,
+                              DEVFS_FL_DEFAULT,
+                              dirname + pos, &guid_handle, NULL);
+
+       if (st < 0) {
+               printk ("Error %d creating symlink\n", st);
+       } else {
+               devfs_auto_unregister (master, guid_handle);
+       };
+};
+
+/*
+  free_disk_guids: kfree all guid data structures alloced for
+  the disk device specified by (dev, minor) and all its partitions.
+
+  This function does not remove symlinks in /dev/guid.
+*/
+static void free_disk_guids (struct gendisk *dev, int minor)
+{
+       int i;
+       efi_guid_t *guid;
+
+       for (i = 0; i < dev->max_p; i++) {
+               guid = dev->part[minor + i].guid;
+               if (!guid) continue;
+               kfree (guid);
+               dev->part[minor + i].guid = NULL;
+       };
+}
+
+#endif /* CONFIG_DEVFS_GUID */
+
 #ifdef CONFIG_DEVFS_FS
 static void devfs_register_partition (struct gendisk *dev, int minor, int part)
 {
@@ -325,7 +436,11 @@
        unsigned int devfs_flags = DEVFS_FL_DEFAULT;
        char devname[16];

-       if (dev->part[minor + part].de) return;
+       /* Even if the devfs handle is still up-to-date,
+          the GUID entry probably isn't */
+       if (dev->part[minor + part].de)
+               goto do_guid;
+
        dir = devfs_get_parent (dev->part[minor].de);
        if (!dir) return;
        if ( dev->flags && (dev->flags[devnum] & GENHD_FL_REMOVABLE) )
@@ -336,6 +451,11 @@
                            dev->major, minor + part,
                            S_IFBLK | S_IRUSR | S_IWUSR,
                            dev->fops, NULL);
+ do_guid:
+#ifdef CONFIG_DEVFS_GUID
+       devfs_register_guid (dev, minor + part);
+#endif
+       return;
 }

 static void devfs_register_disc (struct gendisk *dev, int minor)
@@ -348,7 +468,9 @@
        static unsigned int disc_counter;
        static devfs_handle_t devfs_handle;

-       if (dev->part[minor].de) return;
+       if (dev->part[minor].de)
+               goto do_guid;
+
        if ( dev->flags && (dev->flags[devnum] & GENHD_FL_REMOVABLE) )
                devfs_flags |= DEVFS_FL_REMOVABLE;
        if (dev->de_arr) {
@@ -375,6 +497,12 @@
        devfs_auto_unregister (dev->part[minor].de, slave);
        if (!dev->de_arr)
                devfs_auto_unregister (slave, dir);
+
+ do_guid:
+#ifdef CONFIG_DEVFS_GUID
+       devfs_register_guid (dev, minor);
+#endif
+       return;
 }
 #endif  /*  CONFIG_DEVFS_FS  */

@@ -396,6 +524,7 @@
        if (unregister) {
                devfs_unregister (dev->part[minor].de);
                dev->part[minor].de = NULL;
+               free_disk_guids (dev, minor);
        }
 #endif  /*  CONFIG_DEVFS_FS  */
 }
@@ -413,8 +542,21 @@
 void register_disk(struct gendisk *gdev, kdev_t dev, unsigned minors,
        struct block_device_operations *ops, long size)
 {
+       int i;
+
        if (!gdev)
                return;
+
+#ifdef CONFIG_DEVFS_GUID
+       /* Initialize all guid fields to NULL (=^ not kmalloc'ed).
+          It is assumed that drivers call register_disk after
+          allocating the gen_hd structure, and call grok_partitions
+          directly for a revalidate event, as those drives I've inspected
+          (among which hd and sd) do. */
+       for (i = 0; i < gdev->max_p; i++)
+               gdev->part[MINOR(dev) + i].guid = NULL;
+#endif
+
        grok_partitions(gdev, MINOR(dev)>>gdev->minor_shift, minors, size);
 }

@@ -432,6 +574,13 @@
        if (!size || minors == 1)
                return;

+#ifdef CONFIG_DEVFS_GUID
+       /* In case this is a revalidation, free GUID memory.
+          On the first call for this device,
+          register_disk has set all entries to NULL,
+          and nothing will happen. */
+       free_disk_guids (dev, first_minor);
+#endif
        blk_size[dev->major] = NULL;
        check_partition(dev, MKDEV(dev->major, first_minor), 1 + first_minor);

diff -ru -x *.o -x.* -x*.rej -x*~ linux-2.4.4-orig/fs/partitions/efi.c 
linux-2.4.4mw/fs/partitions/efi.c
--- linux-2.4.4-orig/fs/partitions/efi.c        Wed May 30 20:27:55 2001
+++ linux-2.4.4mw/fs/partitions/efi.c   Wed May 30 20:11:12 2001
@@ -479,7 +479,31 @@
        return 0;
 }

+#ifdef CONFIG_DEVFS_GUID
+/* set_partition_guid */
+/* Fill in the GUID field of the partition.
+   It is set to NULL by register_disk before. */
+static void set_partition_guid (struct gendisk *hd,
+                               const int minor,
+                               const efi_guid_t *guid)
+{
+        char guid_buf[GUID_UNPARSED_LEN + 1];
+       efi_guid_t *part_guid = hd->part[minor].guid;

+       if (!guid || !hd) return;
+
+       part_guid = kmalloc (sizeof (efi_guid_t), GFP_KERNEL);
+
+        if (part_guid) {
+               memcpy (part_guid, guid, sizeof (efi_guid_t));
+       } else {
+               printk (KERN_WARNING
+                        "add_gpt_partitions: cannot allocate GUID memory!\n");
+       };
+
+       hd->part[minor].guid = part_guid;
+}
+#endif /* CONFIG_DEVFS_GUID */

 /*
  * Create devices for each entry in the GUID Partition Table Entries.
@@ -516,6 +540,11 @@
        }

        debug_printk(efi_printk_level "GUID Partition Table is valid!  Yea!\n");
+
+#ifdef CONFIG_DEVFS_GUID
+       set_partition_guid (hd, nextminor - 1, &(gpt->DiskGUID));
+#endif
+
        for (i = 0; i < gpt->NumberOfPartitionEntries &&
                     nummade < (hd->max_p - 1); i++) {
                if (!efi_guidcmp(unusedGuid, ptes[i].PartitionTypeGuid))
@@ -523,6 +552,10 @@

                add_gd_partition(hd, nextminor, ptes[i].StartingLBA,
                                 (ptes[i].EndingLBA-ptes[i].StartingLBA + 1));
+
+#ifdef CONFIG_DEVFS_GUID
+               set_partition_guid (hd, nextminor, 
&(ptes[i].UniquePartitionGuid));
+#endif

                /* If there's this is a RAID volume, tell md */
 #if CONFIG_BLK_DEV_MD && CONFIG_AUTODETECT_RAID
diff -ru -x *.o -x.* -x*.rej -x*~ 
linux-2.4.4-orig/include/linux/devfs_fs_kernel.h 
linux-2.4.4mw/include/linux/devfs_fs_kernel.h
--- linux-2.4.4-orig/include/linux/devfs_fs_kernel.h    Wed May 30 20:27:55 2001
+++ linux-2.4.4mw/include/linux/devfs_fs_kernel.h       Wed May 30 20:24:15 2001
@@ -81,6 +81,9 @@
 extern devfs_handle_t devfs_get_next_sibling (devfs_handle_t de);
 extern void devfs_auto_unregister (devfs_handle_t master,devfs_handle_t slave);
 extern devfs_handle_t devfs_get_unregister_slave (devfs_handle_t master);
+#ifdef CONFIG_DEVFS_GUID
+extern void devfs_unregister_slave (devfs_handle_t master);
+#endif
 extern const char *devfs_get_name (devfs_handle_t de, unsigned int *namelen);
 extern int devfs_register_chrdev (unsigned int major, const char *name,
                                  struct file_operations *fops);
diff -ru -x *.o -x.* -x*.rej -x*~ linux-2.4.4-orig/include/linux/genhd.h 
linux-2.4.4mw/include/linux/genhd.h
--- linux-2.4.4-orig/include/linux/genhd.h      Wed May 30 20:27:55 2001
+++ linux-2.4.4mw/include/linux/genhd.h Wed May 30 18:26:02 2001
@@ -13,6 +13,10 @@
 #include <linux/types.h>
 #include <linux/major.h>

+#ifdef CONFIG_DEVFS_GUID
+#include <asm/efi.h>
+#endif
+
 /* These three have identical behaviour; use the second one if DOS fdisk gets
    confused about extended/logical partitions starting past cylinder 1023. */
 #define DOS_EXTENDED_PARTITION 5
@@ -51,6 +55,9 @@
        long start_sect;
        long nr_sects;
        devfs_handle_t de;              /* primary (master) devfs entry  */
+#ifdef CONFIG_DEVFS_GUID
+       efi_guid_t *guid;
+#endif
 };

 #define GENHD_FL_REMOVABLE  1




<Prev in Thread] Current Thread [Next in Thread>
  • Patch: /dev/guid support, Martin Wilck <=