check.c 17.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 *  fs/partitions/check.c
 *
 *  Code extracted from drivers/block/genhd.c
 *  Copyright (C) 1991-1998  Linus Torvalds
 *  Re-organised Feb 1998 Russell King
 *
 *  We now have independent partition support from the
 *  block drivers, which allows all the partition code to
 *  be grouped in one location, and it to be mostly self
 *  contained.
 *
 *  Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl}
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
19
#include <linux/slab.h>
L
Linus Torvalds 已提交
20 21
#include <linux/kmod.h>
#include <linux/ctype.h>
22
#include <linux/genhd.h>
23
#include <linux/blktrace_api.h>
L
Linus Torvalds 已提交
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38

#include "check.h"

#include "acorn.h"
#include "amiga.h"
#include "atari.h"
#include "ldm.h"
#include "mac.h"
#include "msdos.h"
#include "osf.h"
#include "sgi.h"
#include "sun.h"
#include "ibm.h"
#include "ultrix.h"
#include "efi.h"
39
#include "karma.h"
40
#include "sysv68.h"
L
Linus Torvalds 已提交
41 42 43 44 45 46 47

#ifdef CONFIG_BLK_DEV_MD
extern void md_autodetect_dev(dev_t dev);
#endif

int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/

48
static int (*check_part[])(struct parsed_partitions *) = {
L
Linus Torvalds 已提交
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
	/*
	 * Probe partition formats with tables at disk address 0
	 * that also have an ADFS boot block at 0xdc0.
	 */
#ifdef CONFIG_ACORN_PARTITION_ICS
	adfspart_check_ICS,
#endif
#ifdef CONFIG_ACORN_PARTITION_POWERTEC
	adfspart_check_POWERTEC,
#endif
#ifdef CONFIG_ACORN_PARTITION_EESOX
	adfspart_check_EESOX,
#endif

	/*
	 * Now move on to formats that only have partition info at
	 * disk address 0xdc0.  Since these may also have stale
	 * PC/BIOS partition tables, they need to come before
	 * the msdos entry.
	 */
#ifdef CONFIG_ACORN_PARTITION_CUMANA
	adfspart_check_CUMANA,
#endif
#ifdef CONFIG_ACORN_PARTITION_ADFS
	adfspart_check_ADFS,
#endif

#ifdef CONFIG_EFI_PARTITION
	efi_partition,		/* this must come before msdos */
#endif
#ifdef CONFIG_SGI_PARTITION
	sgi_partition,
#endif
#ifdef CONFIG_LDM_PARTITION
	ldm_partition,		/* this must come before msdos */
#endif
#ifdef CONFIG_MSDOS_PARTITION
	msdos_partition,
#endif
#ifdef CONFIG_OSF_PARTITION
	osf_partition,
#endif
#ifdef CONFIG_SUN_PARTITION
	sun_partition,
#endif
#ifdef CONFIG_AMIGA_PARTITION
	amiga_partition,
#endif
#ifdef CONFIG_ATARI_PARTITION
	atari_partition,
#endif
#ifdef CONFIG_MAC_PARTITION
	mac_partition,
#endif
#ifdef CONFIG_ULTRIX_PARTITION
	ultrix_partition,
#endif
#ifdef CONFIG_IBM_PARTITION
	ibm_partition,
108 109 110
#endif
#ifdef CONFIG_KARMA_PARTITION
	karma_partition,
111 112 113
#endif
#ifdef CONFIG_SYSV68_PARTITION
	sysv68_partition,
L
Linus Torvalds 已提交
114 115 116 117 118 119 120 121 122 123 124
#endif
	NULL
};
 
/*
 * disk_name() is used by partition check code and the genhd driver.
 * It formats the devicename of the indicated disk into
 * the supplied buffer (of size at least 32), and returns
 * a pointer to that same buffer (for convenience).
 */

125
char *disk_name(struct gendisk *hd, int partno, char *buf)
L
Linus Torvalds 已提交
126
{
127
	if (!partno)
L
Linus Torvalds 已提交
128 129
		snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name);
	else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1]))
