X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fpartitions%2Fcheck.c;h=3d73d94d93a7dd9321cdfe5d9750fcf25a836df5;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=3526d3663650b36df511d23828b07c7551b305d4;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 3526d3663..3d73d94d9 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -18,10 +18,8 @@ #include #include #include -#include #include "check.h" -#include "devfs.h" #include "acorn.h" #include "amiga.h" @@ -29,13 +27,13 @@ #include "ldm.h" #include "mac.h" #include "msdos.h" -#include "nec98.h" #include "osf.h" #include "sgi.h" #include "sun.h" #include "ibm.h" #include "ultrix.h" #include "efi.h" +#include "karma.h" #ifdef CONFIG_BLK_DEV_MD extern void md_autodetect_dev(dev_t dev); @@ -74,12 +72,12 @@ static int (*check_part[])(struct parsed_partitions *, struct block_device *) = #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_NEC98_PARTITION - nec98_partition, /* must be come before `msdos_partition' */ -#endif #ifdef CONFIG_MSDOS_PARTITION msdos_partition, #endif @@ -98,14 +96,14 @@ static int (*check_part[])(struct parsed_partitions *, struct block_device *) = #ifdef CONFIG_MAC_PARTITION mac_partition, #endif -#ifdef CONFIG_SGI_PARTITION - sgi_partition, -#endif #ifdef CONFIG_ULTRIX_PARTITION ultrix_partition, #endif #ifdef CONFIG_IBM_PARTITION ibm_partition, +#endif +#ifdef CONFIG_KARMA_PARTITION + karma_partition, #endif NULL }; @@ -138,25 +136,14 @@ const char *bdevname(struct block_device *bdev, char *buf) EXPORT_SYMBOL(bdevname); /* - * NOTE: this cannot be called from interrupt context. - * - * But in interrupt context you should really have a struct - * block_device anyway and use bdevname() above. + * 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) { - struct gendisk *disk; - int part; - - disk = get_gendisk(dev, &part); - if (disk) { - buffer = disk_name(disk, part, buffer); - put_disk(disk); - } else { - snprintf(buffer, BDEVNAME_SIZE, "unknown-block(%u,%u)", + scnprintf(buffer, BDEVNAME_SIZE, "unknown-block(%u,%u)", MAJOR(dev), MINOR(dev)); - } - return buffer; } @@ -166,38 +153,42 @@ static struct parsed_partitions * check_partition(struct gendisk *hd, struct block_device *bdev) { struct parsed_partitions *state; - int i, res; + int i, res, err; state = kmalloc(sizeof(struct parsed_partitions), GFP_KERNEL); if (!state) return NULL; -#ifdef CONFIG_DEVFS_FS - if (hd->devfs_name[0] != '\0') { - printk(KERN_INFO " /dev/%s:", hd->devfs_name); + disk_name(hd, 0, state->name); + printk(KERN_INFO " %s:", state->name); + if (isdigit(state->name[strlen(state->name)-1])) sprintf(state->name, "p"); - } -#endif - else { - disk_name(hd, 0, state->name); - printk(KERN_INFO " %s:", state->name); - if (isdigit(state->name[strlen(state->name)-1])) - sprintf(state->name, "p"); - } + state->limit = hd->minors; - i = res = 0; + i = res = err = 0; while (!res && check_part[i]) { memset(&state->parts, 0, sizeof(state->parts)); res = check_part[i++](state, bdev); + 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; + } + } if (res > 0) return state; + if (!err) + /* The partition is unrecognized. So report I/O errors if there were any */ + res = err; if (!res) printk(" unknown partition table\n"); else if (warn_no_part) printk(" unable to read partition table\n"); kfree(state); - return NULL; + return ERR_PTR(res); } /* @@ -207,6 +198,7 @@ check_partition(struct gendisk *hd, struct block_device *bdev) struct part_attribute { struct attribute attr; ssize_t (*show)(struct hd_struct *,char *); + ssize_t (*store)(struct hd_struct *,const char *, size_t); }; static ssize_t @@ -216,14 +208,33 @@ part_attr_show(struct kobject * kobj, struct attribute * attr, char * page) struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr); ssize_t ret = 0; if (part_attr->show) - ret = part_attr->show(p,page); + ret = part_attr->show(p, page); + return ret; +} +static ssize_t +part_attr_store(struct kobject * kobj, struct attribute * attr, + const char *page, size_t count) +{ + struct hd_struct * p = container_of(kobj,struct hd_struct,kobj); + struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr); + ssize_t ret = 0; + + if (part_attr->store) + ret = part_attr->store(p, page, count); return ret; } static struct sysfs_ops part_sysfs_ops = { .show = part_attr_show, + .store = part_attr_store, }; +static ssize_t part_uevent_store(struct hd_struct * p, + const char *page, size_t count) +{ + kobject_uevent(&p->kobj, KOBJ_ADD); + return count; +} static ssize_t part_dev_read(struct hd_struct * p, char *page) { struct gendisk *disk = container_of(p->kobj.parent,struct gendisk,kobj); @@ -241,9 +252,13 @@ static ssize_t part_size_read(struct hd_struct * p, char *page) static ssize_t part_stat_read(struct hd_struct * p, char *page) { return sprintf(page, "%8u %8llu %8u %8llu\n", - p->reads, (unsigned long long)p->read_sectors, - p->writes, (unsigned long long)p->write_sectors); + p->ios[0], (unsigned long long)p->sectors[0], + p->ios[1], (unsigned long long)p->sectors[1]); } +static struct part_attribute part_attr_uevent = { + .attr = {.name = "uevent", .mode = S_IWUSR }, + .store = part_uevent_store +}; static struct part_attribute part_attr_dev = { .attr = {.name = "dev", .mode = S_IRUGO }, .show = part_dev_read @@ -261,11 +276,39 @@ static struct part_attribute part_attr_stat = { .show = part_stat_read }; +#ifdef CONFIG_FAIL_MAKE_REQUEST + +static ssize_t part_fail_store(struct hd_struct * p, + const char *buf, size_t count) +{ + int i; + + if (count > 0 && sscanf(buf, "%d", &i) > 0) + p->make_it_fail = (i == 0) ? 0 : 1; + + return count; +} +static ssize_t part_fail_read(struct hd_struct * p, char *page) +{ + return sprintf(page, "%d\n", p->make_it_fail); +} +static struct part_attribute part_attr_fail = { + .attr = {.name = "make-it-fail", .mode = S_IRUGO | S_IWUSR }, + .store = part_fail_store, + .show = part_fail_read +}; + +#endif + static struct attribute * default_attrs[] = { + &part_attr_uevent.attr, &part_attr_dev.attr, &part_attr_start.attr, &part_attr_size.attr, &part_attr_stat.attr, +#ifdef CONFIG_FAIL_MAKE_REQUEST + &part_attr_fail.attr, +#endif NULL, }; @@ -283,6 +326,25 @@ struct kobj_type ktype_part = { .sysfs_ops = &part_sysfs_ops, }; +static inline void partition_sysfs_add_subdir(struct hd_struct *p) +{ + struct kobject *k; + + k = kobject_get(&p->kobj); + p->holder_dir = kobject_add_dir(k, "holders"); + kobject_put(k); +} + +static inline void disk_sysfs_add_subdirs(struct gendisk *disk) +{ + struct kobject *k; + + k = kobject_get(&disk->kobj); + disk->holder_dir = kobject_add_dir(k, "holders"); + disk->slave_dir = kobject_add_dir(k, "slaves"); + kobject_put(k); +} + void delete_partition(struct gendisk *disk, int part) { struct hd_struct *p = disk->part[part-1]; @@ -293,9 +355,14 @@ void delete_partition(struct gendisk *disk, int part) disk->part[part-1] = NULL; p->start_sect = 0; p->nr_sects = 0; - p->reads = p->writes = p->read_sectors = p->write_sectors = 0; - devfs_remove("%s/part%d", disk->devfs_name, part); - kobject_unregister(&p->kobj); + p->ios[0] = p->ios[1] = 0; + p->sectors[0] = p->sectors[1] = 0; + sysfs_remove_link(&p->kobj, "subsystem"); + if (p->holder_dir) + kobject_unregister(p->holder_dir); + kobject_uevent(&p->kobj, KOBJ_REMOVE); + kobject_del(&p->kobj); + kobject_put(&p->kobj); } void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len) @@ -310,10 +377,7 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len) p->start_sect = start; p->nr_sects = len; p->partno = part; - - devfs_mk_bdev(MKDEV(disk->major, disk->first_minor + part), - S_IFBLK|S_IRUSR|S_IWUSR, - "%s/part%d", disk->devfs_name, part); + p->policy = disk->policy; if (isdigit(disk->kobj.name[strlen(disk->kobj.name)-1])) snprintf(p->kobj.name,KOBJ_NAME_LEN,"%sp%d",disk->kobj.name,part); @@ -321,26 +385,86 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len) snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->kobj.name,part); p->kobj.parent = &disk->kobj; p->kobj.ktype = &ktype_part; - kobject_register(&p->kobj); + kobject_init(&p->kobj); + kobject_add(&p->kobj); + if (!disk->part_uevent_suppress) + kobject_uevent(&p->kobj, KOBJ_ADD); + sysfs_create_link(&p->kobj, &block_subsys.kset.kobj, "subsystem"); + partition_sysfs_add_subdir(p); disk->part[part-1] = p; } -static void disk_sysfs_symlinks(struct gendisk *disk) +static char *make_block_name(struct gendisk *disk) +{ + char *name; + static char *block_str = "block:"; + int size; + char *s; + + size = strlen(block_str) + strlen(disk->disk_name) + 1; + name = kmalloc(size, GFP_KERNEL); + if (!name) + return NULL; + strcpy(name, block_str); + strcat(name, disk->disk_name); + /* ewww... some of these buggers have / in name... */ + s = strchr(name, '/'); + if (s) + *s = '!'; + return name; +} + +static int disk_sysfs_symlinks(struct gendisk *disk) { struct device *target = get_device(disk->driverfs_dev); + int err; + char *disk_name = NULL; + + if (target) { + disk_name = make_block_name(disk); + if (!disk_name) { + err = -ENOMEM; + goto err_out; + } + + err = sysfs_create_link(&disk->kobj, &target->kobj, "device"); + if (err) + goto err_out_disk_name; + + err = sysfs_create_link(&target->kobj, &disk->kobj, disk_name); + if (err) + goto err_out_dev_link; + } + + err = sysfs_create_link(&disk->kobj, &block_subsys.kset.kobj, + "subsystem"); + if (err) + goto err_out_disk_name_lnk; + + kfree(disk_name); + + return 0; + +err_out_disk_name_lnk: if (target) { - sysfs_create_link(&disk->kobj,&target->kobj,"device"); - sysfs_create_link(&target->kobj,&disk->kobj,"block"); + sysfs_remove_link(&target->kobj, disk_name); +err_out_dev_link: + sysfs_remove_link(&disk->kobj, "device"); +err_out_disk_name: + kfree(disk_name); +err_out: + put_device(target); } + return err; } /* Not exported, helper to add_disk(). */ void register_disk(struct gendisk *disk) { - struct parsed_partitions *state; struct block_device *bdev; char *s; - int j; + int i; + struct hd_struct *p; int err; strlcpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN); @@ -350,42 +474,45 @@ void register_disk(struct gendisk *disk) *s = '!'; if ((err = kobject_add(&disk->kobj))) return; - disk_sysfs_symlinks(disk); - - /* No minors to use for partitions */ - if (disk->minors == 1) { - if (disk->devfs_name[0] != '\0') - devfs_add_disk(disk); + err = disk_sysfs_symlinks(disk); + if (err) { + kobject_del(&disk->kobj); return; } + disk_sysfs_add_subdirs(disk); - /* always add handle for the whole disk */ - devfs_add_partitioned(disk); + /* No minors to use for partitions */ + if (disk->minors == 1) + goto exit; /* No such device (e.g., media were just removed) */ if (!get_capacity(disk)) - return; + goto exit; bdev = bdget_disk(disk, 0); - if (blkdev_get(bdev, FMODE_READ, 0) < 0) - return; - state = check_partition(disk, bdev); - if (state) { - for (j = 1; j < state->limit; j++) { - sector_t size = state->parts[j].size; - sector_t from = state->parts[j].from; - if (!size) - continue; - add_partition(disk, j, from, size); -#ifdef CONFIG_BLK_DEV_MD - if (!state->parts[j].flags) - continue; - md_autodetect_dev(bdev->bd_dev+j); -#endif - } - kfree(state); - } + if (!bdev) + goto exit; + + /* scan partition table, but suppress uevents */ + bdev->bd_invalidated = 1; + disk->part_uevent_suppress = 1; + err = blkdev_get(bdev, FMODE_READ, 0); + disk->part_uevent_suppress = 0; + if (err < 0) + goto exit; blkdev_put(bdev); + +exit: + /* announce disk after possible partitions are already created */ + kobject_uevent(&disk->kobj, KOBJ_ADD); + + /* announce possible partitions */ + for (i = 1; i < disk->minors; i++) { + p = disk->part[i-1]; + if (!p || !p->nr_sects) + continue; + kobject_uevent(&p->kobj, KOBJ_ADD); + } } int rescan_partitions(struct gendisk *disk, struct block_device *bdev) @@ -404,12 +531,18 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) if (disk->fops->revalidate_disk) disk->fops->revalidate_disk(disk); if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) - return res; + return 0; + if (IS_ERR(state)) /* I/O error reading the partition table */ + return PTR_ERR(state); for (p = 1; p < state->limit; p++) { sector_t size = state->parts[p].size; sector_t from = state->parts[p].from; if (!size) continue; + if (from + size > get_capacity(disk)) { + printk(" %s: p%d exceeds device capacity\n", + disk->disk_name, p); + } add_partition(disk, p, from, size); #ifdef CONFIG_BLK_DEV_MD if (state->parts[p].flags) @@ -417,7 +550,7 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) #endif } kfree(state); - return res; + return 0; } unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p) @@ -425,8 +558,8 @@ 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; - page = read_cache_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)), - (filler_t *)mapping->a_ops->readpage, NULL); + page = read_mapping_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)), + NULL); if (!IS_ERR(page)) { wait_on_page_locked(page); if (!PageUptodate(page)) @@ -458,14 +591,23 @@ void del_gendisk(struct gendisk *disk) disk->flags &= ~GENHD_FL_UP; unlink_gendisk(disk); disk_stat_set_all(disk, 0); - disk->stamp = disk->stamp_idle = 0; - - devfs_remove_disk(disk); + disk->stamp = 0; + kobject_uevent(&disk->kobj, KOBJ_REMOVE); + if (disk->holder_dir) + kobject_unregister(disk->holder_dir); + if (disk->slave_dir) + kobject_unregister(disk->slave_dir); if (disk->driverfs_dev) { + char *disk_name = make_block_name(disk); sysfs_remove_link(&disk->kobj, "device"); - sysfs_remove_link(&disk->driverfs_dev->kobj, "block"); + if (disk_name) { + sysfs_remove_link(&disk->driverfs_dev->kobj, disk_name); + kfree(disk_name); + } put_device(disk->driverfs_dev); + disk->driverfs_dev = NULL; } + sysfs_remove_link(&disk->kobj, "subsystem"); kobject_del(&disk->kobj); }