1596 lines · 41.1 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* *  gendisk handling * * Portions Copyright (C) 2020 Christoph Hellwig */ #include <linux/module.h>#include <linux/ctype.h>#include <linux/fs.h>#include <linux/kdev_t.h>#include <linux/kernel.h>#include <linux/blkdev.h>#include <linux/backing-dev.h>#include <linux/init.h>#include <linux/spinlock.h>#include <linux/proc_fs.h>#include <linux/seq_file.h>#include <linux/slab.h>#include <linux/kmod.h>#include <linux/major.h>#include <linux/mutex.h>#include <linux/idr.h>#include <linux/log2.h>#include <linux/pm_runtime.h>#include <linux/badblocks.h>#include <linux/part_stat.h>#include <linux/blktrace_api.h> #include "blk-throttle.h"#include "blk.h"#include "blk-mq-sched.h"#include "blk-rq-qos.h"#include "blk-cgroup.h" static struct kobject *block_depr; /* * Unique, monotonically increasing sequential number associated with block * devices instances (i.e. incremented each time a device is attached). * Associating uevents with block devices in userspace is difficult and racy: * the uevent netlink socket is lossy, and on slow and overloaded systems has * a very high latency. * Block devices do not have exclusive owners in userspace, any process can set * one up (e.g. loop devices). Moreover, device names can be reused (e.g. loop0 * can be reused again and again). * A userspace process setting up a block device and watching for its events * cannot thus reliably tell whether an event relates to the device it just set * up or another earlier instance with the same name. * This sequential number allows userspace processes to solve this problem, and * uniquely associate an uevent to the lifetime to a device. */static atomic64_t diskseq; /* for extended dynamic devt allocation, currently only one major is used */#define NR_EXT_DEVT		(1 << MINORBITS)static DEFINE_IDA(ext_devt_ida); void set_capacity(struct gendisk *disk, sector_t sectors){	if (sectors > BLK_DEV_MAX_SECTORS) {		pr_warn_once("%s: truncate capacity from %lld to %lld\n",				disk->disk_name, sectors,				BLK_DEV_MAX_SECTORS);		sectors = BLK_DEV_MAX_SECTORS;	} 	bdev_set_nr_sectors(disk->part0, sectors);}EXPORT_SYMBOL(set_capacity); /* * Set disk capacity and notify if the size is not currently zero and will not * be set to zero.  Returns true if a uevent was sent, otherwise false. */bool set_capacity_and_notify(struct gendisk *disk, sector_t size){	sector_t capacity = get_capacity(disk);	char *envp[] = { "RESIZE=1", NULL }; 	set_capacity(disk, size); 	/*	 * Only print a message and send a uevent if the gendisk is user visible	 * and alive.  This avoids spamming the log and udev when setting the	 * initial capacity during probing.	 */	if (size == capacity ||	    !disk_live(disk) ||	    (disk->flags & GENHD_FL_HIDDEN))		return false; 	pr_info_ratelimited("%s: detected capacity change from %lld to %lld\n",		disk->disk_name, capacity, size); 	/*	 * Historically we did not send a uevent for changes to/from an empty	 * device.	 */	if (!capacity || !size)		return false;	kobject_uevent_env(&disk_to_dev(disk)->kobj, KOBJ_CHANGE, envp);	return true;}EXPORT_SYMBOL_GPL(set_capacity_and_notify); static void part_stat_read_all(struct block_device *part,		struct disk_stats *stat){	int cpu; 	memset(stat, 0, sizeof(struct disk_stats));	for_each_possible_cpu(cpu) {		struct disk_stats *ptr = per_cpu_ptr(part->bd_stats, cpu);		int group; 		for (group = 0; group < NR_STAT_GROUPS; group++) {			stat->nsecs[group] += ptr->nsecs[group];			stat->sectors[group] += ptr->sectors[group];			stat->ios[group] += ptr->ios[group];			stat->merges[group] += ptr->merges[group];		} 		stat->io_ticks += ptr->io_ticks;	}} static void bdev_count_inflight_rw(struct block_device *part,		unsigned int inflight[2], bool mq_driver){	int write = 0;	int read = 0;	int cpu; 	if (mq_driver) {		blk_mq_in_driver_rw(part, inflight);		return;	} 	for_each_possible_cpu(cpu) {		read += part_stat_local_read_cpu(part, in_flight[READ], cpu);		write += part_stat_local_read_cpu(part, in_flight[WRITE], cpu);	} 	/*	 * While iterating all CPUs, some IOs may be issued from a CPU already	 * traversed and complete on a CPU that has not yet been traversed,	 * causing the inflight number to be negative.	 */	inflight[READ] = read > 0 ? read : 0;	inflight[WRITE] = write > 0 ? write : 0;} /** * bdev_count_inflight - get the number of inflight IOs for a block device. * * @part: the block device. * * Inflight here means started IO accounting, from bdev_start_io_acct() for * bio-based block device, and from blk_account_io_start() for rq-based block * device. */unsigned int bdev_count_inflight(struct block_device *part){	unsigned int inflight[2] = {0}; 	bdev_count_inflight_rw(part, inflight, false); 	return inflight[READ] + inflight[WRITE];}EXPORT_SYMBOL_GPL(bdev_count_inflight); /* * Can be deleted altogether. Later. * */#define BLKDEV_MAJOR_HASH_SIZE 255static struct blk_major_name {	struct blk_major_name *next;	int major;	char name[16];#ifdef CONFIG_BLOCK_LEGACY_AUTOLOAD	void (*probe)(dev_t devt);#endif} *major_names[BLKDEV_MAJOR_HASH_SIZE];static DEFINE_MUTEX(major_names_lock);static DEFINE_SPINLOCK(major_names_spinlock); /* index in the above - for now: assume no multimajor ranges */static inline int major_to_index(unsigned major){	return major % BLKDEV_MAJOR_HASH_SIZE;} #ifdef CONFIG_PROC_FSvoid blkdev_show(struct seq_file *seqf, off_t offset){	struct blk_major_name *dp; 	spin_lock(&major_names_spinlock);	for (dp = major_names[major_to_index(offset)]; dp; dp = dp->next)		if (dp->major == offset)			seq_printf(seqf, "%3d %s\n", dp->major, dp->name);	spin_unlock(&major_names_spinlock);}#endif /* CONFIG_PROC_FS */ /** * __register_blkdev - register a new block device * * @major: the requested major device number [1..BLKDEV_MAJOR_MAX-1]. If *         @major = 0, try to allocate any unused major number. * @name: the name of the new block device as a zero terminated string * @probe: pre-devtmpfs / pre-udev callback used to create disks when their *	   pre-created device node is accessed. When a probe call uses *	   add_disk() and it fails the driver must cleanup resources. This *	   interface may soon be removed. * * The @name must be unique within the system. * * The return value depends on the @major input parameter: * *  - if a major device number was requested in range [1..BLKDEV_MAJOR_MAX-1] *    then the function returns zero on success, or a negative error code *  - if any unused major number was requested with @major = 0 parameter *    then the return value is the allocated major number in range *    [1..BLKDEV_MAJOR_MAX-1] or a negative error code otherwise * * See Documentation/admin-guide/devices.txt for the list of allocated * major numbers. * * Use register_blkdev instead for any new code. */int __register_blkdev(unsigned int major, const char *name,		void (*probe)(dev_t devt)){	struct blk_major_name **n, *p;	int index, ret = 0; 	mutex_lock(&major_names_lock); 	/* temporary */	if (major == 0) {		for (index = ARRAY_SIZE(major_names)-1; index > 0; index--) {			if (major_names[index] == NULL)				break;		} 		if (index == 0) {			printk("%s: failed to get major for %s\n",			       __func__, name);			ret = -EBUSY;			goto out;		}		major = index;		ret = major;	} 	if (major >= BLKDEV_MAJOR_MAX) {		pr_err("%s: major requested (%u) is greater than the maximum (%u) for %s\n",		       __func__, major, BLKDEV_MAJOR_MAX-1, name); 		ret = -EINVAL;		goto out;	} 	p = kmalloc_obj(struct blk_major_name);	if (p == NULL) {		ret = -ENOMEM;		goto out;	} 	p->major = major;#ifdef CONFIG_BLOCK_LEGACY_AUTOLOAD	p->probe = probe;#endif	strscpy(p->name, name, sizeof(p->name));	p->next = NULL;	index = major_to_index(major); 	spin_lock(&major_names_spinlock);	for (n = &major_names[index]; *n; n = &(*n)->next) {		if ((*n)->major == major)			break;	}	if (!*n)		*n = p;	else		ret = -EBUSY;	spin_unlock(&major_names_spinlock); 	if (ret < 0) {		printk("register_blkdev: cannot get major %u for %s\n",		       major, name);		kfree(p);	}out:	mutex_unlock(&major_names_lock);	return ret;}EXPORT_SYMBOL(__register_blkdev); void unregister_blkdev(unsigned int major, const char *name){	struct blk_major_name **n;	struct blk_major_name *p = NULL;	int index = major_to_index(major); 	mutex_lock(&major_names_lock);	spin_lock(&major_names_spinlock);	for (n = &major_names[index]; *n; n = &(*n)->next)		if ((*n)->major == major)			break;	if (!*n || strcmp((*n)->name, name)) {		WARN_ON(1);	} else {		p = *n;		*n = p->next;	}	spin_unlock(&major_names_spinlock);	mutex_unlock(&major_names_lock);	kfree(p);} EXPORT_SYMBOL(unregister_blkdev); int blk_alloc_ext_minor(void){	int idx; 	idx = ida_alloc_range(&ext_devt_ida, 0, NR_EXT_DEVT - 1, GFP_KERNEL);	if (idx == -ENOSPC)		return -EBUSY;	return idx;} void blk_free_ext_minor(unsigned int minor){	ida_free(&ext_devt_ida, minor);} void disk_uevent(struct gendisk *disk, enum kobject_action action){	struct block_device *part;	unsigned long idx; 	rcu_read_lock();	xa_for_each(&disk->part_tbl, idx, part) {		if (bdev_is_partition(part) && !bdev_nr_sectors(part))			continue;		if (!kobject_get_unless_zero(&part->bd_device.kobj))			continue; 		rcu_read_unlock();		kobject_uevent(bdev_kobj(part), action);		put_device(&part->bd_device);		rcu_read_lock();	}	rcu_read_unlock();}EXPORT_SYMBOL_GPL(disk_uevent); int disk_scan_partitions(struct gendisk *disk, blk_mode_t mode){	struct file *file;	int ret = 0; 	if (!disk_has_partscan(disk))		return -EINVAL;	if (disk->open_partitions)		return -EBUSY; 	/*	 * If the device is opened exclusively by current thread already, it's	 * safe to scan partitons, otherwise, use bd_prepare_to_claim() to	 * synchronize with other exclusive openers and other partition	 * scanners.	 */	if (!(mode & BLK_OPEN_EXCL)) {		ret = bd_prepare_to_claim(disk->part0, disk_scan_partitions,					  NULL);		if (ret)			return ret;	} 	set_bit(GD_NEED_PART_SCAN, &disk->state);	file = bdev_file_open_by_dev(disk_devt(disk), mode & ~BLK_OPEN_EXCL,				     NULL, NULL);	if (IS_ERR(file))		ret = PTR_ERR(file);	else		fput(file); 	/*	 * If blkdev_get_by_dev() failed early, GD_NEED_PART_SCAN is still set,	 * and this will cause that re-assemble partitioned raid device will	 * creat partition for underlying disk.	 */	clear_bit(GD_NEED_PART_SCAN, &disk->state);	if (!(mode & BLK_OPEN_EXCL))		bd_abort_claiming(disk->part0, disk_scan_partitions);	return ret;} static void add_disk_final(struct gendisk *disk){	struct device *ddev = disk_to_dev(disk); 	if (!(disk->flags & GENHD_FL_HIDDEN)) {		bdev_add(disk->part0, ddev->devt);		if (get_capacity(disk))			disk_scan_partitions(disk, BLK_OPEN_READ); 		/*		 * Announce the disk and partitions after all partitions are		 * created. (for hidden disks uevents remain suppressed forever)		 */		dev_set_uevent_suppress(ddev, 0);		disk_uevent(disk, KOBJ_ADD);	} 	blk_apply_bdi_limits(disk->bdi, &disk->queue->limits);	disk_add_events(disk);	set_bit(GD_ADDED, &disk->state);} static int __add_disk(struct device *parent, struct gendisk *disk,		      const struct attribute_group **groups,		      struct fwnode_handle *fwnode) {	struct device *ddev = disk_to_dev(disk);	int ret; 	if (WARN_ON_ONCE(bdev_nr_sectors(disk->part0) > BLK_DEV_MAX_SECTORS))		return -EINVAL; 	if (queue_is_mq(disk->queue)) {		/*		 * ->submit_bio and ->poll_bio are bypassed for blk-mq drivers.		 */		if (disk->fops->submit_bio || disk->fops->poll_bio)			return -EINVAL;	} else {		if (!disk->fops->submit_bio)			return -EINVAL;		bdev_set_flag(disk->part0, BD_HAS_SUBMIT_BIO);	} 	/*	 * We do not support partitions with zoned block devices, so do not try	 * to scan the partitions table.	 */	if (blk_queue_is_zoned(disk->queue))		disk->flags |= GENHD_FL_NO_PART; 	/*	 * If the driver provides an explicit major number it also must provide	 * the number of minors numbers supported, and those will be used to	 * setup the gendisk.	 * Otherwise just allocate the device numbers for both the whole device	 * and all partitions from the extended dev_t space.	 */	ret = -EINVAL;	if (disk->major) {		if (WARN_ON(!disk->minors))			goto out; 		if (disk->minors > DISK_MAX_PARTS) {			pr_err("block: can't allocate more than %d partitions\n",				DISK_MAX_PARTS);			disk->minors = DISK_MAX_PARTS;		}		if (disk->first_minor > MINORMASK ||		    disk->minors > MINORMASK + 1 ||		    disk->first_minor + disk->minors > MINORMASK + 1)			goto out;	} else {		if (WARN_ON(disk->minors))			goto out; 		ret = blk_alloc_ext_minor();		if (ret < 0)			goto out;		disk->major = BLOCK_EXT_MAJOR;		disk->first_minor = ret;	} 	/* delay uevents, until we scanned partition table */	dev_set_uevent_suppress(ddev, 1); 	ddev->parent = parent;	ddev->groups = groups;	dev_set_name(ddev, "%s", disk->disk_name);	if (fwnode)		device_set_node(ddev, fwnode);	if (!(disk->flags & GENHD_FL_HIDDEN))		ddev->devt = MKDEV(disk->major, disk->first_minor);	ret = device_add(ddev);	if (ret)

Lines 1–500 of 1596.