130
		snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, partno);
L
Linus Torvalds 已提交
131
	else
132
		snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, partno);
L
Linus Torvalds 已提交
133 134 135 136 137 138

	return buf;
}

const char *bdevname(struct block_device *bdev, char *buf)
{
T
Tejun Heo 已提交
139
	return disk_name(bdev->bd_disk, bdev->bd_part->partno, buf);
L
Linus Torvalds 已提交
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
}

EXPORT_SYMBOL(bdevname);

/*
 * There's very little reason to use this, you should really
 * have a struct block_device just about everywhere and use
 * bdevname() instead.
 */
const char *__bdevname(dev_t dev, char *buffer)
{
	scnprintf(buffer, BDEVNAME_SIZE, "unknown-block(%u,%u)",
				MAJOR(dev), MINOR(dev));
	return buffer;
}

EXPORT_SYMBOL(__bdevname);

static struct parsed_partitions *
check_partition(struct gendisk *hd, struct block_device *bdev)
{
	struct parsed_partitions *state;
S
Suzuki K P 已提交
162
	int i, res, err;
L
Linus Torvalds 已提交
163

164
	state = kzalloc(sizeof(struct parsed_partitions), GFP_KERNEL);
L
Linus Torvalds 已提交
165 166 167
	if (!state)
		return NULL;

168
	state->bdev = bdev;
169 170 171
	disk_name(hd, 0, state->name);
	printk(KERN_INFO " %s:", state->name);
	if (isdigit(state->name[strlen(state->name)-1]))
L
Linus Torvalds 已提交
172
		sprintf(state->name, "p");
173

T
Tejun Heo 已提交
174
	state->limit = disk_max_parts(hd);
S
Suzuki K P 已提交
175
	i = res = err = 0;
L
Linus Torvalds 已提交
176 177
	while (!res && check_part[i]) {
		memset(&state->parts, 0, sizeof(state->parts));
178
		res = check_part[i++](state);
S
Suzuki K P 已提交
179 180 181 182 183 184 185 186
		if (res < 0) {
			/* We have hit an I/O error which we don't report now.
		 	* But record it, and let the others do their job.
		 	*/
			err = res;
			res = 0;
		}

L
Linus Torvalds 已提交
187 188 189
	}
	if (res > 0)
		return state;
190 191
	if (state->access_beyond_eod)
		err = -ENOSPC;
192
	if (err)
S
Suzuki K P 已提交
193 194
	/* The partition is unrecognized. So report I/O errors if there were any */
		res = err;
L
Linus Torvalds 已提交
195 196 197 198 199
	if (!res)
		printk(" unknown partition table\n");
	else if (warn_no_part)
		printk(" unable to read partition table\n");
	kfree(state);
200
	return ERR_PTR(res);
L
Linus Torvalds 已提交
201 202
}

203 204 205 206 207 208 209 210
static ssize_t part_partition_show(struct device *dev,
				   struct device_attribute *attr, char *buf)
{
	struct hd_struct *p = dev_to_part(dev);

	return sprintf(buf, "%d\n", p->partno);
}

211 212
static ssize_t part_start_show(struct device *dev,
			       struct device_attribute *attr, char *buf)
L
Linus Torvalds 已提交
213
{
214
	struct hd_struct *p = dev_to_part(dev);
215

216
	return sprintf(buf, "%llu\n",(unsigned long long)p->start_sect);
L
Linus Torvalds 已提交
217 218
}

T
Tejun Heo 已提交
219 220
ssize_t part_size_show(struct device *dev,
		       struct device_attribute *attr, char *buf)
221
{
222 223
	struct hd_struct *p = dev_to_part(dev);
	return sprintf(buf, "%llu\n",(unsigned long long)p->nr_sects);
224
}
225

226 227 228 229 230 231 232
ssize_t part_alignment_offset_show(struct device *dev,
				   struct device_attribute *attr, char *buf)
{
	struct hd_struct *p = dev_to_part(dev);
	return sprintf(buf, "%llu\n", (unsigned long long)p->alignment_offset);
}

