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

   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 == fops)
  70                                 return major;
  71                 }
  72                 for (major = MAX_CHRDEV-1; major > 0; major--) {
  73                         if (chrdevs[major].fops == NULL) {
  74                                 chrdevs[major].name = name;
  75                                 chrdevs[major].fops = fops;
  76                                 return major;
  77                         }
  78                 }
  79                 return -EBUSY;
  80         }
  81         if (major >= MAX_CHRDEV)
  82                 return -EINVAL;
  83         if (chrdevs[major].fops && chrdevs[major].fops != fops)
  84                 return -EBUSY;
  85         chrdevs[major].name = name;
  86         chrdevs[major].fops = fops;
  87         return 0;
  88 }
  89 
  90 int register_blkdev(unsigned int major, const char * name, struct file_operations *fops)
     /* [previous][next][first][last][top][bottom][index][help] */
  91 {
  92         if (major == 0) {
  93                 for (major = MAX_BLKDEV-1; major > 0; major--) {
  94                         if (blkdevs[major].fops == fops)
  95                                 return major;
  96                 }
  97                 for (major = MAX_BLKDEV-1; major > 0; major--) {
  98                         if (blkdevs[major].fops == NULL) {
  99                                 blkdevs[major].name = name;
 100                                 blkdevs[major].fops = fops;
 101                                 return major;
 102                         }
 103                 }
 104                 return -EBUSY;
 105         }
 106         if (major >= MAX_BLKDEV)
 107                 return -EINVAL;
 108         if (blkdevs[major].fops && blkdevs[major].fops != fops)
 109                 return -EBUSY;
 110         blkdevs[major].name = name;
 111         blkdevs[major].fops = fops;
 112         return 0;
 113 }
 114 
 115 int unregister_chrdev(unsigned int major, const char * name)
     /* [previous][next][first][last][top][bottom][index][help] */
 116 {
 117         if (major >= MAX_CHRDEV)
 118                 return -EINVAL;
 119         if (!chrdevs[major].fops)
 120                 return -EINVAL;
 121         if (strcmp(chrdevs[major].name, name))
 122                 return -EINVAL;
 123         chrdevs[major].name = NULL;
 124         chrdevs[major].fops = NULL;
 125         return 0;
 126 }
 127 
 128 int unregister_blkdev(unsigned int major, const char * name)
     /* [previous][next][first][last][top][bottom][index][help] */
 129 {
 130         if (major >= MAX_BLKDEV)
 131                 return -EINVAL;
 132         if (!blkdevs[major].fops)
 133                 return -EINVAL;
 134         if (strcmp(blkdevs[major].name, name))
 135                 return -EINVAL;
 136         blkdevs[major].name = NULL;
 137         blkdevs[major].fops = NULL;
 138         return 0;
 139 }
 140 
 141 /*
 142  * This routine checks whether a removable media has been changed,
 143  * and invalidates all buffer-cache-entries in that case. This
 144  * is a relatively slow routine, so we have to try to minimize using
 145  * it. Thus it is called only upon a 'mount' or 'open'. This
 146  * is the best way of combining speed and utility, I think.
 147  * People changing diskettes in the middle of an operation deserve
 148  * to loose :-)
 149  */
 150 int check_disk_change(dev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 151 {
 152         int i;
 153         struct file_operations * fops;
 154 
 155         i = MAJOR(dev);
 156         if (i >= MAX_BLKDEV || (fops = blkdevs[i].fops) == NULL)
 157                 return 0;
 158         if (fops->check_media_change == NULL)
 159                 return 0;
 160         if (!fops->check_media_change(dev))
 161                 return 0;
 162 
 163         printk("VFS: Disk change detected on device %d/%d\n",
 164                                         MAJOR(dev), MINOR(dev));
 165         for (i=0 ; i<NR_SUPER ; i++)
 166                 if (super_blocks[i].s_dev == dev)
 167                         put_super(super_blocks[i].s_dev);
 168         invalidate_inodes(dev);
 169         invalidate_buffers(dev);
 170 
 171         if (fops->revalidate)
 172                 fops->revalidate(dev);
 173         return 1;
 174 }
 175 
 176 /*
 177  * Called every time a block special file is opened
 178  */
 179 int blkdev_open(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 180 {
 181         int i;
 182 
 183         i = MAJOR(inode->i_rdev);
 184         if (i >= MAX_BLKDEV || !blkdevs[i].fops)
 185                 return -ENODEV;
 186         filp->f_op = blkdevs[i].fops;
 187         if (filp->f_op->open)
 188                 return filp->f_op->open(inode,filp);
 189         return 0;
 190 }       
 191 
 192 /*
 193  * Dummy default file-operations: the only thing this does
 194  * is contain the open that then fills in the correct operations
 195  * depending on the special file...
 196  */
 197 struct file_operations def_blk_fops = {
 198         NULL,           /* lseek */
 199         NULL,           /* read */
 200         NULL,           /* write */
 201         NULL,           /* readdir */
 202         NULL,           /* select */
 203         NULL,           /* ioctl */
 204         NULL,           /* mmap */
 205         blkdev_open,    /* open */
 206         NULL,           /* release */
 207 };
 208 
 209 struct inode_operations blkdev_inode_operations = {
 210         &def_blk_fops,          /* default file operations */
 211         NULL,                   /* create */
 212         NULL,                   /* lookup */
 213         NULL,                   /* link */
 214         NULL,                   /* unlink */
 215         NULL,                   /* symlink */
 216         NULL,                   /* mkdir */
 217         NULL,                   /* rmdir */
 218         NULL,                   /* mknod */
 219         NULL,                   /* rename */
 220         NULL,                   /* readlink */
 221         NULL,                   /* follow_link */
 222         NULL,                   /* bmap */
 223         NULL,                   /* truncate */
 224         NULL                    /* permission */
 225 };
 226 
 227 /*
 228  * Called every time a character special file is opened
 229  */
 230 int chrdev_open(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 231 {
 232         int i;
 233 
 234         i = MAJOR(inode->i_rdev);
 235         if (i >= MAX_CHRDEV || !chrdevs[i].fops)
 236                 return -ENODEV;
 237         filp->f_op = chrdevs[i].fops;
 238         if (filp->f_op->open)
 239                 return filp->f_op->open(inode,filp);
 240         return 0;
 241 }
 242 
 243 /*
 244  * Dummy default file-operations: the only thing this does
 245  * is contain the open that then fills in the correct operations
 246  * depending on the special file...
 247  */
 248 struct file_operations def_chr_fops = {
 249         NULL,           /* lseek */
 250         NULL,           /* read */
 251         NULL,           /* write */
 252         NULL,           /* readdir */
 253         NULL,           /* select */
 254         NULL,           /* ioctl */
 255         NULL,           /* mmap */
 256         chrdev_open,    /* open */
 257         NULL,           /* release */
 258 };
 259 
 260 struct inode_operations chrdev_inode_operations = {
 261         &def_chr_fops,          /* default file operations */
 262         NULL,                   /* create */
 263         NULL,                   /* lookup */
 264         NULL,                   /* link */
 265         NULL,                   /* unlink */
 266         NULL,                   /* symlink */
 267         NULL,                   /* mkdir */
 268         NULL,                   /* rmdir */
 269         NULL,                   /* mknod */
 270         NULL,                   /* rename */
 271         NULL,                   /* readlink */
 272         NULL,                   /* follow_link */
 273         NULL,                   /* bmap */
 274         NULL,                   /* truncate */
 275         NULL                    /* permission */
 276 };

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