root/fs/devices.c

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

DEFINITIONS

This source file includes following definitions.
  1. get_device_list
  2. get_blkfops
  3. get_chrfops
  4. register_chrdev
  5. register_blkdev
  6. unregister_chrdev
  7. unregister_blkdev
  8. check_disk_change
  9. blkdev_open
  10. chrdev_open
  11. kdevname

   1 /*
   2  *  linux/fs/devices.c
   3  *
   4  * (C) 1993 Matthias Urlichs -- collected common code and tables.
   5  * 
   6  *  Copyright (C) 1991, 1992  Linus Torvalds
   7  */
   8 
   9 #include <linux/fs.h>
  10 #include <linux/major.h>
  11 #include <linux/string.h>
  12 #include <linux/sched.h>
  13 #include <linux/ext_fs.h>
  14 #include <linux/stat.h>
  15 #include <linux/fcntl.h>
  16 #include <linux/errno.h>
  17 
  18 struct device_struct {
  19         const char * name;
  20         struct file_operations * fops;
  21 };
  22 
  23 static struct device_struct chrdevs[MAX_CHRDEV] = {
  24         { NULL, NULL },
  25 };
  26 
  27 static struct device_struct blkdevs[MAX_BLKDEV] = {
  28         { NULL, NULL },
  29 };
  30 
  31 int get_device_list(char * page)
     /* [previous][next][first][last][top][bottom][index][help] */
  32 {
  33         int i;
  34         int len;
  35 
  36         len = sprintf(page, "Character devices:\n");
  37         for (i = 0; i < MAX_CHRDEV ; i++) {
  38                 if (chrdevs[i].fops) {
  39                         len += sprintf(page+len, "%2d %s\n", i, chrdevs[i].name);
  40                 }
  41         }
  42         len += sprintf(page+len, "\nBlock devices:\n");
  43         for (i = 0; i < MAX_BLKDEV ; i++) {
  44                 if (blkdevs[i].fops) {
  45                         len += sprintf(page+len, "%2d %s\n", i, blkdevs[i].name);
  46                 }
  47         }
  48         return len;
  49 }
  50 
  51 struct file_operations * get_blkfops(unsigned int major)
     /* [previous][next][first][last][top][bottom][index][help] */
  52 {
  53         if (major >= MAX_BLKDEV)
  54                 return NULL;
  55         return blkdevs[major].fops;
  56 }
  57 
  58 struct file_operations * get_chrfops(unsigned int major)
     /* [previous][next][first][last][top][bottom][index][help] */
  59 {
  60         if (major >= MAX_CHRDEV)
  61                 return NULL;
  62         return chrdevs[major].fops;
  63 }
  64 
  65 int register_chrdev(unsigned int major, const char * name, struct file_operations *fops)
     /* [previous][next][first][last][top][bottom][index][help] */
  66 {
  67         if (major == 0) {
  68                 for (major = MAX_CHRDEV-1; major > 0; major--) {
  69                         if (chrdevs[major].fops == NULL) {
  70                                 chrdevs[major].name = name;
  71                                 chrdevs[major].fops = fops;
  72                                 return major;
  73                         }
  74                 }
  75                 return -EBUSY;
  76         }
  77         if (major >= MAX_CHRDEV)
  78                 return -EINVAL;
  79         if (chrdevs[major].fops && chrdevs[major].fops != fops)
  80                 return -EBUSY;
  81         chrdevs[major].name = name;
  82         chrdevs[major].fops = fops;
  83         return 0;
  84 }
  85 
  86 int register_blkdev(unsigned int major, const char * name, struct file_operations *fops)
     /* [previous][next][first][last][top][bottom][index][help] */
  87 {
  88         if (major == 0) {
  89                 for (major = MAX_BLKDEV-1; major > 0; major--) {
  90                         if (blkdevs[major].fops == NULL) {
  91                                 blkdevs[major].name = name;
  92                                 blkdevs[major].fops = fops;
  93                                 return major;
  94                         }
  95                 }
  96                 return -EBUSY;
  97         }
  98         if (major >= MAX_BLKDEV)
  99                 return -EINVAL;
 100         if (blkdevs[major].fops && blkdevs[major].fops != fops)
 101                 return -EBUSY;
 102         blkdevs[major].name = name;
 103         blkdevs[major].fops = fops;
 104         return 0;
 105 }
 106 
 107 int unregister_chrdev(unsigned int major, const char * name)
     /* [previous][next][first][last][top][bottom][index][help] */
 108 {
 109         if (major >= MAX_CHRDEV)
 110                 return -EINVAL;
 111         if (!chrdevs[major].fops)
 112                 return -EINVAL;
 113         if (strcmp(chrdevs[major].name, name))
 114                 return -EINVAL;
 115         chrdevs[major].name = NULL;
 116         chrdevs[major].fops = NULL;
 117         return 0;
 118 }
 119 
 120 int unregister_blkdev(unsigned int major, const char * name)
     /* [previous][next][first][last][top][bottom][index][help] */
 121 {
 122         if (major >= MAX_BLKDEV)
 123                 return -EINVAL;
 124         if (!blkdevs[major].fops)
 125                 return -EINVAL;
 126         if (strcmp(blkdevs[major].name, name))
 127                 return -EINVAL;
 128         blkdevs[major].name = NULL;
 129         blkdevs[major].fops = NULL;
 130         return 0;
 131 }
 132 
 133 /*
 134  * This routine checks whether a removable media has been changed,
 135  * and invalidates all buffer-cache-entries in that case. This
 136  * is a relatively slow routine, so we have to try to minimize using
 137  * it. Thus it is called only upon a 'mount' or 'open'. This
 138  * is the best way of combining speed and utility, I think.
 139  * People changing diskettes in the middle of an operation deserve
 140  * to loose :-)
 141  */
 142 int check_disk_change(kdev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 143 {
 144         int i;
 145         struct file_operations * fops;
 146 
 147         i = MAJOR(dev);
 148         if (i >= MAX_BLKDEV || (fops = blkdevs[i].fops) == NULL)
 149                 return 0;
 150         if (fops->check_media_change == NULL)
 151                 return 0;
 152         if (!fops->check_media_change(dev))
 153                 return 0;
 154 
 155         printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
 156                 kdevname(dev));
 157         for (i=0 ; i<NR_SUPER ; i++)
 158                 if (super_blocks[i].s_dev == dev)
 159                         put_super(super_blocks[i].s_dev);
 160         invalidate_inodes(dev);
 161         invalidate_buffers(dev);
 162 
 163         if (fops->revalidate)
 164                 fops->revalidate(dev);
 165         return 1;
 166 }
 167 
 168 /*
 169  * Called every time a block special file is opened
 170  */
 171 int blkdev_open(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 172 {
 173         int i;
 174 
 175         i = MAJOR(inode->i_rdev);
 176         if (i >= MAX_BLKDEV || !blkdevs[i].fops)
 177                 return -ENODEV;
 178         filp->f_op = blkdevs[i].fops;
 179         if (filp->f_op->open)
 180                 return filp->f_op->open(inode,filp);
 181         return 0;
 182 }       
 183 
 184 /*
 185  * Dummy default file-operations: the only thing this does
 186  * is contain the open that then fills in the correct operations
 187  * depending on the special file...
 188  */
 189 struct file_operations def_blk_fops = {
 190         NULL,           /* lseek */
 191         NULL,           /* read */
 192         NULL,           /* write */
 193         NULL,           /* readdir */
 194         NULL,           /* select */
 195         NULL,           /* ioctl */
 196         NULL,           /* mmap */
 197         blkdev_open,    /* open */
 198         NULL,           /* release */
 199 };
 200 
 201 struct inode_operations blkdev_inode_operations = {
 202         &def_blk_fops,          /* default file operations */
 203         NULL,                   /* create */
 204         NULL,                   /* lookup */
 205         NULL,                   /* link */
 206         NULL,                   /* unlink */
 207         NULL,                   /* symlink */
 208         NULL,                   /* mkdir */
 209         NULL,                   /* rmdir */
 210         NULL,                   /* mknod */
 211         NULL,                   /* rename */
 212         NULL,                   /* readlink */
 213         NULL,                   /* follow_link */
 214         NULL,                   /* bmap */
 215         NULL,                   /* truncate */
 216         NULL                    /* permission */
 217 };
 218 
 219 /*
 220  * Called every time a character special file is opened
 221  */
 222 int chrdev_open(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 223 {
 224         int i;
 225 
 226         i = MAJOR(inode->i_rdev);
 227         if (i >= MAX_CHRDEV || !chrdevs[i].fops)
 228                 return -ENODEV;
 229         filp->f_op = chrdevs[i].fops;
 230         if (filp->f_op->open)
 231                 return filp->f_op->open(inode,filp);
 232         return 0;
 233 }
 234 
 235 /*
 236  * Dummy default file-operations: the only thing this does
 237  * is contain the open that then fills in the correct operations
 238  * depending on the special file...
 239  */
 240 struct file_operations def_chr_fops = {
 241         NULL,           /* lseek */
 242         NULL,           /* read */
 243         NULL,           /* write */
 244         NULL,           /* readdir */
 245         NULL,           /* select */
 246         NULL,           /* ioctl */
 247         NULL,           /* mmap */
 248         chrdev_open,    /* open */
 249         NULL,           /* release */
 250 };
 251 
 252 struct inode_operations chrdev_inode_operations = {
 253         &def_chr_fops,          /* default file operations */
 254         NULL,                   /* create */
 255         NULL,                   /* lookup */
 256         NULL,                   /* link */
 257         NULL,                   /* unlink */
 258         NULL,                   /* symlink */
 259         NULL,                   /* mkdir */
 260         NULL,                   /* rmdir */
 261         NULL,                   /* mknod */
 262         NULL,                   /* rename */
 263         NULL,                   /* readlink */
 264         NULL,                   /* follow_link */
 265         NULL,                   /* bmap */
 266         NULL,                   /* truncate */
 267         NULL                    /* permission */
 268 };
 269 
 270 /*
 271  * Print device name (in decimal, hexadecimal or symbolic) -
 272  * at present hexadecimal only.
 273  * Note: returns pointer to static data!
 274  */
 275 char * kdevname(kdev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 276 {
 277         static char buffer[32];
 278         sprintf(buffer, "%02x:%02x", MAJOR(dev), MINOR(dev));
 279         return buffer;
 280 }

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