233 234 235 236 237 238 239
ssize_t part_discard_alignment_show(struct device *dev,
				   struct device_attribute *attr, char *buf)
{
	struct hd_struct *p = dev_to_part(dev);
	return sprintf(buf, "%u\n", p->discard_alignment);
}

T
Tejun Heo 已提交
240 241
ssize_t part_stat_show(struct device *dev,
		       struct device_attribute *attr, char *buf)
L
Linus Torvalds 已提交
242
{
243
	struct hd_struct *p = dev_to_part(dev);
T
Tejun Heo 已提交
244
	int cpu;
245

T
Tejun Heo 已提交
246
	cpu = part_stat_lock();
T
Tejun Heo 已提交
247
	part_round_stats(cpu, p);
T
Tejun Heo 已提交
248
	part_stat_unlock();
249 250 251 252 253 254 255 256 257 258 259 260 261
	return sprintf(buf,
		"%8lu %8lu %8llu %8u "
		"%8lu %8lu %8llu %8u "
		"%8u %8u %8u"
		"\n",
		part_stat_read(p, ios[READ]),
		part_stat_read(p, merges[READ]),
		(unsigned long long)part_stat_read(p, sectors[READ]),
		jiffies_to_msecs(part_stat_read(p, ticks[READ])),
		part_stat_read(p, ios[WRITE]),
		part_stat_read(p, merges[WRITE]),
		(unsigned long long)part_stat_read(p, sectors[WRITE]),
		jiffies_to_msecs(part_stat_read(p, ticks[WRITE])),
262
		part_in_flight(p),
263 264
		jiffies_to_msecs(part_stat_read(p, io_ticks)),
		jiffies_to_msecs(part_stat_read(p, time_in_queue)));
L
Linus Torvalds 已提交
265 266
}

267 268 269 270 271 272 273 274
ssize_t part_inflight_show(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	struct hd_struct *p = dev_to_part(dev);

	return sprintf(buf, "%8u %8u\n", p->in_flight[0], p->in_flight[1]);
}

275
#ifdef CONFIG_FAIL_MAKE_REQUEST
276 277
ssize_t part_fail_show(struct device *dev,
		       struct device_attribute *attr, char *buf)
278 279
{
	struct hd_struct *p = dev_to_part(dev);
280

281 282 283
	return sprintf(buf, "%d\n", p->make_it_fail);
}

284 285 286
ssize_t part_fail_store(struct device *dev,
			struct device_attribute *attr,
			const char *buf, size_t count)
287
{
288
	struct hd_struct *p = dev_to_part(dev);
289 290 291 292 293 294 295
	int i;

	if (count > 0 && sscanf(buf, "%d", &i) > 0)
		p->make_it_fail = (i == 0) ? 0 : 1;

	return count;
}
296
#endif
297

298
static DEVICE_ATTR(partition, S_IRUGO, part_partition_show, NULL);
299 300
static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL);
static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
301
static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL);
302 303
static DEVICE_ATTR(discard_alignment, S_IRUGO, part_discard_alignment_show,
		   NULL);
304
static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
305
static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL);
306 307 308
#ifdef CONFIG_FAIL_MAKE_REQUEST
static struct device_attribute dev_attr_fail =
	__ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store);
309 310
#endif

311
static struct attribute *part_attrs[] = {
312
	&dev_attr_partition.attr,
313 314
	&dev_attr_start.attr,
	&dev_attr_size.attr,
315
	&dev_attr_alignment_offset.attr,
316
	&dev_attr_discard_alignment.attr,
317
	&dev_attr_stat.attr,
318
	&dev_attr_inflight.attr,
319
#ifdef CONFIG_FAIL_MAKE_REQUEST
320
	&dev_attr_fail.attr,
321
#endif
322
	NULL
L
Linus Torvalds 已提交
323 324
};

325 326 327
static struct attribute_group part_attr_group = {
	.attrs = part_attrs,
};
L
Linus Torvalds 已提交
328

