File: /usr/src/linux/drivers/block/genhd.c

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     
26     
27     static rwlock_t gendisk_lock;
28     
29     /*
30      * Global kernel list of partitioning information.
31      *
32      * XXX: you should _never_ access this directly.
33      *	the only reason this is exported is source compatiblity.
34      */
35     /*static*/ struct gendisk *gendisk_head;
36     
37     EXPORT_SYMBOL(gendisk_head);
38     
39     
40     /**
41      * add_gendisk - add partitioning information to kernel list
42      * @gp: per-device partitioning information
43      *
44      * This function registers the partitioning information in @gp
45      * with the kernel.
46      */
47     void
48     add_gendisk(struct gendisk *gp)
49     {
50     	write_lock(&gendisk_lock);
51     	gp->next = gendisk_head;
52     	gendisk_head = gp;
53     	write_unlock(&gendisk_lock);
54     }
55     
56     EXPORT_SYMBOL(add_gendisk);
57     
58     
59     /**
60      * del_gendisk - remove partitioning information from kernel list
61      * @gp: per-device partitioning information
62      *
63      * This function unregisters the partitioning information in @gp
64      * with the kernel.
65      */
66     void
67     del_gendisk(struct gendisk *gp)
68     {
69     	struct gendisk **gpp;
70     
71     	write_lock(&gendisk_lock);
72     	for (gpp = &gendisk_head; *gpp; gpp = &((*gpp)->next))
73     		if (*gpp == gp)
74     			break;
75     	if (*gpp)
76     		*gpp = (*gpp)->next;
77     	write_unlock(&gendisk_lock);
78     }
79     
80     EXPORT_SYMBOL(del_gendisk);
81     
82     
83     /**
84      * get_gendisk - get partitioning information for a given device
85      * @dev: device to get partitioning information for
86      *
87      * This function gets the structure containing partitioning
88      * information for the given device @dev.
89      */
90     struct gendisk *
91     get_gendisk(kdev_t dev)
92     {
93     	struct gendisk *gp = NULL;
94     	int maj = MAJOR(dev);
95     
96     	read_lock(&gendisk_lock);
97     	for (gp = gendisk_head; gp; gp = gp->next)
98     		if (gp->major == maj)
99     			break;
100     	read_unlock(&gendisk_lock);
101     
102     	return gp;
103     }
104     
105     EXPORT_SYMBOL(get_gendisk);
106     
107     
108     #ifdef CONFIG_PROC_FS
109     int
110     get_partition_list(char *page, char **start, off_t offset, int count)
111     {
112     	struct gendisk *gp;
113     	char buf[64];
114     	int len, n;
115     
116     	len = sprintf(page, "major minor  #blocks  name\n\n");
117     	read_lock(&gendisk_lock);
118     	for (gp = gendisk_head; gp; gp = gp->next) {
119     		for (n = 0; n < (gp->nr_real << gp->minor_shift); n++) {
120     			if (gp->part[n].nr_sects == 0)
121     				continue;
122     
123     			len += snprintf(page + len, 63,
124     					"%4d  %4d %10d %s\n",
125     					gp->major, n, gp->sizes[n],
126     					disk_name(gp, n, buf));
127     			if (len < offset)
128     				offset -= len, len = 0;
129     			else if (len >= offset + count)
130     				goto out;
131     		}
132     	}
133     
134     out:
135     	read_unlock(&gendisk_lock);
136     	*start = page + offset;
137     	len -= offset;
138     	if (len < 0)
139     		len = 0;
140     	return len > count ? count : len;
141     }
142     #endif
143     
144     
145     extern int blk_dev_init(void);
146     #ifdef CONFIG_BLK_DEV_DAC960
147     extern void DAC960_Initialize(void);
148     #endif
149     #ifdef CONFIG_FUSION_BOOT
150     extern int fusion_init(void);
151     #endif
152     extern int net_dev_init(void);
153     extern void console_map_init(void);
154     extern int soc_probe(void);
155     extern int atmdev_init(void);
156     extern int i2o_init(void);
157     extern int cpqarray_init(void);
158     
159     int __init device_init(void)
160     {
161     	rwlock_init(&gendisk_lock);
162     	blk_dev_init();
163     	sti();
164     #ifdef CONFIG_I2O
165     	i2o_init();
166     #endif
167     #ifdef CONFIG_BLK_DEV_DAC960
168     	DAC960_Initialize();
169     #endif
170     #ifdef CONFIG_FUSION_BOOT
171     	fusion_init();
172     #endif
173     #ifdef CONFIG_FC4_SOC
174     	/* This has to be done before scsi_dev_init */
175     	soc_probe();
176     #endif
177     #ifdef CONFIG_BLK_CPQ_DA
178     	cpqarray_init();
179     #endif
180     #ifdef CONFIG_NET
181     	net_dev_init();
182     #endif
183     #ifdef CONFIG_ATM
184     	(void) atmdev_init();
185     #endif
186     #ifdef CONFIG_VT
187     	console_map_init();
188     #endif
189     	return 0;
190     }
191     
192     __initcall(device_init);
193