]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
oracleasm: Implement support for QUERY HANDLE operation
authorMartin K. Petersen <martin.petersen@oracle.com>
Fri, 26 Oct 2018 22:07:53 +0000 (18:07 -0400)
committerBrian Maly <brian.maly@oracle.com>
Wed, 14 Nov 2018 18:23:27 +0000 (13:23 -0500)
ASMLib previously relied on tagging the disk handle pointer to store
the integrity format. This had the advantage that a simple masking
operation was all that was required to get from a handle to the
integrity information.

However, we have seen a few cases where it appears the disk handle has
been corrupted in userland post discovery. Consequently, it has proven
necessary to be able to query disk properties without relying on the
disk pointer tag.

The oracleasm driver currently only supports looking up disk by their
label string via the query_disk operation.  Implement a query_handle
operation that is similar to query_disk in that it returns all known
disk properties. However, the lookup is done by disk handle instead of
device node. Otherwise the two queries are identical.

Adding the new operation to oracleasm does not prevent older versions
of the library from working correctly. The old tagging mechanism is
still in place, the use of query_handle is entirely optional. Later
ASMLib versions will use the new mode of operation if the query_handle
transaction file appears in /dev/oracleasm.

Orabug: 28650922

Reviewed-by: Sajid Zia <sajid.zia@oracle.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Rajan Shanmugavelu <rajan.shanmugavelu@oracle.com>
Signed-off-by: Brian Maly <brian.maly@oracle.com>
drivers/block/oracleasm/driver.c
drivers/block/oracleasm/trace.h
include/linux/oracleasm/abi.h
include/linux/oracleasm/manager.h

index a0e5ebead37ee2c66e67af2e2568c88d21e227c7..07ac4139ffc717734cf0c995382b056e3746e9bc 100644 (file)
@@ -237,6 +237,7 @@ static ssize_t asmfs_svc_query_version(struct file *file, char *buf, size_t size
 static ssize_t asmfs_svc_get_iid(struct file *file, char *buf, size_t size);
 static ssize_t asmfs_svc_check_iid(struct file *file, char *buf, size_t size);
 static ssize_t asmfs_svc_query_disk(struct file *file, char *buf, size_t size);
+static ssize_t asmfs_svc_query_handle(struct file *file, char *buf, size_t size);
 static ssize_t asmfs_svc_open_disk(struct file *file, char *buf, size_t size);
 static ssize_t asmfs_svc_close_disk(struct file *file, char *buf, size_t size);
 static ssize_t asmfs_svc_io32(struct file *file, char *buf, size_t size);
@@ -255,6 +256,7 @@ static struct transaction_context trans_contexts[] = {
 #if BITS_PER_LONG == 64
        [ASMOP_IO64]                    = {asmfs_svc_io64},
 #endif
+       [ASMOP_QUERY_HANDLE]            = {asmfs_svc_query_handle},
 };
 
 static struct inode *asmdisk_alloc_inode(struct super_block *sb)
@@ -371,6 +373,15 @@ static int asmdisk_test(struct inode *inode, void *data)
        return (d->d_inode == args->fa_inode) && (handle == args->fa_handle);
 }
 
+static int asmdisk_test_noinode(struct inode *inode, void *data)
+{
+       struct asmdisk_find_inode_args *args = data;
+       struct asm_disk_info *d = ASMDISK_I(inode);
+       unsigned long handle = (unsigned long)(d->d_bdev);
+
+       return handle == args->fa_handle;
+}
+
 static int asmdisk_set(struct inode *inode, void *data)
 {
        struct asmdisk_find_inode_args *args = data;
@@ -2310,6 +2321,64 @@ out_error:
 #endif  /* BITS_PER_LONG == 64 */
 
 
+static ssize_t asmfs_svc_query_handle(struct file *file, char *buf, size_t size)
+{
+       struct oracleasm_query_handle_v2 *qh_info;
+       struct asmdisk_find_inode_args args;
+       struct inode *disk_inode;
+       struct asm_disk_info *d;
+       struct block_device *bdev;
+       unsigned int lsecsz = 0;
+       int ret;
+
+       if (size != sizeof(struct oracleasm_query_handle_v2))
+               return -EINVAL;
+
+       qh_info = (struct oracleasm_query_handle_v2 *)buf;
+
+       ret = asmfs_verify_abi(&qh_info->qh_abi);
+       if (ret)
+               goto out;
+
+       ret = -EBADR;
+       if (qh_info->qh_abi.ai_size != sizeof(struct oracleasm_query_handle_v2))
+               goto out;
+
+       ret = -EBADRQC;
+       if (qh_info->qh_abi.ai_type != ASMOP_QUERY_HANDLE)
+               goto out;
+
+       args.fa_handle = (unsigned long)qh_info->qh_handle;
+       args.fa_inode = 0;
+       disk_inode = ilookup5(asmdisk_mnt->mnt_sb, qh_info->qh_handle,
+                             asmdisk_test_noinode, &args);
+       if (!disk_inode) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       d = ASMDISK_I(disk_inode);
+       iput(disk_inode);
+       bdev = d->d_bdev;
+
+       qh_info->qh_max_sectors = compute_max_sectors(bdev);
+       qh_info->qh_hardsect_size = asm_block_size(bdev);
+       qh_info->qh_feature = asm_integrity_format(bdev) & ASM_INTEGRITY_QDF_MASK;
+       if (use_logical_block_size == false) {
+               lsecsz = ilog2(bdev_logical_block_size(bdev));
+               qh_info->qh_feature |= lsecsz << ASM_LSECSZ_SHIFT
+                       & ASM_LSECSZ_MASK;
+       }
+
+       trace_queryhandle(bdev, qh_info);
+       ret = 0;
+
+out:
+       qh_info->qh_abi.ai_status = ret;
+       return size;
+}
+
+
 /*
  * Because each of these operations need to access the filp->private,
  * we must multiplex.
@@ -2350,11 +2419,16 @@ static ssize_t asmfs_file_read(struct file *file, char *buf, size_t size, loff_t
                        ret = asmfs_svc_io64(file, (char *)buf, size);
                        break;
 #endif  /* BITS_PER_LONG == 64 */
+
+               case ASMOP_QUERY_HANDLE:
+                       ret = asmfs_svc_query_handle(file, (char *)buf, size);
+                       break;
        }
 
        return ret;
 }
 