329
static const struct attribute_group *part_attr_groups[] = {
330
	&part_attr_group,
331 332 333
#ifdef CONFIG_BLK_DEV_IO_TRACE
	&blk_trace_attr_group,
#endif
334 335 336 337
	NULL
};

static void part_release(struct device *dev)
L
Linus Torvalds 已提交
338
{
339
	struct hd_struct *p = dev_to_part(dev);
340
	free_part_stats(p);
L
Linus Torvalds 已提交
341 342 343
	kfree(p);
}

344 345 346
struct device_type part_type = {
	.name		= "partition",
	.groups		= part_attr_groups,
L
Linus Torvalds 已提交
347 348 349
	.release	= part_release,
};

350 351 352 353 354 355 356
static void delete_partition_rcu_cb(struct rcu_head *head)
{
	struct hd_struct *part = container_of(head, struct hd_struct, rcu_head);

	part->start_sect = 0;
	part->nr_sects = 0;
	part_stat_set_all(part, 0);
357
	put_device(part_to_dev(part));
358 359
}

360
void delete_partition(struct gendisk *disk, int partno)
L
Linus Torvalds 已提交
361
{
T
Tejun Heo 已提交
362
	struct disk_part_tbl *ptbl = disk->part_tbl;
363
	struct hd_struct *part;
364

T
Tejun Heo 已提交
365 366 367 368
	if (partno >= ptbl->len)
		return;

	part = ptbl->part[partno];
369
	if (!part)
L
Linus Torvalds 已提交
370
		return;
371

T
Tejun Heo 已提交
372
	blk_free_devt(part_devt(part));
T
Tejun Heo 已提交
373
	rcu_assign_pointer(ptbl->part[partno], NULL);
N
Neil Brown 已提交
374
	rcu_assign_pointer(ptbl->last_lookup, NULL);
375
	kobject_put(part->holder_dir);
376
	device_del(part_to_dev(part));
377 378

	call_rcu(&part->rcu_head, delete_partition_rcu_cb);
L
Linus Torvalds 已提交
379 380
}

381 382 383 384 385 386 387 388
static ssize_t whole_disk_show(struct device *dev,
			       struct device_attribute *attr, char *buf)
{
	return 0;
}
static DEVICE_ATTR(whole_disk, S_IRUSR | S_IRGRP | S_IROTH,
		   whole_disk_show, NULL);

389 390
struct hd_struct *add_partition(struct gendisk *disk, int partno,
				sector_t start, sector_t len, int flags)
