]> git.karo-electronics.de Git - karo-tx-linux.git/blob - block/partitions/check.c
block/partitions: optimize memory allocation in check_partition()
[karo-tx-linux.git] / block / partitions / check.c
1 /*
2  *  fs/partitions/check.c
3  *
4  *  Code extracted from drivers/block/genhd.c
5  *  Copyright (C) 1991-1998  Linus Torvalds
6  *  Re-organised Feb 1998 Russell King
7  *
8  *  We now have independent partition support from the
9  *  block drivers, which allows all the partition code to
10  *  be grouped in one location, and it to be mostly self
11  *  contained.
12  *
13  *  Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl}
14  */
15
16 #include <linux/slab.h>
17 #include <linux/vmalloc.h>
18 #include <linux/ctype.h>
19 #include <linux/genhd.h>
20
21 #include "check.h"
22
23 #include "acorn.h"
24 #include "amiga.h"
25 #include "atari.h"
26 #include "ldm.h"
27 #include "mac.h"
28 #include "msdos.h"
29 #include "osf.h"
30 #include "sgi.h"
31 #include "sun.h"
32 #include "ibm.h"
33 #include "ultrix.h"
34 #include "efi.h"
35 #include "karma.h"
36 #include "sysv68.h"
37
38 int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
39
40 static int (*check_part[])(struct parsed_partitions *) = {
41         /*
42          * Probe partition formats with tables at disk address 0
43          * that also have an ADFS boot block at 0xdc0.
44          */
45 #ifdef CONFIG_ACORN_PARTITION_ICS
46         adfspart_check_ICS,
47 #endif
48 #ifdef CONFIG_ACORN_PARTITION_POWERTEC
49         adfspart_check_POWERTEC,
50 #endif
51 #ifdef CONFIG_ACORN_PARTITION_EESOX
52         adfspart_check_EESOX,
53 #endif
54
55         /*
56          * Now move on to formats that only have partition info at
57          * disk address 0xdc0.  Since these may also have stale
58          * PC/BIOS partition tables, they need to come before
59          * the msdos entry.
60          */
61 #ifdef CONFIG_ACORN_PARTITION_CUMANA
62         adfspart_check_CUMANA,
63 #endif
64 #ifdef CONFIG_ACORN_PARTITION_ADFS
65         adfspart_check_ADFS,
66 #endif
67
68 #ifdef CONFIG_EFI_PARTITION
69         efi_partition,          /* this must come before msdos */
70 #endif
71 #ifdef CONFIG_SGI_PARTITION
72         sgi_partition,
73 #endif
74 #ifdef CONFIG_LDM_PARTITION
75         ldm_partition,          /* this must come before msdos */
76 #endif
77 #ifdef CONFIG_MSDOS_PARTITION
78         msdos_partition,
79 #endif
80 #ifdef CONFIG_OSF_PARTITION
81         osf_partition,
82 #endif
83 #ifdef CONFIG_SUN_PARTITION
84         sun_partition,
85 #endif
86 #ifdef CONFIG_AMIGA_PARTITION
87         amiga_partition,
88 #endif
89 #ifdef CONFIG_ATARI_PARTITION
90         atari_partition,
91 #endif
92 #ifdef CONFIG_MAC_PARTITION
93         mac_partition,
94 #endif
95 #ifdef CONFIG_ULTRIX_PARTITION
96         ultrix_partition,
97 #endif
98 #ifdef CONFIG_IBM_PARTITION
99         ibm_partition,
100 #endif
101 #ifdef CONFIG_KARMA_PARTITION
102         karma_partition,
103 #endif
104 #ifdef CONFIG_SYSV68_PARTITION
105         sysv68_partition,
106 #endif
107         NULL
108 };
109
110 static struct parsed_partitions *allocate_partitions(struct gendisk *hd)
111 {
112         struct parsed_partitions *state;
113         int nr;
114
115         state = kzalloc(sizeof(*state), GFP_KERNEL);
116         if (!state)
117                 return NULL;
118
119         nr = disk_max_parts(hd);
120         state->parts = vzalloc(nr * sizeof(state->parts[0]));
121         if (!state->parts) {
122                 kfree(state);
123                 return NULL;
124         }
125
126         state->limit = nr;
127
128         return state;
129 }
130
131 void free_partitions(struct parsed_partitions *state)
132 {
133         vfree(state->parts);
134         kfree(state);
135 }
136
137 struct parsed_partitions *
138 check_partition(struct gendisk *hd, struct block_device *bdev)
139 {
140         struct parsed_partitions *state;
141         int i, res, err;
142
143         state = allocate_partitions(hd);
144         if (!state)
145                 return NULL;
146         state->pp_buf = (char *)__get_free_page(GFP_KERNEL);
147         if (!state->pp_buf) {
148                 free_partitions(state);
149                 return NULL;
150         }
151         state->pp_buf[0] = '\0';
152
153         state->bdev = bdev;
154         disk_name(hd, 0, state->name);
155         snprintf(state->pp_buf, PAGE_SIZE, " %s:", state->name);
156         if (isdigit(state->name[strlen(state->name)-1]))
157                 sprintf(state->name, "p");
158
159         i = res = err = 0;
160         while (!res && check_part[i]) {
161                 memset(state->parts, 0, state->limit * sizeof(state->parts[0]));
162                 res = check_part[i++](state);
163                 if (res < 0) {
164                         /* We have hit an I/O error which we don't report now.
165                         * But record it, and let the others do their job.
166                         */
167                         err = res;
168                         res = 0;
169                 }
170
171         }
172         if (res > 0) {
173                 printk(KERN_INFO "%s", state->pp_buf);
174
175                 free_page((unsigned long)state->pp_buf);
176                 return state;
177         }
178         if (state->access_beyond_eod)
179                 err = -ENOSPC;
180         if (err)
181         /* The partition is unrecognized. So report I/O errors if there were any */
182                 res = err;
183         if (!res)
184                 strlcat(state->pp_buf, " unknown partition table\n", PAGE_SIZE);
185         else if (warn_no_part)
186                 strlcat(state->pp_buf, " unable to read partition table\n", PAGE_SIZE);
187
188         printk(KERN_INFO "%s", state->pp_buf);
189
190         free_page((unsigned long)state->pp_buf);
191         free_partitions(state);
192         return ERR_PTR(res);
193 }