From: Martin K. Petersen Date: Fri, 26 Oct 2018 22:07:53 +0000 (-0400) Subject: oracleasm: Implement support for QUERY HANDLE operation X-Git-Tag: v4.1.12-124.31.3~422 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=58a85ec5e61a88f67390279b5cc58e6c57025d53;p=users%2Fjedix%2Flinux-maple.git oracleasm: Implement support for QUERY HANDLE operation 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 Signed-off-by: Martin K. Petersen Signed-off-by: Rajan Shanmugavelu Signed-off-by: Brian Maly --- diff --git a/drivers/block/oracleasm/driver.c b/drivers/block/oracleasm/driver.c index a0e5ebead37ee..07ac4139ffc71 100644 --- a/drivers/block/oracleasm/driver.c +++ b/drivers/block/oracleasm/driver.c @@ -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; diff --git a/drivers/block/oracleasm/trace.h b/drivers/block/oracleasm/trace.h index 619e0aade2461..46c1f43cfd7da 100644 --- a/drivers/block/oracleasm/trace.h +++ b/drivers/block/oracleasm/trace.h @@ -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, diff --git a/include/linux/oracleasm/abi.h b/include/linux/oracleasm/abi.h index 0b5e0c480a102..c0ac30bfca44e 100644 --- a/include/linux/oracleasm/abi.h +++ b/include/linux/oracleasm/abi.h @@ -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 */ diff --git a/include/linux/oracleasm/manager.h b/include/linux/oracleasm/manager.h index 0e0d63c7b2515..440d9e6236658 100644 --- a/include/linux/oracleasm/manager.h +++ b/include/linux/oracleasm/manager.h @@ -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("/") +