Rev 3 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | pj | 1 | /* |
2 | * Project: S.Ha.R.K. |
||
3 | * |
||
4 | * Coordinators: |
||
5 | * Giorgio Buttazzo <giorgio@sssup.it> |
||
6 | * Paolo Gai <pj@gandalf.sssup.it> |
||
7 | * |
||
8 | * Authors : |
||
9 | * Paolo Gai <pj@gandalf.sssup.it> |
||
10 | * Massimiliano Giorgi <massy@gandalf.sssup.it> |
||
11 | * Luca Abeni <luca@gandalf.sssup.it> |
||
12 | * (see the web pages for full authors list) |
||
13 | * |
||
14 | * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy) |
||
15 | * |
||
16 | * http://www.sssup.it |
||
17 | * http://retis.sssup.it |
||
18 | * http://shark.sssup.it |
||
19 | */ |
||
20 | |||
21 | |||
22 | /*************************************** |
||
23 | |||
686 | giacomo | 24 | CVS : $Id: bdev.c,v 1.2 2004-05-26 11:20:23 giacomo Exp $ |
2 | pj | 25 | |
686 | giacomo | 26 | Revision: $Revision: 1.2 $ |
2 | pj | 27 | |
686 | giacomo | 28 | Last update: $Date: 2004-05-26 11:20:23 $ |
2 | pj | 29 | |
30 | This module contains the block device manager: it export some functions |
||
31 | to the rest of the kernel that are mapped to a real device driver |
||
32 | sub-system. |
||
33 | |||
34 | ***************************************/ |
||
35 | |||
36 | /* |
||
37 | * Copyright (C) 1999 Massimiliano Giorgi |
||
38 | * |
||
39 | * This program is free software; you can redistribute it and/or modify |
||
40 | * it under the terms of the GNU General Public License as published by |
||
41 | * the Free Software Foundation; either version 2 of the License, or |
||
42 | * (at your option) any later version. |
||
43 | * |
||
44 | * This program is distributed in the hope that it will be useful, |
||
45 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
46 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
47 | * GNU General Public License for more details. |
||
48 | * |
||
49 | * You should have received a copy of the GNU General Public License |
||
50 | * along with this program; if not, write to the Free Software |
||
51 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
52 | * |
||
53 | */ |
||
54 | |||
55 | #include "glue.h" |
||
56 | #include <fs/bdevconf.h> |
||
57 | #include <fs/bdev.h> |
||
58 | #include <fs/magic.h> |
||
59 | #include <fs/assert.h> |
||
60 | #include <fs/sysmacro.h> |
||
61 | #include <fs/bdevinit.h> |
||
62 | #include <fs/fsind.h> |
||
63 | //#include <fs/mutex.h> |
||
64 | |||
65 | #include "bdev.h" |
||
66 | |||
67 | /*+ Log Level to use +*/ |
||
68 | #define BDEVLOG KERN_ERR |
||
69 | |||
70 | /*+ an entry for every block device +*/ |
||
71 | static struct block_device bdev[MAXBLOCKDEVICE]; |
||
72 | |||
73 | /*+ an index into bdev_minor +*/ |
||
74 | int bdev_minor_index=0; |
||
75 | |||
76 | /*+ an entry for every block device minor number +*/ |
||
77 | struct block_device_minor bdev_minor[MAXBLOCKDEVICEMINOR]; |
||
78 | |||
79 | /*+ some operations must be done in mutual exclusion +*/ |
||
80 | NOP_mutexattr_t bdevdef_mutexattr=NOP_MUTEXATTR_INITIALIZER; |
||
81 | __b_mutex_t mutex; |
||
82 | void *bmutexattr=NULL; |
||
83 | static BDEV_PARMS defaultparms=BASE_BDEV; |
||
84 | |||
85 | /*++++++++++++++++++++++++++++++++++++++ |
||
86 | |||
87 | Initialize the block device manager and then initialize every |
||
88 | block-device sub-system defined into bdevconf.h (Actualy it is |
||
89 | impossible to load a module at run-time). |
||
90 | |||
91 | int bdev_init |
||
92 | return 0 on success, other value on error |
||
93 | |||
94 | BDEV_PARMS *parms |
||
95 | pointer to a structure that contains all device inizialization parameter |
||
96 | ++++++++++++++++++++++++++++++++++++++*/ |
||
97 | |||
98 | int bdev_init(BDEV_PARMS *parms) |
||
99 | { |
||
100 | int i; |
||
101 | |||
102 | if (parms==NULL) parms=&defaultparms; |
||
103 | |||
104 | /* 'bmutexattr' initialization */ |
||
105 | bmutexattr=parms->bmutexattr; |
||
106 | if (bmutexattr==NULL) bmutexattr=&bdevdef_mutexattr; |
||
107 | |||
108 | /* initialize mutex */ |
||
109 | __b_mutex_init(&mutex); |
||
110 | |||
111 | /* initialize the bdev[] table */ |
||
112 | for (i=0;i<MAXBLOCKDEVICE;i++) { |
||
113 | magic_set(bdev[i].magic,BLOCK_DEVICE_MAGIC); |
||
114 | bdev[i].bd_flag_used=0; |
||
115 | } |
||
116 | |||
117 | /* initialize the bdev_minor[] table */ |
||
118 | /*for (i=0;i<MAX*/ |
||
119 | |||
120 | #ifdef IDE_BLOCK_DEVICE |
||
121 | /* if requested initialize the IDE subsystem */ |
||
122 | ide_init(parms); |
||
123 | #endif |
||
124 | |||
125 | #ifdef LOOP_BLOCK_DEVICE |
||
126 | /* if requested initialize the "loop device" subsystem */ |
||
127 | loop_init(parms); |
||
128 | #endif |
||
129 | |||
130 | return 0; |
||
131 | } |
||
132 | |||
133 | /*++++++++++++++++++++++++++++++++++++++ |
||
134 | |||
135 | Every block device sub-system must call this function yo register |
||
136 | itself to the device block manager. |
||
137 | |||
138 | int bdev_register |
||
139 | return 0 on success, -1 on failure |
||
140 | |||
141 | __dev_t devmajor |
||
142 | major block device number to register |
||
143 | |||
144 | char *name |
||
145 | the name of the device (must be a pointer to static data) |
||
146 | |||
147 | struct block_device *dev |
||
148 | information to hook the block device routine |
||
149 | ++++++++++++++++++++++++++++++++++++++*/ |
||
150 | |||
151 | int bdev_register(__dev_t devmajor, char *name, struct block_device *dev) |
||
152 | { |
||
153 | __dev_t mj=major(devmajor); |
||
154 | |||
155 | /* check for consistency */ |
||
156 | if (mj<=0||mj>=MAXBLOCKDEVICE) { |
||
157 | printk(BDEVLOG "bdev: request to register invalid major %i", |
||
158 | mj); |
||
159 | return -1; |
||
160 | } |
||
161 | if (bdev[mj].bd_flag_used) { |
||
162 | printk(BDEVLOG "bdev: requet to register used major %i", |
||
163 | mj); |
||
164 | return -1; |
||
165 | } |
||
166 | magic_assert(bdev[mj].magic,BLOCK_DEVICE_MAGIC, |
||
167 | "bdev: device(%i,%i) overwritten prior to use", |
||
168 | mj,minor(devmajor)); |
||
169 | |||
170 | /* register the device */ |
||
171 | memcpy(bdev+mj,dev,sizeof(struct block_device)); |
||
172 | bdev[mj].bd_flag_used=1; |
||
173 | bdev[mj].bd_name=name; |
||
174 | magic_set(bdev[mj].magic,BLOCK_DEVICE_MAGIC); |
||
175 | |||
176 | return 0; |
||
177 | } |
||
178 | |||
179 | static __uint8_t part2sysind(__uint8_t par_ind) |
||
180 | { |
||
181 | switch(par_ind) { |
||
182 | case FSPAR_DOS12: |
||
183 | case FSPAR_DOS16: |
||
184 | case FSPAR_DOSBIG: |
||
185 | return FS_MSDOS; |
||
186 | case FSPAR_LNXNTV: |
||
187 | return FS_EXT2; |
||
188 | } |
||
189 | return FS_DEFAULT; |
||
190 | } |
||
191 | |||
192 | /*++++++++++++++++++++++++++++++++++++++ |
||
193 | |||
194 | Every block device sub-system must call this function to register |
||
195 | itself to the device block manager (these information are used by |
||
196 | the devfs filesystem to export device name to the system in a |
||
197 | POSIX fanshion). |
||
198 | |||
199 | int bdev_register_minor |
||
200 | return a minor index on success, <0 on failure |
||
201 | |||
202 | __dev_t device |
||
203 | block device to register |
||
204 | |||
205 | char *name |
||
206 | the name of the device |
||
207 | |||
208 | __uint8_t fsind |
||
209 | file system indicator (see fsind.h) |
||
210 | ++++++++++++++++++++++++++++++++++++++*/ |
||
211 | |||
212 | int bdev_register_minor(__dev_t device, char *name,__uint8_t fsind) |
||
213 | { |
||
214 | /* checks for bad requests */ |
||
215 | if (bdev_minor_index==MAXBLOCKDEVICEMINOR) return -1; |
||
216 | if (major(device)>MAXBLOCKDEVICE) return -2; |
||
217 | if (!bdev[major(device)].bd_flag_used) return -3; |
||
218 | |||
219 | /* register minor device */ |
||
220 | strncpy(bdev_minor[bdev_minor_index].bdm_name,name,MAXDEVICENAME); |
||
221 | bdev_minor[bdev_minor_index].bdm_name[MAXDEVICENAME-1]='\0'; |
||
222 | bdev_minor[bdev_minor_index].bdm_device=device; |
||
223 | bdev_minor[bdev_minor_index].bdm_fsind=part2sysind(fsind); |
||
224 | |||
225 | return bdev_minor_index++; |
||
226 | } |
||
227 | |||
228 | /*++++++++++++++++++++++++++++++++++++++ |
||
229 | |||
230 | Find a device using its name. |
||
231 | |||
232 | __dev_t bdev_find_byname |
||
233 | return a device number on success, <0 on failure |
||
234 | |||
235 | char *name |
||
236 | the name of the device to find |
||
237 | ++++++++++++++++++++++++++++++++++++++*/ |
||
238 | |||
239 | __dev_t bdev_find_byname(char *name) |
||
240 | { |
||
241 | char *s0,*s1,*s2; |
||
242 | char saved; |
||
243 | int i; |
||
244 | |||
245 | /* |
||
246 | * a name can be, for example, "/dev/ide/hda1"; |
||
247 | * after this code s0 is a pointer to "ide" (the major name) and s1 is |
||
248 | * a pointer to "hda1" (the minor name) |
||
249 | */ |
||
250 | s0=name; |
||
251 | s1=strchr(name,'/'); |
||
252 | if (s1==NULL) return -1; |
||
253 | while ((s2=strchr(s1+1,'/'))!=NULL) { |
||
254 | s0=s1+1; |
||
255 | s1=s2; |
||
256 | } |
||
257 | saved=*s1; |
||
258 | *s1++='\0'; |
||
259 | |||
260 | /* search for a device... */ |
||
261 | for (i=0;i<bdev_minor_index;i++) |
||
262 | /* compare a minor name */ |
||
263 | if (!strcmp(s1,bdev_minor[i].bdm_name)) |
||
264 | /* compare a major name */ |
||
265 | if (!strcmp(bdev[major(bdev_minor[i].bdm_device)].bd_name,s0)) { |
||
266 | *(s1-1)=saved; |
||
267 | return bdev_minor[i].bdm_device; |
||
268 | } |
||
269 | *(s1-1)=saved; |
||
270 | return -2; |
||
271 | } |
||
272 | |||
273 | |||
274 | /*++++++++++++++++++++++++++++++++++++++ |
||
275 | |||
276 | Find major and minor name using a device id (__dev_t). |
||
277 | |||
278 | int bdev_findname |
||
279 | return 0 on success; -1 on failure. |
||
280 | |||
281 | __dev_t dev |
||
282 | device identification |
||
283 | |||
284 | char **major |
||
285 | the major name is pointed here |
||
286 | |||
287 | char **minor |
||
288 | the minor name is pointed here |
||
289 | ++++++++++++++++++++++++++++++++++++++*/ |
||
290 | |||
291 | int bdev_findname(__dev_t dev, char **major,char **minor) |
||
292 | { |
||
293 | int i; |
||
294 | |||
295 | assertk(major!=NULL&&minor!=NULL); |
||
296 | |||
297 | for (i=0;i<bdev_minor_index;i++) |
||
298 | if (bdev_minor[i].bdm_device==dev) { |
||
299 | *minor=bdev_minor[i].bdm_name; |
||
300 | *major=bdev[major(dev)].bd_name; |
||
301 | return 0; |
||
302 | } |
||
303 | |||
304 | return -1; |
||
305 | } |
||
306 | |||
307 | /*++++++++++++++++++++++++++++++++++++++ |
||
308 | |||
309 | Find a device using its file system indicator (the first device |
||
310 | that use this file system). |
||
311 | |||
312 | __dev_t bdev_find_byfs |
||
313 | return a device number on success, <0 on failure |
||
314 | |||
315 | __uint8_t fsind |
||
316 | file system indicator |
||
317 | ++++++++++++++++++++++++++++++++++++++*/ |
||
318 | |||
319 | __dev_t bdev_find_byfs(__uint8_t fsind) |
||
320 | { |
||
321 | int i; |
||
322 | for (i=0;i<bdev_minor_index;i++) |
||
323 | if (bdev_minor[i].bdm_fsind==fsind) |
||
324 | return bdev_minor[i].bdm_device; |
||
325 | return -1; |
||
326 | } |
||
327 | |||
328 | /*++++++++++++++++++++++++++++++++++++++ |
||
329 | |||
330 | Scan all devices into the system: for every device found call |
||
331 | the callback function, if it returns -1 continue scanning else |
||
332 | the values passed is returned. |
||
333 | |||
334 | __dev_t bdev_find_byfs |
||
335 | return a device number on success, <0 on failure |
||
336 | |||
337 | __uint8_t fsind |
||
338 | file system indicator |
||
339 | ++++++++++++++++++++++++++++++++++++++*/ |
||
340 | |||
341 | int bdev_scan_devices(int(*callback)(__dev_t,__uint8_t)) |
||
342 | { |
||
343 | int res=0; |
||
344 | int i; |
||
345 | |||
346 | for (i=0;i<bdev_minor_index;i++) { |
||
347 | res=callback(bdev_minor[i].bdm_device, |
||
348 | bdev_minor[i].bdm_fsind |
||
349 | ); |
||
350 | if (res!=-1) break; |
||
351 | } |
||
352 | return res; |
||
353 | } |
||
354 | |||
355 | //#ifndef NDEBUG |
||
356 | |||
357 | #include <fs/major.h> |
||
358 | extern int ide_dump_startsize(__dev_t, __blkcnt_t*, __blkcnt_t*); |
||
686 | giacomo | 359 | extern void ide_dump_status(void); |
2 | pj | 360 | |
361 | void bdev_dump_names(void) |
||
362 | { |
||
363 | int i; |
||
364 | __blkcnt_t start,size; |
||
365 | |||
366 | printk(KERN_INFO "block device names:"); |
||
367 | for (i=0;i<bdev_minor_index;i++) { |
||
368 | start=size=0; |
||
369 | if (major(bdev_minor[i].bdm_device)==MAJOR_B_IDE) |
||
370 | ide_dump_startsize(bdev_minor[i].bdm_device,&start,&size); |
||
371 | printk(KERN_INFO " %s/%8s %08x (start-%-8li size-%-8li sysind-%02x)", |
||
372 | bdev[major(bdev_minor[i].bdm_device)].bd_name, |
||
373 | bdev_minor[i].bdm_name, |
||
374 | bdev_minor[i].bdm_device, |
||
375 | (long int)start,(long int)size, |
||
376 | bdev_minor[i].bdm_fsind |
||
377 | ); |
||
378 | } |
||
379 | |||
380 | } |
||
381 | |||
382 | void bdev_dump_status(void) |
||
383 | { |
||
384 | int counter,i; |
||
385 | |||
386 | printk(KERN_INFO "block device status:"); |
||
387 | printk(KERN_INFO " registered devices:"); |
||
388 | for (counter=0,i=0;i<MAXBLOCKDEVICE;i++) |
||
389 | if (bdev[i].bd_flag_used) { |
||
390 | printk(KERN_INFO " %s",bdev[i].bd_name); |
||
391 | counter++; |
||
392 | } |
||
393 | printk(KERN_INFO " num. majors: %i",counter); |
||
394 | printk(KERN_INFO " num. minors: %i",bdev_minor_index); |
||
395 | |||
396 | #ifdef IDE_BLOCK_DEVICE |
||
397 | ide_dump_status(); |
||
398 | #endif |
||
399 | |||
400 | } |
||
401 | |||
402 | //#endif |
||
403 | |||
404 | /*++++++++++++++++++++++++++++++++++++++ |
||
405 | |||
406 | Try to lock a device. |
||
407 | Locking a device means that the locking entity can do I/O on that |
||
408 | device (no check is performed during I/O operations). |
||
409 | |||
410 | int bdev_trylock |
||
411 | return 1 on success, 0 on failure and, -1 on error |
||
412 | |||
413 | __dev_t dev |
||
414 | device to lock |
||
415 | ++++++++++++++++++++++++++++++++++++++*/ |
||
416 | |||
417 | int bdev_trylock(__dev_t dev) |
||
418 | { |
||
419 | int res; |
||
420 | |||
421 | magic_assert(bdev[major(dev)].magic,BLOCK_DEVICE_MAGIC, |
||
422 | "bdev: device(%04x:%04x) overwritten", |
||
423 | major(dev),minor(dev)); |
||
424 | |||
425 | if (!bdev[major(dev)].bd_flag_used) { |
||
426 | printk(BDEVLOG "bdev: device(%04x:%04x) not registered", |
||
427 | major(dev),minor(dev)); |
||
428 | return -1; |
||
429 | } |
||
430 | |||
431 | __b_mutex_lock(&mutex); |
||
432 | res=bdev[major(dev)].bd_op->_trylock(dev); |
||
433 | __b_mutex_unlock(&mutex); |
||
434 | |||
435 | return res; |
||
436 | } |
||
437 | |||
438 | /*++++++++++++++++++++++++++++++++++++++ |
||
439 | |||
440 | Try to unlock a device. |
||
441 | |||
442 | int bdev_tryunlock |
||
443 | return 1 on success, 0 on failure and, -1 on error |
||
444 | |||
445 | __dev_t dev |
||
446 | device to unlock |
||
447 | ++++++++++++++++++++++++++++++++++++++*/ |
||
448 | |||
449 | int bdev_tryunlock(__dev_t dev) |
||
450 | { |
||
451 | int res; |
||
452 | |||
453 | magic_assert(bdev[major(dev)].magic,BLOCK_DEVICE_MAGIC, |
||
454 | "bdev: device(%04x:%04x) overwritten", |
||
455 | major(dev),minor(dev)); |
||
456 | |||
457 | if (!bdev[major(dev)].bd_flag_used) { |
||
458 | printk(BDEVLOG "bdev: device(%04x:%04x) not registered", |
||
459 | major(dev),minor(dev)); |
||
460 | return -1; |
||
461 | } |
||
462 | |||
463 | __b_mutex_lock(&mutex); |
||
464 | res=bdev[major(dev)].bd_op->_tryunlock(dev); |
||
465 | __b_mutex_unlock(&mutex); |
||
466 | |||
467 | return res; |
||
468 | } |
||
469 | |||
470 | |||
471 | /*++++++++++++++++++++++++++++++++++++++ |
||
472 | |||
473 | The following function are used to "virtualize" the call of a function |
||
474 | of a block device sub-system. |
||
475 | Actually they are implemeted by function to perform some parameters |
||
476 | check but they will be implemented by macro. |
||
477 | +latex+ \\ |
||
478 | |||
479 | This function request to read a block number. |
||
480 | |||
481 | int bdev_read |
||
482 | return 0 on success, other value on error |
||
483 | |||
484 | __dev_t dev |
||
485 | device where to read from |
||
486 | |||
487 | __blkcnt_t blocknum |
||
488 | block number to read |
||
489 | |||
490 | __uint8_t *buffer |
||
491 | buffer for the readed data |
||
492 | ++++++++++++++++++++++++++++++++++++++*/ |
||
493 | |||
494 | int bdev_read(__dev_t dev, __blkcnt_t blocknum, __uint8_t *buffer) |
||
495 | { |
||
496 | |||
497 | magic_assert(bdev[major(dev)].magic,BLOCK_DEVICE_MAGIC, |
||
498 | "bdev: device(%04x:%04x) overwritten", |
||
499 | major(dev),minor(dev)); |
||
500 | |||
501 | if (!bdev[major(dev)].bd_flag_used) { |
||
502 | printk(BDEVLOG "bdev: device(%04x:%04x) not registered", |
||
503 | major(dev),minor(dev)); |
||
504 | return -1; |
||
505 | } |
||
506 | |||
507 | if (blocknum<0) { |
||
508 | printk(BDEVLOG "bdev: device(%04x:%04x) read request out of range", |
||
509 | major(dev),minor(dev)); |
||
510 | return -1; |
||
511 | } |
||
512 | |||
513 | return bdev[major(dev)].bd_op->read(dev,blocknum,buffer); |
||
514 | } |
||
515 | |||
516 | /*++++++++++++++++++++++++++++++++++++++ |
||
517 | |||
518 | This function request to move the head to a specified block of a device. |
||
519 | |||
520 | int bdev_seek |
||
521 | return 0 on success, other value on error |
||
522 | |||
523 | __dev_t dev |
||
524 | device to seek |
||
525 | |||
526 | __blkcnt_t blocknum |
||
527 | block number to seek into |
||
528 | ++++++++++++++++++++++++++++++++++++++*/ |
||
529 | |||
530 | int bdev_seek(__dev_t dev, __blkcnt_t blocknum) |
||
531 | { |
||
532 | magic_assert(bdev[major(dev)].magic,BLOCK_DEVICE_MAGIC, |
||
533 | "bdev: device(%04x:%04x) overwritten", |
||
534 | major(dev),minor(dev)); |
||
535 | |||
536 | if (!bdev[major(dev)].bd_flag_used) { |
||
537 | printk(BDEVLOG "bdev: device(%04x:%04x) not registered", |
||
538 | major(dev),minor(dev)); |
||
539 | return -1; |
||
540 | } |
||
541 | |||
542 | if (blocknum<0) { |
||
543 | printk(BDEVLOG "bdev: device(%04x:%04x) seek request out of range", |
||
544 | major(dev),minor(dev)); |
||
545 | return -1; |
||
546 | } |
||
547 | |||
548 | return bdev[major(dev)].bd_op->seek(dev,blocknum); |
||
549 | } |
||
550 | |||
551 | /*++++++++++++++++++++++++++++++++++++++ |
||
552 | |||
553 | Write a block into a device. |
||
554 | |||
555 | int bdev_write |
||
556 | return 0 on success, other value on error |
||
557 | |||
558 | __dev_t dev |
||
559 | device to write into |
||
560 | |||
561 | __blkcnt_t blocknum |
||
562 | block number to write |
||
563 | |||
564 | __uint8_t *buffer |
||
565 | buffer with data to write |
||
566 | ++++++++++++++++++++++++++++++++++++++*/ |
||
567 | |||
568 | int bdev_write(__dev_t dev, __blkcnt_t blocknum, __uint8_t *buffer) |
||
569 | { |
||
570 | magic_assert(bdev[major(dev)].magic,BLOCK_DEVICE_MAGIC, |
||
571 | "bdev: device(%04x:%04x) overwritten", |
||
572 | major(dev),minor(dev)); |
||
573 | |||
574 | if (!bdev[major(dev)].bd_flag_used) { |
||
575 | printk(BDEVLOG "bdev: device(%04x:%04x) not registered", |
||
576 | major(dev),minor(dev)); |
||
577 | return -1; |
||
578 | } |
||
579 | |||
580 | if (blocknum<0) { |
||
581 | printk(BDEVLOG "bdev: device(%04x:%04x) write request out of range", |
||
582 | major(dev),minor(dev)); |
||
583 | return -1; |
||
584 | } |
||
585 | |||
586 | return bdev[major(dev)].bd_op->write(dev,blocknum,buffer); |
||
587 | } |