Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 67acd8b4 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* git://git.kernel.org/pub/scm/linux/kernel/git/arjan/linux-2.6-async:
  async: don't do the initcall stuff post boot
  bootchart: improve output based on Dave Jones' feedback
  async: make the final inode deletion an asynchronous event
  fastboot: Make libata initialization even more async
  fastboot: make the libata port scan asynchronous
  fastboot: make scsi probes asynchronous
  async: Asynchronous function calls to speed up kernel boot
parents b13d3720 ad160d23
Loading
Loading
Loading
Loading
+51 −45
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@
#include <linux/workqueue.h>
#include <linux/scatterlist.h>
#include <linux/io.h>
#include <linux/async.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_host.h>
@@ -5909,6 +5910,54 @@ void ata_host_init(struct ata_host *host, struct device *dev,
	host->ops = ops;
}


static void async_port_probe(void *data, async_cookie_t cookie)
{
	int rc;
	struct ata_port *ap = data;
	/* probe */
	if (ap->ops->error_handler) {
		struct ata_eh_info *ehi = &ap->link.eh_info;
		unsigned long flags;

		ata_port_probe(ap);

		/* kick EH for boot probing */
		spin_lock_irqsave(ap->lock, flags);

		ehi->probe_mask |= ATA_ALL_DEVICES;
		ehi->action |= ATA_EH_RESET | ATA_EH_LPM;
		ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;

		ap->pflags &= ~ATA_PFLAG_INITIALIZING;
		ap->pflags |= ATA_PFLAG_LOADING;
		ata_port_schedule_eh(ap);

		spin_unlock_irqrestore(ap->lock, flags);

		/* wait for EH to finish */
		ata_port_wait_eh(ap);
	} else {
		DPRINTK("ata%u: bus probe begin\n", ap->print_id);
		rc = ata_bus_probe(ap);
		DPRINTK("ata%u: bus probe end\n", ap->print_id);

		if (rc) {
			/* FIXME: do something useful here?
			 * Current libata behavior will
			 * tear down everything when
			 * the module is removed
			 * or the h/w is unplugged.
			 */
		}
	}

	/* in order to keep device order, we need to synchronize at this point */
	async_synchronize_cookie(cookie);

	ata_scsi_scan_host(ap, 1);

}
/**
 *	ata_host_register - register initialized ATA host
 *	@host: ATA host to register
@@ -5988,52 +6037,9 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
	DPRINTK("probe begin\n");
	for (i = 0; i < host->n_ports; i++) {
		struct ata_port *ap = host->ports[i];

		/* probe */
		if (ap->ops->error_handler) {
			struct ata_eh_info *ehi = &ap->link.eh_info;
			unsigned long flags;

			ata_port_probe(ap);

			/* kick EH for boot probing */
			spin_lock_irqsave(ap->lock, flags);

			ehi->probe_mask |= ATA_ALL_DEVICES;
			ehi->action |= ATA_EH_RESET | ATA_EH_LPM;
			ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;

			ap->pflags &= ~ATA_PFLAG_INITIALIZING;
			ap->pflags |= ATA_PFLAG_LOADING;
			ata_port_schedule_eh(ap);

			spin_unlock_irqrestore(ap->lock, flags);

			/* wait for EH to finish */
			ata_port_wait_eh(ap);
		} else {
			DPRINTK("ata%u: bus probe begin\n", ap->print_id);
			rc = ata_bus_probe(ap);
			DPRINTK("ata%u: bus probe end\n", ap->print_id);

			if (rc) {
				/* FIXME: do something useful here?
				 * Current libata behavior will
				 * tear down everything when
				 * the module is removed
				 * or the h/w is unplugged.
				 */
			}
		}
	}

	/* probes are done, now scan each port's disk(s) */
	DPRINTK("host probe begin\n");
	for (i = 0; i < host->n_ports; i++) {
		struct ata_port *ap = host->ports[i];

		ata_scsi_scan_host(ap, 1);
		async_schedule(async_port_probe, ap);
	}
	DPRINTK("probe end\n");

	return 0;
}
+3 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/spinlock.h>
#include <linux/async.h>

#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -179,6 +180,8 @@ int scsi_complete_async_scans(void)
	spin_unlock(&async_scan_lock);

	kfree(data);
	/* Synchronize async operations globally */
	async_synchronize_full();
	return 0;
}

+67 −42
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/string_helpers.h>
#include <linux/async.h>
#include <asm/uaccess.h>

#include <scsi/scsi.h>
@@ -1802,6 +1803,71 @@ static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen)
	return 0;
}

/*
 * The asynchronous part of sd_probe
 */
static void sd_probe_async(void *data, async_cookie_t cookie)
{
	struct scsi_disk *sdkp = data;
	struct scsi_device *sdp;
	struct gendisk *gd;
	u32 index;
	struct device *dev;

	sdp = sdkp->device;
	gd = sdkp->disk;
	index = sdkp->index;
	dev = &sdp->sdev_gendev;

	if (!sdp->request_queue->rq_timeout) {
		if (sdp->type != TYPE_MOD)
			blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT);
		else
			blk_queue_rq_timeout(sdp->request_queue,
					     SD_MOD_TIMEOUT);
	}

	device_initialize(&sdkp->dev);
	sdkp->dev.parent = &sdp->sdev_gendev;
	sdkp->dev.class = &sd_disk_class;
	strncpy(sdkp->dev.bus_id, sdp->sdev_gendev.bus_id, BUS_ID_SIZE);

	if (device_add(&sdkp->dev))
		goto out_free_index;

	get_device(&sdp->sdev_gendev);

	if (index < SD_MAX_DISKS) {
		gd->major = sd_major((index & 0xf0) >> 4);
		gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
		gd->minors = SD_MINORS;
	}
	gd->fops = &sd_fops;
	gd->private_data = &sdkp->driver;
	gd->queue = sdkp->device->request_queue;

	sd_revalidate_disk(gd);

	blk_queue_prep_rq(sdp->request_queue, sd_prep_fn);

	gd->driverfs_dev = &sdp->sdev_gendev;
	gd->flags = GENHD_FL_EXT_DEVT | GENHD_FL_DRIVERFS;
	if (sdp->removable)
		gd->flags |= GENHD_FL_REMOVABLE;

	dev_set_drvdata(dev, sdkp);
	add_disk(gd);
	sd_dif_config_host(sdkp);

	sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
		  sdp->removable ? "removable " : "");

	return;

 out_free_index:
	ida_remove(&sd_index_ida, index);
}

