学习啦 > 学习电脑 > 操作系统 > Linux教程 > linux安装文件系统

linux安装文件系统

时间: 春健736 分享

linux安装文件系统

  Linux文件系统中的文件是数据的集合,文件系统不仅包含着文件中的数据而且还有文件系统的结构,所有Linux 用户和程序看到的文件、目录、软连接及文件保护信息等都存储在其中。下面大家与学习啦小编一起来学习一下吧。

  安装linux文件系统

  安装根文件系统式系统初始化的关键部分。Linux内核允许根文件系统放在很多不同的地方,比如硬盘分区、软盘、通过NFS共享的远程文件系统以及保存在ramdisk中。内核要在变量ROOT_DEV中寻找包含根文件系统的磁盘主设备号。当编译内核时,或者像最初的启动装入程序传递一个合适的“root”选项时,根文件系统可以被指定为/dev目录下的一个设备文件。

  安装根文件系统分为两个阶段:

学习啦在线学习网   1,内核安装特殊rootfs文件系统,该文件系统仅提供一个作为初始安装点的空目录

  start_kernel()->vfs_caches_init()->mnt_init()->init_rootfs()

  [cpp] view plain copy print?

学习啦在线学习网   /*初始化根文件系统*/

  int __init init_rootfs(void)

  {

  int err;

学习啦在线学习网   /*初始化ramfs_backing_dev_info*/

学习啦在线学习网   err = bdi_init(&ramfs_backing_dev_info);

  if (err)

  return err;

学习啦在线学习网   /*注册rootfs_fs_type文件类型*/

  err = register_filesystem(&rootfs_fs_type);

  if (err)/*如果出错,销毁上面初始化的*/

  bdi_destroy(&ramfs_backing_dev_info);

  return err;

  }

  [cpp] view plain copy print?

学习啦在线学习网   static struct backing_dev_info ramfs_backing_dev_info = {

学习啦在线学习网   .name = "ramfs",

学习啦在线学习网   .ra_pages = 0, /* No readahead */

  .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK |

学习啦在线学习网   BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY |

学习啦在线学习网   BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP,

  };

学习啦在线学习网   [cpp] view plain copy print?

  /**

  * register_filesystem - register a new filesystem

学习啦在线学习网   * @fs: the file system structure

  *

学习啦在线学习网   * Adds the file system passed to the list of file systems the kernel

学习啦在线学习网   * is aware of for mount and other syscalls. Returns 0 on success,

  * or a negative errno code on an error.

  *

  * The &struct file_system_type that is passed is linked into the kernel

  * structures and must not be freed until the file system has been

学习啦在线学习网   * unregistered.

  */

  /*注册一个新的文件系统*/

  int register_filesystem(struct file_system_type * fs)

  {

  int res = 0;

学习啦在线学习网   struct file_system_type ** p;

  BUG_ON(strchr(fs->name, '.'));

  if (fs->next)

学习啦在线学习网   return -EBUSY;

  INIT_LIST_HEAD(&fs->fs_supers);

  write_lock(&file_systems_lock);

学习啦在线学习网   /*从system_type链表中查找指定名称的file_system_type*/

  p = find_filesystem(fs->name, strlen(fs->name));

  if (*p)

学习啦在线学习网   res = -EBUSY;

  else

  *p = fs;

学习啦在线学习网   write_unlock(&file_systems_lock);

学习啦在线学习网   return res;

  }

学习啦在线学习网   根文件系统定义如下

  [cpp] view plain copy print?

  static struct file_system_type rootfs_fs_type = {

学习啦在线学习网   .name = "rootfs",

  .get_sb = rootfs_get_sb,

学习啦在线学习网   .kill_sb = kill_litter_super,

  };

学习啦在线学习网   下面看看他的两个函数

  [cpp] view plain copy print?

  /*获得根目录的sb*/

  static int rootfs_get_sb(struct file_system_type *fs_type,

学习啦在线学习网   int flags, const char *dev_name, void *data, struct vfsmount *mnt)

  {

学习啦在线学习网   return get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super,

  mnt);

  }

  [cpp] view plain copy print?

