diff options
Diffstat (limited to 'drivers/md/multipath.c')
| -rw-r--r-- | drivers/md/multipath.c | 60 | 
1 files changed, 32 insertions, 28 deletions
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index c3589099098..3535c23af28 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -146,7 +146,7 @@ static void multipath_status (struct seq_file *seq, mddev_t *mddev)  	int i;  	seq_printf (seq, " [%d/%d] [", conf->raid_disks, -						 conf->working_disks); +		    conf->raid_disks - mddev->degraded);  	for (i = 0; i < conf->raid_disks; i++)  		seq_printf (seq, "%s",  			       conf->multipaths[i].rdev &&  @@ -186,35 +186,36 @@ static int multipath_congested(void *data, int bits)  static void multipath_error (mddev_t *mddev, mdk_rdev_t *rdev)  {  	multipath_conf_t *conf = mddev->private; +	char b[BDEVNAME_SIZE]; -	if (conf->working_disks <= 1) { +	if (conf->raid_disks - mddev->degraded <= 1) {  		/*  		 * Uh oh, we can do nothing if this is our last path, but  		 * first check if this is a queued request for a device  		 * which has just failed.  		 */  		printk(KERN_ALERT  -			"multipath: only one IO path left and IO error.\n"); +		       "multipath: only one IO path left and IO error.\n");  		/* leave it active... it's all we have */ -	} else { -		/* -		 * Mark disk as unusable -		 */ -		if (!test_bit(Faulty, &rdev->flags)) { -			char b[BDEVNAME_SIZE]; -			clear_bit(In_sync, &rdev->flags); -			set_bit(Faulty, &rdev->flags); -			set_bit(MD_CHANGE_DEVS, &mddev->flags); -			conf->working_disks--; -			mddev->degraded++; -			printk(KERN_ALERT "multipath: IO failure on %s," -				" disabling IO path.\n" -				"multipath: Operation continuing" -				" on %d IO paths.\n", -				bdevname (rdev->bdev,b), -				conf->working_disks); -		} +		return; +	} +	/* +	 * Mark disk as unusable +	 */ +	if (test_and_clear_bit(In_sync, &rdev->flags)) { +		unsigned long flags; +		spin_lock_irqsave(&conf->device_lock, flags); +		mddev->degraded++; +		spin_unlock_irqrestore(&conf->device_lock, flags);  	} +	set_bit(Faulty, &rdev->flags); +	set_bit(MD_CHANGE_DEVS, &mddev->flags); +	printk(KERN_ALERT "multipath: IO failure on %s," +	       " disabling IO path.\n" +	       "multipath: Operation continuing" +	       " on %d IO paths.\n", +	       bdevname(rdev->bdev, b), +	       conf->raid_disks - mddev->degraded);  }  static void print_multipath_conf (multipath_conf_t *conf) @@ -227,7 +228,7 @@ static void print_multipath_conf (multipath_conf_t *conf)  		printk("(conf==NULL)\n");  		return;  	} -	printk(" --- wd:%d rd:%d\n", conf->working_disks, +	printk(" --- wd:%d rd:%d\n", conf->raid_disks - conf->mddev->degraded,  			 conf->raid_disks);  	for (i = 0; i < conf->raid_disks; i++) { @@ -274,10 +275,11 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)  							   PAGE_CACHE_SIZE - 1);  			} -			conf->working_disks++; +			spin_lock_irq(&conf->device_lock);  			mddev->degraded--;  			rdev->raid_disk = path;  			set_bit(In_sync, &rdev->flags); +			spin_unlock_irq(&conf->device_lock);  			rcu_assign_pointer(p->rdev, rdev);  			err = 0;  			md_integrity_add_rdev(rdev, mddev); @@ -391,6 +393,7 @@ static int multipath_run (mddev_t *mddev)  	int disk_idx;  	struct multipath_info *disk;  	mdk_rdev_t *rdev; +	int working_disks;  	if (md_check_no_bitmap(mddev))  		return -EINVAL; @@ -424,7 +427,7 @@ static int multipath_run (mddev_t *mddev)  		goto out_free_conf;  	} -	conf->working_disks = 0; +	working_disks = 0;  	list_for_each_entry(rdev, &mddev->disks, same_set) {  		disk_idx = rdev->raid_disk;  		if (disk_idx < 0 || @@ -446,7 +449,7 @@ static int multipath_run (mddev_t *mddev)  		}  		if (!test_bit(Faulty, &rdev->flags)) -			conf->working_disks++; +			working_disks++;  	}  	conf->raid_disks = mddev->raid_disks; @@ -454,12 +457,12 @@ static int multipath_run (mddev_t *mddev)  	spin_lock_init(&conf->device_lock);  	INIT_LIST_HEAD(&conf->retry_list); -	if (!conf->working_disks) { +	if (!working_disks) {  		printk(KERN_ERR "multipath: no operational IO paths for %s\n",  			mdname(mddev));  		goto out_free_conf;  	} -	mddev->degraded = conf->raid_disks - conf->working_disks; +	mddev->degraded = conf->raid_disks - working_disks;  	conf->pool = mempool_create_kmalloc_pool(NR_RESERVED_BUFS,  						 sizeof(struct multipath_bh)); @@ -481,7 +484,8 @@ static int multipath_run (mddev_t *mddev)  	printk(KERN_INFO   		"multipath: array %s active with %d out of %d IO paths\n", -		mdname(mddev), conf->working_disks, mddev->raid_disks); +		mdname(mddev), conf->raid_disks - mddev->degraded, +	       mddev->raid_disks);  	/*  	 * Ok, everything is just fine now  	 */  |