2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* 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>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 16:04:11 +08:00
|
|
|
#include <linux/slab.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/kmod.h>
|
|
|
|
#include <linux/ctype.h>
|
2008-02-08 18:04:35 +08:00
|
|
|
#include <linux/genhd.h>
|
2009-01-27 01:00:56 +08:00
|
|
|
#include <linux/blktrace_api.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#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"
|
2006-01-17 14:14:20 +08:00
|
|
|
#include "karma.h"
|
2007-05-08 15:29:15 +08:00
|
|
|
#include "sysv68.h"
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#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*/
|
|
|
|
|
2010-05-16 02:09:30 +08:00
|
|
|
static int (*check_part[])(struct parsed_partitions *) = {
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* 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,
|
2006-01-17 14:14:20 +08:00
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_KARMA_PARTITION
|
|
|
|
karma_partition,
|
2007-05-08 15:29:15 +08:00
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_SYSV68_PARTITION
|
|
|
|
sysv68_partition,
|
2005-04-17 06:20:36 +08:00
|
|
|
#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).
|
|
|
|
*/
|
|
|
|
|
2008-09-03 15:01:09 +08:00
|
|
|
char *disk_name(struct gendisk *hd, int partno, char *buf)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-09-03 15:01:09 +08:00
|
|
|
if (!partno)
|
2005-04-17 06:20:36 +08:00
|
|
|
snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name);
|
|
|
|
else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1]))
|
2008-09-03 15:01:09 +08:00
|
|
|
snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, partno);
|
2005-04-17 06:20:36 +08:00
|
|
|
else
|
2008-09-03 15:01:09 +08:00
|
|
|
snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, partno);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *bdevname(struct block_device *bdev, char *buf)
|
|
|
|
{
|
2008-08-25 18:56:12 +08:00
|
|
|
return disk_name(bdev->bd_disk, bdev->bd_part->partno, buf);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2006-12-07 12:35:16 +08:00
|
|
|
int i, res, err;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2010-05-16 02:09:31 +08:00
|
|
|
state = kzalloc(sizeof(struct parsed_partitions), GFP_KERNEL);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!state)
|
|
|
|
return NULL;
|
2010-08-11 09:03:14 +08:00
|
|
|
state->pp_buf = (char *)__get_free_page(GFP_KERNEL);
|
|
|
|
if (!state->pp_buf) {
|
|
|
|
kfree(state);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
state->pp_buf[0] = '\0';
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2010-05-16 02:09:30 +08:00
|
|
|
state->bdev = bdev;
|
2005-06-21 12:15:16 +08:00
|
|
|
disk_name(hd, 0, state->name);
|
2010-08-11 09:03:14 +08:00
|
|
|
snprintf(state->pp_buf, PAGE_SIZE, " %s:", state->name);
|
2005-06-21 12:15:16 +08:00
|
|
|
if (isdigit(state->name[strlen(state->name)-1]))
|
2005-04-17 06:20:36 +08:00
|
|
|
sprintf(state->name, "p");
|
2005-06-21 12:15:16 +08:00
|
|
|
|
2008-09-03 15:06:42 +08:00
|
|
|
state->limit = disk_max_parts(hd);
|
2006-12-07 12:35:16 +08:00
|
|
|
i = res = err = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
while (!res && check_part[i]) {
|
|
|
|
memset(&state->parts, 0, sizeof(state->parts));
|
2010-05-16 02:09:30 +08:00
|
|
|
res = check_part[i++](state);
|
2006-12-07 12:35:16 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2010-08-11 09:03:14 +08:00
|
|
|
if (res > 0) {
|
|
|
|
printk(KERN_INFO "%s", state->pp_buf);
|
|
|
|
|
|
|
|
free_page((unsigned long)state->pp_buf);
|
2005-04-17 06:20:36 +08:00
|
|
|
return state;
|
2010-08-11 09:03:14 +08:00
|
|
|
}
|
2010-05-16 02:09:31 +08:00
|
|
|
if (state->access_beyond_eod)
|
|
|
|
err = -ENOSPC;
|
2007-03-08 12:41:24 +08:00
|
|
|
if (err)
|
2006-12-07 12:35:16 +08:00
|
|
|
/* The partition is unrecognized. So report I/O errors if there were any */
|
|
|
|
res = err;
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!res)
|
2010-08-11 09:03:14 +08:00
|
|
|
strlcat(state->pp_buf, " unknown partition table\n", PAGE_SIZE);
|
2005-04-17 06:20:36 +08:00
|
|
|
else if (warn_no_part)
|
2010-08-11 09:03:14 +08:00
|
|
|
strlcat(state->pp_buf, " unable to read partition table\n", PAGE_SIZE);
|
|
|
|
|
|
|
|
printk(KERN_INFO "%s", state->pp_buf);
|
|
|
|
|
|
|
|
free_page((unsigned long)state->pp_buf);
|
2005-04-17 06:20:36 +08:00
|
|
|
kfree(state);
|
2006-12-07 12:35:14 +08:00
|
|
|
return ERR_PTR(res);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2008-10-13 19:27:59 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2007-05-22 04:08:01 +08:00
|
|
|
static ssize_t part_start_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2007-05-22 04:08:01 +08:00
|
|
|
struct hd_struct *p = dev_to_part(dev);
|
2005-10-01 20:49:43 +08:00
|
|
|
|
2007-05-22 04:08:01 +08:00
|
|
|
return sprintf(buf, "%llu\n",(unsigned long long)p->start_sect);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2008-08-25 18:56:09 +08:00
|
|
|
ssize_t part_size_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
2005-10-01 20:49:43 +08:00
|
|
|
{
|
2007-05-22 04:08:01 +08:00
|
|
|
struct hd_struct *p = dev_to_part(dev);
|
|
|
|
return sprintf(buf, "%llu\n",(unsigned long long)p->nr_sects);
|
2005-10-01 20:49:43 +08:00
|
|
|
}
|
2007-05-22 04:08:01 +08:00
|
|
|
|
2011-06-13 17:47:24 +08:00
|
|
|
static ssize_t part_ro_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
2010-11-11 16:58:57 +08:00
|
|
|
{
|
|
|
|
struct hd_struct *p = dev_to_part(dev);
|
|
|
|
return sprintf(buf, "%d\n", p->policy ? 1 : 0);
|
|
|
|
}
|
|
|
|
|
2011-06-13 17:47:24 +08:00
|
|
|
static ssize_t part_alignment_offset_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
2009-05-23 05:17:53 +08:00
|
|
|
{
|
|
|
|
struct hd_struct *p = dev_to_part(dev);
|
|
|
|
return sprintf(buf, "%llu\n", (unsigned long long)p->alignment_offset);
|
|
|
|
}
|
|
|
|
|
2011-06-13 17:47:24 +08:00
|
|
|
static ssize_t part_discard_alignment_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
2009-11-10 18:50:21 +08:00
|
|
|
{
|
|
|
|
struct hd_struct *p = dev_to_part(dev);
|
2011-05-30 13:42:51 +08:00
|
|
|
return sprintf(buf, "%u\n", p->discard_alignment);
|
2009-11-10 18:50:21 +08:00
|
|
|
}
|
|
|
|
|
2008-08-25 18:56:14 +08:00
|
|
|
ssize_t part_stat_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2007-05-22 04:08:01 +08:00
|
|
|
struct hd_struct *p = dev_to_part(dev);
|
2008-08-25 18:47:21 +08:00
|
|
|
int cpu;
|
2007-05-22 04:08:01 +08:00
|
|
|
|
2008-08-25 18:56:14 +08:00
|
|
|
cpu = part_stat_lock();
|
2008-08-25 18:47:21 +08:00
|
|
|
part_round_stats(cpu, p);
|
2008-08-25 18:56:14 +08:00
|
|
|
part_stat_unlock();
|
2008-02-08 18:04:55 +08:00
|
|
|
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])),
|
block: Seperate read and write statistics of in_flight requests v2
Commit a9327cac440be4d8333bba975cbbf76045096275 added seperate read
and write statistics of in_flight requests. And exported the number
of read and write requests in progress seperately through sysfs.
But Corrado Zoccolo <czoccolo@gmail.com> reported getting strange
output from "iostat -kx 2". Global values for service time and
utilization were garbage. For interval values, utilization was always
100%, and service time is higher than normal.
So this was reverted by commit 0f78ab9899e9d6acb09d5465def618704255963b
The problem was in part_round_stats_single(), I missed the following:
if (now == part->stamp)
return;
- if (part->in_flight) {
+ if (part_in_flight(part)) {
__part_stat_add(cpu, part, time_in_queue,
part_in_flight(part) * (now - part->stamp));
__part_stat_add(cpu, part, io_ticks, (now - part->stamp));
With this chunk included, the reported regression gets fixed.
Signed-off-by: Nikanth Karthikesan <knikanth@suse.de>
--
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
2009-10-07 02:16:55 +08:00
|
|
|
part_in_flight(p),
|
2008-02-08 18:04:55 +08:00
|
|
|
jiffies_to_msecs(part_stat_read(p, io_ticks)),
|
|
|
|
jiffies_to_msecs(part_stat_read(p, time_in_queue)));
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
block: Seperate read and write statistics of in_flight requests v2
Commit a9327cac440be4d8333bba975cbbf76045096275 added seperate read
and write statistics of in_flight requests. And exported the number
of read and write requests in progress seperately through sysfs.
But Corrado Zoccolo <czoccolo@gmail.com> reported getting strange
output from "iostat -kx 2". Global values for service time and
utilization were garbage. For interval values, utilization was always
100%, and service time is higher than normal.
So this was reverted by commit 0f78ab9899e9d6acb09d5465def618704255963b
The problem was in part_round_stats_single(), I missed the following:
if (now == part->stamp)
return;
- if (part->in_flight) {
+ if (part_in_flight(part)) {
__part_stat_add(cpu, part, time_in_queue,
part_in_flight(part) * (now - part->stamp));
__part_stat_add(cpu, part, io_ticks, (now - part->stamp));
With this chunk included, the reported regression gets fixed.
Signed-off-by: Nikanth Karthikesan <knikanth@suse.de>
--
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
2009-10-07 02:16:55 +08:00
|
|
|
ssize_t part_inflight_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct hd_struct *p = dev_to_part(dev);
|
|
|
|
|
2011-03-22 15:35:35 +08:00
|
|
|
return sprintf(buf, "%8u %8u\n", atomic_read(&p->in_flight[0]),
|
|
|
|
atomic_read(&p->in_flight[1]));
|
block: Seperate read and write statistics of in_flight requests v2
Commit a9327cac440be4d8333bba975cbbf76045096275 added seperate read
and write statistics of in_flight requests. And exported the number
of read and write requests in progress seperately through sysfs.
But Corrado Zoccolo <czoccolo@gmail.com> reported getting strange
output from "iostat -kx 2". Global values for service time and
utilization were garbage. For interval values, utilization was always
100%, and service time is higher than normal.
So this was reverted by commit 0f78ab9899e9d6acb09d5465def618704255963b
The problem was in part_round_stats_single(), I missed the following:
if (now == part->stamp)
return;
- if (part->in_flight) {
+ if (part_in_flight(part)) {
__part_stat_add(cpu, part, time_in_queue,
part_in_flight(part) * (now - part->stamp));
__part_stat_add(cpu, part, io_ticks, (now - part->stamp));
With this chunk included, the reported regression gets fixed.
Signed-off-by: Nikanth Karthikesan <knikanth@suse.de>
--
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
2009-10-07 02:16:55 +08:00
|
|
|
}
|
|
|
|
|
2006-12-08 18:39:46 +08:00
|
|
|
#ifdef CONFIG_FAIL_MAKE_REQUEST
|
2008-08-25 18:56:13 +08:00
|
|
|
ssize_t part_fail_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
2007-05-22 04:08:01 +08:00
|
|
|
{
|
|
|
|
struct hd_struct *p = dev_to_part(dev);
|
2006-12-08 18:39:46 +08:00
|
|
|
|
2007-05-22 04:08:01 +08:00
|
|
|
return sprintf(buf, "%d\n", p->make_it_fail);
|
|
|
|
}
|
|
|
|
|
2008-08-25 18:56:13 +08:00
|
|
|
ssize_t part_fail_store(struct device *dev,
|
|
|
|
struct device_attribute *attr,
|
|
|
|
const char *buf, size_t count)
|
2006-12-08 18:39:46 +08:00
|
|
|
{
|
2007-05-22 04:08:01 +08:00
|
|
|
struct hd_struct *p = dev_to_part(dev);
|
2006-12-08 18:39:46 +08:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (count > 0 && sscanf(buf, "%d", &i) > 0)
|
|
|
|
p->make_it_fail = (i == 0) ? 0 : 1;
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
2007-05-22 04:08:01 +08:00
|
|
|
#endif
|
2006-12-08 18:39:46 +08:00
|
|
|
|
2008-10-13 19:27:59 +08:00
|
|
|
static DEVICE_ATTR(partition, S_IRUGO, part_partition_show, NULL);
|
2007-05-22 04:08:01 +08:00
|
|
|
static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL);
|
|
|
|
static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
|
2010-11-11 16:58:57 +08:00
|
|
|
static DEVICE_ATTR(ro, S_IRUGO, part_ro_show, NULL);
|
2009-05-23 05:17:53 +08:00
|
|
|
static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL);
|
2009-11-10 18:50:21 +08:00
|
|
|
static DEVICE_ATTR(discard_alignment, S_IRUGO, part_discard_alignment_show,
|
|
|
|
NULL);
|
2007-05-22 04:08:01 +08:00
|
|
|
static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
|
block: Seperate read and write statistics of in_flight requests v2
Commit a9327cac440be4d8333bba975cbbf76045096275 added seperate read
and write statistics of in_flight requests. And exported the number
of read and write requests in progress seperately through sysfs.
But Corrado Zoccolo <czoccolo@gmail.com> reported getting strange
output from "iostat -kx 2". Global values for service time and
utilization were garbage. For interval values, utilization was always
100%, and service time is higher than normal.
So this was reverted by commit 0f78ab9899e9d6acb09d5465def618704255963b
The problem was in part_round_stats_single(), I missed the following:
if (now == part->stamp)
return;
- if (part->in_flight) {
+ if (part_in_flight(part)) {
__part_stat_add(cpu, part, time_in_queue,
part_in_flight(part) * (now - part->stamp));
__part_stat_add(cpu, part, io_ticks, (now - part->stamp));
With this chunk included, the reported regression gets fixed.
Signed-off-by: Nikanth Karthikesan <knikanth@suse.de>
--
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
2009-10-07 02:16:55 +08:00
|
|
|
static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL);
|
2007-05-22 04:08:01 +08:00
|
|
|
#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);
|
2006-12-08 18:39:46 +08:00
|
|
|
#endif
|
|
|
|
|
2007-05-22 04:08:01 +08:00
|
|
|
static struct attribute *part_attrs[] = {
|
2008-10-13 19:27:59 +08:00
|
|
|
&dev_attr_partition.attr,
|
2007-05-22 04:08:01 +08:00
|
|
|
&dev_attr_start.attr,
|
|
|
|
&dev_attr_size.attr,
|
2010-11-11 16:58:57 +08:00
|
|
|
&dev_attr_ro.attr,
|
2009-05-23 05:17:53 +08:00
|
|
|
&dev_attr_alignment_offset.attr,
|
2009-11-10 18:50:21 +08:00
|
|
|
&dev_attr_discard_alignment.attr,
|
2007-05-22 04:08:01 +08:00
|
|
|
&dev_attr_stat.attr,
|
block: Seperate read and write statistics of in_flight requests v2
Commit a9327cac440be4d8333bba975cbbf76045096275 added seperate read
and write statistics of in_flight requests. And exported the number
of read and write requests in progress seperately through sysfs.
But Corrado Zoccolo <czoccolo@gmail.com> reported getting strange
output from "iostat -kx 2". Global values for service time and
utilization were garbage. For interval values, utilization was always
100%, and service time is higher than normal.
So this was reverted by commit 0f78ab9899e9d6acb09d5465def618704255963b
The problem was in part_round_stats_single(), I missed the following:
if (now == part->stamp)
return;
- if (part->in_flight) {
+ if (part_in_flight(part)) {
__part_stat_add(cpu, part, time_in_queue,
part_in_flight(part) * (now - part->stamp));
__part_stat_add(cpu, part, io_ticks, (now - part->stamp));
With this chunk included, the reported regression gets fixed.
Signed-off-by: Nikanth Karthikesan <knikanth@suse.de>
--
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
2009-10-07 02:16:55 +08:00
|
|
|
&dev_attr_inflight.attr,
|
2006-12-08 18:39:46 +08:00
|
|
|
#ifdef CONFIG_FAIL_MAKE_REQUEST
|
2007-05-22 04:08:01 +08:00
|
|
|
&dev_attr_fail.attr,
|
2006-12-08 18:39:46 +08:00
|
|
|
#endif
|
2007-05-22 04:08:01 +08:00
|
|
|
NULL
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
2007-05-22 04:08:01 +08:00
|
|
|
static struct attribute_group part_attr_group = {
|
|
|
|
.attrs = part_attrs,
|
|
|
|
};
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-06-25 01:06:31 +08:00
|
|
|
static const struct attribute_group *part_attr_groups[] = {
|
2007-05-22 04:08:01 +08:00
|
|
|
&part_attr_group,
|
blktrace: add ftrace plugin
Impact: New way of using the blktrace infrastructure
This drops the requirement of userspace utilities to use the blktrace
facility.
Configuration is done thru sysfs, adding a "trace" directory to the
partition directory where blktrace can be enabled for the associated
request_queue.
The same filters present in the IOCTL interface are present as sysfs
device attributes.
The /sys/block/sdX/sdXN/trace/enable file allows tracing without any
filters.
The other files in this directory: pid, act_mask, start_lba and end_lba
can be used with the same meaning as with the IOCTL interface.
Using the sysfs interface will only setup the request_queue->blk_trace
fields, tracing will only take place when the "blk" tracer is selected
via the ftrace interface, as in the following example:
To see the trace, one can use the /d/tracing/trace file or the
/d/tracign/trace_pipe file, with semantics defined in the ftrace
documentation in Documentation/ftrace.txt.
[root@f10-1 ~]# cat /t/trace
kjournald-305 [000] 3046.491224: 8,1 A WBS 6367 + 8 <- (8,1) 6304
kjournald-305 [000] 3046.491227: 8,1 Q R 6367 + 8 [kjournald]
kjournald-305 [000] 3046.491236: 8,1 G RB 6367 + 8 [kjournald]
kjournald-305 [000] 3046.491239: 8,1 P NS [kjournald]
kjournald-305 [000] 3046.491242: 8,1 I RBS 6367 + 8 [kjournald]
kjournald-305 [000] 3046.491251: 8,1 D WB 6367 + 8 [kjournald]
kjournald-305 [000] 3046.491610: 8,1 U WS [kjournald] 1
<idle>-0 [000] 3046.511914: 8,1 C RS 6367 + 8 [6367]
[root@f10-1 ~]#
The default line context (prefix) format is the one described in the ftrace
documentation, with the blktrace specific bits using its existing format,
described in blkparse(8).
If one wants to have the classic blktrace formatting, this is possible by
using:
[root@f10-1 ~]# echo blk_classic > /t/trace_options
[root@f10-1 ~]# cat /t/trace
8,1 0 3046.491224 305 A WBS 6367 + 8 <- (8,1) 6304
8,1 0 3046.491227 305 Q R 6367 + 8 [kjournald]
8,1 0 3046.491236 305 G RB 6367 + 8 [kjournald]
8,1 0 3046.491239 305 P NS [kjournald]
8,1 0 3046.491242 305 I RBS 6367 + 8 [kjournald]
8,1 0 3046.491251 305 D WB 6367 + 8 [kjournald]
8,1 0 3046.491610 305 U WS [kjournald] 1
8,1 0 3046.511914 0 C RS 6367 + 8 [6367]
[root@f10-1 ~]#
Using the ftrace standard format allows more flexibility, such
as the ability of asking for backtraces via trace_options:
[root@f10-1 ~]# echo noblk_classic > /t/trace_options
[root@f10-1 ~]# echo stacktrace > /t/trace_options
[root@f10-1 ~]# cat /t/trace
kjournald-305 [000] 3318.826779: 8,1 A WBS 6375 + 8 <- (8,1) 6312
kjournald-305 [000] 3318.826782:
<= submit_bio
<= submit_bh
<= sync_dirty_buffer
<= journal_commit_transaction
<= kjournald
<= kthread
<= child_rip
kjournald-305 [000] 3318.826836: 8,1 Q R 6375 + 8 [kjournald]
kjournald-305 [000] 3318.826837:
<= generic_make_request
<= submit_bio
<= submit_bh
<= sync_dirty_buffer
<= journal_commit_transaction
<= kjournald
<= kthread
Please read the ftrace documentation to use aditional, standardized
tracing filters such as /d/tracing/trace_cpumask, etc.
See also /d/tracing/trace_mark to add comments in the trace stream,
that is equivalent to the /d/block/sdaN/msg interface.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-01-23 22:06:27 +08:00
|
|
|
#ifdef CONFIG_BLK_DEV_IO_TRACE
|
|
|
|
&blk_trace_attr_group,
|
|
|
|
#endif
|
2007-05-22 04:08:01 +08:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
static void part_release(struct device *dev)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2007-05-22 04:08:01 +08:00
|
|
|
struct hd_struct *p = dev_to_part(dev);
|
2008-02-08 18:04:35 +08:00
|
|
|
free_part_stats(p);
|
2010-09-01 04:47:05 +08:00
|
|
|
free_part_info(p);
|
2005-04-17 06:20:36 +08:00
|
|
|
kfree(p);
|
|
|
|
}
|
|
|
|
|
2007-05-22 04:08:01 +08:00
|
|
|
struct device_type part_type = {
|
|
|
|
.name = "partition",
|
|
|
|
.groups = part_attr_groups,
|
2005-04-17 06:20:36 +08:00
|
|
|
.release = part_release,
|
|
|
|
};
|
|
|
|
|
2008-09-03 15:03:02 +08:00
|
|
|
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);
|
2008-08-25 18:56:05 +08:00
|
|
|
put_device(part_to_dev(part));
|
2008-09-03 15:03:02 +08:00
|
|
|
}
|
|
|
|
|
2011-01-07 15:43:37 +08:00
|
|
|
void __delete_partition(struct hd_struct *part)
|
2011-01-05 23:57:38 +08:00
|
|
|
{
|
|
|
|
call_rcu(&part->rcu_head, delete_partition_rcu_cb);
|
|
|
|
}
|
|
|
|
|
2008-09-03 15:01:09 +08:00
|
|
|
void delete_partition(struct gendisk *disk, int partno)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-08-25 18:56:15 +08:00
|
|
|
struct disk_part_tbl *ptbl = disk->part_tbl;
|
2008-09-03 15:03:02 +08:00
|
|
|
struct hd_struct *part;
|
2007-05-22 04:08:01 +08:00
|
|
|
|
2008-08-25 18:56:15 +08:00
|
|
|
if (partno >= ptbl->len)
|
|
|
|
return;
|
|
|
|
|
|
|
|
part = ptbl->part[partno];
|
2008-09-03 15:03:02 +08:00
|
|
|
if (!part)
|
2005-04-17 06:20:36 +08:00
|
|
|
return;
|
2008-09-03 15:03:02 +08:00
|
|
|
|
2008-08-25 18:47:22 +08:00
|
|
|
blk_free_devt(part_devt(part));
|
2008-08-25 18:56:15 +08:00
|
|
|
rcu_assign_pointer(ptbl->part[partno], NULL);
|
2009-01-07 15:55:39 +08:00
|
|
|
rcu_assign_pointer(ptbl->last_lookup, NULL);
|
2008-09-03 15:03:02 +08:00
|
|
|
kobject_put(part->holder_dir);
|
2008-08-25 18:56:05 +08:00
|
|
|
device_del(part_to_dev(part));
|
2008-09-03 15:03:02 +08:00
|
|
|
|
2011-01-07 15:43:37 +08:00
|
|
|
hd_struct_put(part);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2008-02-07 15:33:39 +08:00
|
|
|
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);
|
|
|
|
|
2008-11-10 14:29:58 +08:00
|
|
|
struct hd_struct *add_partition(struct gendisk *disk, int partno,
|
2010-09-01 04:47:05 +08:00
|
|
|
sector_t start, sector_t len, int flags,
|
|
|
|
struct partition_meta_info *info)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct hd_struct *p;
|
2008-08-25 18:47:22 +08:00
|
|
|
dev_t devt = MKDEV(0, 0);
|
2008-08-25 18:56:05 +08:00
|
|
|
struct device *ddev = disk_to_dev(disk);
|
|
|
|
struct device *pdev;
|
2008-08-25 18:56:15 +08:00
|
|
|
struct disk_part_tbl *ptbl;
|
2008-08-25 18:56:05 +08:00
|
|
|
const char *dname;
|
2007-05-22 04:08:01 +08:00
|
|
|
int err;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-08-25 18:56:15 +08:00
|
|
|
err = disk_expand_part_tbl(disk, partno);
|
|
|
|
if (err)
|
2008-11-10 14:29:58 +08:00
|
|
|
return ERR_PTR(err);
|
2008-08-25 18:56:15 +08:00
|
|
|
ptbl = disk->part_tbl;
|
|
|
|
|
|
|
|
if (ptbl->part[partno])
|
2008-11-10 14:29:58 +08:00
|
|
|
return ERR_PTR(-EBUSY);
|
2008-08-25 18:30:16 +08:00
|
|
|
|
some kmalloc/memset ->kzalloc (tree wide)
Transform some calls to kmalloc/memset to a single kzalloc (or kcalloc).
Here is a short excerpt of the semantic patch performing
this transformation:
@@
type T2;
expression x;
identifier f,fld;
expression E;
expression E1,E2;
expression e1,e2,e3,y;
statement S;
@@
x =
- kmalloc
+ kzalloc
(E1,E2)
... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\)
- memset((T2)x,0,E1);
@@
expression E1,E2,E3;
@@
- kzalloc(E1 * E2,E3)
+ kcalloc(E1,E2,E3)
[akpm@linux-foundation.org: get kcalloc args the right way around]
Signed-off-by: Yoann Padioleau <padator@wanadoo.fr>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Acked-by: Russell King <rmk@arm.linux.org.uk>
Cc: Bryan Wu <bryan.wu@analog.com>
Acked-by: Jiri Slaby <jirislaby@gmail.com>
Cc: Dave Airlie <airlied@linux.ie>
Acked-by: Roland Dreier <rolandd@cisco.com>
Cc: Jiri Kosina <jkosina@suse.cz>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Acked-by: Pierre Ossman <drzeus-list@drzeus.cx>
Cc: Jeff Garzik <jeff@garzik.org>
Cc: "David S. Miller" <davem@davemloft.net>
Acked-by: Greg KH <greg@kroah.com>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 16:49:03 +08:00
|
|
|
p = kzalloc(sizeof(*p), GFP_KERNEL);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!p)
|
2008-11-10 14:29:58 +08:00
|
|
|
return ERR_PTR(-EBUSY);
|
2007-05-22 04:08:01 +08:00
|
|
|
|
2008-02-08 18:04:35 +08:00
|
|
|
if (!init_part_stats(p)) {
|
2008-07-25 16:48:25 +08:00
|
|
|
err = -ENOMEM;
|
2008-08-25 18:30:16 +08:00
|
|
|
goto out_free;
|
2008-02-08 18:04:35 +08:00
|
|
|
}
|
2008-08-25 18:56:05 +08:00
|
|
|
pdev = part_to_dev(p);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
p->start_sect = start;
|
2010-01-11 16:21:51 +08:00
|
|
|
p->alignment_offset =
|
|
|
|
queue_limit_alignment_offset(&disk->queue->limits, start);
|
2011-05-30 13:42:51 +08:00
|
|
|
p->discard_alignment =
|
|
|
|
queue_limit_discard_alignment(&disk->queue->limits, start);
|
2005-04-17 06:20:36 +08:00
|
|
|
p->nr_sects = len;
|
2008-09-03 15:01:09 +08:00
|
|
|
p->partno = partno;
|
2008-08-25 18:56:10 +08:00
|
|
|
p->policy = get_disk_ro(disk);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2010-09-01 04:47:05 +08:00
|
|
|
if (info) {
|
|
|
|
struct partition_meta_info *pinfo = alloc_part_info(disk);
|
|
|
|
if (!pinfo)
|
|
|
|
goto out_free_stats;
|
|
|
|
memcpy(pinfo, info, sizeof(*info));
|
|
|
|
p->info = pinfo;
|
|
|
|
}
|
|
|
|
|
2008-08-25 18:56:05 +08:00
|
|
|
dname = dev_name(ddev);
|
|
|
|
if (isdigit(dname[strlen(dname) - 1]))
|
2009-01-07 02:44:43 +08:00
|
|
|
dev_set_name(pdev, "%sp%d", dname, partno);
|
2005-04-17 06:20:36 +08:00
|
|
|
else
|
2009-01-07 02:44:43 +08:00
|
|
|
dev_set_name(pdev, "%s%d", dname, partno);
|
2007-05-22 04:08:01 +08:00
|
|
|
|
2008-08-25 18:56:05 +08:00
|
|
|
device_initialize(pdev);
|
|
|
|
pdev->class = &block_class;
|
|
|
|
pdev->type = &part_type;
|
|
|
|
pdev->parent = ddev;
|
2007-05-22 04:08:01 +08:00
|
|
|
|
2008-08-25 18:47:22 +08:00
|
|
|
err = blk_alloc_devt(p, &devt);
|
|
|
|
if (err)
|
2010-09-01 04:47:05 +08:00
|
|
|
goto out_free_info;
|
2008-08-25 18:56:05 +08:00
|
|
|
pdev->devt = devt;
|
2008-08-25 18:47:22 +08:00
|
|
|
|
2007-05-22 04:08:01 +08:00
|
|
|
/* delay uevent until 'holders' subdir is created */
|
2009-03-01 21:10:49 +08:00
|
|
|
dev_set_uevent_suppress(pdev, 1);
|
2008-08-25 18:56:05 +08:00
|
|
|
err = device_add(pdev);
|
2008-07-25 16:48:25 +08:00
|
|
|
if (err)
|
2008-08-25 18:30:16 +08:00
|
|
|
goto out_put;
|
|
|
|
|
|
|
|
err = -ENOMEM;
|
2008-08-25 18:56:05 +08:00
|
|
|
p->holder_dir = kobject_create_and_add("holders", &pdev->kobj);
|
2008-08-25 18:30:16 +08:00
|
|
|
if (!p->holder_dir)
|
|
|
|
goto out_del;
|
|
|
|
|
2009-03-01 21:10:49 +08:00
|
|
|
dev_set_uevent_suppress(pdev, 0);
|
2008-07-25 16:48:25 +08:00
|
|
|
if (flags & ADDPART_FLAG_WHOLEDISK) {
|
2008-08-25 18:56:05 +08:00
|
|
|
err = device_create_file(pdev, &dev_attr_whole_disk);
|
2008-07-25 16:48:25 +08:00
|
|
|
if (err)
|
2008-08-25 18:30:16 +08:00
|
|
|
goto out_del;
|
2008-07-25 16:48:25 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-08-25 18:30:16 +08:00
|
|
|
/* everything is up and running, commence */
|
2008-08-25 18:56:15 +08:00
|
|
|
rcu_assign_pointer(ptbl->part[partno], p);
|
2008-08-25 18:30:16 +08:00
|
|
|
|
2011-03-31 09:57:33 +08:00
|
|
|
/* suppress uevent if the disk suppresses it */
|
2009-06-11 21:14:40 +08:00
|
|
|
if (!dev_get_uevent_suppress(ddev))
|
2008-08-25 18:56:05 +08:00
|
|
|
kobject_uevent(&pdev->kobj, KOBJ_ADD);
|
2008-07-25 16:48:25 +08:00
|
|
|
|
2011-01-07 15:43:37 +08:00
|
|
|
hd_ref_init(p);
|
2008-11-10 14:29:58 +08:00
|
|
|
return p;
|
2008-07-25 16:48:25 +08:00
|
|
|
|
2010-09-01 04:47:05 +08:00
|
|
|
out_free_info:
|
|
|
|
free_part_info(p);
|
2008-11-10 14:28:59 +08:00
|
|
|
out_free_stats:
|
|
|
|
free_part_stats(p);
|
2008-08-25 18:30:16 +08:00
|
|
|
out_free:
|
|
|
|
kfree(p);
|
2008-11-10 14:29:58 +08:00
|
|
|
return ERR_PTR(err);
|
2008-08-25 18:30:16 +08:00
|
|
|
out_del:
|
|
|
|
kobject_put(p->holder_dir);
|
2008-08-25 18:56:05 +08:00
|
|
|
device_del(pdev);
|
2008-08-25 18:30:16 +08:00
|
|
|
out_put:
|
2008-08-25 18:56:05 +08:00
|
|
|
put_device(pdev);
|
2008-08-25 18:47:22 +08:00
|
|
|
blk_free_devt(devt);
|
2008-11-10 14:29:58 +08:00
|
|
|
return ERR_PTR(err);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2010-05-16 02:09:31 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
|
|
|
|
{
|
2010-05-16 02:09:31 +08:00
|
|
|
struct parsed_partitions *state = NULL;
|
2008-09-03 15:03:02 +08:00
|
|
|
struct disk_part_iter piter;
|
|
|
|
struct hd_struct *part;
|
2008-08-25 18:56:15 +08:00
|
|
|
int p, highest, res;
|
2010-05-16 02:09:28 +08:00
|
|
|
rescan:
|
2010-05-16 02:09:31 +08:00
|
|
|
if (state && !IS_ERR(state)) {
|
|
|
|
kfree(state);
|
|
|
|
state = NULL;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (bdev->bd_part_count)
|
|
|
|
return -EBUSY;
|
|
|
|
res = invalidate_partition(disk, 0);
|
|
|
|
if (res)
|
|
|
|
return res;
|
2008-09-03 15:03:02 +08:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (disk->fops->revalidate_disk)
|
|
|
|
disk->fops->revalidate_disk(disk);
|
2008-09-05 04:27:30 +08:00
|
|
|
check_disk_size_change(disk, bdev);
|
|
|
|
bdev->bd_invalidated = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!get_capacity(disk) || !(state = check_partition(disk, bdev)))
|
|
|
|
return 0;
|
2010-05-16 02:09:31 +08:00
|
|
|
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;
|
|
|
|
}
|
2007-03-17 05:38:25 +08:00
|
|
|
return -EIO;
|
2010-05-16 02:09:31 +08:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If any partition code tried to read beyond EOD, try
|
|
|
|
* unlocking native capacity even if partition table is
|
2011-03-31 09:57:33 +08:00
|
|
|
* successfully read as we could be missing some partitions.
|
2010-05-16 02:09:31 +08:00
|
|
|
*/
|
|
|
|
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;
|
|
|
|
}
|
2008-03-10 04:26:02 +08:00
|
|
|
|
|
|
|
/* tell userspace that the media / partition table may have changed */
|
2008-08-25 18:56:05 +08:00
|
|
|
kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE);
|
2008-03-10 04:26:02 +08:00
|
|
|
|
2008-08-25 18:56:15 +08:00
|
|
|
/* 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 */
|
2005-04-17 06:20:36 +08:00
|
|
|
for (p = 1; p < state->limit; p++) {
|
2009-06-07 19:52:52 +08:00
|
|
|
sector_t size, from;
|
2010-09-01 04:47:05 +08:00
|
|
|
struct partition_meta_info *info = NULL;
|
2010-05-16 02:09:28 +08:00
|
|
|
|
2009-06-07 19:52:52 +08:00
|
|
|
size = state->parts[p].size;
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!size)
|
|
|
|
continue;
|
2009-06-07 19:52:52 +08:00
|
|
|
|
|
|
|
from = state->parts[p].from;
|
block: sanitize invalid partition table entries
We currently follow blindly what the partition table lies about the
disk, and let the kernel create block devices which can not be accessed.
Trying to identify the device leads to kernel logs full of:
sdb: rw=0, want=73392, limit=28800
attempt to access beyond end of device
Here is an example of a broken partition table, where sda2 starts
behind the end of the disk, and sdb3 is larger than the entire disk:
Disk /dev/sdb: 14 MB, 14745600 bytes
1 heads, 29 sectors/track, 993 cylinders, total 28800 sectors
Device Boot Start End Blocks Id System
/dev/sdb1 29 7800 3886 83 Linux
/dev/sdb2 37801 45601 3900+ 83 Linux
/dev/sdb3 15602 73402 28900+ 83 Linux
/dev/sdb4 23403 28796 2697 83 Linux
The kernel creates these completely invalid devices, which can not be
accessed, or may lead to other unpredictable failures:
grep . /sys/class/block/sdb*/{start,size}
/sys/class/block/sdb/size:28800
/sys/class/block/sdb1/start:29
/sys/class/block/sdb1/size:7772
/sys/class/block/sdb2/start:37801
/sys/class/block/sdb2/size:7801
/sys/class/block/sdb3/start:15602
/sys/class/block/sdb3/size:57801
/sys/class/block/sdb4/start:23403
/sys/class/block/sdb4/size:5394
With this patch, we ignore partitions which start behind the end of the disk,
and limit partitions to the end of the disk if they pretend to be larger:
grep . /sys/class/block/sdb*/{start,size}
/sys/class/block/sdb/size:28800
/sys/class/block/sdb1/start:29
/sys/class/block/sdb1/size:7772
/sys/class/block/sdb3/start:15602
/sys/class/block/sdb3/size:13198
/sys/class/block/sdb4/start:23403
/sys/class/block/sdb4/size:5394
These warnings are printed to the kernel log:
sdb: p2 ignored, start 37801 is behind the end of the disk
sdb: p3 size 57801 limited to end of disk
Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
Cc: Herton Ronaldo Krzesinski <herton@mandriva.com.br>
Cc: Jens Axboe <jens.axboe@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-10-16 13:04:21 +08:00
|
|
|
if (from >= get_capacity(disk)) {
|
|
|
|
printk(KERN_WARNING
|
2010-05-16 02:09:31 +08:00
|
|
|
"%s: p%d start %llu is beyond EOD, ",
|
block: sanitize invalid partition table entries
We currently follow blindly what the partition table lies about the
disk, and let the kernel create block devices which can not be accessed.
Trying to identify the device leads to kernel logs full of:
sdb: rw=0, want=73392, limit=28800
attempt to access beyond end of device
Here is an example of a broken partition table, where sda2 starts
behind the end of the disk, and sdb3 is larger than the entire disk:
Disk /dev/sdb: 14 MB, 14745600 bytes
1 heads, 29 sectors/track, 993 cylinders, total 28800 sectors
Device Boot Start End Blocks Id System
/dev/sdb1 29 7800 3886 83 Linux
/dev/sdb2 37801 45601 3900+ 83 Linux
/dev/sdb3 15602 73402 28900+ 83 Linux
/dev/sdb4 23403 28796 2697 83 Linux
The kernel creates these completely invalid devices, which can not be
accessed, or may lead to other unpredictable failures:
grep . /sys/class/block/sdb*/{start,size}
/sys/class/block/sdb/size:28800
/sys/class/block/sdb1/start:29
/sys/class/block/sdb1/size:7772
/sys/class/block/sdb2/start:37801
/sys/class/block/sdb2/size:7801
/sys/class/block/sdb3/start:15602
/sys/class/block/sdb3/size:57801
/sys/class/block/sdb4/start:23403
/sys/class/block/sdb4/size:5394
With this patch, we ignore partitions which start behind the end of the disk,
and limit partitions to the end of the disk if they pretend to be larger:
grep . /sys/class/block/sdb*/{start,size}
/sys/class/block/sdb/size:28800
/sys/class/block/sdb1/start:29
/sys/class/block/sdb1/size:7772
/sys/class/block/sdb3/start:15602
/sys/class/block/sdb3/size:13198
/sys/class/block/sdb4/start:23403
/sys/class/block/sdb4/size:5394
These warnings are printed to the kernel log:
sdb: p2 ignored, start 37801 is behind the end of the disk
sdb: p3 size 57801 limited to end of disk
Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
Cc: Herton Ronaldo Krzesinski <herton@mandriva.com.br>
Cc: Jens Axboe <jens.axboe@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-10-16 13:04:21 +08:00
|
|
|
disk->disk_name, p, (unsigned long long) from);
|
2010-05-16 02:09:31 +08:00
|
|
|
if (disk_unlock_native_capacity(disk))
|
|
|
|
goto rescan;
|
block: sanitize invalid partition table entries
We currently follow blindly what the partition table lies about the
disk, and let the kernel create block devices which can not be accessed.
Trying to identify the device leads to kernel logs full of:
sdb: rw=0, want=73392, limit=28800
attempt to access beyond end of device
Here is an example of a broken partition table, where sda2 starts
behind the end of the disk, and sdb3 is larger than the entire disk:
Disk /dev/sdb: 14 MB, 14745600 bytes
1 heads, 29 sectors/track, 993 cylinders, total 28800 sectors
Device Boot Start End Blocks Id System
/dev/sdb1 29 7800 3886 83 Linux
/dev/sdb2 37801 45601 3900+ 83 Linux
/dev/sdb3 15602 73402 28900+ 83 Linux
/dev/sdb4 23403 28796 2697 83 Linux
The kernel creates these completely invalid devices, which can not be
accessed, or may lead to other unpredictable failures:
grep . /sys/class/block/sdb*/{start,size}
/sys/class/block/sdb/size:28800
/sys/class/block/sdb1/start:29
/sys/class/block/sdb1/size:7772
/sys/class/block/sdb2/start:37801
/sys/class/block/sdb2/size:7801
/sys/class/block/sdb3/start:15602
/sys/class/block/sdb3/size:57801
/sys/class/block/sdb4/start:23403
/sys/class/block/sdb4/size:5394
With this patch, we ignore partitions which start behind the end of the disk,
and limit partitions to the end of the disk if they pretend to be larger:
grep . /sys/class/block/sdb*/{start,size}
/sys/class/block/sdb/size:28800
/sys/class/block/sdb1/start:29
/sys/class/block/sdb1/size:7772
/sys/class/block/sdb3/start:15602
/sys/class/block/sdb3/size:13198
/sys/class/block/sdb4/start:23403
/sys/class/block/sdb4/size:5394
These warnings are printed to the kernel log:
sdb: p2 ignored, start 37801 is behind the end of the disk
sdb: p3 size 57801 limited to end of disk
Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
Cc: Herton Ronaldo Krzesinski <herton@mandriva.com.br>
Cc: Jens Axboe <jens.axboe@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-10-16 13:04:21 +08:00
|
|
|
continue;
|
|
|
|
}
|
2009-06-07 19:52:52 +08:00
|
|
|
|
2006-06-23 17:06:07 +08:00
|
|
|
if (from + size > get_capacity(disk)) {
|
2008-09-13 17:33:25 +08:00
|
|
|
printk(KERN_WARNING
|
2010-05-16 02:09:31 +08:00
|
|
|
"%s: p%d size %llu extends beyond EOD, ",
|
block: sanitize invalid partition table entries
We currently follow blindly what the partition table lies about the
disk, and let the kernel create block devices which can not be accessed.
Trying to identify the device leads to kernel logs full of:
sdb: rw=0, want=73392, limit=28800
attempt to access beyond end of device
Here is an example of a broken partition table, where sda2 starts
behind the end of the disk, and sdb3 is larger than the entire disk:
Disk /dev/sdb: 14 MB, 14745600 bytes
1 heads, 29 sectors/track, 993 cylinders, total 28800 sectors
Device Boot Start End Blocks Id System
/dev/sdb1 29 7800 3886 83 Linux
/dev/sdb2 37801 45601 3900+ 83 Linux
/dev/sdb3 15602 73402 28900+ 83 Linux
/dev/sdb4 23403 28796 2697 83 Linux
The kernel creates these completely invalid devices, which can not be
accessed, or may lead to other unpredictable failures:
grep . /sys/class/block/sdb*/{start,size}
/sys/class/block/sdb/size:28800
/sys/class/block/sdb1/start:29
/sys/class/block/sdb1/size:7772
/sys/class/block/sdb2/start:37801
/sys/class/block/sdb2/size:7801
/sys/class/block/sdb3/start:15602
/sys/class/block/sdb3/size:57801
/sys/class/block/sdb4/start:23403
/sys/class/block/sdb4/size:5394
With this patch, we ignore partitions which start behind the end of the disk,
and limit partitions to the end of the disk if they pretend to be larger:
grep . /sys/class/block/sdb*/{start,size}
/sys/class/block/sdb/size:28800
/sys/class/block/sdb1/start:29
/sys/class/block/sdb1/size:7772
/sys/class/block/sdb3/start:15602
/sys/class/block/sdb3/size:13198
/sys/class/block/sdb4/start:23403
/sys/class/block/sdb4/size:5394
These warnings are printed to the kernel log:
sdb: p2 ignored, start 37801 is behind the end of the disk
sdb: p3 size 57801 limited to end of disk
Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
Cc: Herton Ronaldo Krzesinski <herton@mandriva.com.br>
Cc: Jens Axboe <jens.axboe@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-10-16 13:04:21 +08:00
|
|
|
disk->disk_name, p, (unsigned long long) size);
|
2009-06-07 19:52:52 +08:00
|
|
|
|
2010-05-16 02:09:31 +08:00
|
|
|
if (disk_unlock_native_capacity(disk)) {
|
2010-05-16 02:09:28 +08:00
|
|
|
/* free state and restart */
|
|
|
|
goto rescan;
|
2009-06-07 19:52:52 +08:00
|
|
|
} 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;
|
|
|
|
}
|
2008-07-25 16:48:26 +08:00
|
|
|
}
|
2010-09-01 04:47:05 +08:00
|
|
|
|
|
|
|
if (state->parts[p].has_info)
|
|
|
|
info = &state->parts[p].info;
|
2008-11-10 14:29:58 +08:00
|
|
|
part = add_partition(disk, p, from, size,
|
2010-09-01 04:47:05 +08:00
|
|
|
state->parts[p].flags,
|
|
|
|
&state->parts[p].info);
|
2008-11-10 14:29:58 +08:00
|
|
|
if (IS_ERR(part)) {
|
|
|
|
printk(KERN_ERR " %s: p%d could not be added: %ld\n",
|
|
|
|
disk->disk_name, p, -PTR_ERR(part));
|
2008-07-25 16:48:26 +08:00
|
|
|
continue;
|
2006-06-23 17:06:07 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
#ifdef CONFIG_BLK_DEV_MD
|
2007-02-11 15:50:00 +08:00
|
|
|
if (state->parts[p].flags & ADDPART_FLAG_RAID)
|
2008-11-10 14:30:47 +08:00
|
|
|
md_autodetect_dev(part_to_dev(part)->devt);
|
2005-04-17 06:20:36 +08:00
|
|
|
#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;
|
|
|
|
|
2006-06-23 17:05:08 +08:00
|
|
|
page = read_mapping_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)),
|
|
|
|
NULL);
|
2005-04-17 06:20:36 +08:00
|
|
|
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);
|