学习啦在线学习网   int get_sb_nodev(struct file_system_type *fs_type,

学习啦在线学习网   int flags, void *data,

  int (*fill_super)(struct super_block *, void *, int),

  struct vfsmount *mnt)

  {

  int error;

学习啦在线学习网   /*获得sb结构*/

  struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);

  if (IS_ERR(s))

  return PTR_ERR(s);

学习啦在线学习网   s->s_flags = flags;

  /*这里实际调用ramfs_fill_super,对sb结构的属性进行设置*/

学习啦在线学习网   error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);

学习啦在线学习网   if (error) {

  deactivate_locked_super(s);

  return error;

  }

  s->s_flags |= MS_ACTIVE;

学习啦在线学习网   simple_set_mnt(mnt, s);/*设置mnt和sb关联*/

学习啦在线学习网   return 0;

  }

  [cpp] view plain copy print?

  /**

  * sget - find or create a superblock

学习啦在线学习网   * @type: filesystem type superblock should belong to

  * @test: comparison callback

  * @set: setup callback

学习啦在线学习网   * @data: argument to each of them

  */

学习啦在线学习网   /*查找或创建一个sb结构*/

  struct super_block *sget(struct file_system_type *type,

学习啦在线学习网   int (*test)(struct super_block *,void *),

学习啦在线学习网   int (*set)(struct super_block *,void *),

  void *data)

  {

  struct super_block *s = NULL;

  struct super_block *old;

  int err;

  retry:

  spin_lock(&sb_lock);

学习啦在线学习网   if (test) {

学习啦在线学习网   list_for_each_entry(old, &type->fs_supers, s_instances) {

学习啦在线学习网   if (!test(old, data))

  continue;

学习啦在线学习网   if (!grab_super(old))

学习啦在线学习网   goto retry;

学习啦在线学习网   if (s) {

学习啦在线学习网   up_write(&s->s_umount);

学习啦在线学习网   destroy_super(s);

  }

  return old;

  }

  }

学习啦在线学习网   if (!s) {/*如果找不到sb,从内存中申请一个*/

学习啦在线学习网   spin_unlock(&sb_lock);

学习啦在线学习网   s = alloc_super(type);

  if (!s)

  return ERR_PTR(-ENOMEM);

学习啦在线学习网   goto retry;

  }

  err = set(s, data);

学习啦在线学习网   if (err) {

  spin_unlock(&sb_lock);

  up_write(&s->s_umount);

学习啦在线学习网   destroy_super(s);

  return ERR_PTR(err);

  }

  /*初始化得到的sb结构*/

  s->s_type = type;

  strlcpy(s->s_id, type->name, sizeof(s->s_id));

学习啦在线学习网   /*加入链表尾*/

  list_add_tail(&s->s_list, &super_blocks);

学习啦在线学习网   list_add(&s->s_instances, &type->fs_supers);

学习啦在线学习网   spin_unlock(&sb_lock);

  get_filesystem(type);

学习啦在线学习网   return s;

  }