/**
 *	sd_probe - called during driver initialization and whenever a
 *	new scsi device is attached to the system. It is called once
@@ -1865,48 +1931,7 @@ static int sd_probe(struct device *dev)
	sdkp->openers = 0;
	sdkp->previous_state = 1;

	if (!sdp->request_queue->rq_timeout) {
		if (sdp->type != TYPE_MOD)
			blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT);
		else
			blk_queue_rq_timeout(sdp->request_queue,
					     SD_MOD_TIMEOUT);
	}

	device_initialize(&sdkp->dev);
	sdkp->dev.parent = &sdp->sdev_gendev;
	sdkp->dev.class = &sd_disk_class;
	strncpy(sdkp->dev.bus_id, sdp->sdev_gendev.bus_id, BUS_ID_SIZE);

	if (device_add(&sdkp->dev))
		goto out_free_index;

	get_device(&sdp->sdev_gendev);

	if (index < SD_MAX_DISKS) {
		gd->major = sd_major((index & 0xf0) >> 4);
		gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
		gd->minors = SD_MINORS;
	}
	gd->fops = &sd_fops;
	gd->private_data = &sdkp->driver;
	gd->queue = sdkp->device->request_queue;

	sd_revalidate_disk(gd);

	blk_queue_prep_rq(sdp->request_queue, sd_prep_fn);

	gd->driverfs_dev = &sdp->sdev_gendev;
	gd->flags = GENHD_FL_EXT_DEVT | GENHD_FL_DRIVERFS;
	if (sdp->removable)
		gd->flags |= GENHD_FL_REMOVABLE;

	dev_set_drvdata(dev, sdkp);
	add_disk(gd);
	sd_dif_config_host(sdkp);

	sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
		  sdp->removable ? "removable " : "");
	async_schedule(sd_probe_async, sdkp);

	return 0;

+13 −7
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <linux/bootmem.h>
#include <linux/inotify.h>
#include <linux/mount.h>
#include <linux/async.h>

/*
 * This is needed for the following functions:
@@ -1138,16 +1139,11 @@ EXPORT_SYMBOL(remove_inode_hash);
 * I_FREEING is set so that no-one will take a new reference to the inode while
 * it is being deleted.
 */
void generic_delete_inode(struct inode *inode)
static void generic_delete_inode_async(void *data, async_cookie_t cookie)
{
	struct inode *inode = data;
	const struct super_operations *op = inode->i_sb->s_op;

	list_del_init(&inode->i_list);
	list_del_init(&inode->i_sb_list);
	inode->i_state |= I_FREEING;
	inodes_stat.nr_inodes--;
	spin_unlock(&inode_lock);

	security_inode_delete(inode);

	if (op->delete_inode) {
@@ -1171,6 +1167,16 @@ void generic_delete_inode(struct inode *inode)
	destroy_inode(inode);
}

void generic_delete_inode(struct inode *inode)
{
	list_del_init(&inode->i_list);
	list_del_init(&inode->i_sb_list);
	inode->i_state |= I_FREEING;
	inodes_stat.nr_inodes--;
	spin_unlock(&inode_lock);
	async_schedule_special(generic_delete_inode_async, inode, &inode->i_sb->s_async_list);
}

EXPORT_SYMBOL(generic_delete_inode);

static void generic_forget_inode(struct inode *inode)
+10 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
#include <linux/kobject.h>
#include <linux/mutex.h>
#include <linux/file.h>
#include <linux/async.h>
#include <asm/uaccess.h>
#include "internal.h"

@@ -71,6 +72,7 @@ static struct super_block *alloc_super(struct file_system_type *type)
		INIT_HLIST_HEAD(&s->s_anon);
		INIT_LIST_HEAD(&s->s_inodes);
		INIT_LIST_HEAD(&s->s_dentry_lru);
		INIT_LIST_HEAD(&s->s_async_list);
		init_rwsem(&s->s_umount);
		mutex_init(&s->s_lock);
		lockdep_set_class(&s->s_umount, &type->s_umount_key);
@@ -289,11 +291,18 @@ void generic_shutdown_super(struct super_block *sb)
{
	const struct super_operations *sop = sb->s_op;


	if (sb->s_root) {
		shrink_dcache_for_umount(sb);
		fsync_super(sb);
		lock_super(sb);
		sb->s_flags &= ~MS_ACTIVE;

		/*
		 * wait for asynchronous fs operations to finish before going further
		 */
		async_synchronize_full_special(&sb->s_async_list);

		/* bad name - it should be evict_inodes() */
		invalidate_inodes(sb);
		lock_kernel();
@@ -449,6 +458,7 @@ void sync_filesystems(int wait)
		if (sb->s_flags & MS_RDONLY)
			continue;
		sb->s_need_sync_fs = 1;
		async_synchronize_full_special(&sb->s_async_list);
	}

restart:
Loading