18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 1991-1998 Linus Torvalds 48c2ecf20Sopenharmony_ci * Re-organised Feb 1998 Russell King 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#include <linux/fs.h> 78c2ecf20Sopenharmony_ci#include <linux/slab.h> 88c2ecf20Sopenharmony_ci#include <linux/ctype.h> 98c2ecf20Sopenharmony_ci#include <linux/genhd.h> 108c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 118c2ecf20Sopenharmony_ci#include <linux/blktrace_api.h> 128c2ecf20Sopenharmony_ci#include <linux/raid/detect.h> 138c2ecf20Sopenharmony_ci#include "check.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic int (*check_part[])(struct parsed_partitions *) = { 168c2ecf20Sopenharmony_ci /* 178c2ecf20Sopenharmony_ci * Probe partition formats with tables at disk address 0 188c2ecf20Sopenharmony_ci * that also have an ADFS boot block at 0xdc0. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci#ifdef CONFIG_ACORN_PARTITION_ICS 218c2ecf20Sopenharmony_ci adfspart_check_ICS, 228c2ecf20Sopenharmony_ci#endif 238c2ecf20Sopenharmony_ci#ifdef CONFIG_ACORN_PARTITION_POWERTEC 248c2ecf20Sopenharmony_ci adfspart_check_POWERTEC, 258c2ecf20Sopenharmony_ci#endif 268c2ecf20Sopenharmony_ci#ifdef CONFIG_ACORN_PARTITION_EESOX 278c2ecf20Sopenharmony_ci adfspart_check_EESOX, 288c2ecf20Sopenharmony_ci#endif 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci /* 318c2ecf20Sopenharmony_ci * Now move on to formats that only have partition info at 328c2ecf20Sopenharmony_ci * disk address 0xdc0. Since these may also have stale 338c2ecf20Sopenharmony_ci * PC/BIOS partition tables, they need to come before 348c2ecf20Sopenharmony_ci * the msdos entry. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci#ifdef CONFIG_ACORN_PARTITION_CUMANA 378c2ecf20Sopenharmony_ci adfspart_check_CUMANA, 388c2ecf20Sopenharmony_ci#endif 398c2ecf20Sopenharmony_ci#ifdef CONFIG_ACORN_PARTITION_ADFS 408c2ecf20Sopenharmony_ci adfspart_check_ADFS, 418c2ecf20Sopenharmony_ci#endif 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#ifdef CONFIG_CMDLINE_PARTITION 448c2ecf20Sopenharmony_ci cmdline_partition, 458c2ecf20Sopenharmony_ci#endif 468c2ecf20Sopenharmony_ci#ifdef CONFIG_EFI_PARTITION 478c2ecf20Sopenharmony_ci efi_partition, /* this must come before msdos */ 488c2ecf20Sopenharmony_ci#endif 498c2ecf20Sopenharmony_ci#ifdef CONFIG_SGI_PARTITION 508c2ecf20Sopenharmony_ci sgi_partition, 518c2ecf20Sopenharmony_ci#endif 528c2ecf20Sopenharmony_ci#ifdef CONFIG_LDM_PARTITION 538c2ecf20Sopenharmony_ci ldm_partition, /* this must come before msdos */ 548c2ecf20Sopenharmony_ci#endif 558c2ecf20Sopenharmony_ci#ifdef CONFIG_MSDOS_PARTITION 568c2ecf20Sopenharmony_ci msdos_partition, 578c2ecf20Sopenharmony_ci#endif 588c2ecf20Sopenharmony_ci#ifdef CONFIG_OSF_PARTITION 598c2ecf20Sopenharmony_ci osf_partition, 608c2ecf20Sopenharmony_ci#endif 618c2ecf20Sopenharmony_ci#ifdef CONFIG_SUN_PARTITION 628c2ecf20Sopenharmony_ci sun_partition, 638c2ecf20Sopenharmony_ci#endif 648c2ecf20Sopenharmony_ci#ifdef CONFIG_AMIGA_PARTITION 658c2ecf20Sopenharmony_ci amiga_partition, 668c2ecf20Sopenharmony_ci#endif 678c2ecf20Sopenharmony_ci#ifdef CONFIG_ATARI_PARTITION 688c2ecf20Sopenharmony_ci atari_partition, 698c2ecf20Sopenharmony_ci#endif 708c2ecf20Sopenharmony_ci#ifdef CONFIG_MAC_PARTITION 718c2ecf20Sopenharmony_ci mac_partition, 728c2ecf20Sopenharmony_ci#endif 738c2ecf20Sopenharmony_ci#ifdef CONFIG_ULTRIX_PARTITION 748c2ecf20Sopenharmony_ci ultrix_partition, 758c2ecf20Sopenharmony_ci#endif 768c2ecf20Sopenharmony_ci#ifdef CONFIG_IBM_PARTITION 778c2ecf20Sopenharmony_ci ibm_partition, 788c2ecf20Sopenharmony_ci#endif 798c2ecf20Sopenharmony_ci#ifdef CONFIG_KARMA_PARTITION 808c2ecf20Sopenharmony_ci karma_partition, 818c2ecf20Sopenharmony_ci#endif 828c2ecf20Sopenharmony_ci#ifdef CONFIG_SYSV68_PARTITION 838c2ecf20Sopenharmony_ci sysv68_partition, 848c2ecf20Sopenharmony_ci#endif 858c2ecf20Sopenharmony_ci NULL 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic struct parsed_partitions *allocate_partitions(struct gendisk *hd) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci struct parsed_partitions *state; 918c2ecf20Sopenharmony_ci int nr; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci state = kzalloc(sizeof(*state), GFP_KERNEL); 948c2ecf20Sopenharmony_ci if (!state) 958c2ecf20Sopenharmony_ci return NULL; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci nr = disk_max_parts(hd); 988c2ecf20Sopenharmony_ci state->parts = vzalloc(array_size(nr, sizeof(state->parts[0]))); 998c2ecf20Sopenharmony_ci if (!state->parts) { 1008c2ecf20Sopenharmony_ci kfree(state); 1018c2ecf20Sopenharmony_ci return NULL; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci state->limit = nr; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return state; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic void free_partitions(struct parsed_partitions *state) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci vfree(state->parts); 1128c2ecf20Sopenharmony_ci kfree(state); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic struct parsed_partitions *check_partition(struct gendisk *hd, 1168c2ecf20Sopenharmony_ci struct block_device *bdev) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct parsed_partitions *state; 1198c2ecf20Sopenharmony_ci int i, res, err; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci state = allocate_partitions(hd); 1228c2ecf20Sopenharmony_ci if (!state) 1238c2ecf20Sopenharmony_ci return NULL; 1248c2ecf20Sopenharmony_ci state->pp_buf = (char *)__get_free_page(GFP_KERNEL); 1258c2ecf20Sopenharmony_ci if (!state->pp_buf) { 1268c2ecf20Sopenharmony_ci free_partitions(state); 1278c2ecf20Sopenharmony_ci return NULL; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci state->pp_buf[0] = '\0'; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci state->bdev = bdev; 1328c2ecf20Sopenharmony_ci disk_name(hd, 0, state->name); 1338c2ecf20Sopenharmony_ci snprintf(state->pp_buf, PAGE_SIZE, " %s:", state->name); 1348c2ecf20Sopenharmony_ci if (isdigit(state->name[strlen(state->name)-1])) 1358c2ecf20Sopenharmony_ci sprintf(state->name, "p"); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci i = res = err = 0; 1388c2ecf20Sopenharmony_ci while (!res && check_part[i]) { 1398c2ecf20Sopenharmony_ci memset(state->parts, 0, state->limit * sizeof(state->parts[0])); 1408c2ecf20Sopenharmony_ci res = check_part[i++](state); 1418c2ecf20Sopenharmony_ci if (res < 0) { 1428c2ecf20Sopenharmony_ci /* 1438c2ecf20Sopenharmony_ci * We have hit an I/O error which we don't report now. 1448c2ecf20Sopenharmony_ci * But record it, and let the others do their job. 1458c2ecf20Sopenharmony_ci */ 1468c2ecf20Sopenharmony_ci err = res; 1478c2ecf20Sopenharmony_ci res = 0; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci if (res > 0) { 1528c2ecf20Sopenharmony_ci printk(KERN_INFO "%s", state->pp_buf); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci free_page((unsigned long)state->pp_buf); 1558c2ecf20Sopenharmony_ci return state; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci if (state->access_beyond_eod) 1588c2ecf20Sopenharmony_ci err = -ENOSPC; 1598c2ecf20Sopenharmony_ci /* 1608c2ecf20Sopenharmony_ci * The partition is unrecognized. So report I/O errors if there were any 1618c2ecf20Sopenharmony_ci */ 1628c2ecf20Sopenharmony_ci if (err) 1638c2ecf20Sopenharmony_ci res = err; 1648c2ecf20Sopenharmony_ci if (res) { 1658c2ecf20Sopenharmony_ci strlcat(state->pp_buf, 1668c2ecf20Sopenharmony_ci " unable to read partition table\n", PAGE_SIZE); 1678c2ecf20Sopenharmony_ci printk(KERN_INFO "%s", state->pp_buf); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci free_page((unsigned long)state->pp_buf); 1718c2ecf20Sopenharmony_ci free_partitions(state); 1728c2ecf20Sopenharmony_ci return ERR_PTR(res); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic ssize_t part_partition_show(struct device *dev, 1768c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci struct hd_struct *p = dev_to_part(dev); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", p->partno); 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic ssize_t part_start_show(struct device *dev, 1848c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci struct hd_struct *p = dev_to_part(dev); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci return sprintf(buf, "%llu\n",(unsigned long long)p->start_sect); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic ssize_t part_ro_show(struct device *dev, 1928c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct hd_struct *p = dev_to_part(dev); 1958c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", p->policy ? 1 : 0); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic ssize_t part_alignment_offset_show(struct device *dev, 1998c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci struct hd_struct *p = dev_to_part(dev); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", 2048c2ecf20Sopenharmony_ci queue_limit_alignment_offset(&part_to_disk(p)->queue->limits, 2058c2ecf20Sopenharmony_ci p->start_sect)); 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic ssize_t part_discard_alignment_show(struct device *dev, 2098c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct hd_struct *p = dev_to_part(dev); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", 2148c2ecf20Sopenharmony_ci queue_limit_discard_alignment(&part_to_disk(p)->queue->limits, 2158c2ecf20Sopenharmony_ci p->start_sect)); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic DEVICE_ATTR(partition, 0444, part_partition_show, NULL); 2198c2ecf20Sopenharmony_cistatic DEVICE_ATTR(start, 0444, part_start_show, NULL); 2208c2ecf20Sopenharmony_cistatic DEVICE_ATTR(size, 0444, part_size_show, NULL); 2218c2ecf20Sopenharmony_cistatic DEVICE_ATTR(ro, 0444, part_ro_show, NULL); 2228c2ecf20Sopenharmony_cistatic DEVICE_ATTR(alignment_offset, 0444, part_alignment_offset_show, NULL); 2238c2ecf20Sopenharmony_cistatic DEVICE_ATTR(discard_alignment, 0444, part_discard_alignment_show, NULL); 2248c2ecf20Sopenharmony_cistatic DEVICE_ATTR(stat, 0444, part_stat_show, NULL); 2258c2ecf20Sopenharmony_cistatic DEVICE_ATTR(inflight, 0444, part_inflight_show, NULL); 2268c2ecf20Sopenharmony_ci#ifdef CONFIG_FAIL_MAKE_REQUEST 2278c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_fail = 2288c2ecf20Sopenharmony_ci __ATTR(make-it-fail, 0644, part_fail_show, part_fail_store); 2298c2ecf20Sopenharmony_ci#endif 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic struct attribute *part_attrs[] = { 2328c2ecf20Sopenharmony_ci &dev_attr_partition.attr, 2338c2ecf20Sopenharmony_ci &dev_attr_start.attr, 2348c2ecf20Sopenharmony_ci &dev_attr_size.attr, 2358c2ecf20Sopenharmony_ci &dev_attr_ro.attr, 2368c2ecf20Sopenharmony_ci &dev_attr_alignment_offset.attr, 2378c2ecf20Sopenharmony_ci &dev_attr_discard_alignment.attr, 2388c2ecf20Sopenharmony_ci &dev_attr_stat.attr, 2398c2ecf20Sopenharmony_ci &dev_attr_inflight.attr, 2408c2ecf20Sopenharmony_ci#ifdef CONFIG_FAIL_MAKE_REQUEST 2418c2ecf20Sopenharmony_ci &dev_attr_fail.attr, 2428c2ecf20Sopenharmony_ci#endif 2438c2ecf20Sopenharmony_ci NULL 2448c2ecf20Sopenharmony_ci}; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic struct attribute_group part_attr_group = { 2478c2ecf20Sopenharmony_ci .attrs = part_attrs, 2488c2ecf20Sopenharmony_ci}; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic const struct attribute_group *part_attr_groups[] = { 2518c2ecf20Sopenharmony_ci &part_attr_group, 2528c2ecf20Sopenharmony_ci#ifdef CONFIG_BLK_DEV_IO_TRACE 2538c2ecf20Sopenharmony_ci &blk_trace_attr_group, 2548c2ecf20Sopenharmony_ci#endif 2558c2ecf20Sopenharmony_ci NULL 2568c2ecf20Sopenharmony_ci}; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic void part_release(struct device *dev) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci struct hd_struct *p = dev_to_part(dev); 2618c2ecf20Sopenharmony_ci blk_free_devt(dev->devt); 2628c2ecf20Sopenharmony_ci hd_free_part(p); 2638c2ecf20Sopenharmony_ci kfree(p); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic int part_uevent(struct device *dev, struct kobj_uevent_env *env) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci struct hd_struct *part = dev_to_part(dev); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci add_uevent_var(env, "PARTN=%u", part->partno); 2718c2ecf20Sopenharmony_ci if (part->info && part->info->volname[0]) 2728c2ecf20Sopenharmony_ci add_uevent_var(env, "PARTNAME=%s", part->info->volname); 2738c2ecf20Sopenharmony_ci return 0; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistruct device_type part_type = { 2778c2ecf20Sopenharmony_ci .name = "partition", 2788c2ecf20Sopenharmony_ci .groups = part_attr_groups, 2798c2ecf20Sopenharmony_ci .release = part_release, 2808c2ecf20Sopenharmony_ci .uevent = part_uevent, 2818c2ecf20Sopenharmony_ci}; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic void hd_struct_free_work(struct work_struct *work) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci struct hd_struct *part = 2868c2ecf20Sopenharmony_ci container_of(to_rcu_work(work), struct hd_struct, rcu_work); 2878c2ecf20Sopenharmony_ci struct gendisk *disk = part_to_disk(part); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* 2908c2ecf20Sopenharmony_ci * Release the disk reference acquired in delete_partition here. 2918c2ecf20Sopenharmony_ci * We can't release it in hd_struct_free because the final put_device 2928c2ecf20Sopenharmony_ci * needs process context and thus can't be run directly from a 2938c2ecf20Sopenharmony_ci * percpu_ref ->release handler. 2948c2ecf20Sopenharmony_ci */ 2958c2ecf20Sopenharmony_ci put_device(disk_to_dev(disk)); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci part->start_sect = 0; 2988c2ecf20Sopenharmony_ci part->nr_sects = 0; 2998c2ecf20Sopenharmony_ci part_stat_set_all(part, 0); 3008c2ecf20Sopenharmony_ci put_device(part_to_dev(part)); 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic void hd_struct_free(struct percpu_ref *ref) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci struct hd_struct *part = container_of(ref, struct hd_struct, ref); 3068c2ecf20Sopenharmony_ci struct gendisk *disk = part_to_disk(part); 3078c2ecf20Sopenharmony_ci struct disk_part_tbl *ptbl = 3088c2ecf20Sopenharmony_ci rcu_dereference_protected(disk->part_tbl, 1); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci rcu_assign_pointer(ptbl->last_lookup, NULL); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci INIT_RCU_WORK(&part->rcu_work, hd_struct_free_work); 3138c2ecf20Sopenharmony_ci queue_rcu_work(system_wq, &part->rcu_work); 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ciint hd_ref_init(struct hd_struct *part) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci if (percpu_ref_init(&part->ref, hd_struct_free, 0, GFP_KERNEL)) 3198c2ecf20Sopenharmony_ci return -ENOMEM; 3208c2ecf20Sopenharmony_ci return 0; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci/* 3248c2ecf20Sopenharmony_ci * Must be called either with bd_mutex held, before a disk can be opened or 3258c2ecf20Sopenharmony_ci * after all disk users are gone. 3268c2ecf20Sopenharmony_ci */ 3278c2ecf20Sopenharmony_civoid delete_partition(struct hd_struct *part) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci struct gendisk *disk = part_to_disk(part); 3308c2ecf20Sopenharmony_ci struct disk_part_tbl *ptbl = 3318c2ecf20Sopenharmony_ci rcu_dereference_protected(disk->part_tbl, 1); 3328c2ecf20Sopenharmony_ci struct block_device *bdev; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* 3358c2ecf20Sopenharmony_ci * ->part_tbl is referenced in this part's release handler, so 3368c2ecf20Sopenharmony_ci * we have to hold the disk device 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_ci get_device(disk_to_dev(disk)); 3398c2ecf20Sopenharmony_ci rcu_assign_pointer(ptbl->part[part->partno], NULL); 3408c2ecf20Sopenharmony_ci kobject_put(part->holder_dir); 3418c2ecf20Sopenharmony_ci device_del(part_to_dev(part)); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* 3448c2ecf20Sopenharmony_ci * Remove gendisk pointer from idr so that it cannot be looked up 3458c2ecf20Sopenharmony_ci * while RCU period before freeing gendisk is running to prevent 3468c2ecf20Sopenharmony_ci * use-after-free issues. Note that the device number stays 3478c2ecf20Sopenharmony_ci * "in-use" until we really free the gendisk. 3488c2ecf20Sopenharmony_ci */ 3498c2ecf20Sopenharmony_ci blk_invalidate_devt(part_devt(part)); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci bdev = bdget_part(part); 3528c2ecf20Sopenharmony_ci if (bdev) { 3538c2ecf20Sopenharmony_ci remove_inode_hash(bdev->bd_inode); 3548c2ecf20Sopenharmony_ci bdput(bdev); 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci percpu_ref_kill(&part->ref); 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic ssize_t whole_disk_show(struct device *dev, 3608c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci return 0; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_cistatic DEVICE_ATTR(whole_disk, 0444, whole_disk_show, NULL); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci/* 3678c2ecf20Sopenharmony_ci * Must be called either with bd_mutex held, before a disk can be opened or 3688c2ecf20Sopenharmony_ci * after all disk users are gone. 3698c2ecf20Sopenharmony_ci */ 3708c2ecf20Sopenharmony_cistatic struct hd_struct *add_partition(struct gendisk *disk, int partno, 3718c2ecf20Sopenharmony_ci sector_t start, sector_t len, int flags, 3728c2ecf20Sopenharmony_ci struct partition_meta_info *info) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci struct hd_struct *p; 3758c2ecf20Sopenharmony_ci dev_t devt = MKDEV(0, 0); 3768c2ecf20Sopenharmony_ci struct device *ddev = disk_to_dev(disk); 3778c2ecf20Sopenharmony_ci struct device *pdev; 3788c2ecf20Sopenharmony_ci struct disk_part_tbl *ptbl; 3798c2ecf20Sopenharmony_ci const char *dname; 3808c2ecf20Sopenharmony_ci int err; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* 3838c2ecf20Sopenharmony_ci * Partitions are not supported on zoned block devices that are used as 3848c2ecf20Sopenharmony_ci * such. 3858c2ecf20Sopenharmony_ci */ 3868c2ecf20Sopenharmony_ci switch (disk->queue->limits.zoned) { 3878c2ecf20Sopenharmony_ci case BLK_ZONED_HM: 3888c2ecf20Sopenharmony_ci pr_warn("%s: partitions not supported on host managed zoned block device\n", 3898c2ecf20Sopenharmony_ci disk->disk_name); 3908c2ecf20Sopenharmony_ci return ERR_PTR(-ENXIO); 3918c2ecf20Sopenharmony_ci case BLK_ZONED_HA: 3928c2ecf20Sopenharmony_ci pr_info("%s: disabling host aware zoned block device support due to partitions\n", 3938c2ecf20Sopenharmony_ci disk->disk_name); 3948c2ecf20Sopenharmony_ci disk->queue->limits.zoned = BLK_ZONED_NONE; 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci case BLK_ZONED_NONE: 3978c2ecf20Sopenharmony_ci break; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci err = disk_expand_part_tbl(disk, partno); 4018c2ecf20Sopenharmony_ci if (err) 4028c2ecf20Sopenharmony_ci return ERR_PTR(err); 4038c2ecf20Sopenharmony_ci ptbl = rcu_dereference_protected(disk->part_tbl, 1); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (ptbl->part[partno]) 4068c2ecf20Sopenharmony_ci return ERR_PTR(-EBUSY); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci p = kzalloc(sizeof(*p), GFP_KERNEL); 4098c2ecf20Sopenharmony_ci if (!p) 4108c2ecf20Sopenharmony_ci return ERR_PTR(-EBUSY); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci p->dkstats = alloc_percpu(struct disk_stats); 4138c2ecf20Sopenharmony_ci if (!p->dkstats) { 4148c2ecf20Sopenharmony_ci err = -ENOMEM; 4158c2ecf20Sopenharmony_ci goto out_free; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci hd_sects_seq_init(p); 4198c2ecf20Sopenharmony_ci pdev = part_to_dev(p); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci p->start_sect = start; 4228c2ecf20Sopenharmony_ci p->nr_sects = len; 4238c2ecf20Sopenharmony_ci p->partno = partno; 4248c2ecf20Sopenharmony_ci p->policy = get_disk_ro(disk); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (info) { 4278c2ecf20Sopenharmony_ci struct partition_meta_info *pinfo; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci pinfo = kzalloc_node(sizeof(*pinfo), GFP_KERNEL, disk->node_id); 4308c2ecf20Sopenharmony_ci if (!pinfo) { 4318c2ecf20Sopenharmony_ci err = -ENOMEM; 4328c2ecf20Sopenharmony_ci goto out_free_stats; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci memcpy(pinfo, info, sizeof(*info)); 4358c2ecf20Sopenharmony_ci p->info = pinfo; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci dname = dev_name(ddev); 4398c2ecf20Sopenharmony_ci if (isdigit(dname[strlen(dname) - 1])) 4408c2ecf20Sopenharmony_ci dev_set_name(pdev, "%sp%d", dname, partno); 4418c2ecf20Sopenharmony_ci else 4428c2ecf20Sopenharmony_ci dev_set_name(pdev, "%s%d", dname, partno); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci device_initialize(pdev); 4458c2ecf20Sopenharmony_ci pdev->class = &block_class; 4468c2ecf20Sopenharmony_ci pdev->type = &part_type; 4478c2ecf20Sopenharmony_ci pdev->parent = ddev; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci err = blk_alloc_devt(p, &devt); 4508c2ecf20Sopenharmony_ci if (err) 4518c2ecf20Sopenharmony_ci goto out_free_info; 4528c2ecf20Sopenharmony_ci pdev->devt = devt; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci /* delay uevent until 'holders' subdir is created */ 4558c2ecf20Sopenharmony_ci dev_set_uevent_suppress(pdev, 1); 4568c2ecf20Sopenharmony_ci err = device_add(pdev); 4578c2ecf20Sopenharmony_ci if (err) 4588c2ecf20Sopenharmony_ci goto out_put; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci err = -ENOMEM; 4618c2ecf20Sopenharmony_ci p->holder_dir = kobject_create_and_add("holders", &pdev->kobj); 4628c2ecf20Sopenharmony_ci if (!p->holder_dir) 4638c2ecf20Sopenharmony_ci goto out_del; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci dev_set_uevent_suppress(pdev, 0); 4668c2ecf20Sopenharmony_ci if (flags & ADDPART_FLAG_WHOLEDISK) { 4678c2ecf20Sopenharmony_ci err = device_create_file(pdev, &dev_attr_whole_disk); 4688c2ecf20Sopenharmony_ci if (err) 4698c2ecf20Sopenharmony_ci goto out_del; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci err = hd_ref_init(p); 4738c2ecf20Sopenharmony_ci if (err) { 4748c2ecf20Sopenharmony_ci if (flags & ADDPART_FLAG_WHOLEDISK) 4758c2ecf20Sopenharmony_ci goto out_remove_file; 4768c2ecf20Sopenharmony_ci goto out_del; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci /* everything is up and running, commence */ 4808c2ecf20Sopenharmony_ci rcu_assign_pointer(ptbl->part[partno], p); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci /* suppress uevent if the disk suppresses it */ 4838c2ecf20Sopenharmony_ci if (!dev_get_uevent_suppress(ddev)) 4848c2ecf20Sopenharmony_ci kobject_uevent(&pdev->kobj, KOBJ_ADD); 4858c2ecf20Sopenharmony_ci return p; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ciout_free_info: 4888c2ecf20Sopenharmony_ci kfree(p->info); 4898c2ecf20Sopenharmony_ciout_free_stats: 4908c2ecf20Sopenharmony_ci free_percpu(p->dkstats); 4918c2ecf20Sopenharmony_ciout_free: 4928c2ecf20Sopenharmony_ci kfree(p); 4938c2ecf20Sopenharmony_ci return ERR_PTR(err); 4948c2ecf20Sopenharmony_ciout_remove_file: 4958c2ecf20Sopenharmony_ci device_remove_file(pdev, &dev_attr_whole_disk); 4968c2ecf20Sopenharmony_ciout_del: 4978c2ecf20Sopenharmony_ci kobject_put(p->holder_dir); 4988c2ecf20Sopenharmony_ci device_del(pdev); 4998c2ecf20Sopenharmony_ciout_put: 5008c2ecf20Sopenharmony_ci put_device(pdev); 5018c2ecf20Sopenharmony_ci return ERR_PTR(err); 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic bool partition_overlaps(struct gendisk *disk, sector_t start, 5058c2ecf20Sopenharmony_ci sector_t length, int skip_partno) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci struct disk_part_iter piter; 5088c2ecf20Sopenharmony_ci struct hd_struct *part; 5098c2ecf20Sopenharmony_ci bool overlap = false; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY); 5128c2ecf20Sopenharmony_ci while ((part = disk_part_iter_next(&piter))) { 5138c2ecf20Sopenharmony_ci if (part->partno == skip_partno || 5148c2ecf20Sopenharmony_ci start >= part->start_sect + part->nr_sects || 5158c2ecf20Sopenharmony_ci start + length <= part->start_sect) 5168c2ecf20Sopenharmony_ci continue; 5178c2ecf20Sopenharmony_ci overlap = true; 5188c2ecf20Sopenharmony_ci break; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci disk_part_iter_exit(&piter); 5228c2ecf20Sopenharmony_ci return overlap; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ciint bdev_add_partition(struct block_device *bdev, int partno, 5268c2ecf20Sopenharmony_ci sector_t start, sector_t length) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci struct hd_struct *part; 5298c2ecf20Sopenharmony_ci struct gendisk *disk = bdev->bd_disk; 5308c2ecf20Sopenharmony_ci int ret; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci mutex_lock(&bdev->bd_mutex); 5338c2ecf20Sopenharmony_ci if (!(disk->flags & GENHD_FL_UP)) { 5348c2ecf20Sopenharmony_ci ret = -ENXIO; 5358c2ecf20Sopenharmony_ci goto out; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if (partition_overlaps(disk, start, length, -1)) { 5398c2ecf20Sopenharmony_ci ret = -EBUSY; 5408c2ecf20Sopenharmony_ci goto out; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci part = add_partition(disk, partno, start, length, 5448c2ecf20Sopenharmony_ci ADDPART_FLAG_NONE, NULL); 5458c2ecf20Sopenharmony_ci ret = PTR_ERR_OR_ZERO(part); 5468c2ecf20Sopenharmony_ciout: 5478c2ecf20Sopenharmony_ci mutex_unlock(&bdev->bd_mutex); 5488c2ecf20Sopenharmony_ci return ret; 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ciint bdev_del_partition(struct block_device *bdev, int partno) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci struct block_device *bdevp; 5548c2ecf20Sopenharmony_ci struct hd_struct *part = NULL; 5558c2ecf20Sopenharmony_ci int ret; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci bdevp = bdget_disk(bdev->bd_disk, partno); 5588c2ecf20Sopenharmony_ci if (!bdevp) 5598c2ecf20Sopenharmony_ci return -ENXIO; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci mutex_lock(&bdevp->bd_mutex); 5628c2ecf20Sopenharmony_ci mutex_lock_nested(&bdev->bd_mutex, 1); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci ret = -ENXIO; 5658c2ecf20Sopenharmony_ci part = disk_get_part(bdev->bd_disk, partno); 5668c2ecf20Sopenharmony_ci if (!part) 5678c2ecf20Sopenharmony_ci goto out_unlock; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci ret = -EBUSY; 5708c2ecf20Sopenharmony_ci if (bdevp->bd_openers) 5718c2ecf20Sopenharmony_ci goto out_unlock; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci sync_blockdev(bdevp); 5748c2ecf20Sopenharmony_ci invalidate_bdev(bdevp); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci delete_partition(part); 5778c2ecf20Sopenharmony_ci ret = 0; 5788c2ecf20Sopenharmony_ciout_unlock: 5798c2ecf20Sopenharmony_ci mutex_unlock(&bdev->bd_mutex); 5808c2ecf20Sopenharmony_ci mutex_unlock(&bdevp->bd_mutex); 5818c2ecf20Sopenharmony_ci bdput(bdevp); 5828c2ecf20Sopenharmony_ci if (part) 5838c2ecf20Sopenharmony_ci disk_put_part(part); 5848c2ecf20Sopenharmony_ci return ret; 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ciint bdev_resize_partition(struct block_device *bdev, int partno, 5888c2ecf20Sopenharmony_ci sector_t start, sector_t length) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci struct block_device *bdevp; 5918c2ecf20Sopenharmony_ci struct hd_struct *part; 5928c2ecf20Sopenharmony_ci int ret = 0; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci part = disk_get_part(bdev->bd_disk, partno); 5958c2ecf20Sopenharmony_ci if (!part) 5968c2ecf20Sopenharmony_ci return -ENXIO; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci ret = -ENOMEM; 5998c2ecf20Sopenharmony_ci bdevp = bdget_part(part); 6008c2ecf20Sopenharmony_ci if (!bdevp) 6018c2ecf20Sopenharmony_ci goto out_put_part; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci mutex_lock(&bdevp->bd_mutex); 6048c2ecf20Sopenharmony_ci mutex_lock_nested(&bdev->bd_mutex, 1); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci ret = -EINVAL; 6078c2ecf20Sopenharmony_ci if (start != part->start_sect) 6088c2ecf20Sopenharmony_ci goto out_unlock; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci ret = -EBUSY; 6118c2ecf20Sopenharmony_ci if (partition_overlaps(bdev->bd_disk, start, length, partno)) 6128c2ecf20Sopenharmony_ci goto out_unlock; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci part_nr_sects_write(part, length); 6158c2ecf20Sopenharmony_ci bd_set_nr_sectors(bdevp, length); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci ret = 0; 6188c2ecf20Sopenharmony_ciout_unlock: 6198c2ecf20Sopenharmony_ci mutex_unlock(&bdevp->bd_mutex); 6208c2ecf20Sopenharmony_ci mutex_unlock(&bdev->bd_mutex); 6218c2ecf20Sopenharmony_ci bdput(bdevp); 6228c2ecf20Sopenharmony_ciout_put_part: 6238c2ecf20Sopenharmony_ci disk_put_part(part); 6248c2ecf20Sopenharmony_ci return ret; 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_cistatic bool disk_unlock_native_capacity(struct gendisk *disk) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci const struct block_device_operations *bdops = disk->fops; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (bdops->unlock_native_capacity && 6328c2ecf20Sopenharmony_ci !(disk->flags & GENHD_FL_NATIVE_CAPACITY)) { 6338c2ecf20Sopenharmony_ci printk(KERN_CONT "enabling native capacity\n"); 6348c2ecf20Sopenharmony_ci bdops->unlock_native_capacity(disk); 6358c2ecf20Sopenharmony_ci disk->flags |= GENHD_FL_NATIVE_CAPACITY; 6368c2ecf20Sopenharmony_ci return true; 6378c2ecf20Sopenharmony_ci } else { 6388c2ecf20Sopenharmony_ci printk(KERN_CONT "truncated\n"); 6398c2ecf20Sopenharmony_ci return false; 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ciint blk_drop_partitions(struct block_device *bdev) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci struct disk_part_iter piter; 6468c2ecf20Sopenharmony_ci struct hd_struct *part; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci if (bdev->bd_part_count) 6498c2ecf20Sopenharmony_ci return -EBUSY; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci sync_blockdev(bdev); 6528c2ecf20Sopenharmony_ci invalidate_bdev(bdev); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci disk_part_iter_init(&piter, bdev->bd_disk, DISK_PITER_INCL_EMPTY); 6558c2ecf20Sopenharmony_ci while ((part = disk_part_iter_next(&piter))) 6568c2ecf20Sopenharmony_ci delete_partition(part); 6578c2ecf20Sopenharmony_ci disk_part_iter_exit(&piter); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci return 0; 6608c2ecf20Sopenharmony_ci} 6618c2ecf20Sopenharmony_ci#ifdef CONFIG_S390 6628c2ecf20Sopenharmony_ci/* for historic reasons in the DASD driver */ 6638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(blk_drop_partitions); 6648c2ecf20Sopenharmony_ci#endif 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_cistatic bool blk_add_partition(struct gendisk *disk, struct block_device *bdev, 6678c2ecf20Sopenharmony_ci struct parsed_partitions *state, int p) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci sector_t size = state->parts[p].size; 6708c2ecf20Sopenharmony_ci sector_t from = state->parts[p].from; 6718c2ecf20Sopenharmony_ci struct hd_struct *part; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci if (!size) 6748c2ecf20Sopenharmony_ci return true; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci if (from >= get_capacity(disk)) { 6778c2ecf20Sopenharmony_ci printk(KERN_WARNING 6788c2ecf20Sopenharmony_ci "%s: p%d start %llu is beyond EOD, ", 6798c2ecf20Sopenharmony_ci disk->disk_name, p, (unsigned long long) from); 6808c2ecf20Sopenharmony_ci if (disk_unlock_native_capacity(disk)) 6818c2ecf20Sopenharmony_ci return false; 6828c2ecf20Sopenharmony_ci return true; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci if (from + size > get_capacity(disk)) { 6868c2ecf20Sopenharmony_ci printk(KERN_WARNING 6878c2ecf20Sopenharmony_ci "%s: p%d size %llu extends beyond EOD, ", 6888c2ecf20Sopenharmony_ci disk->disk_name, p, (unsigned long long) size); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci if (disk_unlock_native_capacity(disk)) 6918c2ecf20Sopenharmony_ci return false; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci /* 6948c2ecf20Sopenharmony_ci * We can not ignore partitions of broken tables created by for 6958c2ecf20Sopenharmony_ci * example camera firmware, but we limit them to the end of the 6968c2ecf20Sopenharmony_ci * disk to avoid creating invalid block devices. 6978c2ecf20Sopenharmony_ci */ 6988c2ecf20Sopenharmony_ci size = get_capacity(disk) - from; 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci part = add_partition(disk, p, from, size, state->parts[p].flags, 7028c2ecf20Sopenharmony_ci &state->parts[p].info); 7038c2ecf20Sopenharmony_ci if (IS_ERR(part) && PTR_ERR(part) != -ENXIO) { 7048c2ecf20Sopenharmony_ci printk(KERN_ERR " %s: p%d could not be added: %ld\n", 7058c2ecf20Sopenharmony_ci disk->disk_name, p, -PTR_ERR(part)); 7068c2ecf20Sopenharmony_ci return true; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci if (IS_BUILTIN(CONFIG_BLK_DEV_MD) && 7108c2ecf20Sopenharmony_ci (state->parts[p].flags & ADDPART_FLAG_RAID)) 7118c2ecf20Sopenharmony_ci md_autodetect_dev(part_to_dev(part)->devt); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci return true; 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ciint blk_add_partitions(struct gendisk *disk, struct block_device *bdev) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci struct parsed_partitions *state; 7198c2ecf20Sopenharmony_ci int ret = -EAGAIN, p, highest; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (!disk_part_scan_enabled(disk)) 7228c2ecf20Sopenharmony_ci return 0; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci state = check_partition(disk, bdev); 7258c2ecf20Sopenharmony_ci if (!state) 7268c2ecf20Sopenharmony_ci return 0; 7278c2ecf20Sopenharmony_ci if (IS_ERR(state)) { 7288c2ecf20Sopenharmony_ci /* 7298c2ecf20Sopenharmony_ci * I/O error reading the partition table. If we tried to read 7308c2ecf20Sopenharmony_ci * beyond EOD, retry after unlocking the native capacity. 7318c2ecf20Sopenharmony_ci */ 7328c2ecf20Sopenharmony_ci if (PTR_ERR(state) == -ENOSPC) { 7338c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: partition table beyond EOD, ", 7348c2ecf20Sopenharmony_ci disk->disk_name); 7358c2ecf20Sopenharmony_ci if (disk_unlock_native_capacity(disk)) 7368c2ecf20Sopenharmony_ci return -EAGAIN; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci return -EIO; 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci /* 7428c2ecf20Sopenharmony_ci * Partitions are not supported on host managed zoned block devices. 7438c2ecf20Sopenharmony_ci */ 7448c2ecf20Sopenharmony_ci if (disk->queue->limits.zoned == BLK_ZONED_HM) { 7458c2ecf20Sopenharmony_ci pr_warn("%s: ignoring partition table on host managed zoned block device\n", 7468c2ecf20Sopenharmony_ci disk->disk_name); 7478c2ecf20Sopenharmony_ci ret = 0; 7488c2ecf20Sopenharmony_ci goto out_free_state; 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* 7528c2ecf20Sopenharmony_ci * If we read beyond EOD, try unlocking native capacity even if the 7538c2ecf20Sopenharmony_ci * partition table was successfully read as we could be missing some 7548c2ecf20Sopenharmony_ci * partitions. 7558c2ecf20Sopenharmony_ci */ 7568c2ecf20Sopenharmony_ci if (state->access_beyond_eod) { 7578c2ecf20Sopenharmony_ci printk(KERN_WARNING 7588c2ecf20Sopenharmony_ci "%s: partition table partially beyond EOD, ", 7598c2ecf20Sopenharmony_ci disk->disk_name); 7608c2ecf20Sopenharmony_ci if (disk_unlock_native_capacity(disk)) 7618c2ecf20Sopenharmony_ci goto out_free_state; 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci /* tell userspace that the media / partition table may have changed */ 7658c2ecf20Sopenharmony_ci kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci /* 7688c2ecf20Sopenharmony_ci * Detect the highest partition number and preallocate disk->part_tbl. 7698c2ecf20Sopenharmony_ci * This is an optimization and not strictly necessary. 7708c2ecf20Sopenharmony_ci */ 7718c2ecf20Sopenharmony_ci for (p = 1, highest = 0; p < state->limit; p++) 7728c2ecf20Sopenharmony_ci if (state->parts[p].size) 7738c2ecf20Sopenharmony_ci highest = p; 7748c2ecf20Sopenharmony_ci disk_expand_part_tbl(disk, highest); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci for (p = 1; p < state->limit; p++) 7778c2ecf20Sopenharmony_ci if (!blk_add_partition(disk, bdev, state, p)) 7788c2ecf20Sopenharmony_ci goto out_free_state; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci ret = 0; 7818c2ecf20Sopenharmony_ciout_free_state: 7828c2ecf20Sopenharmony_ci free_partitions(state); 7838c2ecf20Sopenharmony_ci return ret; 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_civoid *read_part_sector(struct parsed_partitions *state, sector_t n, Sector *p) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci struct address_space *mapping = state->bdev->bd_inode->i_mapping; 7898c2ecf20Sopenharmony_ci struct page *page; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci if (n >= get_capacity(state->bdev->bd_disk)) { 7928c2ecf20Sopenharmony_ci state->access_beyond_eod = true; 7938c2ecf20Sopenharmony_ci return NULL; 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci page = read_mapping_page(mapping, 7978c2ecf20Sopenharmony_ci (pgoff_t)(n >> (PAGE_SHIFT - 9)), NULL); 7988c2ecf20Sopenharmony_ci if (IS_ERR(page)) 7998c2ecf20Sopenharmony_ci goto out; 8008c2ecf20Sopenharmony_ci if (PageError(page)) 8018c2ecf20Sopenharmony_ci goto out_put_page; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci p->v = page; 8048c2ecf20Sopenharmony_ci return (unsigned char *)page_address(page) + 8058c2ecf20Sopenharmony_ci ((n & ((1 << (PAGE_SHIFT - 9)) - 1)) << SECTOR_SHIFT); 8068c2ecf20Sopenharmony_ciout_put_page: 8078c2ecf20Sopenharmony_ci put_page(page); 8088c2ecf20Sopenharmony_ciout: 8098c2ecf20Sopenharmony_ci p->v = NULL; 8108c2ecf20Sopenharmony_ci return NULL; 8118c2ecf20Sopenharmony_ci} 812