爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      linux文件系统解读

      首页 知识中心 服务器 文章详情页

      linux文件系统解读

      2023-06-20 09:18:34 阅读次数:113

      kernel,linux

      解读linux的文件系统, 内核版本为 linux-2.1.129

      文件系统核心抽象概念:

      一. super_block

      名字的由来是磁盘特定扇区中的超级块, 该对象记录文件系统本身的特性.

      例如用ext4格式化磁盘后, 磁盘的超级块里就保持ext4文件系统的信息. 

      struct super_block {
      struct list_head s_list; /* Keep this first */
      kdev_t s_dev;
      unsigned long s_blocksize;
      unsigned char s_blocksize_bits;
      unsigned char s_lock;
      unsigned char s_rd_only;
      unsigned char s_dirt;
      struct file_system_type *s_type;
      struct super_operations *s_op;
      struct dquot_operations *dq_op;
      unsigned long s_flags;
      unsigned long s_magic;
      unsigned long s_time;
      struct dentry *s_root;
      struct wait_queue *s_wait;

      struct inode *s_ibasket;
      short int s_ibasket_count;
      short int s_ibasket_max;
      struct list_head s_dirty; /* dirty inodes */

      union {
      struct minix_sb_info minix_sb;
      struct ext2_sb_info ext2_sb;
      struct hpfs_sb_info hpfs_sb;
      struct ntfs_sb_info ntfs_sb;
      struct msdos_sb_info msdos_sb;
      struct isofs_sb_info isofs_sb;
      struct nfs_sb_info nfs_sb;
      struct sysv_sb_info sysv_sb;
      struct affs_sb_info affs_sb;
      struct ufs_sb_info ufs_sb;
      struct romfs_sb_info romfs_sb;
      struct smb_sb_info smbfs_sb;
      struct hfs_sb_info hfs_sb;
      struct adfs_sb_info adfs_sb;
      struct qnx4_sb_info qnx4_sb;
      void *generic_sbp;
      } u;
      };
      struct super_operations {
      void (*read_inode) (struct inode *);
      void (*write_inode) (struct inode *);
      void (*put_inode) (struct inode *);
      void (*delete_inode) (struct inode *);
      int (*notify_change) (struct dentry *, struct iattr *);
      void (*put_super) (struct super_block *);
      void (*write_super) (struct super_block *);
      int (*statfs) (struct super_block *, struct statfs *, int);
      int (*remount_fs) (struct super_block *, int *, char *);
      void (*clear_inode) (struct inode *);
      void (*umount_begin) (struct super_block *);
      };
      struct file_system_type {
      const char *name;
      int fs_flags;
      struct super_block *(*read_super) (struct super_block *, void *, int);
      struct file_system_type * next;
      };

      二. inode

      记录文件的元信息, 该对象需要保持在磁盘上持久化.

      struct inode {
      struct list_head i_hash;
      struct list_head i_list;
      struct list_head i_dentry;

      unsigned long i_ino;
      unsigned int i_count;
      kdev_t i_dev;
      umode_t i_mode;
      nlink_t i_nlink;
      uid_t i_uid;
      gid_t i_gid;
      kdev_t i_rdev;
      off_t i_size;
      time_t i_atime;
      time_t i_mtime;
      time_t i_ctime;
      unsigned long i_blksize;
      unsigned long i_blocks;
      unsigned long i_version;
      unsigned long i_nrpages;
      struct semaphore i_sem;
      struct semaphore i_atomic_write;
      struct inode_operations *i_op;
      struct super_block *i_sb;
      struct wait_queue *i_wait;
      struct file_lock *i_flock;
      struct vm_area_struct *i_mmap;
      struct page *i_pages;
      struct dquot *i_dquot[MAXQUOTAS];

      unsigned long i_state;

      unsigned int i_flags;
      unsigned char i_pipe;
      unsigned char i_sock;

      int i_writecount;
      unsigned int i_attr_flags;
      union {
      struct pipe_inode_info pipe_i;
      struct minix_inode_info minix_i;
      struct ext2_inode_info ext2_i;
      struct hpfs_inode_info hpfs_i;
      struct ntfs_inode_info ntfs_i;
      struct msdos_inode_info msdos_i;
      struct umsdos_inode_info umsdos_i;
      struct iso_inode_info isofs_i;
      struct nfs_inode_info nfs_i;
      struct sysv_inode_info sysv_i;
      struct affs_inode_info affs_i;
      struct ufs_inode_info ufs_i;
      struct romfs_inode_info romfs_i;
      struct coda_inode_info coda_i;
      struct smb_inode_info smbfs_i;
      struct hfs_inode_info hfs_i;
      struct adfs_inode_info adfs_i;
      struct qnx4_inode_info qnx4_i;
      struct socket socket_i;
      void *generic_ip;
      } u;
      };
      struct inode_operations {
      struct file_operations * default_file_ops;
      int (*create) (struct inode *,struct dentry *,int);
      int (*lookup) (struct inode *,struct dentry *);
      int (*link) (struct dentry *,struct inode *,struct dentry *);
      int (*unlink) (struct inode *,struct dentry *);
      int (*symlink) (struct inode *,struct dentry *,const char *);
      int (*mkdir) (struct inode *,struct dentry *,int);
      int (*rmdir) (struct inode *,struct dentry *);
      int (*mknod) (struct inode *,struct dentry *,int,int);
      int (*rename) (struct inode *, struct dentry *,
      struct inode *, struct dentry *);
      int (*readlink) (struct dentry *, char *,int);
      struct dentry * (*follow_link) (struct dentry *, struct dentry *, unsigned int);
      int (*readpage) (struct file *, struct page *);
      int (*writepage) (struct file *, struct page *);
      int (*bmap) (struct inode *,int);
      void (*truncate) (struct inode *);
      int (*permission) (struct inode *, int);
      int (*smap) (struct inode *,int);
      int (*updatepage) (struct file *, struct page *, unsigned long, unsigned int, int);
      int (*revalidate) (struct dentry *);
      };

      三. dentry

      目录项, 记录文件名和inode节点间的关系. 查询目录时候使用dentry, 并且使用了缓存加快查找速度

      struct dentry {
      int d_count;
      unsigned int d_flags;
      struct inode * d_inode; /* Where the name belongs to - NULL is negative */
      struct dentry * d_parent; /* parent directory */
      struct dentry * d_mounts; /* mount information */
      struct dentry * d_covers;
      struct list_head d_hash; /* lookup hash list */
      struct list_head d_lru; /* d_count = 0 LRU list */
      struct list_head d_child; /* child of parent list */
      struct list_head d_subdirs; /* our children */
      struct list_head d_alias; /* inode alias list */
      struct qstr d_name;
      unsigned long d_time; /* used by d_revalidate */
      struct dentry_operations *d_op;
      struct super_block * d_sb; /* The root of the dentry tree */
      unsigned long d_reftime; /* last time referenced */
      void * d_fsdata; /* fs-specific data */
      unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */
      };
      struct dentry_operations {
      int (*d_revalidate)(struct dentry *);
      int (*d_hash) (struct dentry *, struct qstr *);
      int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);
      void (*d_delete)(struct dentry *);
      void (*d_release)(struct dentry *);
      void (*d_iput)(struct dentry *, struct inode *);
      };

      文件系统的设计思想:

      一. 面向对象

      面向对象的一个直观的解释是将操作和数据组合在一起, 形成一个功能单元.

      用纯c实现的话, 就是将回调函数, 和数据定义, 放在同一个struct里.

      例如dentry:

      struct dentry {
      int d_count;
      unsigned int d_flags;
      struct inode * d_inode; /* Where the name belongs to - NULL is negative */
      struct dentry * d_parent; /* parent directory */
      struct dentry * d_mounts; /* mount information */
      struct dentry * d_covers;
      struct list_head d_hash; /* lookup hash list */
      struct list_head d_lru; /* d_count = 0 LRU list */
      struct list_head d_child; /* child of parent list */
      struct list_head d_subdirs; /* our children */
      struct list_head d_alias; /* inode alias list */
      struct qstr d_name;
      unsigned long d_time; /* used by d_revalidate */
      struct dentry_operations *d_op;
      struct super_block * d_sb; /* The root of the dentry tree */
      unsigned long d_reftime; /* last time referenced */
      void * d_fsdata; /* fs-specific data */
      unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */
      };

      struct dentry_operations {
      int (*d_revalidate)(struct dentry *);
      int (*d_hash) (struct dentry *, struct qstr *);
      int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);
      void (*d_delete)(struct dentry *);
      void (*d_release)(struct dentry *);
      void (*d_iput)(struct dentry *, struct inode *);
      };

      二. VFS

      这点非常值得学习, 在各种文件系统之上, 增加了一层抽象. 类似于k8s中的csi, 也是对各种csi做了一层抽象.

      In this section I'll briefly describe how things work, before
      launching into the details. I'll start with describing what happens
      when user programmes open and manipulate files, and then look from the
      other view which is how a filesystem is supported and subsequently
      mounted.

      注册和挂载文件系统:

      Registering and Mounting a Filesystem                              <subsection>
      -------------------------------------

      If you want to support a new kind of filesystem in the kernel, all you
      need to do is call register_filesystem(). You pass a structure
      describing the filesystem implementation (struct file_system_type)
      which is then added to an internal table of supported filesystems. You
      can do:

      % cat /proc/filesystems

      to see what filesystems are currently available on your system.

      When a request is made to mount a block device onto a directory in
      your filespace the VFS will call the appropriate method for the
      specific filesystem. The dentry for the mount point will then be
      updated to point to the root inode for the new filesystem.

      struct file_system_type <section>
      =======================

      This describes the filesystem. As of kernel 2.1.99, the following
      members are defined:

      struct file_system_type {
      const char *name;
      int fs_flags;
      struct super_block *(*read_super) (struct super_block *, void *, int);
      struct file_system_type * next;
      };

      name: the name of the filesystem type, such as "ext2", "iso9660",
      "msdos" and so on

      fs_flags: various flags (i.e. if it is a read-only FS)

      read_super: the method to call when a new instance of this
      filesystem should be mounted

      next: for internal VFS use: you should initialise this to NULL

      The read_super() method has the following arguments:

      struct super_block *sb: the superblock structure. This is partially
      initialised by the VFS and the rest must be initialised by the
      read_super() method

      void *data: arbitrary mount options, usually comes as an ASCII
      string

      int silent: whether or not to be silent on error

      The read_super() method must determine if the block device specified
      in the superblock contains a filesystem of the type the method
      supports. On success the method returns the superblock pointer, on
      failure it returns NULL.

      The most interesting member of the superblock structure that the
      read_super() method fills in is the "s_op" field. This is a pointer to
      a "struct super_operations" which describes the next level of the
      filesystem implementation.

      核心操作:

      sys_open

      asmlinkage int sys_open(const char * filename, int flags, int mode)
      {
      char * tmp;
      int fd, error;

      lock_kernel();
      fd = get_unused_fd();
      if (fd < 0)
      goto out;

      tmp = getname(filename);
      error = PTR_ERR(tmp);
      if (IS_ERR(tmp))
      goto out_fail;
      error = do_open(tmp, flags, mode, fd);
      putname(tmp);
      if (error)
      goto out_fail;
      out:
      unlock_kernel();
      return fd;

      out_fail:
      put_unused_fd(fd);
      fd = error;
      goto out;
      }
      /* should probably go into sys_open() */
      static int do_open(const char * filename, int flags, int mode, int fd)
      {
      struct file * f;

      f = filp_open(filename, flags, mode);
      if (IS_ERR(f))
      return PTR_ERR(f);
      fd_install(fd, f);
      return 0;
      }
      /*
      * Note that while the flag value (low two bits) for sys_open means:
      * 00 - read-only
      * 01 - write-only
      * 10 - read-write
      * 11 - special
      * it is changed into
      * 00 - no permissions needed
      * 01 - read-permission
      * 10 - write-permission
      * 11 - read-write
      * for the internal routines (ie open_namei()/follow_link() etc). 00 is
      * used by symlinks.
      */
      struct file *filp_open(const char * filename, int flags, int mode)
      {
      struct inode * inode;
      struct dentry * dentry;
      struct file * f;
      int flag,error;

      error = -ENFILE;
      f = get_empty_filp();
      if (!f)
      goto out;
      f->f_flags = flag = flags;
      f->f_mode = (flag+1) & O_ACCMODE;
      if (f->f_mode)
      flag++;
      if (flag & O_TRUNC)
      flag |= 2;
      dentry = open_namei(filename,flag,mode);
      error = PTR_ERR(dentry);
      if (IS_ERR(dentry))
      goto cleanup_file;
      inode = dentry->d_inode;
      if (f->f_mode & FMODE_WRITE) {
      error = get_write_access(inode);
      if (error)
      goto cleanup_dentry;
      }

      f->f_dentry = dentry;
      f->f_pos = 0;
      f->f_reada = 0;
      f->f_op = NULL;
      if (inode->i_op)
      f->f_op = inode->i_op->default_file_ops;
      if (f->f_op && f->f_op->open) {
      error = f->f_op->open(inode,f);
      if (error)
      goto cleanup_all;
      }
      f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);

      return f;

      cleanup_all:
      if (f->f_mode & FMODE_WRITE)
      put_write_access(inode);
      cleanup_dentry:
      f->f_dentry = NULL;
      dput(dentry);
      cleanup_file:
      put_filp(f);
      out:
      return ERR_PTR(error);
      }
      /*
      * open_namei()
      *
      * namei for open - this is in fact almost the whole open-routine.
      *
      * Note that the low bits of "flag" aren't the same as in the open
      * system call - they are 00 - no permissions needed
      * 01 - read permission needed
      * 10 - write permission needed
      * 11 - read/write permissions needed
      * which is a lot more logical, and also allows the "no perm" needed
      * for symlinks (where the permissions are checked later).
      */
      struct dentry * open_namei(const char * pathname, int flag, int mode)
      {
      int acc_mode, error;
      struct inode *inode;
      struct dentry *dentry;

      mode &= S_IALLUGO & ~current->fs->umask;
      mode |= S_IFREG;

      dentry = lookup_dentry(pathname, NULL, lookup_flags(flag));
      if (IS_ERR(dentry))
      return dentry;

      acc_mode = ACC_MODE(flag);
      if (flag & O_CREAT) {
      struct dentry *dir;

      error = -EEXIST;
      if (dentry->d_inode && (flag & O_EXCL))
      goto exit;

      dir = lock_parent(dentry);
      error = PTR_ERR(dir);
      if (IS_ERR(dir))
      goto exit;

      /*
      * Somebody might have created the file while we
      * waited for the directory lock.. So we have to
      * re-do the existence test.
      */
      if (dentry->d_inode) {
      error = 0;
      if (flag & O_EXCL)
      error = -EEXIST;
      } else if (IS_RDONLY(dir->d_inode))
      error = -EROFS;
      else if (!dir->d_inode->i_op || !dir->d_inode->i_op->create)
      error = -EACCES;
      else if ((error = permission(dir->d_inode,MAY_WRITE | MAY_EXEC)) == 0) {
      DQUOT_INIT(dir->d_inode);
      error = dir->d_inode->i_op->create(dir->d_inode, dentry, mode);
      /* Don't check for write permission, don't truncate */
      acc_mode = 0;
      flag &= ~O_TRUNC;
      }
      unlock_dir(dir);
      if (error)
      goto exit;
      }

      error = -ENOENT;
      inode = dentry->d_inode;
      if (!inode)
      goto exit;

      error = -ELOOP;
      if (S_ISLNK(inode->i_mode))
      goto exit;

      error = -EISDIR;
      if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE))
      goto exit;

      error = permission(inode,acc_mode);
      if (error)
      goto exit;

      /*
      * FIFO's, sockets and device files are special: they don't
      * actually live on the filesystem itself, and as such you
      * can write to them even if the filesystem is read-only.
      */
      if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
      flag &= ~O_TRUNC;
      } else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
      error = -EACCES;
      if (IS_NODEV(inode))
      goto exit;

      flag &= ~O_TRUNC;
      } else {
      error = -EROFS;
      if (IS_RDONLY(inode) && (flag & 2))
      goto exit;
      }
      /*
      * An append-only file must be opened in append mode for writing.
      */
      error = -EPERM;
      if (IS_APPEND(inode)) {
      if ((flag & FMODE_WRITE) && !(flag & O_APPEND))
      goto exit;
      if (flag & O_TRUNC)
      goto exit;
      }

      if (flag & O_TRUNC) {
      error = get_write_access(inode);
      if (error)
      goto exit;

      /*
      * Refuse to truncate files with mandatory locks held on them.
      */
      error = locks_verify_locked(inode);
      if (!error) {
      DQUOT_INIT(inode);

      error = do_truncate(dentry, 0);
      }
      put_write_access(inode);
      if (error)
      goto exit;
      } else
      if (flag & FMODE_WRITE)
      DQUOT_INIT(inode);

      return dentry;

      exit:
      dput(dentry);
      return ERR_PTR(error);
      }
      /*
      * Name resolution.
      *
      * This is the basic name resolution function, turning a pathname
      * into the final dentry.
      */
      struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned int lookup_flags)
      {
      struct dentry * dentry;
      struct inode *inode;

      if (*name == '/') {
      if (base)
      dput(base);
      do {
      name++;
      } while (*name == '/');
      __prefix_lookup_dentry(name, lookup_flags);
      base = dget(current->fs->root);
      } else if (!base) {
      base = dget(current->fs->pwd);
      }

      if (!*name)
      goto return_base;

      inode = base->d_inode;
      lookup_flags &= LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_SLASHOK;

      /* At this point we know we have a real path component. */
      for(;;) {
      int err;
      unsigned long hash;
      struct qstr this;
      unsigned int flags;
      unsigned int c;

      err = permission(inode, MAY_EXEC);
      dentry = ERR_PTR(err);
      if (err)
      break;

      this.name = name;
      c = *(const unsigned char *)name;

      hash = init_name_hash();
      do {
      name++;
      hash = partial_name_hash(c, hash);
      c = *(const unsigned char *)name;
      } while (c && (c != '/'));
      this.len = name - (const char *) this.name;
      this.hash = end_name_hash(hash);

      /* remove trailing slashes? */
      flags = lookup_flags;
      if (c) {
      char tmp;

      flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
      do {
      tmp = *++name;
      } while (tmp == '/');
      if (tmp)
      flags |= LOOKUP_CONTINUE;
      }

      /*
      * See if the low-level filesystem might want
      * to use its own hash..
      */
      if (base->d_op && base->d_op->d_hash) {
      int error;
      error = base->d_op->d_hash(base, &this);
      if (error < 0) {
      dentry = ERR_PTR(error);
      break;
      }
      }

      /* This does the actual lookups.. */
      dentry = reserved_lookup(base, &this);
      if (!dentry) {
      dentry = cached_lookup(base, &this);
      if (!dentry) {
      dentry = real_lookup(base, &this);
      if (IS_ERR(dentry))
      break;
      }
      }

      /* Check mountpoints.. */
      dentry = follow_mount(dentry);

      if (!(flags & LOOKUP_FOLLOW))
      break;

      base = do_follow_link(base, dentry, flags);
      if (IS_ERR(base))
      goto return_base;

      inode = base->d_inode;
      if (flags & LOOKUP_DIRECTORY) {
      if (!inode)
      goto no_inode;
      dentry = ERR_PTR(-ENOTDIR);
      if (!inode->i_op || !inode->i_op->lookup)
      break;
      if (flags & LOOKUP_CONTINUE)
      continue;
      }
      return_base:
      return base;
      /*
      * The case of a nonexisting file is special.
      *
      * In the middle of a pathname lookup (ie when
      * LOOKUP_CONTINUE is set), it's an obvious
      * error and returns ENOENT.
      *
      * At the end of a pathname lookup it's legal,
      * and we return a negative dentry. However, we
      * get here only if there were trailing slashes,
      * which is legal only if we know it's supposed
      * to be a directory (ie "mkdir"). Thus the
      * LOOKUP_SLASHOK flag.
      */
      no_inode:
      dentry = ERR_PTR(-ENOENT);
      if (flags & LOOKUP_CONTINUE)
      break;
      if (flags & LOOKUP_SLASHOK)
      goto return_base;
      break;
      }
      dput(base);
      return dentry;
      }
      /*
      * This is called when everything else fails, and we actually have
      * to go to the low-level filesystem to find out what we should do..
      *
      * We get the directory semaphore, and after getting that we also
      * make sure that nobody added the entry to the dcache in the meantime..
      */
      static struct dentry * real_lookup(struct dentry * parent, struct qstr * name)
      {
      struct dentry * result;
      struct inode *dir = parent->d_inode;

      down(&dir->i_sem);
      /*
      * First re-do the cached lookup just in case it was created
      * while we waited for the directory semaphore..
      *
      * FIXME! This could use version numbering or similar to
      * avoid unnecessary cache lookups.
      */
      result = cached_lookup(parent, name);
      if (!result) {
      struct dentry * dentry = d_alloc(parent, name);
      result = ERR_PTR(-ENOMEM);
      if (dentry) {
      int error = dir->i_op->lookup(dir, dentry);
      result = dentry;
      if (error) {
      dput(dentry);
      result = ERR_PTR(error);
      }
      }
      }
      up(&dir->i_sem);
      return result;
      }
      struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)
      {
      char * str;
      struct dentry *dentry;

      /*
      * Prune the dcache if there are too many unused dentries.
      */
      if (dentry_stat.nr_unused > 3*(nr_inodes >> 1)) {
      #ifdef DCACHE_DEBUG
      printk("d_alloc: %d unused, pruning dcache\n", dentry_stat.nr_unused);
      #endif
      prune_dcache(8);
      free_inode_memory(8);
      }

      dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL);
      if (!dentry)
      return NULL;

      if (name->len > DNAME_INLINE_LEN-1) {
      str = kmalloc(NAME_ALLOC_LEN(name->len), GFP_KERNEL);
      if (!str) {
      kmem_cache_free(dentry_cache, dentry);
      return NULL;
      }
      } else
      str = dentry->d_iname;

      memcpy(str, name->name, name->len);
      str[name->len] = 0;

      dentry->d_count = 1;
      dentry->d_flags = 0;
      dentry->d_inode = NULL;
      dentry->d_parent = NULL;
      dentry->d_sb = NULL;
      if (parent) {
      dentry->d_parent = dget(parent);
      dentry->d_sb = parent->d_sb;
      list_add(&dentry->d_child, &parent->d_subdirs);
      } else
      INIT_LIST_HEAD(&dentry->d_child);

      dentry->d_mounts = dentry;
      dentry->d_covers = dentry;
      INIT_LIST_HEAD(&dentry->d_hash);
      INIT_LIST_HEAD(&dentry->d_lru);
      INIT_LIST_HEAD(&dentry->d_subdirs);
      INIT_LIST_HEAD(&dentry->d_alias);

      dentry->d_name.name = str;
      dentry->d_name.len = name->len;
      dentry->d_name.hash = name->hash;
      dentry->d_op = NULL;
      dentry->d_fsdata = NULL;
      return dentry;
      }
      if (dentry) {
      int error = dir->i_op->lookup(dir, dentry);
      result = dentry;
      if (error) {
      dput(dentry);
      result = ERR_PTR(error);
      }
      }

      sys_mount

      /*
      * Flags is a 16-bit value that allows up to 16 non-fs dependent flags to
      * be given to the mount() call (ie: read-only, no-dev, no-suid etc).
      *
      * data is a (void *) that can point to any structure up to
      * PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent
      * information (or be NULL).
      *
      * NOTE! As old versions of mount() didn't use this setup, the flags
      * have to have a special 16-bit magic number in the high word:
      * 0xC0ED. If this magic word isn't present, the flags and data info
      * aren't used, as the syscall assumes we are talking to an older
      * version that didn't understand them.
      */
      asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
      unsigned long new_flags, void * data)
      {
      struct file_system_type * fstype;
      struct dentry * dentry = NULL;
      struct inode * inode = NULL;
      kdev_t dev;
      int retval = -EPERM;
      unsigned long flags = 0;
      unsigned long page = 0;
      struct file dummy; /* allows read-write or read-only flag */

      lock_kernel();
      if (!capable(CAP_SYS_ADMIN))
      goto out;
      if ((new_flags &
      (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) {
      retval = copy_mount_options (data, &page);
      if (retval < 0)
      goto out;
      retval = do_remount(dir_name,
      new_flags & ~MS_MGC_MSK & ~MS_REMOUNT,
      (char *) page);
      free_page(page);
      goto out;
      }

      retval = copy_mount_options (type, &page);
      if (retval < 0)
      goto out;
      fstype = get_fs_type((char *) page);
      free_page(page);
      retval = -ENODEV;
      if (!fstype)
      goto out;

      memset(&dummy, 0, sizeof(dummy));
      if (fstype->fs_flags & FS_REQUIRES_DEV) {
      dentry = namei(dev_name);
      retval = PTR_ERR(dentry);
      if (IS_ERR(dentry))
      goto out;

      inode = dentry->d_inode;
      retval = -ENOTBLK;
      if (!S_ISBLK(inode->i_mode))
      goto dput_and_out;

      retval = -EACCES;
      if (IS_NODEV(inode))
      goto dput_and_out;

      dev = inode->i_rdev;
      retval = -ENXIO;
      if (MAJOR(dev) >= MAX_BLKDEV)
      goto dput_and_out;

      retval = -ENOTBLK;
      dummy.f_op = get_blkfops(MAJOR(dev));
      if (!dummy.f_op)
      goto dput_and_out;

      if (dummy.f_op->open) {
      dummy.f_dentry = dentry;
      dummy.f_mode = (new_flags & MS_RDONLY) ? 1 : 3;
      retval = dummy.f_op->open(inode, &dummy);
      if (retval)
      goto dput_and_out;
      }

      } else {
      retval = -EMFILE;
      if (!(dev = get_unnamed_dev()))
      goto out;
      }

      page = 0;
      if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) {
      flags = new_flags & ~MS_MGC_MSK;
      retval = copy_mount_options(data, &page);
      if (retval < 0)
      goto clean_up;
      }
      retval = do_mount(dev, dev_name, dir_name, fstype->name, flags,
      (void *) page);
      free_page(page);
      if (retval)
      goto clean_up;

      dput_and_out:
      dput(dentry);
      out:
      unlock_kernel();
      return retval;

      clean_up:
      if (dummy.f_op) {
      if (dummy.f_op->release)
      dummy.f_op->release(inode, NULL);
      } else
      put_unnamed_dev(dev);
      goto dput_and_out;
      }
      /*
      * do_mount() does the actual mounting after sys_mount has done the ugly
      * parameter parsing. When enough time has gone by, and everything uses the
      * new mount() parameters, sys_mount() can then be cleaned up.
      *
      * We cannot mount a filesystem if it has active, used, or dirty inodes.
      * We also have to flush all inode-data for this device, as the new mount
      * might need new info.
      *
      * [21-Mar-97] T.Schoebel-Theuer: Now this can be overridden when
      * supplying a leading "!" before the dir_name, allowing "stacks" of
      * mounted filesystems. The stacking will only influence any pathname lookups
      * _after_ the mount, but open file descriptors or working directories that
      * are now covered remain valid. For example, when you overmount /home, any
      * process with old cwd /home/joe will continue to use the old versions,
      * as long as relative paths are used, but absolute paths like /home/joe/xxx
      * will go to the new "top of stack" version. In general, crossing a
      * mount point will always go to the top of stack element.
      * Anyone using this new feature must know what he/she is doing.
      */

      int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const char * type, int flags, void * data)
      {
      struct dentry * dir_d;
      struct super_block * sb;
      struct vfsmount *vfsmnt;
      int error;

      error = -EACCES;
      if (!(flags & MS_RDONLY) && dev && is_read_only(dev))
      goto out;

      /*
      * Do the lookup first to force automounting.
      */
      dir_d = namei(dir_name);
      error = PTR_ERR(dir_d);
      if (IS_ERR(dir_d))
      goto out;

      down(&mount_sem);
      error = -ENOTDIR;
      if (!S_ISDIR(dir_d->d_inode->i_mode))
      goto dput_and_out;

      error = -EBUSY;
      if (dir_d->d_covers != dir_d)
      goto dput_and_out;

      /*
      * Note: If the superblock already exists,
      * read_super just does a get_super().
      */
      error = -EINVAL;
      sb = read_super(dev, type, flags, data, 0);
      if (!sb)
      goto dput_and_out;

      /*
      * We may have slept while reading the super block,
      * so we check afterwards whether it's safe to mount.
      */
      error = -EBUSY;
      if (!fs_may_mount(dev))
      goto dput_and_out;

      error = -ENOMEM;
      vfsmnt = add_vfsmnt(sb, dev_name, dir_name);
      if (vfsmnt) {
      d_mount(dget(dir_d), sb->s_root);
      error = 0;
      }

      dput_and_out:
      dput(dir_d);
      up(&mount_sem);
      out:
      return error;
      }
      static struct vfsmount *add_vfsmnt(struct super_block *sb,
      const char *dev_name, const char *dir_name)
      {
      struct vfsmount *lptr;
      char *tmp, *name;

      lptr = (struct vfsmount *)kmalloc(sizeof(struct vfsmount), GFP_KERNEL);
      if (!lptr)
      goto out;
      memset(lptr, 0, sizeof(struct vfsmount));

      lptr->mnt_sb = sb;
      lptr->mnt_dev = sb->s_dev;
      lptr->mnt_flags = sb->s_flags;

      sema_init(&lptr->mnt_dquot.semaphore, 1);
      lptr->mnt_dquot.flags = 0;

      /* N.B. Is it really OK to have a vfsmount without names? */
      if (dev_name && !IS_ERR(tmp = getname(dev_name))) {
      name = (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL);
      if (name) {
      strcpy(name, tmp);
      lptr->mnt_devname = name;
      }
      putname(tmp);
      }
      if (dir_name && !IS_ERR(tmp = getname(dir_name))) {
      name = (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL);
      if (name) {
      strcpy(name, tmp);
      lptr->mnt_dirname = name;
      }
      putname(tmp);
      }

      if (vfsmntlist == (struct vfsmount *)NULL) {
      vfsmntlist = vfsmnttail = lptr;
      } else {
      vfsmnttail->mnt_next = lptr;
      vfsmnttail = lptr;
      }
      out:
      return lptr;
      }
      static void d_mount(struct dentry *covered, struct dentry *dentry)
      {
      if (covered->d_mounts != covered) {
      printk("VFS: mount - already mounted\n");
      return;
      }
      covered->d_mounts = dentry;
      dentry->d_covers = covered;
      }
      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://blog.51cto.com/adofsauron/5707990,作者:帝尊悟世,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:springboot 静态方法中使用@Autowired注入配置和Bean

      下一篇:Linux实战技巧(1)CentOS虚拟机之间设置SSH免密登录

      相关文章

      2025-05-19 09:04:53

      查看RISC-V版本的gcc中默认定义的宏

      查看RISC-V版本的gcc中默认定义的宏

      2025-05-19 09:04:53
      c++ , linux
      2025-05-13 09:50:48

      error: "net.bridge.bridge-nf-call-ip6tables" is an unknown key

      error: "net.bridge.bridge-nf-call-ip6tables" is an unknown key

      2025-05-13 09:50:48
      core , kernel
      2025-04-01 10:28:37

      小课2:筛选信息命令

      小课2:筛选信息命令

      2025-04-01 10:28:37
      bash , linux , 升序 , 服务器 , 运维
      2025-03-26 09:31:12

      shell脚本实现查询代码中定义了多少宏的方法

      shell脚本实现查询代码中定义了多少宏的方法

      2025-03-26 09:31:12
      bash , linux , 运维
      2025-03-14 09:05:42

      编译src.rpm源码包的方法

      编译src.rpm源码包的方法

      2025-03-14 09:05:42
      kernel , rpm , tmp , yum
      2025-03-06 09:15:26

      spring cloud系统安装涉及的技术说明

      spring cloud系统安装涉及的技术说明

      2025-03-06 09:15:26
      docker , linux , 安装 , 技术
      2025-03-05 09:24:43

      【Python】使用numpy库实现Tic-Tac-Toe井字棋

      【Python】使用numpy库实现Tic-Tac-Toe井字棋

      2025-03-05 09:24:43
      linux , 右键 , 安装 , 打开 , 输入
      2025-02-10 08:53:59

      【linux】linux C 程序 注册信号处理函数

      【linux】linux C 程序 注册信号处理函数  

      2025-02-10 08:53:59
      linux , 函数 , 注册 , 程序
      2025-01-17 09:07:21

      课时3:处理信息命令

      课时3:处理信息命令

      2025-01-17 09:07:21
      linux , shell , 数据库 , 服务器 , 运维
      2024-12-31 06:01:41

      The path "" is not a valid path to the 3.10.0-957.el7.x86_64 kernel headers

      The path "" is not a valid path to the 3.10.0-957.el7.x86_64 kernel headers

      2024-12-31 06:01:41
      kernel
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5241779

      查看更多

      最新文章

      小课2:筛选信息命令

      2025-04-01 10:28:37

      课时3:处理信息命令

      2025-01-17 09:07:21

      Linux 系统日常巡检脚本

      2024-11-20 09:46:57

      提权工具推荐(PEASS-ng、linpeas_linux_amd64、winPEASany_ofs)

      2024-11-20 09:46:57

      Linux 系统日常巡检脚本 干货

      2024-11-20 09:46:57

      LINUX的基本管理(1.0)

      2024-11-18 09:54:27

      查看更多

      热门文章

      linux篇-linux iptables配置

      2023-03-16 06:47:52

      Linux运维小技巧---每日收集所有服务器信息并归档到指定服务器

      2023-03-16 07:49:58

      linux中常见工具安装问题集锦

      2023-05-05 10:12:49

      linux环境日志排查,cat命令关键字查找、最近1000条、定位到指定位置

      2022-12-28 07:22:30

      小型自动化运维--expect脚本V2版

      2023-05-16 09:38:32

      Mac 终端连接linux程服务器并相互传输文件

      2023-04-23 09:44:23

      查看更多

      热门标签

      服务器 linux 虚拟机 Linux 数据库 运维 网络 日志 数据恢复 java python 配置 nginx centos mysql
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      Linux命令之查看登录者信息w

      【Linux】进程状态|优先级|进程切换|环境变量

      Linux:锁定文件chattr

      ARM Linux启动详解(1)–系统上电到执行到linux kenel

      linux之权限管理命令

      CentOS8提高篇6:磁盘容量配额管理

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号