L
Linus Torvalds 已提交
391 392
{
	struct hd_struct *p;
T
Tejun Heo 已提交
393
	dev_t devt = MKDEV(0, 0);
394 395
	struct device *ddev = disk_to_dev(disk);
	struct device *pdev;
T
Tejun Heo 已提交
396
	struct disk_part_tbl *ptbl;
397
	const char *dname;
398
	int err;
L
Linus Torvalds 已提交
399

T
Tejun Heo 已提交
400 401
	err = disk_expand_part_tbl(disk, partno);
	if (err)
402
		return ERR_PTR(err);
T
Tejun Heo 已提交
403 404 405
	ptbl = disk->part_tbl;

	if (ptbl->part[partno])
406
		return ERR_PTR(-EBUSY);
407

408
	p = kzalloc(sizeof(*p), GFP_KERNEL);
L
Linus Torvalds 已提交
409
	if (!p)
410
		return ERR_PTR(-EBUSY);
411

412
	if (!init_part_stats(p)) {
413
		err = -ENOMEM;
414
		goto out_free;
415
	}
416 417
	pdev = part_to_dev(p);

L
Linus Torvalds 已提交
418
	p->start_sect = start;
419 420 421 422
	p->alignment_offset =
		queue_limit_alignment_offset(&disk->queue->limits, start);
	p->discard_alignment =
		queue_limit_discard_alignment(&disk->queue->limits, start);
L
Linus Torvalds 已提交
423
	p->nr_sects = len;
424
	p->partno = partno;
T
Tejun Heo 已提交
425
	p->policy = get_disk_ro(disk);
L
Linus Torvalds 已提交
426

427 428
	dname = dev_name(ddev);
	if (isdigit(dname[strlen(dname) - 1]))
429
		dev_set_name(pdev, "%sp%d", dname, partno);
L
Linus Torvalds 已提交
430
	else
431
		dev_set_name(pdev, "%s%d", dname, partno);
432

433 434 435 436
	device_initialize(pdev);
	pdev->class = &block_class;
	pdev->type = &part_type;
	pdev->parent = ddev;
437

T
Tejun Heo 已提交
438 439
	err = blk_alloc_devt(p, &devt);
	if (err)
T
Tejun Heo 已提交
440
		goto out_free_stats;
441
	pdev->devt = devt;
T
Tejun Heo 已提交
442

443
	/* delay uevent until 'holders' subdir is created */
444
	dev_set_uevent_suppress(pdev, 1);
445
	err = device_add(pdev);
446
	if (err)
447 448 449
		goto out_put;

	err = -ENOMEM;
450
	p->holder_dir = kobject_create_and_add("holders", &pdev->kobj);
451 452 453
	if (!p->holder_dir)
		goto out_del;

454
	dev_set_uevent_suppress(pdev, 0);
455
	if (flags & ADDPART_FLAG_WHOLEDISK) {
456
		err = device_create_file(pdev, &dev_attr_whole_disk);
457
		if (err)
458
			goto out_del;
459
	}
L
Linus Torvalds 已提交
460

461
	/* everything is up and running, commence */
T
Tejun Heo 已提交
462
	rcu_assign_pointer(ptbl->part[partno], p);
463

464
	/* suppress uevent if the disk supresses it */
465
	if (!dev_get_uevent_suppress(ddev))
466
		kobject_uevent(&pdev->kobj, KOBJ_ADD);
467

468
	return p;
469

T
Tejun Heo 已提交
470 471
out_free_stats:
	free_part_stats(p);
472 473
out_free:
	kfree(p);
474
	return ERR_PTR(err);
475 476
out_del:
	kobject_put(p->holder_dir);
477
	device_del(pdev);
478
out_put:
479
	put_device(pdev);
T
Tejun Heo 已提交
480
	blk_free_devt(devt);
481
	return ERR_PTR(err);
L
Linus Torvalds 已提交
482 483 484 485 486
}

/* Not exported, helper to add_disk(). */
void register_disk(struct gendisk *disk)
{
487
	struct device *ddev = disk_to_dev(disk);
L
Linus Torvalds 已提交
488
	struct block_device *bdev;
489 490
	struct disk_part_iter piter;
	struct hd_struct *part;
L
Linus Torvalds 已提交
491 492
	int err;

493
	ddev->parent = disk->driverfs_dev;
494

495
	dev_set_name(ddev, disk->disk_name);
496 497

	/* delay uevents, until we scanned partition table */
498
	dev_set_uevent_suppress(ddev, 1);
499

500
	if (device_add(ddev))
L
Linus Torvalds 已提交
501
		return;
502
#ifndef CONFIG_SYSFS_DEPRECATED
503 504
	err = sysfs_create_link(block_depr, &ddev->kobj,
				kobject_name(&ddev->kobj));
505
	if (err) {
506
		device_del(ddev);
507 508
		return;
	}
509
#endif
510 511
	disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj);
	disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj);
L
Linus Torvalds 已提交
512 513

	/* No minors to use for partitions */
T
Tejun Heo 已提交
514
	if (!disk_partitionable(disk))
515
		goto exit;
L
Linus Torvalds 已提交
516 517 518

	/* No such device (e.g., media were just removed) */
	if (!get_capacity(disk))
519
		goto exit;
L
Linus Torvalds 已提交
520 521 522

	bdev = bdget_disk(disk, 0);
	if (!bdev)
523
		goto exit;
L
Linus Torvalds 已提交
524 525

	bdev->bd_invalidated = 1;