学习啦在线学习网   [cpp] view plain copy print?

  /*所有超级块对象都以双向循环链表的形式链接在一起,量表中第一个

  元素用super_blocks变量表示,而超级块对象的s_list字段存放指向链表

  相邻元素的指针*/

  LIST_HEAD(super_blocks);

  [cpp] view plain copy print?

  /**

学习啦在线学习网   * alloc_super - create new superblock

  * @type: filesystem type superblock should belong to

  *

学习啦在线学习网   * Allocates and initializes a new &struct super_block. alloc_super()

  * returns a pointer new superblock or %NULL if allocation had failed.

  */

  static struct super_block *alloc_super(struct file_system_type *type)

  {

学习啦在线学习网   /*从内存中申请sb*/

  struct super_block *s = kzalloc(sizeof(struct super_block), GFP_USER);

学习啦在线学习网   static const struct super_operations default_op;

学习啦在线学习网   if (s) {

  if (security_sb_alloc(s)) {

学习啦在线学习网   kfree(s);

  s = NULL;

  goto out;

  }

  /*初始化*/

学习啦在线学习网   INIT_LIST_HEAD(&s->s_files);

  INIT_LIST_HEAD(&s->s_instances);

学习啦在线学习网   INIT_HLIST_HEAD(&s->s_anon);

  INIT_LIST_HEAD(&s->s_inodes);

  INIT_LIST_HEAD(&s->s_dentry_lru);

  init_rwsem(&s->s_umount);

  mutex_init(&s->s_lock);

  lockdep_set_class(&s->s_umount, &type->s_umount_key);

  /*

  * The locking rules for s_lock are up to the

  * filesystem. For example ext3fs has different

  * lock ordering than usbfs:

  */

学习啦在线学习网   lockdep_set_class(&s->s_lock, &type->s_lock_key);

  /*

学习啦在线学习网   * sget() can have s_umount recursion.

  *

  * When it cannot find a suitable sb, it allocates a new

学习啦在线学习网   * one (this one), and tries again to find a suitable old

  * one.

  *

  * In case that succeeds, it will acquire the s_umount

  * lock of the old one. Since these are clearly distrinct

学习啦在线学习网   * locks, and this object isn't exposed yet, there's no

  * risk of deadlocks.

  *

  * Annotate this by putting this lock in a different

  * subclass.

  */

  down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING);

  s->s_count = S_BIAS;

学习啦在线学习网   atomic_set(&s->s_active, 1);

  mutex_init(&s->s_vfs_rename_mutex);

  mutex_init(&s->s_dquot.dqio_mutex);

  mutex_init(&s->s_dquot.dqonoff_mutex);

  init_rwsem(&s->s_dquot.dqptr_sem);

学习啦在线学习网   init_waitqueue_head(&s->s_wait_unfrozen);

学习啦在线学习网   s->s_maxbytes = MAX_NON_LFS;

  s->dq_op = sb_dquot_ops;

学习啦在线学习网   s->s_qcop = sb_quotactl_ops;

  s->s_op = &default_op;

学习啦在线学习网   s->s_time_gran = 1000000000;

  }

  out:

  return s;

  }

  kill_litter_super的过程相反,这里不再写了。

  构造根目录是由init_mount_tree()函数实现的,该函数在前面已经介绍过了。

  2,安装实际根文件系统

  关于__setup宏

  __setup宏来注册关键字及相关联的处理函数,__setup宏在include/linux/init.h中定义,其原型如下:

学习啦在线学习网   __setup(string, _handler);

  其中:string是关键字,_handler是关联处理函数。__setup只是告诉内核在启动时输入串中含有string时,内核要去

  执行_handler。String必须以“=”符结束以使parse_args更方便解析。紧随“=”后的任何文本都会作为输入传给

学习啦在线学习网   _handler。下面的例子来自于init/do_mounts.c,其中root_dev_setup作为处理程序被注册给“root=”关键字:

  __setup("root=", root_dev_setup);

  比如我们在启动向参数终有

学习啦在线学习网   noinitrd root=/dev/mtdblock2 console=/linuxrc

  setup_arch解释时会发现root=/dev/mtdblock2,然后它就会调用root_dev_setup

  [cpp] view plain copy print?

  static int __init root_dev_setup(char *line)

  {

  strlcpy(saved_root_name, line, sizeof(saved_root_name));

  return 1;

  }

  __setup("root=", root_dev_setup);

  Start_kernel->rest_init->init-> prepare_namespace->

