root/drivers/block/md.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. find_gendisk
  2. partition_name
  3. set_ra
  4. md_ioctl
  5. md_open
  6. md_release
  7. md_map
  8. do_md_request
  9. md_geninit
  10. get_md_status
  11. register_md_personality
  12. unregister_md_personality
  13. md_init

   1 
   2 /*
   3    md.c : Multiple Devices driver for Linux
   4           Copyright (C) 1994-96 Marc ZYNGIER
   5           <zyngier@ufr-info-p7.ibp.fr> or
   6           <maz@gloups.fdn.fr>
   7 
   8    A lot of inspiration came from hd.c ...
   9 
  10    kerneld support by Boris Tobotras <boris@xtalk.msk.su>
  11 
  12    This program is free software; you can redistribute it and/or modify
  13    it under the terms of the GNU General Public License as published by
  14    the Free Software Foundation; either version 2, or (at your option)
  15    any later version.
  16    
  17    You should have received a copy of the GNU General Public License
  18    (for example /usr/src/linux/COPYING); if not, write to the Free
  19    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
  20 */
  21 
  22 #include <linux/config.h>
  23 #include <linux/module.h>
  24 #include <linux/version.h>
  25 #include <linux/malloc.h>
  26 #include <linux/mm.h>
  27 #include <linux/md.h>
  28 #include <linux/hdreg.h>
  29 #include <linux/stat.h>
  30 #include <linux/fs.h>
  31 #include <linux/proc_fs.h>
  32 #include <linux/blkdev.h>
  33 #include <linux/genhd.h>
  34 #ifdef CONFIG_KERNELD
  35 #include <linux/kerneld.h>
  36 #endif
  37 #include <linux/errno.h>
  38 
  39 #define MAJOR_NR MD_MAJOR
  40 #define MD_DRIVER
  41 
  42 #include <linux/blk.h>
  43 
  44 static struct hd_struct md_hd_struct[MAX_MD_DEV];
  45 static int md_blocksizes[MAX_MD_DEV];
  46 
  47 int md_size[MAX_MD_DEV]={0, };
  48 
  49 static void md_geninit (struct gendisk *);
  50 
  51 static struct gendisk md_gendisk=
  52 {
  53   MD_MAJOR,
  54   "md",
  55   0,
  56   1,
  57   MAX_MD_DEV,
  58   md_geninit,
  59   md_hd_struct,
  60   md_size,
  61   MAX_MD_DEV,
  62   NULL,
  63   NULL
  64 };
  65 
  66 static struct md_personality *pers[MAX_PERSONALITY]={NULL, };
  67 
  68 struct real_dev devices[MAX_MD_DEV][MAX_REAL];
  69 struct md_dev md_dev[MAX_MD_DEV];
  70 
  71 static struct gendisk *find_gendisk (kdev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  72 {
  73   struct gendisk *tmp=gendisk_head;
  74 
  75   while (tmp != NULL)
  76   {
  77     if (tmp->major==MAJOR(dev))
  78       return (tmp);
  79     
  80     tmp=tmp->next;
  81   }
  82 
  83   return (NULL);
  84 }
  85 
  86 
  87 /* Picked up from genhd.c */
  88 char *partition_name (kdev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  89 {
  90   static char name[40];         /* This should be long
  91                                    enough for a device name ! */
  92   struct gendisk *hd = find_gendisk (dev);
  93 
  94   if (!hd)
  95   {
  96     printk ("No gendisk entry for dev %s\n", kdevname(dev));
  97     sprintf (name, "dev %s", kdevname(dev));
  98     return (name);
  99   }
 100 
 101   return disk_name (hd, MINOR(dev), name);  /* routine in genhd.c */
 102 }
 103 
 104 
 105 static void set_ra (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 106 {
 107   int i, j, minra=INT_MAX;
 108 
 109   for (i=0; i<MAX_MD_DEV; i++)
 110   {
 111     if (!md_dev[i].pers)
 112       continue;
 113     
 114     for (j=0; j<md_dev[i].nb_dev; j++)
 115       if (read_ahead[MAJOR(devices[i][j].dev)]<minra)
 116         minra=read_ahead[MAJOR(devices[i][j].dev)];
 117   }
 118   
 119   read_ahead[MD_MAJOR]=minra;
 120 }
 121 
 122 
 123 static int md_ioctl (struct inode *inode, struct file *file,
     /* [previous][next][first][last][top][bottom][index][help] */
 124                      unsigned int cmd, unsigned long arg)
 125 {
 126   int minor, index, err, current_ra;
 127   struct gendisk *gen_real;
 128   struct hd_geometry *loc = (struct hd_geometry *) arg;
 129   kdev_t dev;
 130 
 131   if (!suser())
 132     return -EACCES;
 133 
 134   if (((minor=MINOR(inode->i_rdev)) & 0x80) &&
 135       (minor & 0x7f) < MAX_PERSONALITY &&
 136       pers[minor & 0x7f] &&
 137       pers[minor & 0x7f]->ioctl)
 138     return (pers[minor & 0x7f]->ioctl (inode, file, cmd, arg));
 139   
 140   if (minor >= MAX_MD_DEV)
 141     return -EINVAL;
 142 
 143   switch (cmd)
 144   {
 145     case REGISTER_DEV:
 146     dev=to_kdev_t ((dev_t) arg);
 147     if (MAJOR(dev)==MD_MAJOR || md_dev[minor].nb_dev==MAX_REAL)
 148       return -EINVAL;
 149 
 150     if (!fs_may_mount (dev) || md_dev[minor].pers)
 151       return -EBUSY;
 152 
 153     if (!(gen_real=find_gendisk (dev)))
 154       return -ENOENT;
 155 
 156     index=md_dev[minor].nb_dev++;
 157     devices[minor][index].dev=dev;
 158 
 159     /* Lock the device by inserting a dummy inode. This doesn't
 160        smell very good, but I need to be consistent with the
 161        mount stuff, specially with fs_may_mount. If someone have
 162        a better idea, please help ! */
 163     
 164     devices[minor][index].inode=get_empty_inode ();
 165     devices[minor][index].inode->i_dev=dev; /* don't care about
 166                                                other fields */
 167     insert_inode_hash (devices[minor][index].inode);
 168     
 169     /* Devices sizes are rounded to a multiple of page (needed for
 170        paging). This is NOT done by fdisk when partitioning,
 171        but that's a DOS thing anyway... */
 172     
 173     devices[minor][index].size=gen_real->sizes[MINOR(dev)] & ~((PAGE_SIZE >> 10)-1);
 174     devices[minor][index].offset=index ?
 175       (devices[minor][index-1].offset + devices[minor][index-1].size) : 0;
 176 
 177     if (!index)
 178       md_size[minor]=devices[minor][index].size;
 179     else
 180       md_size[minor]+=devices[minor][index].size;
 181 
 182     printk("REGISTER_DEV %s to md%x done\n", partition_name(dev), minor);
 183     break;
 184 
 185     case START_MD:
 186     if (!md_dev[minor].nb_dev)
 187       return -EINVAL;
 188 
 189     if (md_dev[minor].pers)
 190       return -EBUSY;
 191 
 192     md_dev[minor].repartition=(int) arg;
 193     
 194     if ((index=PERSONALITY(md_dev+minor) >> (PERSONALITY_SHIFT))
 195         >= MAX_PERSONALITY)
 196       return -EINVAL;
 197 
 198     if (!pers[index])
 199     {
 200 #ifdef CONFIG_KERNELD
 201       char module_name[80];
 202       sprintf (module_name, "md-personality-%d", index);
 203       request_module (module_name);
 204       if (!pers[index])
 205 #endif
 206         return -EINVAL;
 207     }
 208 
 209     md_dev[minor].pers=pers[index];
 210 
 211     if ((err=md_dev[minor].pers->run (minor, md_dev+minor)))
 212     {
 213       md_dev[minor].pers=NULL;
 214       return (err);
 215     }
 216 
 217     /* FIXME : We assume here we have blocks
 218        that are twice as large as sectors.
 219        THIS MAY NOT BE TRUE !!! */
 220     md_hd_struct[minor].start_sect=0;
 221     md_hd_struct[minor].nr_sects=md_size[minor]<<1;
 222 
 223     /* It would be better to have a per-md-dev read_ahead. Currently,
 224        we only use the smallest read_ahead among md-attached devices */
 225 
 226     current_ra=read_ahead[MD_MAJOR];
 227     
 228     for (index=0; index<md_dev[minor].nb_dev; index++)
 229     {
 230       if (current_ra>read_ahead[MAJOR(devices[minor][index].dev)])
 231         current_ra=read_ahead[MAJOR(devices[minor][index].dev)];
 232 
 233       devices[minor][index].fault_count=0;
 234       devices[minor][index].invalid=VALID;
 235     }
 236 
 237     read_ahead[MD_MAJOR]=current_ra;
 238 
 239     printk ("START_DEV md%x %s\n", minor, md_dev[minor].pers->name);
 240     break;
 241 
 242     case STOP_MD:
 243     if (inode->i_count>1 || md_dev[minor].busy>1) /* ioctl : one open channel */
 244     {
 245       printk ("STOP_MD md%x failed : i_count=%d, busy=%d\n", minor, inode->i_count, md_dev[minor].busy);
 246       return -EBUSY;
 247     }
 248 
 249     if (md_dev[minor].pers)
 250     {
 251       /*  The device won't exist anymore -> flush it now */
 252       fsync_dev (inode->i_rdev);
 253       invalidate_buffers (inode->i_rdev);
 254       md_dev[minor].pers->stop (minor, md_dev+minor);
 255     }
 256 
 257     /* Remove locks. */
 258     for (index=0; index<md_dev[minor].nb_dev; index++)
 259       clear_inode (devices[minor][index].inode);
 260 
 261     md_dev[minor].nb_dev=md_size[minor]=0;
 262     md_dev[minor].pers=NULL;
 263 
 264     set_ra ();                  /* calculate new read_ahead */
 265     
 266     printk ("STOP_DEV md%x\n", minor);
 267     break;
 268 
 269 #if defined(CONFIG_MD_SUPPORT_RAID1) || defined(CONFIG_MD_SUPPORT_RAID5)
 270     case MD_INVALID:
 271     dev=to_kdev_t ((dev_t) arg);
 272     if (!(err=md_valid_device (minor, dev, INVALID_ALWAYS)))
 273       printk ("md%d : %s disabled\n", minor, partition_name (dev));
 274 
 275     return (err);
 276 
 277     case MD_VALID:
 278     dev=to_kdev_t ((dev_t) arg);
 279     if (!(err=md_valid_device (minor, dev, VALID)))
 280       printk ("md%d : %s enabled\n", minor, partition_name (dev));
 281 
 282     return (err);
 283 #endif
 284     
 285     case BLKGETSIZE:   /* Return device size */
 286     if  (!arg)  return -EINVAL;
 287     err=verify_area (VERIFY_WRITE, (long *) arg, sizeof(long));
 288     if (err)
 289       return err;
 290     put_user (md_hd_struct[MINOR(inode->i_rdev)].nr_sects, (long *) arg);
 291     break;
 292 
 293     case BLKFLSBUF:
 294     fsync_dev (inode->i_rdev);
 295     invalidate_buffers (inode->i_rdev);
 296     break;
 297 
 298     case BLKRASET:
 299     if (arg > 0xff)
 300       return -EINVAL;
 301     read_ahead[MAJOR(inode->i_rdev)] = arg;
 302     return 0;
 303     
 304     case BLKRAGET:
 305     if  (!arg)  return -EINVAL;
 306     err=verify_area (VERIFY_WRITE, (long *) arg, sizeof(long));
 307     if (err)
 308       return err;
 309     put_user (read_ahead[MAJOR(inode->i_rdev)], (long *) arg);
 310     break;
 311 
 312     case HDIO_GETGEO:
 313     if (!loc)  return -EINVAL;
 314     err = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
 315     if (err)
 316       return err;
 317     put_user (2, (char *) &loc->heads);
 318     put_user (4, (char *) &loc->sectors);
 319     put_user (md_hd_struct[minor].nr_sects/8, (short *) &loc->cylinders);
 320     put_user (md_hd_struct[MINOR(inode->i_rdev)].start_sect,
 321                 (long *) &loc->start);
 322     break;
 323     
 324     RO_IOCTLS(inode->i_rdev,arg);
 325     
 326     default:
 327     printk ("Unknown md_ioctl %d\n", cmd);
 328     return -EINVAL;
 329   }
 330 
 331   return (0);
 332 }
 333 
 334 
 335 static int md_open (struct inode *inode, struct file *file)
     /* [previous][next][first][last][top][bottom][index][help] */
 336 {
 337   int minor=MINOR(inode->i_rdev);
 338 
 339   md_dev[minor].busy++;
 340   return (0);                   /* Always succeed */
 341 }
 342 
 343 
 344 static void md_release (struct inode *inode, struct file *file)
     /* [previous][next][first][last][top][bottom][index][help] */
 345 {
 346   int minor=MINOR(inode->i_rdev);
 347 
 348   sync_dev (inode->i_rdev);
 349   md_dev[minor].busy--;
 350 }
 351 
 352 
 353 static struct file_operations md_fops=
 354 {
 355   NULL,
 356   block_read,
 357   block_write,
 358   NULL,
 359   NULL,
 360   md_ioctl,
 361   NULL,
 362   md_open,
 363   md_release,
 364   block_fsync
 365 };
 366 
 367 int md_map (int minor, kdev_t *rdev, unsigned long *rsector, unsigned long size)
     /* [previous][next][first][last][top][bottom][index][help] */
 368 {
 369   if ((unsigned int) minor >= MAX_MD_DEV)
 370   {
 371     printk ("Bad md device %d\n", minor);
 372     return (-1);
 373   }
 374   
 375   if (!md_dev[minor].pers)
 376   {
 377     printk ("Oops ! md%d not running, giving up !\n", minor);
 378     return (-1);
 379   }
 380 
 381   return (md_dev[minor].pers->map(md_dev+minor, rdev, rsector, size));
 382 }
 383   
 384 
 385 static void do_md_request (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 386 {
 387   printk ("Got md request, not good...");
 388   return;
 389 }  
 390 
 391 static struct symbol_table md_symbol_table=
 392 {
 393 #include <linux/symtab_begin.h>
 394 
 395   X(devices),
 396   X(md_size),
 397   X(register_md_personality),
 398   X(unregister_md_personality),
 399   X(partition_name),
 400 
 401 #if defined(CONFIG_MD_SUPPORT_RAID1) || defined(CONFIG_MD_SUPPORT_RAID5)
 402   X(md_valid_device),
 403   X(md_can_reemit),
 404 #endif
 405 
 406 #include <linux/symtab_end.h>
 407 };
 408 
 409 
 410 static void md_geninit (struct gendisk *gdisk)
     /* [previous][next][first][last][top][bottom][index][help] */
 411 {
 412   int i;
 413   
 414   for(i=0;i<MAX_MD_DEV;i++)
 415   {
 416     md_blocksizes[i] = 1024;
 417     md_gendisk.part[i].start_sect=-1;
 418     md_dev[i].pers=NULL;
 419 #ifdef MD_COUNT_SIZES
 420     md_dev[i].smallest_count=md_dev[i].biggest_count=md_dev[i].equal_count=0;
 421 #endif
 422   }
 423 
 424   blksize_size[MAJOR_NR] = md_blocksizes;
 425   register_symtab (&md_symbol_table);
 426 
 427   proc_register(&proc_root,
 428                 &(struct proc_dir_entry)
 429               {
 430                 PROC_MD, 6, "mdstat",
 431                 S_IFREG | S_IRUGO, 1, 0, 0,
 432               });
 433 }
 434 
 435 
 436 int get_md_status (char *page)
     /* [previous][next][first][last][top][bottom][index][help] */
 437 {
 438   int sz=0, i, j;
 439 
 440   sz+=sprintf( page+sz, "Personalities : ");
 441   for (i=0; i<MAX_PERSONALITY; i++)
 442     if (pers[i])
 443       sz+=sprintf (page+sz, "[%d %s] ", i, pers[i]->name);
 444 
 445   page[sz-1]='\n';
 446 
 447   sz+=sprintf (page+sz, "read_ahead ");
 448   if (read_ahead[MD_MAJOR]==INT_MAX)
 449     sz+=sprintf (page+sz, "not set\n");
 450   else
 451     sz+=sprintf (page+sz, "%d sectors\n", read_ahead[MD_MAJOR]);
 452   
 453   for (i=0; i<MAX_MD_DEV; i++)
 454   {
 455     sz+=sprintf (page+sz, "md%d : %sactive", i, md_dev[i].pers ? "" : "in");
 456 
 457     if (md_dev[i].pers)
 458       sz+=sprintf (page+sz, " %s", md_dev[i].pers->name);
 459 
 460     for (j=0; j<md_dev[i].nb_dev; j++)
 461       sz+=sprintf (page+sz, " %s%s%s",
 462                    (devices[i][j].invalid==VALID) ? "" : "(",
 463                    partition_name(devices[i][j].dev),
 464                    (devices[i][j].invalid==VALID) ? "" : ")");
 465     
 466     if (md_dev[i].nb_dev)
 467       sz+=sprintf (page+sz, " %d blocks", md_size[i]);
 468 
 469     if (!md_dev[i].pers)
 470     {
 471       sz+=sprintf (page+sz, "\n");
 472       continue;
 473     }
 474 
 475     if (md_dev[i].pers->max_invalid_dev)
 476       sz+=sprintf (page+sz, " maxfault=%ld", MAX_FAULT(md_dev+i));
 477 
 478     if (md_dev[i].pers != pers[(LINEAR>>PERSONALITY_SHIFT)])
 479     {
 480       sz+=sprintf (page+sz, " %dk chunks", 1<<FACTOR_SHIFT(FACTOR(md_dev+i)));
 481     }
 482     sz+=sprintf (page+sz, "\n");
 483     sz+=md_dev[i].pers->status (page+sz, i, md_dev+i);
 484   }
 485 
 486   return (sz);
 487 }
 488 
 489 int register_md_personality (int p_num, struct md_personality *p)
     /* [previous][next][first][last][top][bottom][index][help] */
 490 {
 491   int i=(p_num >> PERSONALITY_SHIFT);
 492 
 493   if (i >= MAX_PERSONALITY)
 494     return -EINVAL;
 495 
 496   if (pers[i])
 497     return -EBUSY;
 498   
 499   pers[i]=p;
 500   printk ("%s personality registered\n", p->name);
 501   return 0;
 502 }
 503 
 504 int unregister_md_personality (int p_num)
     /* [previous][next][first][last][top][bottom][index][help] */
 505 {
 506   int i=(p_num >> PERSONALITY_SHIFT);
 507 
 508   if (i >= MAX_PERSONALITY)
 509     return -EINVAL;
 510 
 511   printk ("%s personality unregistered\n", pers[i]->name);
 512   pers[i]=NULL;
 513   return 0;
 514 } 
 515 
 516 void linear_init (void);
 517 void raid0_init (void);
 518 void raid1_init (void);
 519 void raid5_init (void);
 520 
 521 int md_init (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 522 {
 523   printk ("md driver %s MAX_MD_DEV=%d, MAX_REAL=%d\n", MD_VERSION, MAX_MD_DEV, MAX_REAL);
 524 
 525   if (register_blkdev (MD_MAJOR, "md", &md_fops))
 526   {
 527     printk ("Unable to get major %d for md\n", MD_MAJOR);
 528     return (-1);
 529   }
 530 
 531   blk_dev[MD_MAJOR].request_fn=DEVICE_REQUEST;
 532   blk_dev[MD_MAJOR].current_request=NULL;
 533   read_ahead[MD_MAJOR]=INT_MAX;
 534   md_gendisk.next=gendisk_head;
 535 
 536   gendisk_head=&md_gendisk;
 537 
 538 #ifdef CONFIG_MD_LINEAR
 539   linear_init ();
 540 #endif
 541 #ifdef CONFIG_MD_STRIPED
 542   raid0_init ();
 543 #endif
 544   
 545   return (0);
 546 }

/* [previous][next][first][last][top][bottom][index][help] */