526
	err = blkdev_get(bdev, FMODE_READ);
527 528
	if (err < 0)
		goto exit;
A
Al Viro 已提交
529
	blkdev_put(bdev, FMODE_READ);
530 531

exit:
532
	/* announce disk after possible partitions are created */
533
	dev_set_uevent_suppress(ddev, 0);
534
	kobject_uevent(&ddev->kobj, KOBJ_ADD);
535 536

	/* announce possible partitions */
537 538
	disk_part_iter_init(&piter, disk, 0);
	while ((part = disk_part_iter_next(&piter)))
539
		kobject_uevent(&part_to_dev(part)->kobj, KOBJ_ADD);
540
	disk_part_iter_exit(&piter);
L
Linus Torvalds 已提交
541 542
}

543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
static bool disk_unlock_native_capacity(struct gendisk *disk)
{
	const struct block_device_operations *bdops = disk->fops;

	if (bdops->unlock_native_capacity &&
	    !(disk->flags & GENHD_FL_NATIVE_CAPACITY)) {
		printk(KERN_CONT "enabling native capacity\n");
		bdops->unlock_native_capacity(disk);
		disk->flags |= GENHD_FL_NATIVE_CAPACITY;
		return true;
	} else {
		printk(KERN_CONT "truncated\n");
		return false;
	}
}

L
Linus Torvalds 已提交
559 560
int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
{
561
	struct parsed_partitions *state = NULL;
562 563
	struct disk_part_iter piter;
	struct hd_struct *part;
T
Tejun Heo 已提交
564
	int p, highest, res;
565
rescan:
566 567 568 569 570
	if (state && !IS_ERR(state)) {
		kfree(state);
		state = NULL;
	}

L
Linus Torvalds 已提交
571 572 573 574 575
	if (bdev->bd_part_count)
		return -EBUSY;
	res = invalidate_partition(disk, 0);
	if (res)
		return res;
576 577 578 579 580 581

	disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY);
	while ((part = disk_part_iter_next(&piter)))
		delete_partition(disk, part->partno);
	disk_part_iter_exit(&piter);

L
Linus Torvalds 已提交
582 583
	if (disk->fops->revalidate_disk)
		disk->fops->revalidate_disk(disk);
584 585
	check_disk_size_change(disk, bdev);
	bdev->bd_invalidated = 0;
L
Linus Torvalds 已提交
586 587
	if (!get_capacity(disk) || !(state = check_partition(disk, bdev)))
		return 0;
588 589 590 591 592 593 594 595 596 597 598 599
	if (IS_ERR(state)) {
		/*
		 * I/O error reading the partition table.  If any
		 * partition code tried to read beyond EOD, retry
		 * after unlocking native capacity.
		 */
		if (PTR_ERR(state) == -ENOSPC) {
			printk(KERN_WARNING "%s: partition table beyond EOD, ",
			       disk->disk_name);
			if (disk_unlock_native_capacity(disk))
				goto rescan;
		}
600
		return -EIO;
601 602 603 604 605 606 607 608 609 610 611 612 613
	}
	/*
	 * If any partition code tried to read beyond EOD, try
	 * unlocking native capacity even if partition table is
	 * sucessfully read as we could be missing some partitions.
	 */
	if (state->access_beyond_eod) {
		printk(KERN_WARNING
		       "%s: partition table partially beyond EOD, ",
		       disk->disk_name);
		if (disk_unlock_native_capacity(disk))
			goto rescan;
	}
614 615

	/* tell userspace that the media / partition table may have changed */
616
	kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE);
617

T
Tejun Heo 已提交
618 619 620 621 622 623 624 625 626 627 628
	/* Detect the highest partition number and preallocate
	 * disk->part_tbl.  This is an optimization and not strictly
	 * necessary.
	 */
	for (p = 1, highest = 0; p < state->limit; p++)
		if (state->parts[p].size)
			highest = p;

	disk_expand_part_tbl(disk, highest);

	/* add partitions */
