home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / fs / super.c < prev   
Encoding:
C/C++ Source or Header  |  1995-01-18  |  14.8 KB  |  692 lines

  1. /*
  2.  *  linux/fs/super.c
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  */
  6.  
  7. /*
  8.  * super.c contains code to handle the super-block tables.
  9.  */
  10. #include <stdarg.h>
  11.  
  12. #include <linux/config.h>
  13. #include <linux/sched.h>
  14. #include <linux/kernel.h>
  15. #include <linux/major.h>
  16. #include <linux/stat.h>
  17. #include <linux/errno.h>
  18. #include <linux/string.h>
  19. #include <linux/locks.h>
  20. #include <linux/mm.h>
  21.  
  22. #include <asm/system.h>
  23. #include <asm/segment.h>
  24. #include <asm/bitops.h>
  25.  
  26. extern struct file_operations * get_blkfops(unsigned int);
  27. extern struct file_operations * get_chrfops(unsigned int);
  28.  
  29. extern void wait_for_keypress(void);
  30.  
  31. extern int root_mountflags;
  32.  
  33. struct super_block super_blocks[NR_SUPER];
  34.  
  35. static int do_remount_sb(struct super_block *sb, int flags, char * data);
  36.  
  37. /* this is initialized in init/main.c */
  38. dev_t ROOT_DEV = 0;
  39.  
  40. static struct file_system_type * file_systems = NULL;
  41.  
  42. int register_filesystem(struct file_system_type * fs)
  43. {
  44.     struct file_system_type ** tmp;
  45.  
  46.     if (!fs)
  47.         return -EINVAL;
  48.     if (fs->next)
  49.         return -EBUSY;
  50.     tmp = &file_systems;
  51.     while (*tmp) {
  52.         if (strcmp((*tmp)->name, fs->name) == 0)
  53.             return -EBUSY;
  54.         tmp = &(*tmp)->next;
  55.     }
  56.     *tmp = fs;
  57.     return 0;
  58. }
  59.  
  60. int unregister_filesystem(struct file_system_type * fs)
  61. {
  62.     struct file_system_type ** tmp;
  63.  
  64.     tmp = &file_systems;
  65.     while (*tmp) {
  66.         if (fs == *tmp) {
  67.             *tmp = fs->next;
  68.             fs->next = NULL;
  69.             return 0;
  70.         }
  71.         tmp = &(*tmp)->next;
  72.     }
  73.     return -EINVAL;
  74. }
  75.  
  76. static int fs_index(const char * __name)
  77. {
  78.     struct file_system_type * tmp;
  79.     char * name;
  80.     int err, index;
  81.  
  82.     err = getname(__name, &name);
  83.     if (err)
  84.         return err;
  85.     index = 0;
  86.     for (tmp = file_systems ; tmp ; tmp = tmp->next) {
  87.         if (strcmp(tmp->name, name) == 0) {
  88.             putname(name);
  89.             return index;
  90.         }
  91.         index++;
  92.     }
  93.     putname(name);
  94.     return -EINVAL;
  95. }
  96.  
  97. static int fs_name(unsigned int index, char * buf)
  98. {
  99.     struct file_system_type * tmp;
  100.     int err, len;
  101.  
  102.     tmp = file_systems;
  103.     while (tmp && index > 0) {
  104.         tmp = tmp->next;
  105.         index--;
  106.     }
  107.     if (!tmp)
  108.         return -EINVAL;
  109.     len = strlen(tmp->name) + 1;
  110.     err = verify_area(VERIFY_WRITE, buf, len);
  111.     if (err)
  112.         return err;
  113.     memcpy_tofs(buf, tmp->name, len);
  114.     return 0;
  115. }
  116.  
  117. static int fs_maxindex(void)
  118. {
  119.     struct file_system_type * tmp;
  120.     int index;
  121.  
  122.     index = 0;
  123.     for (tmp = file_systems ; tmp ; tmp = tmp->next)
  124.         index++;
  125.     return index;
  126. }
  127.  
  128. /*
  129.  * Whee.. Weird sysv syscall. 
  130.  */
  131. asmlinkage int sys_sysfs(int option, ...)
  132. {
  133.     va_list args;
  134.     int retval = -EINVAL;
  135.     unsigned int index;
  136.  
  137.     va_start(args, option);
  138.     switch (option) {
  139.         case 1:
  140.             retval = fs_index(va_arg(args, const char *));
  141.             break;
  142.  
  143.         case 2:
  144.             index = va_arg(args, unsigned int);
  145.             retval = fs_name(index, va_arg(args, char *));
  146.             break;
  147.  
  148.         case 3:
  149.             retval = fs_maxindex();
  150.             break;
  151.     }
  152.     va_end(args);
  153.     return retval;
  154. }
  155.  
  156. int get_filesystem_list(char * buf)
  157. {
  158.     int len = 0;
  159.     struct file_system_type * tmp;
  160.  
  161.     tmp = file_systems;
  162.     while (tmp && len < PAGE_SIZE - 80) {
  163.         len += sprintf(buf+len, "%s\t%s\n",
  164.             tmp->requires_dev ? "" : "nodev",
  165.             tmp->name);
  166.         tmp = tmp->next;
  167.     }
  168.     return len;
  169. }
  170.  
  171. struct file_system_type *get_fs_type(char *name)
  172. {
  173.     struct file_system_type * fs = file_systems;
  174.     
  175.     if (!name)
  176.         return fs;
  177.     while (fs) {
  178.         if (!strcmp(name,fs->name))
  179.             break;
  180.         fs = fs->next;
  181.     }
  182.     return fs;
  183. }
  184.  
  185. void __wait_on_super(struct super_block * sb)
  186. {
  187.     struct wait_queue wait = { current, NULL };
  188.  
  189.     add_wait_queue(&sb->s_wait, &wait);
  190. repeat:
  191.     current->state = TASK_UNINTERRUPTIBLE;
  192.     if (sb->s_lock) {
  193.         schedule();
  194.         goto repeat;
  195.     }
  196.     remove_wait_queue(&sb->s_wait, &wait);
  197.     current->state = TASK_RUNNING;
  198. }
  199.  
  200. void sync_supers(dev_t dev)
  201. {
  202.     struct super_block * sb;
  203.  
  204.     for (sb = super_blocks + 0 ; sb < super_blocks + NR_SUPER ; sb++) {
  205.         if (!sb->s_dev)
  206.             continue;
  207.         if (dev && sb->s_dev != dev)
  208.             continue;
  209.         wait_on_super(sb);
  210.         if (!sb->s_dev || !sb->s_dirt)
  211.             continue;
  212.         if (dev && (dev != sb->s_dev))
  213.             continue;
  214.         if (sb->s_op && sb->s_op->write_super)
  215.             sb->s_op->write_super(sb);
  216.     }
  217. }
  218.  
  219. static struct super_block * get_super(dev_t dev)
  220. {
  221.     struct super_block * s;
  222.  
  223.     if (!dev)
  224.         return NULL;
  225.     s = 0+super_blocks;
  226.     while (s < NR_SUPER+super_blocks)
  227.         if (s->s_dev == dev) {
  228.             wait_on_super(s);
  229.             if (s->s_dev == dev)
  230.                 return s;
  231.             s = 0+super_blocks;
  232.         } else
  233.             s++;
  234.     return NULL;
  235. }
  236.  
  237. void put_super(dev_t dev)
  238. {
  239.     struct super_block * sb;
  240.  
  241.     if (dev == ROOT_DEV) {
  242.         printk("VFS: Root device %d/%d: prepare for armageddon\n",
  243.                             MAJOR(dev), MINOR(dev));
  244.         return;
  245.     }
  246.     if (!(sb = get_super(dev)))
  247.         return;
  248.     if (sb->s_covered) {
  249.         printk("VFS: Mounted device %d/%d - tssk, tssk\n",
  250.                         MAJOR(dev), MINOR(dev));
  251.         return;
  252.     }
  253.     if (sb->s_op && sb->s_op->put_super)
  254.         sb->s_op->put_super(sb);
  255. }
  256.  
  257. static struct super_block * read_super(dev_t dev,char *name,int flags,
  258.                        void *data, int silent)
  259. {
  260.     struct super_block * s;
  261.     struct file_system_type *type;
  262.  
  263.     if (!dev)
  264.         return NULL;
  265.     check_disk_change(dev);
  266.     s = get_super(dev);
  267.     if (s)
  268.         return s;
  269.     if (!(type = get_fs_type(name))) {
  270.         printk("VFS: on device %d/%d: get_fs_type(%s) failed\n",
  271.                         MAJOR(dev), MINOR(dev), name);
  272.         return NULL;
  273.     }
  274.     for (s = 0+super_blocks ;; s++) {
  275.         if (s >= NR_SUPER+super_blocks)
  276.             return NULL;
  277.         if (!s->s_dev)
  278.             break;
  279.     }
  280.     s->s_dev = dev;
  281.     s->s_flags = flags;
  282.     if (!type->read_super(s,data, silent)) {
  283.         s->s_dev = 0;
  284.         return NULL;
  285.     }
  286.     s->s_dev = dev;
  287.     s->s_covered = NULL;
  288.     s->s_rd_only = 0;
  289.     s->s_dirt = 0;
  290.     s->s_type = type;
  291.     return s;
  292. }
  293.  
  294. /*
  295.  * Unnamed block devices are dummy devices used by virtual
  296.  * filesystems which don't use real block-devices.  -- jrs
  297.  */
  298.  
  299. static char unnamed_dev_in_use[256/8] = { 0, };
  300.  
  301. static dev_t get_unnamed_dev(void)
  302. {
  303.     int i;
  304.  
  305.     for (i = 1; i < 256; i++) {
  306.         if (!set_bit(i,unnamed_dev_in_use))
  307.             return (UNNAMED_MAJOR << 8) | i;
  308.     }
  309.     return 0;
  310. }
  311.  
  312. static void put_unnamed_dev(dev_t dev)
  313. {
  314.     if (!dev)
  315.         return;
  316.     if (MAJOR(dev) == UNNAMED_MAJOR &&
  317.         clear_bit(MINOR(dev), unnamed_dev_in_use))
  318.         return;
  319.     printk("VFS: put_unnamed_dev: freeing unused device %d/%d\n",
  320.             MAJOR(dev), MINOR(dev));
  321. }
  322.  
  323. static int do_umount(dev_t dev)
  324. {
  325.     struct super_block * sb;
  326.     int retval;
  327.     
  328.     if (dev==ROOT_DEV) {
  329.         /* Special case for "unmounting" root.  We just try to remount
  330.            it readonly, and sync() the device. */
  331.         if (!(sb=get_super(dev)))
  332.             return -ENOENT;
  333.         if (!(sb->s_flags & MS_RDONLY)) {
  334.             fsync_dev(dev);
  335.             retval = do_remount_sb(sb, MS_RDONLY, 0);
  336.             if (retval)
  337.                 return retval;
  338.         }
  339.         return 0;
  340.     }
  341.     if (!(sb=get_super(dev)) || !(sb->s_covered))
  342.         return -ENOENT;
  343.     if (!sb->s_covered->i_mount)
  344.         printk("VFS: umount(%d/%d): mounted inode has i_mount=NULL\n",
  345.                             MAJOR(dev), MINOR(dev));
  346.     if (!fs_may_umount(dev, sb->s_mounted))
  347.         return -EBUSY;
  348.     sb->s_covered->i_mount = NULL;
  349.     iput(sb->s_covered);
  350.     sb->s_covered = NULL;
  351.     iput(sb->s_mounted);
  352.     sb->s_mounted = NULL;
  353.     if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
  354.         sb->s_op->write_super(sb);
  355.     put_super(dev);
  356.     return 0;
  357. }
  358.  
  359. /*
  360.  * Now umount can handle mount points as well as block devices.
  361.  * This is important for filesystems which use unnamed block devices.
  362.  *
  363.  * There is a little kludge here with the dummy_inode.  The current
  364.  * vfs release functions only use the r_dev field in the inode so
  365.  * we give them the info they need without using a real inode.
  366.  * If any other fields are ever needed by any block device release
  367.  * functions, they should be faked here.  -- jrs
  368.  */
  369.  
  370. asmlinkage int sys_umount(char * name)
  371. {
  372.     struct inode * inode;
  373.     dev_t dev;
  374.     int retval;
  375.     struct inode dummy_inode;
  376.     struct file_operations * fops;
  377.  
  378.     if (!suser())
  379.         return -EPERM;
  380.     retval = namei(name,&inode);
  381.     if (retval) {
  382.         retval = lnamei(name,&inode);
  383.         if (retval)
  384.             return retval;
  385.     }
  386.     if (S_ISBLK(inode->i_mode)) {
  387.         dev = inode->i_rdev;
  388.         if (IS_NODEV(inode)) {
  389.             iput(inode);
  390.             return -EACCES;
  391.         }
  392.     } else {
  393.         if (!inode->i_sb || inode != inode->i_sb->s_mounted) {
  394.             iput(inode);
  395.             return -EINVAL;
  396.         }
  397.         dev = inode->i_sb->s_dev;
  398.         iput(inode);
  399.         memset(&dummy_inode, 0, sizeof(dummy_inode));
  400.         dummy_inode.i_rdev = dev;
  401.         inode = &dummy_inode;
  402.     }
  403.     if (MAJOR(dev) >= MAX_BLKDEV) {
  404.         iput(inode);
  405.         return -ENXIO;
  406.     }
  407.     if (!(retval = do_umount(dev)) && dev != ROOT_DEV) {
  408.         fops = get_blkfops(MAJOR(dev));
  409.         if (fops && fops->release)
  410.             fops->release(inode,NULL);
  411.         if (MAJOR(dev) == UNNAMED_MAJOR)
  412.             put_unnamed_dev(dev);
  413.     }
  414.     if (inode != &dummy_inode)
  415.         iput(inode);
  416.     if (retval)
  417.         return retval;
  418.     fsync_dev(dev);
  419.     return 0;
  420. }
  421.  
  422. /*
  423.  * do_mount() does the actual mounting after sys_mount has done the ugly
  424.  * parameter parsing. When enough time has gone by, and everything uses the
  425.  * new mount() parameters, sys_mount() can then be cleaned up.
  426.  *
  427.  * We cannot mount a filesystem if it has active, used, or dirty inodes.
  428.  * We also have to flush all inode-data for this device, as the new mount
  429.  * might need new info.
  430.  */
  431. static int do_mount(dev_t dev, const char * dir, char * type, int flags, void * data)
  432. {
  433.     struct inode * dir_i;
  434.     struct super_block * sb;
  435.     int error;
  436.  
  437.     error = namei(dir,&dir_i);
  438.     if (error)
  439.         return error;
  440.     if (dir_i->i_count != 1 || dir_i->i_mount) {
  441.         iput(dir_i);
  442.         return -EBUSY;
  443.     }
  444.     if (!S_ISDIR(dir_i->i_mode)) {
  445.         iput(dir_i);
  446.         return -ENOTDIR;
  447.     }
  448.     if (!fs_may_mount(dev)) {
  449.         iput(dir_i);
  450.         return -EBUSY;
  451.     }
  452.     sb = read_super(dev,type,flags,data,0);
  453.     if (!sb) {
  454.         iput(dir_i);
  455.         return -EINVAL;
  456.     }
  457.     if (sb->s_covered) {
  458.         iput(dir_i);
  459.         return -EBUSY;
  460.     }
  461.     sb->s_covered = dir_i;
  462.     dir_i->i_mount = sb->s_mounted;
  463.     return 0;        /* we don't iput(dir_i) - see umount */
  464. }
  465.  
  466.  
  467. /*
  468.  * Alters the mount flags of a mounted file system. Only the mount point
  469.  * is used as a reference - file system type and the device are ignored.
  470.  * FS-specific mount options can't be altered by remounting.
  471.  */
  472.  
  473. static int do_remount_sb(struct super_block *sb, int flags, char *data)
  474. {
  475.     int retval;
  476.     
  477.     if (!(flags & MS_RDONLY ) && sb->s_dev && is_read_only(sb->s_dev))
  478.         return -EACCES;
  479.         /*flags |= MS_RDONLY;*/
  480.     /* If we are remounting RDONLY, make sure there are no rw files open */
  481.     if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))
  482.         if (!fs_may_remount_ro(sb->s_dev))
  483.             return -EBUSY;
  484.     if (sb->s_op && sb->s_op->remount_fs) {
  485.         retval = sb->s_op->remount_fs(sb, &flags, data);
  486.         if (retval)
  487.             return retval;
  488.     }
  489.     sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) |
  490.         (flags & MS_RMT_MASK);
  491.     return 0;
  492. }
  493.  
  494. static int do_remount(const char *dir,int flags,char *data)
  495. {
  496.     struct inode *dir_i;
  497.     int retval;
  498.  
  499.     retval = namei(dir,&dir_i);
  500.     if (retval)
  501.         return retval;
  502.     if (dir_i != dir_i->i_sb->s_mounted) {
  503.         iput(dir_i);
  504.         return -EINVAL;
  505.     }
  506.     retval = do_remount_sb(dir_i->i_sb, flags, data);
  507.     iput(dir_i);
  508.     return retval;
  509. }
  510.  
  511. static int copy_mount_options (const void * data, unsigned long *where)
  512. {
  513.     int i;
  514.     unsigned long page;
  515.     struct vm_area_struct * vma;
  516.  
  517.     *where = 0;
  518.     if (!data)
  519.         return 0;
  520.  
  521.     vma = find_vma(current, (unsigned long) data);
  522.     if (!vma || (unsigned long) data < vma->vm_start)
  523.         return -EFAULT;
  524.     i = vma->vm_end - (unsigned long) data;
  525.     if (PAGE_SIZE <= (unsigned long) i)
  526.         i = PAGE_SIZE-1;
  527.     if (!(page = __get_free_page(GFP_KERNEL))) {
  528.         return -ENOMEM;
  529.     }
  530.     memcpy_fromfs((void *) page,data,i);
  531.     *where = page;
  532.     return 0;
  533. }
  534.  
  535. /*
  536.  * Flags is a 16-bit value that allows up to 16 non-fs dependent flags to
  537.  * be given to the mount() call (ie: read-only, no-dev, no-suid etc).
  538.  *
  539.  * data is a (void *) that can point to any structure up to
  540.  * PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent
  541.  * information (or be NULL).
  542.  *
  543.  * NOTE! As old versions of mount() didn't use this setup, the flags
  544.  * has to have a special 16-bit magic number in the hight word:
  545.  * 0xC0ED. If this magic word isn't present, the flags and data info
  546.  * isn't used, as the syscall assumes we are talking to an older
  547.  * version that didn't understand them.
  548.  */
  549. asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
  550.     unsigned long new_flags, void * data)
  551. {
  552.     struct file_system_type * fstype;
  553.     struct inode * inode;
  554.     struct file_operations * fops;
  555.     dev_t dev;
  556.     int retval;
  557.     char * t;
  558.     unsigned long flags = 0;
  559.     unsigned long page = 0;
  560.  
  561.     if (!suser())
  562.         return -EPERM;
  563.     if ((new_flags &
  564.          (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) {
  565.         retval = copy_mount_options (data, &page);
  566.         if (retval < 0)
  567.             return retval;
  568.         retval = do_remount(dir_name,
  569.                     new_flags & ~MS_MGC_MSK & ~MS_REMOUNT,
  570.                     (char *) page);
  571.         free_page(page);
  572.         return retval;
  573.     }
  574.     retval = copy_mount_options (type, &page);
  575.     if (retval < 0)
  576.         return retval;
  577.     fstype = get_fs_type((char *) page);
  578.     free_page(page);
  579.     if (!fstype)        
  580.         return -ENODEV;
  581.     t = fstype->name;
  582.     fops = NULL;
  583.     if (fstype->requires_dev) {
  584.         retval = namei(dev_name,&inode);
  585.         if (retval)
  586.             return retval;
  587.         if (!S_ISBLK(inode->i_mode)) {
  588.             iput(inode);
  589.             return -ENOTBLK;
  590.         }
  591.         if (IS_NODEV(inode)) {
  592.             iput(inode);
  593.             return -EACCES;
  594.         }
  595.         dev = inode->i_rdev;
  596.         if (MAJOR(dev) >= MAX_BLKDEV) {
  597.             iput(inode);
  598.             return -ENXIO;
  599.         }
  600.         fops = get_blkfops(MAJOR(dev));
  601.         if (!fops) {
  602.             iput(inode);
  603.             return -ENOTBLK;
  604.         }
  605.         if (fops->open) {
  606.             struct file dummy;    /* allows read-write or read-only flag */
  607.             memset(&dummy, 0, sizeof(dummy));
  608.             dummy.f_inode = inode;
  609.             dummy.f_mode = (new_flags & MS_RDONLY) ? 1 : 3;
  610.             retval = fops->open(inode, &dummy);
  611.             if (retval) {
  612.                 iput(inode);
  613.                 return retval;
  614.             }
  615.         }
  616.  
  617.     } else {
  618.         if (!(dev = get_unnamed_dev()))
  619.             return -EMFILE;
  620.         inode = NULL;
  621.     }
  622.     page = 0;
  623.     if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) {
  624.         flags = new_flags & ~MS_MGC_MSK;
  625.         retval = copy_mount_options(data, &page);
  626.         if (retval < 0) {
  627.             iput(inode);
  628.             return retval;
  629.         }
  630.     }
  631.     retval = do_mount(dev,dir_name,t,flags,(void *) page);
  632.     free_page(page);
  633.     if (retval && fops && fops->release)
  634.         fops->release(inode, NULL);
  635.     iput(inode);
  636.     return retval;
  637. }
  638.  
  639. void mount_root(void)
  640. {
  641.     struct file_system_type * fs_type;
  642.     struct super_block * sb;
  643.     struct inode * inode, d_inode;
  644.     struct file filp;
  645.     int retval;
  646.  
  647.     memset(super_blocks, 0, sizeof(super_blocks));
  648. #ifdef CONFIG_BLK_DEV_FD
  649.     if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
  650.         printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");
  651.         wait_for_keypress();
  652.     }
  653. #endif
  654.  
  655.     memset(&filp, 0, sizeof(filp));
  656.     memset(&d_inode, 0, sizeof(d_inode));
  657.     d_inode.i_rdev = ROOT_DEV;
  658.     filp.f_inode = &d_inode;
  659.     if ( root_mountflags & MS_RDONLY)
  660.         filp.f_mode = 1; /* read only */
  661.     else
  662.         filp.f_mode = 3; /* read write */
  663.     retval = blkdev_open(&d_inode, &filp);
  664.     if(retval == -EROFS){
  665.         root_mountflags |= MS_RDONLY;
  666.         filp.f_mode = 1;
  667.         retval = blkdev_open(&d_inode, &filp);
  668.     }
  669.  
  670.     for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
  671.         if(retval)
  672.             break;
  673.         if (!fs_type->requires_dev)
  674.             continue;
  675.         sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1);
  676.         if (sb) {
  677.             inode = sb->s_mounted;
  678.             inode->i_count += 3 ;    /* NOTE! it is logically used 4 times, not 1 */
  679.             sb->s_covered = inode;
  680.             sb->s_flags = root_mountflags;
  681.             current->fs->pwd = inode;
  682.             current->fs->root = inode;
  683.             printk ("VFS: Mounted root (%s filesystem)%s.\n",
  684.                 fs_type->name,
  685.                 (sb->s_flags & MS_RDONLY) ? " readonly" : "");
  686.             return;
  687.         }
  688.     }
  689.     panic("VFS: Unable to mount root fs on %02x:%02x",
  690.         MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
  691. }
  692.