linux-old/drivers/block/genhd.c History
<<
>>
Prefs
   1/*
   2 *  Code extracted from
   3 *  linux/kernel/hd.c
   4 *
   5 *  Copyright (C) 1991-1998  Linus Torvalds
   6 *
   7 *  devfs support - jj, rgooch, 980122
   8 *
   9 *  Moved partition checking code to fs/partitions* - Russell King
  10 *  (linux@arm.uk.linux.org)
  11 */
  12
  13/*
  14 * TODO:  rip out the remaining init crap from this file  --hch
  15 */
  16
  17#include <linux/config.h>
  18#include <linux/module.h>
  19#include <linux/fs.h>
  20#include <linux/genhd.h>
  21#include <linux/kernel.h>
  22#include <linux/blk.h>
  23#include <linux/init.h>
  24#include <linux/spinlock.h>
  25#include <linux/seq_file.h>
  26
  27
  28/*
  29 * Global kernel list of partitioning information.
  30 *
  31 * XXX: you should _never_ access this directly.
  32 *      the only reason this is exported is source compatiblity.
  33 */
  34/*static*/ struct gendisk *gendisk_head;
  35static struct gendisk *gendisk_array[MAX_BLKDEV];
  36static rwlock_t gendisk_lock = RW_LOCK_UNLOCKED;
  37
  38EXPORT_SYMBOL(gendisk_head);
  39
  40
  41/**
  42 * add_gendisk - add partitioning information to kernel list
  43 * @gp: per-device partitioning information
  44 *
  45 * This function registers the partitioning information in @gp
  46 * with the kernel.
  47 */
  48void
  49add_gendisk(struct gendisk *gp)
  50{
  51        struct gendisk *sgp;
  52
  53        write_lock(&gendisk_lock);
  54
  55        /*
  56         *      In 2.5 this will go away. Fix the drivers who rely on
  57         *      old behaviour.
  58         */
  59
  60        for (sgp = gendisk_head; sgp; sgp = sgp->next)
  61        {
  62                if (sgp == gp)
  63                {
  64//                      printk(KERN_ERR "add_gendisk: device major %d is buggy and added a live gendisk!\n",
  65//                              sgp->major)
  66                        goto out;
  67                }
  68        }
  69        gendisk_array[gp->major] = gp;
  70        gp->next = gendisk_head;
  71        gendisk_head = gp;
  72out:
  73        write_unlock(&gendisk_lock);
  74}
  75
  76EXPORT_SYMBOL(add_gendisk);
  77
  78
  79/**
  80 * del_gendisk - remove partitioning information from kernel list
  81 * @gp: per-device partitioning information
  82 *
  83 * This function unregisters the partitioning information in @gp
  84 * with the kernel.
  85 */
  86void
  87del_gendisk(struct gendisk *gp)
  88{
  89        struct gendisk **gpp;
  90
  91        write_lock(&gendisk_lock);
  92        gendisk_array[gp->major] = NULL;
  93        for (gpp = &gendisk_head; *gpp; gpp = &((*gpp)->next))
  94                if (*gpp == gp)
  95                        break;
  96        if (*gpp)
  97                *gpp = (*gpp)->next;
  98        write_unlock(&gendisk_lock);
  99}
 100
 101EXPORT_SYMBOL(del_gendisk);
 102
 103
 104/**
 105 * get_gendisk - get partitioning information for a given device
 106 * @dev: device to get partitioning information for
 107 *
 108 * This function gets the structure containing partitioning
 109 * information for the given device @dev.
 110 */
 111struct gendisk *
 112get_gendisk(kdev_t dev)
 113{
 114        struct gendisk *gp = NULL;
 115        int maj = MAJOR(dev);
 116
 117        read_lock(&gendisk_lock);
 118        if ((gp = gendisk_array[maj]))
 119                goto out;
 120
 121        /* This is needed for early 2.4 source compatiblity.  --hch */
 122        for (gp = gendisk_head; gp; gp = gp->next)
 123                if (gp->major == maj)
 124                        break;
 125out:
 126        read_unlock(&gendisk_lock);
 127        return gp;
 128}
 129
 130EXPORT_SYMBOL(get_gendisk);
 131
 132
 133/**
 134 * walk_gendisk - issue a command for every registered gendisk
 135 * @walk: user-specified callback
 136 * @data: opaque data for the callback
 137 *
 138 * This function walks through the gendisk chain and calls back
 139 * into @walk for every element.
 140 */
 141int
 142walk_gendisk(int (*walk)(struct gendisk *, void *), void *data)
 143{
 144        struct gendisk *gp;
 145        int error = 0;
 146
 147        read_lock(&gendisk_lock);
 148        for (gp = gendisk_head; gp; gp = gp->next)
 149                if ((error = walk(gp, data)))
 150                        break;
 151        read_unlock(&gendisk_lock);
 152
 153        return error;
 154}
 155
 156#ifdef CONFIG_PROC_FS
 157/* iterator */
 158static void *part_start(struct seq_file *s, loff_t *ppos)
 159{
 160        struct gendisk *gp;
 161        loff_t pos = *ppos;
 162
 163        read_lock(&gendisk_lock);
 164        for (gp = gendisk_head; gp; gp = gp->next)
 165                if (!pos--)
 166                        return gp;
 167        return NULL;
 168}
 169
 170static void *part_next(struct seq_file *s, void *v, loff_t *pos)
 171{
 172        ++*pos;
 173        return ((struct gendisk *)v)->next;
 174}
 175
 176static void part_stop(struct seq_file *s, void *v)
 177{
 178        read_unlock(&gendisk_lock);
 179}
 180
 181static int part_show(struct seq_file *s, void *v)
 182{
 183        struct gendisk *gp = v;
 184        char buf[64];
 185        int n;
 186
 187        if (gp == gendisk_head) {
 188                seq_puts(s, "major minor  #blocks  name"
 189#ifdef CONFIG_BLK_STATS
 190                            "     rio rmerge rsect ruse wio wmerge "
 191                            "wsect wuse running use aveq"
 192#endif
 193                           "\n\n");
 194        }
 195
 196        /* show the full disk and all non-0 size partitions of it */
 197        for (n = 0; n < (gp->nr_real << gp->minor_shift); n++) {
 198                if (gp->part[n].nr_sects) {
 199#ifdef CONFIG_BLK_STATS
 200                        struct hd_struct *hd = &gp->part[n];
 201
 202                        disk_round_stats(hd);
 203                        seq_printf(s, "%4d  %4d %10d %s "
 204                                      "%d %d %d %d %d %d %d %d %d %d %d\n",
 205                                      gp->major, n, gp->sizes[n],
 206                                      disk_name(gp, n, buf),
 207                                      hd->rd_ios, hd->rd_merges,
 208#define MSEC(x) ((x) * 1000 / HZ)
 209                                      hd->rd_sectors, MSEC(hd->rd_ticks),
 210                                      hd->wr_ios, hd->wr_merges,
 211                                      hd->wr_sectors, MSEC(hd->wr_ticks),
 212                                      hd->ios_in_flight, MSEC(hd->io_ticks),
 213                                      MSEC(hd->aveq));
 214#else
 215                        seq_printf(s, "%4d  %4d %10d %s\n",
 216                                   gp->major, n, gp->sizes[n],
 217                                   disk_name(gp, n, buf));
 218#endif /* CONFIG_BLK_STATS */
 219                }
 220        }
 221
 222        return 0;
 223}
 224
 225struct seq_operations partitions_op = {
 226        .start          = part_start,
 227        .next           = part_next,
 228        .stop           = part_stop,
 229        .show           = part_show,
 230};
 231#endif
 232
 233extern int blk_dev_init(void);
 234extern int net_dev_init(void);
 235extern void console_map_init(void);
 236extern int atmdev_init(void);
 237
 238int __init device_init(void)
 239{
 240        blk_dev_init();
 241        sti();
 242#ifdef CONFIG_NET
 243        net_dev_init();
 244#endif
 245#ifdef CONFIG_ATM
 246        (void) atmdev_init();
 247#endif
 248#ifdef CONFIG_VT
 249        console_map_init();
 250#endif
 251        return 0;
 252}
 253
 254__initcall(device_init);
 255
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.