L
Linus Torvalds 已提交
629
	for (p = 1; p < state->limit; p++) {
630
		sector_t size, from;
631

632
		size = state->parts[p].size;
L
Linus Torvalds 已提交
633 634
		if (!size)
			continue;
635 636

		from = state->parts[p].from;
637 638
		if (from >= get_capacity(disk)) {
			printk(KERN_WARNING
639
			       "%s: p%d start %llu is beyond EOD, ",
640
			       disk->disk_name, p, (unsigned long long) from);
641 642
			if (disk_unlock_native_capacity(disk))
				goto rescan;
643 644
			continue;
		}
645

646
		if (from + size > get_capacity(disk)) {
647
			printk(KERN_WARNING
648
			       "%s: p%d size %llu extends beyond EOD, ",
649
			       disk->disk_name, p, (unsigned long long) size);
650

651
			if (disk_unlock_native_capacity(disk)) {
652 653
				/* free state and restart */
				goto rescan;
654 655 656 657 658 659 660 661 662
			} else {
				/*
				 * we can not ignore partitions of broken tables
				 * created by for example camera firmware, but
				 * we limit them to the end of the disk to avoid
				 * creating invalid block devices
				 */
				size = get_capacity(disk) - from;
			}
663
		}
664 665 666 667 668
		part = add_partition(disk, p, from, size,
				     state->parts[p].flags);
		if (IS_ERR(part)) {
			printk(KERN_ERR " %s: p%d could not be added: %ld\n",
			       disk->disk_name, p, -PTR_ERR(part));
669
			continue;
670
		}
L
Linus Torvalds 已提交
671
#ifdef CONFIG_BLK_DEV_MD
672
		if (state->parts[p].flags & ADDPART_FLAG_RAID)
T
Tejun Heo 已提交
673
			md_autodetect_dev(part_to_dev(part)->devt);
L
Linus Torvalds 已提交
674 675 676 677 678 679 680 681 682 683 684
#endif
	}
	kfree(state);
	return 0;
}

unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p)
{
	struct address_space *mapping = bdev->bd_inode->i_mapping;
	struct page *page;

685 686
	page = read_mapping_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)),
				 NULL);
L
Linus Torvalds 已提交
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
	if (!IS_ERR(page)) {
		if (PageError(page))
			goto fail;
		p->v = page;
		return (unsigned char *)page_address(page) +  ((n & ((1 << (PAGE_CACHE_SHIFT - 9)) - 1)) << 9);
fail:
		page_cache_release(page);
	}
	p->v = NULL;
	return NULL;
}

EXPORT_SYMBOL(read_dev_sector);

void del_gendisk(struct gendisk *disk)
{
703 704
	struct disk_part_iter piter;
	struct hd_struct *part;
L
Linus Torvalds 已提交
705 706

	/* invalidate stuff */
707 708 709 710 711
	disk_part_iter_init(&piter, disk,
			     DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE);
	while ((part = disk_part_iter_next(&piter))) {
		invalidate_partition(disk, part->partno);
		delete_partition(disk, part->partno);
L
Linus Torvalds 已提交
712
	}
713 714
	disk_part_iter_exit(&piter);

L
Linus Torvalds 已提交
715
	invalidate_partition(disk, 0);
716
	blk_free_devt(disk_to_dev(disk)->devt);
717
	set_capacity(disk, 0);
L
Linus Torvalds 已提交
718 719
	disk->flags &= ~GENHD_FL_UP;
	unlink_gendisk(disk);
T
Tejun Heo 已提交
720 721
	part_stat_set_all(&disk->part0, 0);
	disk->part0.stamp = 0;
L
Linus Torvalds 已提交
722

723
	kobject_put(disk->part0.holder_dir);
724
	kobject_put(disk->slave_dir);
725 726
	disk->driverfs_dev = NULL;
#ifndef CONFIG_SYSFS_DEPRECATED
727
	sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk)));
728
#endif
729
	device_del(disk_to_dev(disk));
L
Linus Torvalds 已提交
730
}