162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * gendisk handling 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Portions Copyright (C) 2020 Christoph Hellwig 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/ctype.h> 1062306a36Sopenharmony_ci#include <linux/fs.h> 1162306a36Sopenharmony_ci#include <linux/kdev_t.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/blkdev.h> 1462306a36Sopenharmony_ci#include <linux/backing-dev.h> 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci#include <linux/spinlock.h> 1762306a36Sopenharmony_ci#include <linux/proc_fs.h> 1862306a36Sopenharmony_ci#include <linux/seq_file.h> 1962306a36Sopenharmony_ci#include <linux/slab.h> 2062306a36Sopenharmony_ci#include <linux/kmod.h> 2162306a36Sopenharmony_ci#include <linux/major.h> 2262306a36Sopenharmony_ci#include <linux/mutex.h> 2362306a36Sopenharmony_ci#include <linux/idr.h> 2462306a36Sopenharmony_ci#include <linux/log2.h> 2562306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2662306a36Sopenharmony_ci#include <linux/badblocks.h> 2762306a36Sopenharmony_ci#include <linux/part_stat.h> 2862306a36Sopenharmony_ci#include <linux/blktrace_api.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include "blk-throttle.h" 3162306a36Sopenharmony_ci#include "blk.h" 3262306a36Sopenharmony_ci#include "blk-mq-sched.h" 3362306a36Sopenharmony_ci#include "blk-rq-qos.h" 3462306a36Sopenharmony_ci#include "blk-cgroup.h" 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic struct kobject *block_depr; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* 3962306a36Sopenharmony_ci * Unique, monotonically increasing sequential number associated with block 4062306a36Sopenharmony_ci * devices instances (i.e. incremented each time a device is attached). 4162306a36Sopenharmony_ci * Associating uevents with block devices in userspace is difficult and racy: 4262306a36Sopenharmony_ci * the uevent netlink socket is lossy, and on slow and overloaded systems has 4362306a36Sopenharmony_ci * a very high latency. 4462306a36Sopenharmony_ci * Block devices do not have exclusive owners in userspace, any process can set 4562306a36Sopenharmony_ci * one up (e.g. loop devices). Moreover, device names can be reused (e.g. loop0 4662306a36Sopenharmony_ci * can be reused again and again). 4762306a36Sopenharmony_ci * A userspace process setting up a block device and watching for its events 4862306a36Sopenharmony_ci * cannot thus reliably tell whether an event relates to the device it just set 4962306a36Sopenharmony_ci * up or another earlier instance with the same name. 5062306a36Sopenharmony_ci * This sequential number allows userspace processes to solve this problem, and 5162306a36Sopenharmony_ci * uniquely associate an uevent to the lifetime to a device. 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_cistatic atomic64_t diskseq; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* for extended dynamic devt allocation, currently only one major is used */ 5662306a36Sopenharmony_ci#define NR_EXT_DEVT (1 << MINORBITS) 5762306a36Sopenharmony_cistatic DEFINE_IDA(ext_devt_ida); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_civoid set_capacity(struct gendisk *disk, sector_t sectors) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci bdev_set_nr_sectors(disk->part0, sectors); 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ciEXPORT_SYMBOL(set_capacity); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* 6662306a36Sopenharmony_ci * Set disk capacity and notify if the size is not currently zero and will not 6762306a36Sopenharmony_ci * be set to zero. Returns true if a uevent was sent, otherwise false. 6862306a36Sopenharmony_ci */ 6962306a36Sopenharmony_cibool set_capacity_and_notify(struct gendisk *disk, sector_t size) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci sector_t capacity = get_capacity(disk); 7262306a36Sopenharmony_ci char *envp[] = { "RESIZE=1", NULL }; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci set_capacity(disk, size); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci /* 7762306a36Sopenharmony_ci * Only print a message and send a uevent if the gendisk is user visible 7862306a36Sopenharmony_ci * and alive. This avoids spamming the log and udev when setting the 7962306a36Sopenharmony_ci * initial capacity during probing. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci if (size == capacity || 8262306a36Sopenharmony_ci !disk_live(disk) || 8362306a36Sopenharmony_ci (disk->flags & GENHD_FL_HIDDEN)) 8462306a36Sopenharmony_ci return false; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci pr_info("%s: detected capacity change from %lld to %lld\n", 8762306a36Sopenharmony_ci disk->disk_name, capacity, size); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* 9062306a36Sopenharmony_ci * Historically we did not send a uevent for changes to/from an empty 9162306a36Sopenharmony_ci * device. 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_ci if (!capacity || !size) 9462306a36Sopenharmony_ci return false; 9562306a36Sopenharmony_ci kobject_uevent_env(&disk_to_dev(disk)->kobj, KOBJ_CHANGE, envp); 9662306a36Sopenharmony_ci return true; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(set_capacity_and_notify); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic void part_stat_read_all(struct block_device *part, 10162306a36Sopenharmony_ci struct disk_stats *stat) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci int cpu; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci memset(stat, 0, sizeof(struct disk_stats)); 10662306a36Sopenharmony_ci for_each_possible_cpu(cpu) { 10762306a36Sopenharmony_ci struct disk_stats *ptr = per_cpu_ptr(part->bd_stats, cpu); 10862306a36Sopenharmony_ci int group; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci for (group = 0; group < NR_STAT_GROUPS; group++) { 11162306a36Sopenharmony_ci stat->nsecs[group] += ptr->nsecs[group]; 11262306a36Sopenharmony_ci stat->sectors[group] += ptr->sectors[group]; 11362306a36Sopenharmony_ci stat->ios[group] += ptr->ios[group]; 11462306a36Sopenharmony_ci stat->merges[group] += ptr->merges[group]; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci stat->io_ticks += ptr->io_ticks; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic unsigned int part_in_flight(struct block_device *part) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci unsigned int inflight = 0; 12462306a36Sopenharmony_ci int cpu; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci for_each_possible_cpu(cpu) { 12762306a36Sopenharmony_ci inflight += part_stat_local_read_cpu(part, in_flight[0], cpu) + 12862306a36Sopenharmony_ci part_stat_local_read_cpu(part, in_flight[1], cpu); 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci if ((int)inflight < 0) 13162306a36Sopenharmony_ci inflight = 0; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci return inflight; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic void part_in_flight_rw(struct block_device *part, 13762306a36Sopenharmony_ci unsigned int inflight[2]) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci int cpu; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci inflight[0] = 0; 14262306a36Sopenharmony_ci inflight[1] = 0; 14362306a36Sopenharmony_ci for_each_possible_cpu(cpu) { 14462306a36Sopenharmony_ci inflight[0] += part_stat_local_read_cpu(part, in_flight[0], cpu); 14562306a36Sopenharmony_ci inflight[1] += part_stat_local_read_cpu(part, in_flight[1], cpu); 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci if ((int)inflight[0] < 0) 14862306a36Sopenharmony_ci inflight[0] = 0; 14962306a36Sopenharmony_ci if ((int)inflight[1] < 0) 15062306a36Sopenharmony_ci inflight[1] = 0; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci/* 15462306a36Sopenharmony_ci * Can be deleted altogether. Later. 15562306a36Sopenharmony_ci * 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_ci#define BLKDEV_MAJOR_HASH_SIZE 255 15862306a36Sopenharmony_cistatic struct blk_major_name { 15962306a36Sopenharmony_ci struct blk_major_name *next; 16062306a36Sopenharmony_ci int major; 16162306a36Sopenharmony_ci char name[16]; 16262306a36Sopenharmony_ci#ifdef CONFIG_BLOCK_LEGACY_AUTOLOAD 16362306a36Sopenharmony_ci void (*probe)(dev_t devt); 16462306a36Sopenharmony_ci#endif 16562306a36Sopenharmony_ci} *major_names[BLKDEV_MAJOR_HASH_SIZE]; 16662306a36Sopenharmony_cistatic DEFINE_MUTEX(major_names_lock); 16762306a36Sopenharmony_cistatic DEFINE_SPINLOCK(major_names_spinlock); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/* index in the above - for now: assume no multimajor ranges */ 17062306a36Sopenharmony_cistatic inline int major_to_index(unsigned major) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci return major % BLKDEV_MAJOR_HASH_SIZE; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 17662306a36Sopenharmony_civoid blkdev_show(struct seq_file *seqf, off_t offset) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci struct blk_major_name *dp; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci spin_lock(&major_names_spinlock); 18162306a36Sopenharmony_ci for (dp = major_names[major_to_index(offset)]; dp; dp = dp->next) 18262306a36Sopenharmony_ci if (dp->major == offset) 18362306a36Sopenharmony_ci seq_printf(seqf, "%3d %s\n", dp->major, dp->name); 18462306a36Sopenharmony_ci spin_unlock(&major_names_spinlock); 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci#endif /* CONFIG_PROC_FS */ 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci/** 18962306a36Sopenharmony_ci * __register_blkdev - register a new block device 19062306a36Sopenharmony_ci * 19162306a36Sopenharmony_ci * @major: the requested major device number [1..BLKDEV_MAJOR_MAX-1]. If 19262306a36Sopenharmony_ci * @major = 0, try to allocate any unused major number. 19362306a36Sopenharmony_ci * @name: the name of the new block device as a zero terminated string 19462306a36Sopenharmony_ci * @probe: pre-devtmpfs / pre-udev callback used to create disks when their 19562306a36Sopenharmony_ci * pre-created device node is accessed. When a probe call uses 19662306a36Sopenharmony_ci * add_disk() and it fails the driver must cleanup resources. This 19762306a36Sopenharmony_ci * interface may soon be removed. 19862306a36Sopenharmony_ci * 19962306a36Sopenharmony_ci * The @name must be unique within the system. 20062306a36Sopenharmony_ci * 20162306a36Sopenharmony_ci * The return value depends on the @major input parameter: 20262306a36Sopenharmony_ci * 20362306a36Sopenharmony_ci * - if a major device number was requested in range [1..BLKDEV_MAJOR_MAX-1] 20462306a36Sopenharmony_ci * then the function returns zero on success, or a negative error code 20562306a36Sopenharmony_ci * - if any unused major number was requested with @major = 0 parameter 20662306a36Sopenharmony_ci * then the return value is the allocated major number in range 20762306a36Sopenharmony_ci * [1..BLKDEV_MAJOR_MAX-1] or a negative error code otherwise 20862306a36Sopenharmony_ci * 20962306a36Sopenharmony_ci * See Documentation/admin-guide/devices.txt for the list of allocated 21062306a36Sopenharmony_ci * major numbers. 21162306a36Sopenharmony_ci * 21262306a36Sopenharmony_ci * Use register_blkdev instead for any new code. 21362306a36Sopenharmony_ci */ 21462306a36Sopenharmony_ciint __register_blkdev(unsigned int major, const char *name, 21562306a36Sopenharmony_ci void (*probe)(dev_t devt)) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci struct blk_major_name **n, *p; 21862306a36Sopenharmony_ci int index, ret = 0; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci mutex_lock(&major_names_lock); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* temporary */ 22362306a36Sopenharmony_ci if (major == 0) { 22462306a36Sopenharmony_ci for (index = ARRAY_SIZE(major_names)-1; index > 0; index--) { 22562306a36Sopenharmony_ci if (major_names[index] == NULL) 22662306a36Sopenharmony_ci break; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (index == 0) { 23062306a36Sopenharmony_ci printk("%s: failed to get major for %s\n", 23162306a36Sopenharmony_ci __func__, name); 23262306a36Sopenharmony_ci ret = -EBUSY; 23362306a36Sopenharmony_ci goto out; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci major = index; 23662306a36Sopenharmony_ci ret = major; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (major >= BLKDEV_MAJOR_MAX) { 24062306a36Sopenharmony_ci pr_err("%s: major requested (%u) is greater than the maximum (%u) for %s\n", 24162306a36Sopenharmony_ci __func__, major, BLKDEV_MAJOR_MAX-1, name); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci ret = -EINVAL; 24462306a36Sopenharmony_ci goto out; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci p = kmalloc(sizeof(struct blk_major_name), GFP_KERNEL); 24862306a36Sopenharmony_ci if (p == NULL) { 24962306a36Sopenharmony_ci ret = -ENOMEM; 25062306a36Sopenharmony_ci goto out; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci p->major = major; 25462306a36Sopenharmony_ci#ifdef CONFIG_BLOCK_LEGACY_AUTOLOAD 25562306a36Sopenharmony_ci p->probe = probe; 25662306a36Sopenharmony_ci#endif 25762306a36Sopenharmony_ci strscpy(p->name, name, sizeof(p->name)); 25862306a36Sopenharmony_ci p->next = NULL; 25962306a36Sopenharmony_ci index = major_to_index(major); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci spin_lock(&major_names_spinlock); 26262306a36Sopenharmony_ci for (n = &major_names[index]; *n; n = &(*n)->next) { 26362306a36Sopenharmony_ci if ((*n)->major == major) 26462306a36Sopenharmony_ci break; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci if (!*n) 26762306a36Sopenharmony_ci *n = p; 26862306a36Sopenharmony_ci else 26962306a36Sopenharmony_ci ret = -EBUSY; 27062306a36Sopenharmony_ci spin_unlock(&major_names_spinlock); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (ret < 0) { 27362306a36Sopenharmony_ci printk("register_blkdev: cannot get major %u for %s\n", 27462306a36Sopenharmony_ci major, name); 27562306a36Sopenharmony_ci kfree(p); 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ciout: 27862306a36Sopenharmony_ci mutex_unlock(&major_names_lock); 27962306a36Sopenharmony_ci return ret; 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ciEXPORT_SYMBOL(__register_blkdev); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_civoid unregister_blkdev(unsigned int major, const char *name) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci struct blk_major_name **n; 28662306a36Sopenharmony_ci struct blk_major_name *p = NULL; 28762306a36Sopenharmony_ci int index = major_to_index(major); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci mutex_lock(&major_names_lock); 29062306a36Sopenharmony_ci spin_lock(&major_names_spinlock); 29162306a36Sopenharmony_ci for (n = &major_names[index]; *n; n = &(*n)->next) 29262306a36Sopenharmony_ci if ((*n)->major == major) 29362306a36Sopenharmony_ci break; 29462306a36Sopenharmony_ci if (!*n || strcmp((*n)->name, name)) { 29562306a36Sopenharmony_ci WARN_ON(1); 29662306a36Sopenharmony_ci } else { 29762306a36Sopenharmony_ci p = *n; 29862306a36Sopenharmony_ci *n = p->next; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci spin_unlock(&major_names_spinlock); 30162306a36Sopenharmony_ci mutex_unlock(&major_names_lock); 30262306a36Sopenharmony_ci kfree(p); 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ciEXPORT_SYMBOL(unregister_blkdev); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ciint blk_alloc_ext_minor(void) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci int idx; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci idx = ida_alloc_range(&ext_devt_ida, 0, NR_EXT_DEVT - 1, GFP_KERNEL); 31262306a36Sopenharmony_ci if (idx == -ENOSPC) 31362306a36Sopenharmony_ci return -EBUSY; 31462306a36Sopenharmony_ci return idx; 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_civoid blk_free_ext_minor(unsigned int minor) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci ida_free(&ext_devt_ida, minor); 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_civoid disk_uevent(struct gendisk *disk, enum kobject_action action) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct block_device *part; 32562306a36Sopenharmony_ci unsigned long idx; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci rcu_read_lock(); 32862306a36Sopenharmony_ci xa_for_each(&disk->part_tbl, idx, part) { 32962306a36Sopenharmony_ci if (bdev_is_partition(part) && !bdev_nr_sectors(part)) 33062306a36Sopenharmony_ci continue; 33162306a36Sopenharmony_ci if (!kobject_get_unless_zero(&part->bd_device.kobj)) 33262306a36Sopenharmony_ci continue; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci rcu_read_unlock(); 33562306a36Sopenharmony_ci kobject_uevent(bdev_kobj(part), action); 33662306a36Sopenharmony_ci put_device(&part->bd_device); 33762306a36Sopenharmony_ci rcu_read_lock(); 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci rcu_read_unlock(); 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(disk_uevent); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ciint disk_scan_partitions(struct gendisk *disk, blk_mode_t mode) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci struct block_device *bdev; 34662306a36Sopenharmony_ci int ret = 0; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (disk->flags & (GENHD_FL_NO_PART | GENHD_FL_HIDDEN)) 34962306a36Sopenharmony_ci return -EINVAL; 35062306a36Sopenharmony_ci if (test_bit(GD_SUPPRESS_PART_SCAN, &disk->state)) 35162306a36Sopenharmony_ci return -EINVAL; 35262306a36Sopenharmony_ci if (disk->open_partitions) 35362306a36Sopenharmony_ci return -EBUSY; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* 35662306a36Sopenharmony_ci * If the device is opened exclusively by current thread already, it's 35762306a36Sopenharmony_ci * safe to scan partitons, otherwise, use bd_prepare_to_claim() to 35862306a36Sopenharmony_ci * synchronize with other exclusive openers and other partition 35962306a36Sopenharmony_ci * scanners. 36062306a36Sopenharmony_ci */ 36162306a36Sopenharmony_ci if (!(mode & BLK_OPEN_EXCL)) { 36262306a36Sopenharmony_ci ret = bd_prepare_to_claim(disk->part0, disk_scan_partitions, 36362306a36Sopenharmony_ci NULL); 36462306a36Sopenharmony_ci if (ret) 36562306a36Sopenharmony_ci return ret; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci set_bit(GD_NEED_PART_SCAN, &disk->state); 36962306a36Sopenharmony_ci bdev = blkdev_get_by_dev(disk_devt(disk), mode & ~BLK_OPEN_EXCL, NULL, 37062306a36Sopenharmony_ci NULL); 37162306a36Sopenharmony_ci if (IS_ERR(bdev)) 37262306a36Sopenharmony_ci ret = PTR_ERR(bdev); 37362306a36Sopenharmony_ci else 37462306a36Sopenharmony_ci blkdev_put(bdev, NULL); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* 37762306a36Sopenharmony_ci * If blkdev_get_by_dev() failed early, GD_NEED_PART_SCAN is still set, 37862306a36Sopenharmony_ci * and this will cause that re-assemble partitioned raid device will 37962306a36Sopenharmony_ci * creat partition for underlying disk. 38062306a36Sopenharmony_ci */ 38162306a36Sopenharmony_ci clear_bit(GD_NEED_PART_SCAN, &disk->state); 38262306a36Sopenharmony_ci if (!(mode & BLK_OPEN_EXCL)) 38362306a36Sopenharmony_ci bd_abort_claiming(disk->part0, disk_scan_partitions); 38462306a36Sopenharmony_ci return ret; 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci/** 38862306a36Sopenharmony_ci * device_add_disk - add disk information to kernel list 38962306a36Sopenharmony_ci * @parent: parent device for the disk 39062306a36Sopenharmony_ci * @disk: per-device partitioning information 39162306a36Sopenharmony_ci * @groups: Additional per-device sysfs groups 39262306a36Sopenharmony_ci * 39362306a36Sopenharmony_ci * This function registers the partitioning information in @disk 39462306a36Sopenharmony_ci * with the kernel. 39562306a36Sopenharmony_ci */ 39662306a36Sopenharmony_ciint __must_check device_add_disk(struct device *parent, struct gendisk *disk, 39762306a36Sopenharmony_ci const struct attribute_group **groups) 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci struct device *ddev = disk_to_dev(disk); 40162306a36Sopenharmony_ci int ret; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* Only makes sense for bio-based to set ->poll_bio */ 40462306a36Sopenharmony_ci if (queue_is_mq(disk->queue) && disk->fops->poll_bio) 40562306a36Sopenharmony_ci return -EINVAL; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* 40862306a36Sopenharmony_ci * The disk queue should now be all set with enough information about 40962306a36Sopenharmony_ci * the device for the elevator code to pick an adequate default 41062306a36Sopenharmony_ci * elevator if one is needed, that is, for devices requesting queue 41162306a36Sopenharmony_ci * registration. 41262306a36Sopenharmony_ci */ 41362306a36Sopenharmony_ci elevator_init_mq(disk->queue); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* Mark bdev as having a submit_bio, if needed */ 41662306a36Sopenharmony_ci disk->part0->bd_has_submit_bio = disk->fops->submit_bio != NULL; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci /* 41962306a36Sopenharmony_ci * If the driver provides an explicit major number it also must provide 42062306a36Sopenharmony_ci * the number of minors numbers supported, and those will be used to 42162306a36Sopenharmony_ci * setup the gendisk. 42262306a36Sopenharmony_ci * Otherwise just allocate the device numbers for both the whole device 42362306a36Sopenharmony_ci * and all partitions from the extended dev_t space. 42462306a36Sopenharmony_ci */ 42562306a36Sopenharmony_ci ret = -EINVAL; 42662306a36Sopenharmony_ci if (disk->major) { 42762306a36Sopenharmony_ci if (WARN_ON(!disk->minors)) 42862306a36Sopenharmony_ci goto out_exit_elevator; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (disk->minors > DISK_MAX_PARTS) { 43162306a36Sopenharmony_ci pr_err("block: can't allocate more than %d partitions\n", 43262306a36Sopenharmony_ci DISK_MAX_PARTS); 43362306a36Sopenharmony_ci disk->minors = DISK_MAX_PARTS; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci if (disk->first_minor > MINORMASK || 43662306a36Sopenharmony_ci disk->minors > MINORMASK + 1 || 43762306a36Sopenharmony_ci disk->first_minor + disk->minors > MINORMASK + 1) 43862306a36Sopenharmony_ci goto out_exit_elevator; 43962306a36Sopenharmony_ci } else { 44062306a36Sopenharmony_ci if (WARN_ON(disk->minors)) 44162306a36Sopenharmony_ci goto out_exit_elevator; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci ret = blk_alloc_ext_minor(); 44462306a36Sopenharmony_ci if (ret < 0) 44562306a36Sopenharmony_ci goto out_exit_elevator; 44662306a36Sopenharmony_ci disk->major = BLOCK_EXT_MAJOR; 44762306a36Sopenharmony_ci disk->first_minor = ret; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci /* delay uevents, until we scanned partition table */ 45162306a36Sopenharmony_ci dev_set_uevent_suppress(ddev, 1); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci ddev->parent = parent; 45462306a36Sopenharmony_ci ddev->groups = groups; 45562306a36Sopenharmony_ci dev_set_name(ddev, "%s", disk->disk_name); 45662306a36Sopenharmony_ci if (!(disk->flags & GENHD_FL_HIDDEN)) 45762306a36Sopenharmony_ci ddev->devt = MKDEV(disk->major, disk->first_minor); 45862306a36Sopenharmony_ci ret = device_add(ddev); 45962306a36Sopenharmony_ci if (ret) 46062306a36Sopenharmony_ci goto out_free_ext_minor; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci ret = disk_alloc_events(disk); 46362306a36Sopenharmony_ci if (ret) 46462306a36Sopenharmony_ci goto out_device_del; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci ret = sysfs_create_link(block_depr, &ddev->kobj, 46762306a36Sopenharmony_ci kobject_name(&ddev->kobj)); 46862306a36Sopenharmony_ci if (ret) 46962306a36Sopenharmony_ci goto out_device_del; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci /* 47262306a36Sopenharmony_ci * avoid probable deadlock caused by allocating memory with 47362306a36Sopenharmony_ci * GFP_KERNEL in runtime_resume callback of its all ancestor 47462306a36Sopenharmony_ci * devices 47562306a36Sopenharmony_ci */ 47662306a36Sopenharmony_ci pm_runtime_set_memalloc_noio(ddev, true); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci disk->part0->bd_holder_dir = 47962306a36Sopenharmony_ci kobject_create_and_add("holders", &ddev->kobj); 48062306a36Sopenharmony_ci if (!disk->part0->bd_holder_dir) { 48162306a36Sopenharmony_ci ret = -ENOMEM; 48262306a36Sopenharmony_ci goto out_del_block_link; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj); 48562306a36Sopenharmony_ci if (!disk->slave_dir) { 48662306a36Sopenharmony_ci ret = -ENOMEM; 48762306a36Sopenharmony_ci goto out_put_holder_dir; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci ret = blk_register_queue(disk); 49162306a36Sopenharmony_ci if (ret) 49262306a36Sopenharmony_ci goto out_put_slave_dir; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (!(disk->flags & GENHD_FL_HIDDEN)) { 49562306a36Sopenharmony_ci ret = bdi_register(disk->bdi, "%u:%u", 49662306a36Sopenharmony_ci disk->major, disk->first_minor); 49762306a36Sopenharmony_ci if (ret) 49862306a36Sopenharmony_ci goto out_unregister_queue; 49962306a36Sopenharmony_ci bdi_set_owner(disk->bdi, ddev); 50062306a36Sopenharmony_ci ret = sysfs_create_link(&ddev->kobj, 50162306a36Sopenharmony_ci &disk->bdi->dev->kobj, "bdi"); 50262306a36Sopenharmony_ci if (ret) 50362306a36Sopenharmony_ci goto out_unregister_bdi; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* Make sure the first partition scan will be proceed */ 50662306a36Sopenharmony_ci if (get_capacity(disk) && !(disk->flags & GENHD_FL_NO_PART) && 50762306a36Sopenharmony_ci !test_bit(GD_SUPPRESS_PART_SCAN, &disk->state)) 50862306a36Sopenharmony_ci set_bit(GD_NEED_PART_SCAN, &disk->state); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci bdev_add(disk->part0, ddev->devt); 51162306a36Sopenharmony_ci if (get_capacity(disk)) 51262306a36Sopenharmony_ci disk_scan_partitions(disk, BLK_OPEN_READ); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* 51562306a36Sopenharmony_ci * Announce the disk and partitions after all partitions are 51662306a36Sopenharmony_ci * created. (for hidden disks uevents remain suppressed forever) 51762306a36Sopenharmony_ci */ 51862306a36Sopenharmony_ci dev_set_uevent_suppress(ddev, 0); 51962306a36Sopenharmony_ci disk_uevent(disk, KOBJ_ADD); 52062306a36Sopenharmony_ci } else { 52162306a36Sopenharmony_ci /* 52262306a36Sopenharmony_ci * Even if the block_device for a hidden gendisk is not 52362306a36Sopenharmony_ci * registered, it needs to have a valid bd_dev so that the 52462306a36Sopenharmony_ci * freeing of the dynamic major works. 52562306a36Sopenharmony_ci */ 52662306a36Sopenharmony_ci disk->part0->bd_dev = MKDEV(disk->major, disk->first_minor); 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci disk_update_readahead(disk); 53062306a36Sopenharmony_ci disk_add_events(disk); 53162306a36Sopenharmony_ci set_bit(GD_ADDED, &disk->state); 53262306a36Sopenharmony_ci return 0; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ciout_unregister_bdi: 53562306a36Sopenharmony_ci if (!(disk->flags & GENHD_FL_HIDDEN)) 53662306a36Sopenharmony_ci bdi_unregister(disk->bdi); 53762306a36Sopenharmony_ciout_unregister_queue: 53862306a36Sopenharmony_ci blk_unregister_queue(disk); 53962306a36Sopenharmony_ci rq_qos_exit(disk->queue); 54062306a36Sopenharmony_ciout_put_slave_dir: 54162306a36Sopenharmony_ci kobject_put(disk->slave_dir); 54262306a36Sopenharmony_ci disk->slave_dir = NULL; 54362306a36Sopenharmony_ciout_put_holder_dir: 54462306a36Sopenharmony_ci kobject_put(disk->part0->bd_holder_dir); 54562306a36Sopenharmony_ciout_del_block_link: 54662306a36Sopenharmony_ci sysfs_remove_link(block_depr, dev_name(ddev)); 54762306a36Sopenharmony_ci pm_runtime_set_memalloc_noio(ddev, false); 54862306a36Sopenharmony_ciout_device_del: 54962306a36Sopenharmony_ci device_del(ddev); 55062306a36Sopenharmony_ciout_free_ext_minor: 55162306a36Sopenharmony_ci if (disk->major == BLOCK_EXT_MAJOR) 55262306a36Sopenharmony_ci blk_free_ext_minor(disk->first_minor); 55362306a36Sopenharmony_ciout_exit_elevator: 55462306a36Sopenharmony_ci if (disk->queue->elevator) 55562306a36Sopenharmony_ci elevator_exit(disk->queue); 55662306a36Sopenharmony_ci return ret; 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ciEXPORT_SYMBOL(device_add_disk); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_cistatic void blk_report_disk_dead(struct gendisk *disk, bool surprise) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci struct block_device *bdev; 56362306a36Sopenharmony_ci unsigned long idx; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci rcu_read_lock(); 56662306a36Sopenharmony_ci xa_for_each(&disk->part_tbl, idx, bdev) { 56762306a36Sopenharmony_ci if (!kobject_get_unless_zero(&bdev->bd_device.kobj)) 56862306a36Sopenharmony_ci continue; 56962306a36Sopenharmony_ci rcu_read_unlock(); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci bdev_mark_dead(bdev, surprise); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci put_device(&bdev->bd_device); 57462306a36Sopenharmony_ci rcu_read_lock(); 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci rcu_read_unlock(); 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_cistatic void __blk_mark_disk_dead(struct gendisk *disk) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci /* 58262306a36Sopenharmony_ci * Fail any new I/O. 58362306a36Sopenharmony_ci */ 58462306a36Sopenharmony_ci if (test_and_set_bit(GD_DEAD, &disk->state)) 58562306a36Sopenharmony_ci return; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (test_bit(GD_OWNS_QUEUE, &disk->state)) 58862306a36Sopenharmony_ci blk_queue_flag_set(QUEUE_FLAG_DYING, disk->queue); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci /* 59162306a36Sopenharmony_ci * Stop buffered writers from dirtying pages that can't be written out. 59262306a36Sopenharmony_ci */ 59362306a36Sopenharmony_ci set_capacity(disk, 0); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci /* 59662306a36Sopenharmony_ci * Prevent new I/O from crossing bio_queue_enter(). 59762306a36Sopenharmony_ci */ 59862306a36Sopenharmony_ci blk_queue_start_drain(disk->queue); 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci/** 60262306a36Sopenharmony_ci * blk_mark_disk_dead - mark a disk as dead 60362306a36Sopenharmony_ci * @disk: disk to mark as dead 60462306a36Sopenharmony_ci * 60562306a36Sopenharmony_ci * Mark as disk as dead (e.g. surprise removed) and don't accept any new I/O 60662306a36Sopenharmony_ci * to this disk. 60762306a36Sopenharmony_ci */ 60862306a36Sopenharmony_civoid blk_mark_disk_dead(struct gendisk *disk) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci __blk_mark_disk_dead(disk); 61162306a36Sopenharmony_ci blk_report_disk_dead(disk, true); 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(blk_mark_disk_dead); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci/** 61662306a36Sopenharmony_ci * del_gendisk - remove the gendisk 61762306a36Sopenharmony_ci * @disk: the struct gendisk to remove 61862306a36Sopenharmony_ci * 61962306a36Sopenharmony_ci * Removes the gendisk and all its associated resources. This deletes the 62062306a36Sopenharmony_ci * partitions associated with the gendisk, and unregisters the associated 62162306a36Sopenharmony_ci * request_queue. 62262306a36Sopenharmony_ci * 62362306a36Sopenharmony_ci * This is the counter to the respective __device_add_disk() call. 62462306a36Sopenharmony_ci * 62562306a36Sopenharmony_ci * The final removal of the struct gendisk happens when its refcount reaches 0 62662306a36Sopenharmony_ci * with put_disk(), which should be called after del_gendisk(), if 62762306a36Sopenharmony_ci * __device_add_disk() was used. 62862306a36Sopenharmony_ci * 62962306a36Sopenharmony_ci * Drivers exist which depend on the release of the gendisk to be synchronous, 63062306a36Sopenharmony_ci * it should not be deferred. 63162306a36Sopenharmony_ci * 63262306a36Sopenharmony_ci * Context: can sleep 63362306a36Sopenharmony_ci */ 63462306a36Sopenharmony_civoid del_gendisk(struct gendisk *disk) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci struct request_queue *q = disk->queue; 63762306a36Sopenharmony_ci struct block_device *part; 63862306a36Sopenharmony_ci unsigned long idx; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci might_sleep(); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci if (WARN_ON_ONCE(!disk_live(disk) && !(disk->flags & GENHD_FL_HIDDEN))) 64362306a36Sopenharmony_ci return; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci disk_del_events(disk); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci /* 64862306a36Sopenharmony_ci * Prevent new openers by unlinked the bdev inode. 64962306a36Sopenharmony_ci */ 65062306a36Sopenharmony_ci mutex_lock(&disk->open_mutex); 65162306a36Sopenharmony_ci xa_for_each(&disk->part_tbl, idx, part) 65262306a36Sopenharmony_ci remove_inode_hash(part->bd_inode); 65362306a36Sopenharmony_ci mutex_unlock(&disk->open_mutex); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci /* 65662306a36Sopenharmony_ci * Tell the file system to write back all dirty data and shut down if 65762306a36Sopenharmony_ci * it hasn't been notified earlier. 65862306a36Sopenharmony_ci */ 65962306a36Sopenharmony_ci if (!test_bit(GD_DEAD, &disk->state)) 66062306a36Sopenharmony_ci blk_report_disk_dead(disk, false); 66162306a36Sopenharmony_ci __blk_mark_disk_dead(disk); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* 66462306a36Sopenharmony_ci * Drop all partitions now that the disk is marked dead. 66562306a36Sopenharmony_ci */ 66662306a36Sopenharmony_ci mutex_lock(&disk->open_mutex); 66762306a36Sopenharmony_ci xa_for_each_start(&disk->part_tbl, idx, part, 1) 66862306a36Sopenharmony_ci drop_partition(part); 66962306a36Sopenharmony_ci mutex_unlock(&disk->open_mutex); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci if (!(disk->flags & GENHD_FL_HIDDEN)) { 67262306a36Sopenharmony_ci sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi"); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci /* 67562306a36Sopenharmony_ci * Unregister bdi before releasing device numbers (as they can 67662306a36Sopenharmony_ci * get reused and we'd get clashes in sysfs). 67762306a36Sopenharmony_ci */ 67862306a36Sopenharmony_ci bdi_unregister(disk->bdi); 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci blk_unregister_queue(disk); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci kobject_put(disk->part0->bd_holder_dir); 68462306a36Sopenharmony_ci kobject_put(disk->slave_dir); 68562306a36Sopenharmony_ci disk->slave_dir = NULL; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci part_stat_set_all(disk->part0, 0); 68862306a36Sopenharmony_ci disk->part0->bd_stamp = 0; 68962306a36Sopenharmony_ci sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk))); 69062306a36Sopenharmony_ci pm_runtime_set_memalloc_noio(disk_to_dev(disk), false); 69162306a36Sopenharmony_ci device_del(disk_to_dev(disk)); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci blk_mq_freeze_queue_wait(q); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci blk_throtl_cancel_bios(disk); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci blk_sync_queue(q); 69862306a36Sopenharmony_ci blk_flush_integrity(); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci if (queue_is_mq(q)) 70162306a36Sopenharmony_ci blk_mq_cancel_work_sync(q); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci blk_mq_quiesce_queue(q); 70462306a36Sopenharmony_ci if (q->elevator) { 70562306a36Sopenharmony_ci mutex_lock(&q->sysfs_lock); 70662306a36Sopenharmony_ci elevator_exit(q); 70762306a36Sopenharmony_ci mutex_unlock(&q->sysfs_lock); 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci rq_qos_exit(q); 71062306a36Sopenharmony_ci blk_mq_unquiesce_queue(q); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci /* 71362306a36Sopenharmony_ci * If the disk does not own the queue, allow using passthrough requests 71462306a36Sopenharmony_ci * again. Else leave the queue frozen to fail all I/O. 71562306a36Sopenharmony_ci */ 71662306a36Sopenharmony_ci if (!test_bit(GD_OWNS_QUEUE, &disk->state)) { 71762306a36Sopenharmony_ci blk_queue_flag_clear(QUEUE_FLAG_INIT_DONE, q); 71862306a36Sopenharmony_ci __blk_mq_unfreeze_queue(q, true); 71962306a36Sopenharmony_ci } else { 72062306a36Sopenharmony_ci if (queue_is_mq(q)) 72162306a36Sopenharmony_ci blk_mq_exit_queue(q); 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ciEXPORT_SYMBOL(del_gendisk); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci/** 72762306a36Sopenharmony_ci * invalidate_disk - invalidate the disk 72862306a36Sopenharmony_ci * @disk: the struct gendisk to invalidate 72962306a36Sopenharmony_ci * 73062306a36Sopenharmony_ci * A helper to invalidates the disk. It will clean the disk's associated 73162306a36Sopenharmony_ci * buffer/page caches and reset its internal states so that the disk 73262306a36Sopenharmony_ci * can be reused by the drivers. 73362306a36Sopenharmony_ci * 73462306a36Sopenharmony_ci * Context: can sleep 73562306a36Sopenharmony_ci */ 73662306a36Sopenharmony_civoid invalidate_disk(struct gendisk *disk) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci struct block_device *bdev = disk->part0; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci invalidate_bdev(bdev); 74162306a36Sopenharmony_ci bdev->bd_inode->i_mapping->wb_err = 0; 74262306a36Sopenharmony_ci set_capacity(disk, 0); 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ciEXPORT_SYMBOL(invalidate_disk); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci/* sysfs access to bad-blocks list. */ 74762306a36Sopenharmony_cistatic ssize_t disk_badblocks_show(struct device *dev, 74862306a36Sopenharmony_ci struct device_attribute *attr, 74962306a36Sopenharmony_ci char *page) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci struct gendisk *disk = dev_to_disk(dev); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci if (!disk->bb) 75462306a36Sopenharmony_ci return sprintf(page, "\n"); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci return badblocks_show(disk->bb, page, 0); 75762306a36Sopenharmony_ci} 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_cistatic ssize_t disk_badblocks_store(struct device *dev, 76062306a36Sopenharmony_ci struct device_attribute *attr, 76162306a36Sopenharmony_ci const char *page, size_t len) 76262306a36Sopenharmony_ci{ 76362306a36Sopenharmony_ci struct gendisk *disk = dev_to_disk(dev); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci if (!disk->bb) 76662306a36Sopenharmony_ci return -ENXIO; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci return badblocks_store(disk->bb, page, len, 0); 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci#ifdef CONFIG_BLOCK_LEGACY_AUTOLOAD 77262306a36Sopenharmony_civoid blk_request_module(dev_t devt) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci unsigned int major = MAJOR(devt); 77562306a36Sopenharmony_ci struct blk_major_name **n; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci mutex_lock(&major_names_lock); 77862306a36Sopenharmony_ci for (n = &major_names[major_to_index(major)]; *n; n = &(*n)->next) { 77962306a36Sopenharmony_ci if ((*n)->major == major && (*n)->probe) { 78062306a36Sopenharmony_ci (*n)->probe(devt); 78162306a36Sopenharmony_ci mutex_unlock(&major_names_lock); 78262306a36Sopenharmony_ci return; 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci mutex_unlock(&major_names_lock); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0) 78862306a36Sopenharmony_ci /* Make old-style 2.4 aliases work */ 78962306a36Sopenharmony_ci request_module("block-major-%d", MAJOR(devt)); 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci#endif /* CONFIG_BLOCK_LEGACY_AUTOLOAD */ 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 79462306a36Sopenharmony_ci/* iterator */ 79562306a36Sopenharmony_cistatic void *disk_seqf_start(struct seq_file *seqf, loff_t *pos) 79662306a36Sopenharmony_ci{ 79762306a36Sopenharmony_ci loff_t skip = *pos; 79862306a36Sopenharmony_ci struct class_dev_iter *iter; 79962306a36Sopenharmony_ci struct device *dev; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci iter = kmalloc(sizeof(*iter), GFP_KERNEL); 80262306a36Sopenharmony_ci if (!iter) 80362306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci seqf->private = iter; 80662306a36Sopenharmony_ci class_dev_iter_init(iter, &block_class, NULL, &disk_type); 80762306a36Sopenharmony_ci do { 80862306a36Sopenharmony_ci dev = class_dev_iter_next(iter); 80962306a36Sopenharmony_ci if (!dev) 81062306a36Sopenharmony_ci return NULL; 81162306a36Sopenharmony_ci } while (skip--); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci return dev_to_disk(dev); 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_cistatic void *disk_seqf_next(struct seq_file *seqf, void *v, loff_t *pos) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci struct device *dev; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci (*pos)++; 82162306a36Sopenharmony_ci dev = class_dev_iter_next(seqf->private); 82262306a36Sopenharmony_ci if (dev) 82362306a36Sopenharmony_ci return dev_to_disk(dev); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci return NULL; 82662306a36Sopenharmony_ci} 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_cistatic void disk_seqf_stop(struct seq_file *seqf, void *v) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci struct class_dev_iter *iter = seqf->private; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci /* stop is called even after start failed :-( */ 83362306a36Sopenharmony_ci if (iter) { 83462306a36Sopenharmony_ci class_dev_iter_exit(iter); 83562306a36Sopenharmony_ci kfree(iter); 83662306a36Sopenharmony_ci seqf->private = NULL; 83762306a36Sopenharmony_ci } 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_cistatic void *show_partition_start(struct seq_file *seqf, loff_t *pos) 84162306a36Sopenharmony_ci{ 84262306a36Sopenharmony_ci void *p; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci p = disk_seqf_start(seqf, pos); 84562306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(p) && !*pos) 84662306a36Sopenharmony_ci seq_puts(seqf, "major minor #blocks name\n\n"); 84762306a36Sopenharmony_ci return p; 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cistatic int show_partition(struct seq_file *seqf, void *v) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci struct gendisk *sgp = v; 85362306a36Sopenharmony_ci struct block_device *part; 85462306a36Sopenharmony_ci unsigned long idx; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci if (!get_capacity(sgp) || (sgp->flags & GENHD_FL_HIDDEN)) 85762306a36Sopenharmony_ci return 0; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci rcu_read_lock(); 86062306a36Sopenharmony_ci xa_for_each(&sgp->part_tbl, idx, part) { 86162306a36Sopenharmony_ci if (!bdev_nr_sectors(part)) 86262306a36Sopenharmony_ci continue; 86362306a36Sopenharmony_ci seq_printf(seqf, "%4d %7d %10llu %pg\n", 86462306a36Sopenharmony_ci MAJOR(part->bd_dev), MINOR(part->bd_dev), 86562306a36Sopenharmony_ci bdev_nr_sectors(part) >> 1, part); 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci rcu_read_unlock(); 86862306a36Sopenharmony_ci return 0; 86962306a36Sopenharmony_ci} 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_cistatic const struct seq_operations partitions_op = { 87262306a36Sopenharmony_ci .start = show_partition_start, 87362306a36Sopenharmony_ci .next = disk_seqf_next, 87462306a36Sopenharmony_ci .stop = disk_seqf_stop, 87562306a36Sopenharmony_ci .show = show_partition 87662306a36Sopenharmony_ci}; 87762306a36Sopenharmony_ci#endif 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_cistatic int __init genhd_device_init(void) 88062306a36Sopenharmony_ci{ 88162306a36Sopenharmony_ci int error; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci error = class_register(&block_class); 88462306a36Sopenharmony_ci if (unlikely(error)) 88562306a36Sopenharmony_ci return error; 88662306a36Sopenharmony_ci blk_dev_init(); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci register_blkdev(BLOCK_EXT_MAJOR, "blkext"); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci /* create top-level block dir */ 89162306a36Sopenharmony_ci block_depr = kobject_create_and_add("block", NULL); 89262306a36Sopenharmony_ci return 0; 89362306a36Sopenharmony_ci} 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_cisubsys_initcall(genhd_device_init); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_cistatic ssize_t disk_range_show(struct device *dev, 89862306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci struct gendisk *disk = dev_to_disk(dev); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci return sprintf(buf, "%d\n", disk->minors); 90362306a36Sopenharmony_ci} 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_cistatic ssize_t disk_ext_range_show(struct device *dev, 90662306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 90762306a36Sopenharmony_ci{ 90862306a36Sopenharmony_ci struct gendisk *disk = dev_to_disk(dev); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci return sprintf(buf, "%d\n", 91162306a36Sopenharmony_ci (disk->flags & GENHD_FL_NO_PART) ? 1 : DISK_MAX_PARTS); 91262306a36Sopenharmony_ci} 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_cistatic ssize_t disk_removable_show(struct device *dev, 91562306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 91662306a36Sopenharmony_ci{ 91762306a36Sopenharmony_ci struct gendisk *disk = dev_to_disk(dev); 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci return sprintf(buf, "%d\n", 92062306a36Sopenharmony_ci (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0)); 92162306a36Sopenharmony_ci} 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_cistatic ssize_t disk_hidden_show(struct device *dev, 92462306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 92562306a36Sopenharmony_ci{ 92662306a36Sopenharmony_ci struct gendisk *disk = dev_to_disk(dev); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci return sprintf(buf, "%d\n", 92962306a36Sopenharmony_ci (disk->flags & GENHD_FL_HIDDEN ? 1 : 0)); 93062306a36Sopenharmony_ci} 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_cistatic ssize_t disk_ro_show(struct device *dev, 93362306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 93462306a36Sopenharmony_ci{ 93562306a36Sopenharmony_ci struct gendisk *disk = dev_to_disk(dev); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci return sprintf(buf, "%d\n", get_disk_ro(disk) ? 1 : 0); 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cissize_t part_size_show(struct device *dev, 94162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci return sprintf(buf, "%llu\n", bdev_nr_sectors(dev_to_bdev(dev))); 94462306a36Sopenharmony_ci} 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_cissize_t part_stat_show(struct device *dev, 94762306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 94862306a36Sopenharmony_ci{ 94962306a36Sopenharmony_ci struct block_device *bdev = dev_to_bdev(dev); 95062306a36Sopenharmony_ci struct request_queue *q = bdev_get_queue(bdev); 95162306a36Sopenharmony_ci struct disk_stats stat; 95262306a36Sopenharmony_ci unsigned int inflight; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci if (queue_is_mq(q)) 95562306a36Sopenharmony_ci inflight = blk_mq_in_flight(q, bdev); 95662306a36Sopenharmony_ci else 95762306a36Sopenharmony_ci inflight = part_in_flight(bdev); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci if (inflight) { 96062306a36Sopenharmony_ci part_stat_lock(); 96162306a36Sopenharmony_ci update_io_ticks(bdev, jiffies, true); 96262306a36Sopenharmony_ci part_stat_unlock(); 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci part_stat_read_all(bdev, &stat); 96562306a36Sopenharmony_ci return sprintf(buf, 96662306a36Sopenharmony_ci "%8lu %8lu %8llu %8u " 96762306a36Sopenharmony_ci "%8lu %8lu %8llu %8u " 96862306a36Sopenharmony_ci "%8u %8u %8u " 96962306a36Sopenharmony_ci "%8lu %8lu %8llu %8u " 97062306a36Sopenharmony_ci "%8lu %8u" 97162306a36Sopenharmony_ci "\n", 97262306a36Sopenharmony_ci stat.ios[STAT_READ], 97362306a36Sopenharmony_ci stat.merges[STAT_READ], 97462306a36Sopenharmony_ci (unsigned long long)stat.sectors[STAT_READ], 97562306a36Sopenharmony_ci (unsigned int)div_u64(stat.nsecs[STAT_READ], NSEC_PER_MSEC), 97662306a36Sopenharmony_ci stat.ios[STAT_WRITE], 97762306a36Sopenharmony_ci stat.merges[STAT_WRITE], 97862306a36Sopenharmony_ci (unsigned long long)stat.sectors[STAT_WRITE], 97962306a36Sopenharmony_ci (unsigned int)div_u64(stat.nsecs[STAT_WRITE], NSEC_PER_MSEC), 98062306a36Sopenharmony_ci inflight, 98162306a36Sopenharmony_ci jiffies_to_msecs(stat.io_ticks), 98262306a36Sopenharmony_ci (unsigned int)div_u64(stat.nsecs[STAT_READ] + 98362306a36Sopenharmony_ci stat.nsecs[STAT_WRITE] + 98462306a36Sopenharmony_ci stat.nsecs[STAT_DISCARD] + 98562306a36Sopenharmony_ci stat.nsecs[STAT_FLUSH], 98662306a36Sopenharmony_ci NSEC_PER_MSEC), 98762306a36Sopenharmony_ci stat.ios[STAT_DISCARD], 98862306a36Sopenharmony_ci stat.merges[STAT_DISCARD], 98962306a36Sopenharmony_ci (unsigned long long)stat.sectors[STAT_DISCARD], 99062306a36Sopenharmony_ci (unsigned int)div_u64(stat.nsecs[STAT_DISCARD], NSEC_PER_MSEC), 99162306a36Sopenharmony_ci stat.ios[STAT_FLUSH], 99262306a36Sopenharmony_ci (unsigned int)div_u64(stat.nsecs[STAT_FLUSH], NSEC_PER_MSEC)); 99362306a36Sopenharmony_ci} 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_cissize_t part_inflight_show(struct device *dev, struct device_attribute *attr, 99662306a36Sopenharmony_ci char *buf) 99762306a36Sopenharmony_ci{ 99862306a36Sopenharmony_ci struct block_device *bdev = dev_to_bdev(dev); 99962306a36Sopenharmony_ci struct request_queue *q = bdev_get_queue(bdev); 100062306a36Sopenharmony_ci unsigned int inflight[2]; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci if (queue_is_mq(q)) 100362306a36Sopenharmony_ci blk_mq_in_flight_rw(q, bdev, inflight); 100462306a36Sopenharmony_ci else 100562306a36Sopenharmony_ci part_in_flight_rw(bdev, inflight); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci return sprintf(buf, "%8u %8u\n", inflight[0], inflight[1]); 100862306a36Sopenharmony_ci} 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_cistatic ssize_t disk_capability_show(struct device *dev, 101162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 101262306a36Sopenharmony_ci{ 101362306a36Sopenharmony_ci dev_warn_once(dev, "the capability attribute has been deprecated.\n"); 101462306a36Sopenharmony_ci return sprintf(buf, "0\n"); 101562306a36Sopenharmony_ci} 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_cistatic ssize_t disk_alignment_offset_show(struct device *dev, 101862306a36Sopenharmony_ci struct device_attribute *attr, 101962306a36Sopenharmony_ci char *buf) 102062306a36Sopenharmony_ci{ 102162306a36Sopenharmony_ci struct gendisk *disk = dev_to_disk(dev); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci return sprintf(buf, "%d\n", bdev_alignment_offset(disk->part0)); 102462306a36Sopenharmony_ci} 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_cistatic ssize_t disk_discard_alignment_show(struct device *dev, 102762306a36Sopenharmony_ci struct device_attribute *attr, 102862306a36Sopenharmony_ci char *buf) 102962306a36Sopenharmony_ci{ 103062306a36Sopenharmony_ci struct gendisk *disk = dev_to_disk(dev); 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci return sprintf(buf, "%d\n", bdev_alignment_offset(disk->part0)); 103362306a36Sopenharmony_ci} 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_cistatic ssize_t diskseq_show(struct device *dev, 103662306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 103762306a36Sopenharmony_ci{ 103862306a36Sopenharmony_ci struct gendisk *disk = dev_to_disk(dev); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci return sprintf(buf, "%llu\n", disk->diskseq); 104162306a36Sopenharmony_ci} 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_cistatic DEVICE_ATTR(range, 0444, disk_range_show, NULL); 104462306a36Sopenharmony_cistatic DEVICE_ATTR(ext_range, 0444, disk_ext_range_show, NULL); 104562306a36Sopenharmony_cistatic DEVICE_ATTR(removable, 0444, disk_removable_show, NULL); 104662306a36Sopenharmony_cistatic DEVICE_ATTR(hidden, 0444, disk_hidden_show, NULL); 104762306a36Sopenharmony_cistatic DEVICE_ATTR(ro, 0444, disk_ro_show, NULL); 104862306a36Sopenharmony_cistatic DEVICE_ATTR(size, 0444, part_size_show, NULL); 104962306a36Sopenharmony_cistatic DEVICE_ATTR(alignment_offset, 0444, disk_alignment_offset_show, NULL); 105062306a36Sopenharmony_cistatic DEVICE_ATTR(discard_alignment, 0444, disk_discard_alignment_show, NULL); 105162306a36Sopenharmony_cistatic DEVICE_ATTR(capability, 0444, disk_capability_show, NULL); 105262306a36Sopenharmony_cistatic DEVICE_ATTR(stat, 0444, part_stat_show, NULL); 105362306a36Sopenharmony_cistatic DEVICE_ATTR(inflight, 0444, part_inflight_show, NULL); 105462306a36Sopenharmony_cistatic DEVICE_ATTR(badblocks, 0644, disk_badblocks_show, disk_badblocks_store); 105562306a36Sopenharmony_cistatic DEVICE_ATTR(diskseq, 0444, diskseq_show, NULL); 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci#ifdef CONFIG_FAIL_MAKE_REQUEST 105862306a36Sopenharmony_cissize_t part_fail_show(struct device *dev, 105962306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 106062306a36Sopenharmony_ci{ 106162306a36Sopenharmony_ci return sprintf(buf, "%d\n", dev_to_bdev(dev)->bd_make_it_fail); 106262306a36Sopenharmony_ci} 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_cissize_t part_fail_store(struct device *dev, 106562306a36Sopenharmony_ci struct device_attribute *attr, 106662306a36Sopenharmony_ci const char *buf, size_t count) 106762306a36Sopenharmony_ci{ 106862306a36Sopenharmony_ci int i; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci if (count > 0 && sscanf(buf, "%d", &i) > 0) 107162306a36Sopenharmony_ci dev_to_bdev(dev)->bd_make_it_fail = i; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci return count; 107462306a36Sopenharmony_ci} 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_cistatic struct device_attribute dev_attr_fail = 107762306a36Sopenharmony_ci __ATTR(make-it-fail, 0644, part_fail_show, part_fail_store); 107862306a36Sopenharmony_ci#endif /* CONFIG_FAIL_MAKE_REQUEST */ 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci#ifdef CONFIG_FAIL_IO_TIMEOUT 108162306a36Sopenharmony_cistatic struct device_attribute dev_attr_fail_timeout = 108262306a36Sopenharmony_ci __ATTR(io-timeout-fail, 0644, part_timeout_show, part_timeout_store); 108362306a36Sopenharmony_ci#endif 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_cistatic struct attribute *disk_attrs[] = { 108662306a36Sopenharmony_ci &dev_attr_range.attr, 108762306a36Sopenharmony_ci &dev_attr_ext_range.attr, 108862306a36Sopenharmony_ci &dev_attr_removable.attr, 108962306a36Sopenharmony_ci &dev_attr_hidden.attr, 109062306a36Sopenharmony_ci &dev_attr_ro.attr, 109162306a36Sopenharmony_ci &dev_attr_size.attr, 109262306a36Sopenharmony_ci &dev_attr_alignment_offset.attr, 109362306a36Sopenharmony_ci &dev_attr_discard_alignment.attr, 109462306a36Sopenharmony_ci &dev_attr_capability.attr, 109562306a36Sopenharmony_ci &dev_attr_stat.attr, 109662306a36Sopenharmony_ci &dev_attr_inflight.attr, 109762306a36Sopenharmony_ci &dev_attr_badblocks.attr, 109862306a36Sopenharmony_ci &dev_attr_events.attr, 109962306a36Sopenharmony_ci &dev_attr_events_async.attr, 110062306a36Sopenharmony_ci &dev_attr_events_poll_msecs.attr, 110162306a36Sopenharmony_ci &dev_attr_diskseq.attr, 110262306a36Sopenharmony_ci#ifdef CONFIG_FAIL_MAKE_REQUEST 110362306a36Sopenharmony_ci &dev_attr_fail.attr, 110462306a36Sopenharmony_ci#endif 110562306a36Sopenharmony_ci#ifdef CONFIG_FAIL_IO_TIMEOUT 110662306a36Sopenharmony_ci &dev_attr_fail_timeout.attr, 110762306a36Sopenharmony_ci#endif 110862306a36Sopenharmony_ci NULL 110962306a36Sopenharmony_ci}; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_cistatic umode_t disk_visible(struct kobject *kobj, struct attribute *a, int n) 111262306a36Sopenharmony_ci{ 111362306a36Sopenharmony_ci struct device *dev = container_of(kobj, typeof(*dev), kobj); 111462306a36Sopenharmony_ci struct gendisk *disk = dev_to_disk(dev); 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci if (a == &dev_attr_badblocks.attr && !disk->bb) 111762306a36Sopenharmony_ci return 0; 111862306a36Sopenharmony_ci return a->mode; 111962306a36Sopenharmony_ci} 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_cistatic struct attribute_group disk_attr_group = { 112262306a36Sopenharmony_ci .attrs = disk_attrs, 112362306a36Sopenharmony_ci .is_visible = disk_visible, 112462306a36Sopenharmony_ci}; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_cistatic const struct attribute_group *disk_attr_groups[] = { 112762306a36Sopenharmony_ci &disk_attr_group, 112862306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_IO_TRACE 112962306a36Sopenharmony_ci &blk_trace_attr_group, 113062306a36Sopenharmony_ci#endif 113162306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_INTEGRITY 113262306a36Sopenharmony_ci &blk_integrity_attr_group, 113362306a36Sopenharmony_ci#endif 113462306a36Sopenharmony_ci NULL 113562306a36Sopenharmony_ci}; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci/** 113862306a36Sopenharmony_ci * disk_release - releases all allocated resources of the gendisk 113962306a36Sopenharmony_ci * @dev: the device representing this disk 114062306a36Sopenharmony_ci * 114162306a36Sopenharmony_ci * This function releases all allocated resources of the gendisk. 114262306a36Sopenharmony_ci * 114362306a36Sopenharmony_ci * Drivers which used __device_add_disk() have a gendisk with a request_queue 114462306a36Sopenharmony_ci * assigned. Since the request_queue sits on top of the gendisk for these 114562306a36Sopenharmony_ci * drivers we also call blk_put_queue() for them, and we expect the 114662306a36Sopenharmony_ci * request_queue refcount to reach 0 at this point, and so the request_queue 114762306a36Sopenharmony_ci * will also be freed prior to the disk. 114862306a36Sopenharmony_ci * 114962306a36Sopenharmony_ci * Context: can sleep 115062306a36Sopenharmony_ci */ 115162306a36Sopenharmony_cistatic void disk_release(struct device *dev) 115262306a36Sopenharmony_ci{ 115362306a36Sopenharmony_ci struct gendisk *disk = dev_to_disk(dev); 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci might_sleep(); 115662306a36Sopenharmony_ci WARN_ON_ONCE(disk_live(disk)); 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci blk_trace_remove(disk->queue); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci /* 116162306a36Sopenharmony_ci * To undo the all initialization from blk_mq_init_allocated_queue in 116262306a36Sopenharmony_ci * case of a probe failure where add_disk is never called we have to 116362306a36Sopenharmony_ci * call blk_mq_exit_queue here. We can't do this for the more common 116462306a36Sopenharmony_ci * teardown case (yet) as the tagset can be gone by the time the disk 116562306a36Sopenharmony_ci * is released once it was added. 116662306a36Sopenharmony_ci */ 116762306a36Sopenharmony_ci if (queue_is_mq(disk->queue) && 116862306a36Sopenharmony_ci test_bit(GD_OWNS_QUEUE, &disk->state) && 116962306a36Sopenharmony_ci !test_bit(GD_ADDED, &disk->state)) 117062306a36Sopenharmony_ci blk_mq_exit_queue(disk->queue); 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci blkcg_exit_disk(disk); 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci bioset_exit(&disk->bio_split); 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci disk_release_events(disk); 117762306a36Sopenharmony_ci kfree(disk->random); 117862306a36Sopenharmony_ci disk_free_zone_bitmaps(disk); 117962306a36Sopenharmony_ci xa_destroy(&disk->part_tbl); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci disk->queue->disk = NULL; 118262306a36Sopenharmony_ci blk_put_queue(disk->queue); 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci if (test_bit(GD_ADDED, &disk->state) && disk->fops->free_disk) 118562306a36Sopenharmony_ci disk->fops->free_disk(disk); 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci iput(disk->part0->bd_inode); /* frees the disk */ 118862306a36Sopenharmony_ci} 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_cistatic int block_uevent(const struct device *dev, struct kobj_uevent_env *env) 119162306a36Sopenharmony_ci{ 119262306a36Sopenharmony_ci const struct gendisk *disk = dev_to_disk(dev); 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci return add_uevent_var(env, "DISKSEQ=%llu", disk->diskseq); 119562306a36Sopenharmony_ci} 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_cistruct class block_class = { 119862306a36Sopenharmony_ci .name = "block", 119962306a36Sopenharmony_ci .dev_uevent = block_uevent, 120062306a36Sopenharmony_ci}; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_cistatic char *block_devnode(const struct device *dev, umode_t *mode, 120362306a36Sopenharmony_ci kuid_t *uid, kgid_t *gid) 120462306a36Sopenharmony_ci{ 120562306a36Sopenharmony_ci struct gendisk *disk = dev_to_disk(dev); 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci if (disk->fops->devnode) 120862306a36Sopenharmony_ci return disk->fops->devnode(disk, mode); 120962306a36Sopenharmony_ci return NULL; 121062306a36Sopenharmony_ci} 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ciconst struct device_type disk_type = { 121362306a36Sopenharmony_ci .name = "disk", 121462306a36Sopenharmony_ci .groups = disk_attr_groups, 121562306a36Sopenharmony_ci .release = disk_release, 121662306a36Sopenharmony_ci .devnode = block_devnode, 121762306a36Sopenharmony_ci}; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 122062306a36Sopenharmony_ci/* 122162306a36Sopenharmony_ci * aggregate disk stat collector. Uses the same stats that the sysfs 122262306a36Sopenharmony_ci * entries do, above, but makes them available through one seq_file. 122362306a36Sopenharmony_ci * 122462306a36Sopenharmony_ci * The output looks suspiciously like /proc/partitions with a bunch of 122562306a36Sopenharmony_ci * extra fields. 122662306a36Sopenharmony_ci */ 122762306a36Sopenharmony_cistatic int diskstats_show(struct seq_file *seqf, void *v) 122862306a36Sopenharmony_ci{ 122962306a36Sopenharmony_ci struct gendisk *gp = v; 123062306a36Sopenharmony_ci struct block_device *hd; 123162306a36Sopenharmony_ci unsigned int inflight; 123262306a36Sopenharmony_ci struct disk_stats stat; 123362306a36Sopenharmony_ci unsigned long idx; 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci /* 123662306a36Sopenharmony_ci if (&disk_to_dev(gp)->kobj.entry == block_class.devices.next) 123762306a36Sopenharmony_ci seq_puts(seqf, "major minor name" 123862306a36Sopenharmony_ci " rio rmerge rsect ruse wio wmerge " 123962306a36Sopenharmony_ci "wsect wuse running use aveq" 124062306a36Sopenharmony_ci "\n\n"); 124162306a36Sopenharmony_ci */ 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci rcu_read_lock(); 124462306a36Sopenharmony_ci xa_for_each(&gp->part_tbl, idx, hd) { 124562306a36Sopenharmony_ci if (bdev_is_partition(hd) && !bdev_nr_sectors(hd)) 124662306a36Sopenharmony_ci continue; 124762306a36Sopenharmony_ci if (queue_is_mq(gp->queue)) 124862306a36Sopenharmony_ci inflight = blk_mq_in_flight(gp->queue, hd); 124962306a36Sopenharmony_ci else 125062306a36Sopenharmony_ci inflight = part_in_flight(hd); 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci if (inflight) { 125362306a36Sopenharmony_ci part_stat_lock(); 125462306a36Sopenharmony_ci update_io_ticks(hd, jiffies, true); 125562306a36Sopenharmony_ci part_stat_unlock(); 125662306a36Sopenharmony_ci } 125762306a36Sopenharmony_ci part_stat_read_all(hd, &stat); 125862306a36Sopenharmony_ci seq_printf(seqf, "%4d %7d %pg " 125962306a36Sopenharmony_ci "%lu %lu %lu %u " 126062306a36Sopenharmony_ci "%lu %lu %lu %u " 126162306a36Sopenharmony_ci "%u %u %u " 126262306a36Sopenharmony_ci "%lu %lu %lu %u " 126362306a36Sopenharmony_ci "%lu %u" 126462306a36Sopenharmony_ci "\n", 126562306a36Sopenharmony_ci MAJOR(hd->bd_dev), MINOR(hd->bd_dev), hd, 126662306a36Sopenharmony_ci stat.ios[STAT_READ], 126762306a36Sopenharmony_ci stat.merges[STAT_READ], 126862306a36Sopenharmony_ci stat.sectors[STAT_READ], 126962306a36Sopenharmony_ci (unsigned int)div_u64(stat.nsecs[STAT_READ], 127062306a36Sopenharmony_ci NSEC_PER_MSEC), 127162306a36Sopenharmony_ci stat.ios[STAT_WRITE], 127262306a36Sopenharmony_ci stat.merges[STAT_WRITE], 127362306a36Sopenharmony_ci stat.sectors[STAT_WRITE], 127462306a36Sopenharmony_ci (unsigned int)div_u64(stat.nsecs[STAT_WRITE], 127562306a36Sopenharmony_ci NSEC_PER_MSEC), 127662306a36Sopenharmony_ci inflight, 127762306a36Sopenharmony_ci jiffies_to_msecs(stat.io_ticks), 127862306a36Sopenharmony_ci (unsigned int)div_u64(stat.nsecs[STAT_READ] + 127962306a36Sopenharmony_ci stat.nsecs[STAT_WRITE] + 128062306a36Sopenharmony_ci stat.nsecs[STAT_DISCARD] + 128162306a36Sopenharmony_ci stat.nsecs[STAT_FLUSH], 128262306a36Sopenharmony_ci NSEC_PER_MSEC), 128362306a36Sopenharmony_ci stat.ios[STAT_DISCARD], 128462306a36Sopenharmony_ci stat.merges[STAT_DISCARD], 128562306a36Sopenharmony_ci stat.sectors[STAT_DISCARD], 128662306a36Sopenharmony_ci (unsigned int)div_u64(stat.nsecs[STAT_DISCARD], 128762306a36Sopenharmony_ci NSEC_PER_MSEC), 128862306a36Sopenharmony_ci stat.ios[STAT_FLUSH], 128962306a36Sopenharmony_ci (unsigned int)div_u64(stat.nsecs[STAT_FLUSH], 129062306a36Sopenharmony_ci NSEC_PER_MSEC) 129162306a36Sopenharmony_ci ); 129262306a36Sopenharmony_ci } 129362306a36Sopenharmony_ci rcu_read_unlock(); 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci return 0; 129662306a36Sopenharmony_ci} 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_cistatic const struct seq_operations diskstats_op = { 129962306a36Sopenharmony_ci .start = disk_seqf_start, 130062306a36Sopenharmony_ci .next = disk_seqf_next, 130162306a36Sopenharmony_ci .stop = disk_seqf_stop, 130262306a36Sopenharmony_ci .show = diskstats_show 130362306a36Sopenharmony_ci}; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_cistatic int __init proc_genhd_init(void) 130662306a36Sopenharmony_ci{ 130762306a36Sopenharmony_ci proc_create_seq("diskstats", 0, NULL, &diskstats_op); 130862306a36Sopenharmony_ci proc_create_seq("partitions", 0, NULL, &partitions_op); 130962306a36Sopenharmony_ci return 0; 131062306a36Sopenharmony_ci} 131162306a36Sopenharmony_cimodule_init(proc_genhd_init); 131262306a36Sopenharmony_ci#endif /* CONFIG_PROC_FS */ 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_cidev_t part_devt(struct gendisk *disk, u8 partno) 131562306a36Sopenharmony_ci{ 131662306a36Sopenharmony_ci struct block_device *part; 131762306a36Sopenharmony_ci dev_t devt = 0; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci rcu_read_lock(); 132062306a36Sopenharmony_ci part = xa_load(&disk->part_tbl, partno); 132162306a36Sopenharmony_ci if (part) 132262306a36Sopenharmony_ci devt = part->bd_dev; 132362306a36Sopenharmony_ci rcu_read_unlock(); 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci return devt; 132662306a36Sopenharmony_ci} 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_cistruct gendisk *__alloc_disk_node(struct request_queue *q, int node_id, 132962306a36Sopenharmony_ci struct lock_class_key *lkclass) 133062306a36Sopenharmony_ci{ 133162306a36Sopenharmony_ci struct gendisk *disk; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci disk = kzalloc_node(sizeof(struct gendisk), GFP_KERNEL, node_id); 133462306a36Sopenharmony_ci if (!disk) 133562306a36Sopenharmony_ci return NULL; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci if (bioset_init(&disk->bio_split, BIO_POOL_SIZE, 0, 0)) 133862306a36Sopenharmony_ci goto out_free_disk; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci disk->bdi = bdi_alloc(node_id); 134162306a36Sopenharmony_ci if (!disk->bdi) 134262306a36Sopenharmony_ci goto out_free_bioset; 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci /* bdev_alloc() might need the queue, set before the first call */ 134562306a36Sopenharmony_ci disk->queue = q; 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci disk->part0 = bdev_alloc(disk, 0); 134862306a36Sopenharmony_ci if (!disk->part0) 134962306a36Sopenharmony_ci goto out_free_bdi; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci disk->node_id = node_id; 135262306a36Sopenharmony_ci mutex_init(&disk->open_mutex); 135362306a36Sopenharmony_ci xa_init(&disk->part_tbl); 135462306a36Sopenharmony_ci if (xa_insert(&disk->part_tbl, 0, disk->part0, GFP_KERNEL)) 135562306a36Sopenharmony_ci goto out_destroy_part_tbl; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci if (blkcg_init_disk(disk)) 135862306a36Sopenharmony_ci goto out_erase_part0; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci rand_initialize_disk(disk); 136162306a36Sopenharmony_ci disk_to_dev(disk)->class = &block_class; 136262306a36Sopenharmony_ci disk_to_dev(disk)->type = &disk_type; 136362306a36Sopenharmony_ci device_initialize(disk_to_dev(disk)); 136462306a36Sopenharmony_ci inc_diskseq(disk); 136562306a36Sopenharmony_ci q->disk = disk; 136662306a36Sopenharmony_ci lockdep_init_map(&disk->lockdep_map, "(bio completion)", lkclass, 0); 136762306a36Sopenharmony_ci#ifdef CONFIG_BLOCK_HOLDER_DEPRECATED 136862306a36Sopenharmony_ci INIT_LIST_HEAD(&disk->slave_bdevs); 136962306a36Sopenharmony_ci#endif 137062306a36Sopenharmony_ci return disk; 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ciout_erase_part0: 137362306a36Sopenharmony_ci xa_erase(&disk->part_tbl, 0); 137462306a36Sopenharmony_ciout_destroy_part_tbl: 137562306a36Sopenharmony_ci xa_destroy(&disk->part_tbl); 137662306a36Sopenharmony_ci disk->part0->bd_disk = NULL; 137762306a36Sopenharmony_ci iput(disk->part0->bd_inode); 137862306a36Sopenharmony_ciout_free_bdi: 137962306a36Sopenharmony_ci bdi_put(disk->bdi); 138062306a36Sopenharmony_ciout_free_bioset: 138162306a36Sopenharmony_ci bioset_exit(&disk->bio_split); 138262306a36Sopenharmony_ciout_free_disk: 138362306a36Sopenharmony_ci kfree(disk); 138462306a36Sopenharmony_ci return NULL; 138562306a36Sopenharmony_ci} 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_cistruct gendisk *__blk_alloc_disk(int node, struct lock_class_key *lkclass) 138862306a36Sopenharmony_ci{ 138962306a36Sopenharmony_ci struct request_queue *q; 139062306a36Sopenharmony_ci struct gendisk *disk; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci q = blk_alloc_queue(node); 139362306a36Sopenharmony_ci if (!q) 139462306a36Sopenharmony_ci return NULL; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci disk = __alloc_disk_node(q, node, lkclass); 139762306a36Sopenharmony_ci if (!disk) { 139862306a36Sopenharmony_ci blk_put_queue(q); 139962306a36Sopenharmony_ci return NULL; 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci set_bit(GD_OWNS_QUEUE, &disk->state); 140262306a36Sopenharmony_ci return disk; 140362306a36Sopenharmony_ci} 140462306a36Sopenharmony_ciEXPORT_SYMBOL(__blk_alloc_disk); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci/** 140762306a36Sopenharmony_ci * put_disk - decrements the gendisk refcount 140862306a36Sopenharmony_ci * @disk: the struct gendisk to decrement the refcount for 140962306a36Sopenharmony_ci * 141062306a36Sopenharmony_ci * This decrements the refcount for the struct gendisk. When this reaches 0 141162306a36Sopenharmony_ci * we'll have disk_release() called. 141262306a36Sopenharmony_ci * 141362306a36Sopenharmony_ci * Note: for blk-mq disk put_disk must be called before freeing the tag_set 141462306a36Sopenharmony_ci * when handling probe errors (that is before add_disk() is called). 141562306a36Sopenharmony_ci * 141662306a36Sopenharmony_ci * Context: Any context, but the last reference must not be dropped from 141762306a36Sopenharmony_ci * atomic context. 141862306a36Sopenharmony_ci */ 141962306a36Sopenharmony_civoid put_disk(struct gendisk *disk) 142062306a36Sopenharmony_ci{ 142162306a36Sopenharmony_ci if (disk) 142262306a36Sopenharmony_ci put_device(disk_to_dev(disk)); 142362306a36Sopenharmony_ci} 142462306a36Sopenharmony_ciEXPORT_SYMBOL(put_disk); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_cistatic void set_disk_ro_uevent(struct gendisk *gd, int ro) 142762306a36Sopenharmony_ci{ 142862306a36Sopenharmony_ci char event[] = "DISK_RO=1"; 142962306a36Sopenharmony_ci char *envp[] = { event, NULL }; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci if (!ro) 143262306a36Sopenharmony_ci event[8] = '0'; 143362306a36Sopenharmony_ci kobject_uevent_env(&disk_to_dev(gd)->kobj, KOBJ_CHANGE, envp); 143462306a36Sopenharmony_ci} 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci/** 143762306a36Sopenharmony_ci * set_disk_ro - set a gendisk read-only 143862306a36Sopenharmony_ci * @disk: gendisk to operate on 143962306a36Sopenharmony_ci * @read_only: %true to set the disk read-only, %false set the disk read/write 144062306a36Sopenharmony_ci * 144162306a36Sopenharmony_ci * This function is used to indicate whether a given disk device should have its 144262306a36Sopenharmony_ci * read-only flag set. set_disk_ro() is typically used by device drivers to 144362306a36Sopenharmony_ci * indicate whether the underlying physical device is write-protected. 144462306a36Sopenharmony_ci */ 144562306a36Sopenharmony_civoid set_disk_ro(struct gendisk *disk, bool read_only) 144662306a36Sopenharmony_ci{ 144762306a36Sopenharmony_ci if (read_only) { 144862306a36Sopenharmony_ci if (test_and_set_bit(GD_READ_ONLY, &disk->state)) 144962306a36Sopenharmony_ci return; 145062306a36Sopenharmony_ci } else { 145162306a36Sopenharmony_ci if (!test_and_clear_bit(GD_READ_ONLY, &disk->state)) 145262306a36Sopenharmony_ci return; 145362306a36Sopenharmony_ci } 145462306a36Sopenharmony_ci set_disk_ro_uevent(disk, read_only); 145562306a36Sopenharmony_ci} 145662306a36Sopenharmony_ciEXPORT_SYMBOL(set_disk_ro); 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_civoid inc_diskseq(struct gendisk *disk) 145962306a36Sopenharmony_ci{ 146062306a36Sopenharmony_ci disk->diskseq = atomic64_inc_return(&diskseq); 146162306a36Sopenharmony_ci} 1462