学习啦在线学习网   [cpp] view plain copy print?

  /*

  * Prepare the namespace - decide what/where to mount, load ramdisks, etc.

  */

  void __init prepare_namespace(void)

  {

  int is_floppy;

学习啦在线学习网   if (root_delay) {

  printk(KERN_INFO "Waiting %dsec before mounting root device...\n",

学习啦在线学习网   root_delay);

  ssleep(root_delay);

  }

  /*

  * wait for the known devices to complete their probing

  *

  * Note: this is a potential source of long boot delays.

学习啦在线学习网   * For example, it is not atypical to wait 5 seconds here

学习啦在线学习网   * for the touchpad of a laptop to initialize.

  */

  wait_for_device_probe();

学习啦在线学习网   /*创建/dev/ram0,必须得,因为initrd要放到/dev/ram0里*/

学习啦在线学习网   md_run_setup();

  if (saved_root_name[0]) {/*saved_root_name为从启动参数"root"中获取的设备文件名*/

  root_device_name = saved_root_name;

学习啦在线学习网   if (!strncmp(root_device_name, "mtd", 3) ||

  !strncmp(root_device_name, "ubi", 3)) {/*如果设备名开头为这两个*/

  mount_block_root(root_device_name, root_mountflags);

学习啦在线学习网   goto out;

  }

  /*主设备号和次设备号*/

学习啦在线学习网   ROOT_DEV = name_to_dev_t(root_device_name);

学习啦在线学习网   if (strncmp(root_device_name, "/dev/", 5) == 0)

  root_device_name += 5;/*滤掉'/dev/'字符*/

  }

  if (initrd_load())

学习啦在线学习网   goto out;

  /* wait for any asynchronous scanning to complete */

学习啦在线学习网   if ((ROOT_DEV == 0) && root_wait) {

学习啦在线学习网   printk(KERN_INFO "Waiting for root device %s...\n",

  saved_root_name);

  while (driver_probe_done() != 0 ||

  (ROOT_DEV = name_to_dev_t(saved_root_name)) == 0)

  msleep(100);

学习啦在线学习网   async_synchronize_full();

  }

  is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;

  if (is_floppy && rd_doload && rd_load_disk(0))

  ROOT_DEV = Root_RAM0;

  /*实际操作*/

  mount_root();

  out:

  devtmpfs_mount("dev");/*devfs从虚拟的根文件系统的/dev umount*/

  sys_mount(".", "/", NULL, MS_MOVE, NULL);/*将挂载点从当前目录【/root】(在mount_root函数中设置的)移到根目录*/

学习啦在线学习网   /*当前目录即【/root】(真正文件系统挂载的目录)做为系统根目录*/

  sys_chroot(".");

  }

学习啦在线学习网   mount_root操作

学习啦在线学习网   [cpp] view plain copy print?

学习啦在线学习网   void __init mount_root(void)

  {

学习啦在线学习网   #ifdef CONFIG_ROOT_NFS

  if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {

学习啦在线学习网   if (mount_nfs_root())

  return;

学习啦在线学习网   printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");

学习啦在线学习网   ROOT_DEV = Root_FD0;

  }

  #endif

  #ifdef CONFIG_BLK_DEV_FD

  if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {

  /* rd_doload is 2 for a dual initrd/ramload setup */

学习啦在线学习网   if (rd_doload==2) {

  if (rd_load_disk(1)) {

  ROOT_DEV = Root_RAM1;

学习啦在线学习网   root_device_name = NULL;

  }

  } else

学习啦在线学习网   change_floppy("root floppy");

  }

  #endif

  #ifdef CONFIG_BLOCK/*这里是一般流程*/

  create_dev("/dev/root", ROOT_DEV);/*用系统调用创建"/dev/root"*/

  mount_block_root("/dev/root", root_mountflags);

  #endif

  }