+
 static struct file_operations asmfs_file_operations = {
        .open           = asmfs_file_open,
        .release        = asmfs_file_release,
@@ -2526,6 +2600,18 @@ static int asmfs_fill_super(struct super_block *sb,
                goto out_genocide;
        d_add(dentry, inode);
 
+       name.name = asm_operation_files[ASMOP_QUERY_HANDLE];
+       name.len = strlen(asm_operation_files[ASMOP_QUERY_HANDLE]);
+       name.hash = full_name_hash(name.name, name.len);
+       dentry = d_alloc(root, &name);
+       if (!dentry)
+               goto out_genocide;
+       inode = new_transaction_inode(sb, 0770,
+                                     &trans_contexts[ASMOP_QUERY_HANDLE]);
+       if (!inode)
+               goto out_genocide;
+       d_add(dentry, inode);
+
        sb->s_root = root;
 
 
index 619e0aade2461d28a415fd5c3a1ec79f024f806b..46c1f43cfd7da9bb9495571cb11a80691e97f0b3 100644 (file)
@@ -197,6 +197,38 @@ TRACE_EVENT(querydisk,
                  show_ifmt(__entry->integrity))
 );
 
+TRACE_EVENT(queryhandle,
+
+       TP_PROTO(struct block_device *bdev, struct oracleasm_query_handle_v2 *qh),
+
+       TP_ARGS(bdev, qh),
+
+       TP_STRUCT__entry(
+               __field(void *          , bdev          )
+               __field(void *          , qh            )
+               __field(dev_t           , dev           )
+               __field(sector_t        , max           )
+               __field(unsigned int    , pbs           )
+               __field(unsigned int    , lbs           )
+               __field(unsigned char   , integrity     )
+       ),
+
+       TP_fast_assign(
+               __entry->bdev           = bdev;
+               __entry->qh             = qh;
+               __entry->dev            = bdev->bd_dev ? bdev->bd_dev : 0;
+               __entry->max            = qh->qh_max_sectors;
+               __entry->pbs            = qh->qh_hardsect_size;
+               __entry->lbs            = 1 << (qh->qh_feature >> ASM_LSECSZ_SHIFT);
+               __entry->integrity      = qh->qh_feature & ASM_INTEGRITY_QDF_MASK;
+       ),
+
+       TP_printk("   dev=%u:%u max_blocks=%llu pbs=%u lbs=%u integrity=%s",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long long)__entry->max, __entry->pbs, __entry->lbs,
+                 show_ifmt(__entry->integrity))
+);
+
 TRACE_EVENT(integrity,
 
        TP_PROTO(struct oracleasm_integrity_v2 *it,
index 0b5e0c480a10257ce557bc8fac67ef90b621859b..c0ac30bfca44e20353b006ebedd9af4de7ce7f1b 100644 (file)
@@ -103,6 +103,7 @@ enum asm_operation_types
        ASMOP_CLOSE_DISK,
        ASMOP_IO32,
        ASMOP_IO64,
+       ASMOP_QUERY_HANDLE,
        ASM_NUM_OPERATIONS  /* This must always be last */
 };
 
@@ -217,5 +218,14 @@ struct oracleasm_get_iid_v2
 /*18*/
 };
 
+struct oracleasm_query_handle_v2
+{
+/*00*/ struct oracleasm_abi_info       qh_abi;
+/*10*/ __u64                           qh_handle;
+       __u32                           qh_max_sectors;
+       __u32                           qh_hardsect_size;
+       __u32                           qh_feature;
+};
+
 #endif  /* _ORACLEASM_ABI_H */
 
index 0e0d63c7b25150a9c48de3ccd90b0668e4575d35..440d9e6236658eb0450685092abeb89c966175bd 100644 (file)
@@ -106,6 +106,7 @@ static char *asm_operation_files[] = {
        [ASMOP_QUERY_VERSION]   = ".query_version",
        [ASMOP_GET_IID]         = ".get_iid",
        [ASMOP_CHECK_IID]       = ".check_iid",
+       [ASMOP_QUERY_HANDLE]    = ".query_handle",
        [ASMOP_QUERY_DISK]      = ".query_disk",
 
        /*
@@ -219,7 +220,7 @@ static inline char *asm_operation_path(const char *manager,
 
        if (!manager || !*manager)
                return NULL;
-       if (op > ASM_LAST_TRANSACTION_OP)
+       if (op > ASM_LAST_TRANSACTION_OP && op != ASMOP_QUERY_HANDLE)
                return NULL;
 
        len = strlen(manager) + strlen("/") +