学习啦在线学习网   [cpp] view plain copy print?

  void __init mount_block_root(char *name, int flags)

  {

学习啦在线学习网   /*从cache中分配空间*/

  char *fs_names = __getname_gfp(GFP_KERNEL

学习啦在线学习网   | __GFP_NOTRACK_FALSE_POSITIVE);

  char *p;

学习啦在线学习网   #ifdef CONFIG_BLOCK

  char b[BDEVNAME_SIZE];

  #else

  const char *b = name;

  #endif

  /*获得文件系统类型,如果在bootoption里有,

学习啦在线学习网   则就为这个文件系统类型,如果没有指定,

学习啦在线学习网   则返回ilesytem链上所有类型,下面再对每个进行尝试.*/

  get_fs_names(fs_names);

  retry:

  for (p = fs_names; *p; p += strlen(p)+1) {

学习啦在线学习网   /*实际的安装工作,这里调用了mount系统调用

学习啦在线学习网   将文件系统挂到/root目录,p为文件系统类型,由get_fs_names得到

  */

  int err = do_mount_root(name, p, flags, root_mount_data);

  switch (err) {

  case 0:

  goto out;

学习啦在线学习网   case -EACCES:

  flags |= MS_RDONLY;

学习啦在线学习网   goto retry;

学习啦在线学习网   case -EINVAL:

  continue;

  }

  /*

  * Allow the user to distinguish between failed sys_open

  * and bad superblock on root device.

  * and give them a list of the available devices

  */

学习啦在线学习网   #ifdef CONFIG_BLOCK

学习啦在线学习网   __bdevname(ROOT_DEV, b);

  #endif

  printk("VFS: Cannot open root device \"%s\" or %s\n",

学习啦在线学习网   root_device_name, b);

学习啦在线学习网   printk("Please append a correct \"root=\" boot option; here are the available partitions:\n");

学习啦在线学习网   printk_all_partitions();

学习啦在线学习网   #ifdef CONFIG_DEBUG_BLOCK_EXT_DEVT

  printk("DEBUG_BLOCK_EXT_DEVT is enabled, you need to specify "

  "explicit textual name for \"root=\" boot option.\n");

  #endif

  panic("VFS: Unable to mount root fs on %s", b);

  }

学习啦在线学习网   printk("List of all partitions:\n");

学习啦在线学习网   printk_all_partitions();

学习啦在线学习网   printk("No filesystem could mount root, tried: ");

学习啦在线学习网   for (p = fs_names; *p; p += strlen(p)+1)

学习啦在线学习网   printk(" %s", p);

  printk("\n");

  #ifdef CONFIG_BLOCK

  __bdevname(ROOT_DEV, b);

  #endif

  panic("VFS: Unable to mount root fs on %s", b);

  out:

学习啦在线学习网   putname(fs_names);

  }

  [cpp] view plain copy print?

  static int __init do_mount_root(char *name, char *fs, int flags, void *data)

  {

学习啦在线学习网   /*mount系统调用来做实际的安装文件系统工作*/

学习啦在线学习网   int err = sys_mount(name, "/root", fs, flags, data);

  if (err)

  return err;

学习啦在线学习网   /*改变当前路径到根目录*/

  sys_chdir("/root");

学习啦在线学习网   ROOT_DEV = current->fs->pwd.mnt->mnt_sb->s_dev;

  printk("VFS: Mounted root (%s filesystem)%s on device %u:%u.\n",

学习啦在线学习网   current->fs->pwd.mnt->mnt_sb->s_type->name,

学习啦在线学习网   current->fs->pwd.mnt->mnt_sb->s_flags & MS_RDONLY ?

学习啦在线学习网   " readonly" : "", MAJOR(ROOT_DEV), MINOR(ROOT_DEV));

学习啦在线学习网   return 0;

  }

学习啦在线学习网   到此,根文件系统的安装过程算是完成了,中间关于mount等系统调用将在后面分析。可以看出总的步骤主要有:

  1,创建一个rootfs,这个是虚拟的rootfs,是内存文件系统(和ramfs),后面还会指向具体的根文件系统;

  2,从系统启动参数中获取设备文件名以及设备号;

  3,调用系统调用创建符号链接,并调用mount系统调用进程实际的安装操作;

学习啦在线学习网   4,改变进程当前目录;

学习啦在线学习网   5,移动rootfs文件系统根目录上得已经安装文件系统的安装点;

  rootfs特殊文件系统没有被卸载,他只是隐藏在基于磁盘的根文件系统下了。

655506