爆款云主机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内核设计与实现(14)--虚拟文件系统

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

      Linux内核设计与实现(14)--虚拟文件系统

      2023-06-14 09:11:10 阅读次数:451

      Linux,unix,目录

       

      虚拟文件系统,简称VFS。系统中所有文件系统不但依赖VFS共存,而且也依靠VFS系统协同工作。程序可以利用标准的Unix系统调用对不同的文件系统,甚至不同介质上的文件系统进行读写操作。

      1.通用文件系统接口

      VFS使得用户可以直接使用open(),read()和write()这样的系统调用而无需考虑具体文件系统和实际物理介质,这点DOS是不具备的,DOS中任何对非本地文件系统的访问都要依靠特殊工具才能完成。

      VFS与块I/O相结合,提供抽象、接口以及交融,使得用户空间的程序调用统一的系统调用访问各种文件,不管文件系统是什么,也不管文件系统位于何种介质,采用命名策略是统一的。

      2.文件系统抽象层

       

      VFS可以为应用提供通用接口操作各类文件系统,是因为内核在底层文件系统接口上建立了一个抽象层。这个抽象系统模型,包括了任何文件系统的常用功能集和行为。当然,该模型偏重于Unix风格的文件系统。

      内核通过抽象层能够方便、简单地支持各种类型的文件系统,实际文件系统通过编程提供VFS所期望的抽象接口和数据结构。比如用户空间的一个写操作:

      ret = write(fd, buf, len);

      write系统调用将buf指针指向的长度为len字节的数据写入文件描述符fd对应的文件的当前位置。这个系统调用首先调用sys_write()处理,sys_write()函数要找到fd所在的文件系统实际给出的是哪个写操作,然后再执行该操作。具体文件系统的写方法是文件系统实现的一部分,数据最终写入介质。

      3.Unix文件系统

       

      Unix使用了四种和文件系统相关的传统抽象概念:文件、目录项、索引节点和安装点(mount point)。

      从本质上讲文件系统是特殊的数据分层存储结构,包含文件、目录和相关控制信息。

      文件系统通用操作包含创建、删除和安装等。在Unix中,文件系统采用全局命名空间,挂载到系统根目录下的一个子节点。

      Unix文件概念和面向记录的文件系统形(比如OpenVMS的File-11)成鲜明对比,面向记录的文件系统提供更丰富、更结构化的表示,而简单的面向字节流抽象的Unix文件则以简单性和相当的灵活性为代价。

      Unix中,目录属于普通文件,它列出包含在其中的所有文件,由于VFS把目录当作文件对待,所以可以对目录执行和文件相同的操作。

      Unix系统将文件的信息和文件本身这两个概念加以区分,例如访问控制权限、大小、拥有者、创建时间等。文件相关信息称作文件的元数据,被存储在一个单独的数据结构中,叫做索引节点(inode)。索引节点存储在超级块中。超级块是一种包含文件系统信息的数据结构。

      Linux的VFS设计目标就是要保证能与支持或实现了这些概念的文件系统协同工作。

      非Unixf风格的文件系统(比如FAT或NTFS),要在Linux上工作,必须经过封装,提供一个符合这些概念的界面。这个封装转换需要在使用现场引入一些特殊处理,这样文件系统仍然能工作,但其带来的开销是很大的。

       

      4.VFS对象及其数据结构

       

      VFS其实采用的是面向对象的设计,内核是纯C开发,用结构体来实现对象,结构体包含数据和操作这些数据的函数指针。

      VFS有四个主要对象类型,分别是:

      超级块对象:代表一个具体已安装文件系统

      索引节点对象:代表一个具体文件

      目录项对象:代表一个目录项,是路径的一个组成部分

      文件对象:它代表由进程打开的文件

      注意,这里的目录项代表的是路径的一个组成部分,可能包含一个普通文件。这不同于目录。Unix中,目录仅是一个普通文件。

      每个主要对象中,都包含一个操作对象,这些操作对象描述了内核针对主要对象可以使用的方法:

      super_operations对象,包含针对特定文件系统调用方法,比如write_inode(),sync_fs等

      inode_operations对象,包含create(),link()等;

      dentry_operations对象,包含d_compare(),d_delete()等

      file_operations对象,包含进程针对已打开文件所能调用的方法,比如read()和write()等

      操作对象作为一个结构体指针来实现,此结构体中包含指向操作其父对象的函数指针。通常来说,可以继承使用VFS通用函数,如果通用函数提供的基本功能无法满足需要,那就必须使用实际文件系统独有方法填充这些函数指针,使其指向文件系统实例。

      VFS使用了大量结构体对象,还包括file_system_type描述文件系统及其性能,vfsmount包含安装点相关信息等。

      5.超级块对象

       

      各种文件系统都必须实现超级块对象,该对象用于存储特定文件系统信息,通常对应于存放在磁盘特定扇区中的文件系统超级块或者文件系统控制块(超级块对象)。对于非基于磁盘的文件系统(比如基于内存的文件系统sysfs),它们会在使用现场创建超级块并将其保存到内存中。

      超级块对象由super_block结构体表示,定义在 中:

       

      此处)折叠或打开

       

      1. struct super_block {
      2. struct list_head s_list; /* Keep this first *///指向所有超级快的链表
      3. dev_t s_dev; /* search index; _not_ kdev_t *///设备标识符
      4. unsigned char s_dirt; //修改(脏)标志
      5. unsigned char s_blocksize_bits; //块大小,单位bit
      6. unsigned long s_blocksize; //块大小,单位字节
      7. loff_t s_maxbytes; /* Max file size *///文件大小上限
      8. struct file_system_type *s_type; //文件系统类型
      9. const struct super_operations *s_op; //超级块方法
      10. const struct dquot_operations *dq_op; //磁盘限额方法
      11. const struct quotactl_ops *s_qcop; //限额控制方法
      12. const struct export_operations *s_export_op;//导出方法
      13. unsigned long s_flags; //挂载标志
      14. unsigned long s_magic; //文件系统幻数
      15. struct dentry *s_root; //目录挂载点
      16. struct rw_semaphore s_umount; //卸载信号量
      17. struct mutex s_lock; //超级块信号量
      18. int s_count; //超级块引用计数
      19. int s_need_sync; //尚未同步标志
      20. atomic_t s_active; //活动引用计数
      21. #ifdef CONFIG_SECURITY
      22. void *s_security; //活动模块
      23. #endif
      24. struct xattr_handler **s_xattr; //扩展属性操作
      25.
      26. struct list_head s_inodes; /* all inodes *///inodes链表
      27. struct hlist_head s_anon; /* anonymous dentries for (nfs) exporting *///匿名目录项
      28. struct list_head s_files; //被分配文件链表
      29. /* s_dentry_lru and s_nr_dentry_unused are protected by dcache_lock */
      30. struct list_head s_dentry_lru; /* unused dentry lru *///未被使用目录项链表
      31. int s_nr_dentry_unused; /* # of dentry on lru *///链表中目录项的数目
      32.
      33. struct block_device *s_bdev; //相关块设备
      34. struct backing_dev_info *s_bdi;
      35. struct mtd_info *s_mtd; //存储磁盘信息
      36. struct list_head s_instances; //该类型文件系统
      37. struct quota_info s_dquot; /* Diskquota specific options *///限额相关选项
      38.
      39. int s_frozen; //frozen标志位
      40. wait_queue_head_t s_wait_unfrozen; //冻结的等待队列
      41.
      42. char s_id[32]; /* Informational name *///文本名字
      43.
      44. void *s_fs_info; /* Filesystem private info *///文件系统特殊信息
      45. fmode_t s_mode; //安装权限
      46.
      47. /* Granularity of c/m/atime in ns.
      48. Cannot be worse than a second */
      49. u32 s_time_gran; //时间戳粒度
      50.
      51. /*
      52. * The next field is for VFS *only*. No filesystems have any business
      53. * even looking at it. You had been warned.
      54. */
      55. struct mutex s_vfs_rename_mutex; /* Kludge *///重命名信号量
      56.
      57. /*
      58. * Filesystem subtype. If non-empty the filesystem type field
      59. * in /proc/mounts will be "type.subtype"
      60. */
      61. char *s_subtype;//子类型名称
      62.
      63. /*
      64. * Saved mount options for lazy filesystems using
      65. * generic_show_options()
      66. */
      67. char *s_options; //已存安装选项
      68. };

       

      创建、管理和撤销超级块对象的代码位于文件fs/super.c中,超级块对象通过alloc_super()函数创建并初始化。在文件系统安装时,文件系统会调用该函数以便从磁盘读取文件系统超级块,并且将其信息填充到内存中的超级块对象中。

      6.超级块操作

       

      超级块对象中最重要的一个域是s_op, 它指向超级块的操作函数表,操作函数表在 定义

      该结构体每一项都是一个指向超级块操作函数的指针,超级块操作函数执行文件系统和索引节点的底层操作。

      当文件系统需要对其超级块执行操作时,首先要在超级块对象中找到合适的方法,比如一个文件系要写自己的超级块,需要调用

      sb->s_op->write_super(sb);

      由于C语言无法直接得到操作函数的父对象,所以必须将父对象以参数显示传给操作函数。

       

      此处)折叠或打开

       

       

      1. struct super_operations {
      2. //在给定的超级块下创建和初始化一个新的索引节点对象
      3. struct inode *(*alloc_inode)(struct super_block *sb);
      4. //释放给定的索引节点
      5. void (*destroy_inode)(struct inode *);
      6. //VFS在索引节点脏(被修改)时会调用此函数
      7. //日志文件系统,(比如ext3/etx4)执行该函数进行日志更新
      8. void (*dirty_inode) (struct inode *);
      9. //用于将给定的索引节点写入磁盘,wait参数指明写操作是否需同步
      10. int (*write_inode) (struct inode *, struct writeback_control *wbc);
      11. //在最后一个指向索引节点的引用被释放后,VFS会调用该函数,VFS只需要简单地删除这个索引节点后,Unix文件系统就不会定义这个函数了
      12. void (*drop_inode) (struct inode *);
      13. void (*delete_inode) (struct inode *);//从磁盘删除给定的索引节点
      14. void (*put_super) (struct super_block *);//卸载文件系统时被VFS调用,用来释放超级块,调用者必须持有s_lock锁
      15. //用给定的超级块更新磁盘上的超级块,VFS通过该函数对内存中的超级块和磁盘中的超级块进行同步,调用者必须持有s_lock锁
      16. void (*write_super) (struct super_block *);
      17. //使文件系统的数据元与磁盘上的文件系统同步,wait参数指定操作是否同步
      18. int (*sync_fs)(struct super_block *sb, int wait);
      19. int (*freeze_fs) (struct super_block *);
      20. int (*unfreeze_fs) (struct super_block *);
      21. int (*statfs) (struct dentry *, struct kstatfs *);//获取文件系统状态
      22. //当执行新的安装选项重新安装文件系统时,VFS会调用,必须持有s_lock锁
      23. int (*remount_fs) (struct super_block *, int *, char *);
      24. //VFS调用,释放索引节点,并清空包含相关数据所有页面
      25. void (*clear_inode) (struct inode *);
      26. //VFS调用中断安装操作,该函数被网络文件系统使用,如NFS。
      27. void (*umount_begin) (struct super_block *);
      28.
      29. int (*show_options)(struct seq_file *, struct vfsmount *);
      30. int (*show_stats)(struct seq_file *, struct vfsmount *);
      31. #ifdef CONFIG_QUOTA
      32. ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
      33. ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
      34. #endif
      35. int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t);
      36. };

       

      以上函数都是由VFS在进程上下文调用,除了dirty_inode(),其他函数可以阻塞。

      其中一些函数是可选的,不需要的函数设为NULL,如果VFS发现操作函数指针是NULL,它调用通用函数指向相应操作,或者什么都不做。

      7.索引节点对象

       

      索引节点对象,包含了内核在操作文件或目录时需要的全部信息。

      对于Unix风格的文件系统来说,这些信息可以从磁盘索引节点直接读入。有的文件系统没有索引节点,没有将数据和控制信息分开存放。不管哪种情况、采用哪种方式,索引节点对象必须在内存中创建,以便于文件系统调用。

      索引节点对象inode结构,在 中定义

      此处)折叠或打开

      1. struct inode {
      2. struct hlist_node i_hash; //散列表
      3. /* backing dev IO list */
      4. struct list_head i_list; //索引节点链表
      5. struct list_head i_sb_list; //超级块链表
      6. struct list_head i_dentry; //目录项链表
      7. unsigned long i_ino; //节点号
      8. atomic_t i_count; //引用计数
      9. unsigned int i_nlink; //硬链接数
      10. uid_t i_uid; //使用者id
      11. gid_t i_gid; //使用组id
      12. dev_t i_rdev; //实际设备标志符
      13. unsigned int i_blkbits; //以位单位文件大小
      14. u64 i_version; //版本号
      15. loff_t i_size; //以字节单位文件大小
      16. #ifdef __NEED_I_SIZE_ORDERED
      17. seqcount_t i_size_seqcount; //以i_size进行串行计数
      18. #endif
      19. struct timespec i_atime; //最后访问时间
      20. struct timespec i_mtime; //最后修改时间
      21. struct timespec i_ctime; //最后改变时间
      22. blkcnt_t i_blocks; //文件的块数
      23. unsigned short i_bytes; //使用的字节数
      24. umode_t i_mode; //访问权限
      25. /* i_blocks, i_bytes, maybe i_size */
      26. spinlock_t i_lock; //自旋锁
      27. struct mutex i_mutex; //互斥锁
      28. struct rw_semaphore i_alloc_sem; //嵌入i_sem内部
      29. const struct inode_operations *i_op;//索引节点操作表
      30. /* former ->i_op->default_file_ops */
      31. const struct file_operations *i_fop;//缺省的索引节点操作表
      32. struct super_block *i_sb; //相关的超级块
      33. struct file_lock *i_flock;
      34. struct address_space *i_mapping;//相关的地址映射
      35. struct address_space i_data; //设备地址映射
      36. #ifdef CONFIG_QUOTA
      37. struct dquot *i_dquot[MAXQUOTAS];
      38. #endif
      39. struct list_head i_devices;
      40. union {
      41. struct pipe_inode_info *i_pipe; //管道信息
      42. struct block_device *i_bdev; //块设备驱动
      43. struct cdev *i_cdev; //字符设备驱动
      44. };
      45.
      46. __u32 i_generation;
      47.
      48. #ifdef CONFIG_FSNOTIFY
      49. __u32 i_fsnotify_mask; /* all events this inode cares about */
      50. struct hlist_head i_fsnotify_mark_entries; /* fsnotify mark entries */
      51. #endif
      52.
      53. #ifdef CONFIG_INOTIFY
      54. struct list_head inotify_watches; /* watches on this inode */
      55. struct mutex inotify_mutex; /* protects the watches list */
      56. #endif
      57.
      58. unsigned long i_state;
      59. unsigned long dirtied_when; /* jiffies of first dirtying */
      60.
      61. unsigned int i_flags; //文件系统标志
      62.
      63. atomic_t i_writecount; //写者技数
      64. #ifdef CONFIG_SECURITY
      65. void *i_security; //安全模块
      66. #endif
      67. #ifdef CONFIG_FS_POSIX_ACL
      68. struct posix_acl *i_acl;
      69. struct posix_acl *i_default_acl;
      70. #endif
      71. /* fs or device private pointer */
      72.
      73. void *i_private;//fs私有指针
      74. };

       

      一个索引节点代表文件系统中的一个文件(索引节点仅当文件被访问时,才在内存中创建),也可以是设备文件或管道文件这样的特殊文件。

      8.索引节点操作

       

      索引节点对象的inode_operations项非常重要,因为它描述了操作索引节点的所有方法,这些方法由文件系统实现。在 定义

       

      此处)折叠或打开

       

       

      1. struct inode_operations {
      2. //VFS通过系统调用create()和open()来调用该函数,从而为dentry对象创建
      3. //一个新的索引节点
      4. int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
      5. //在特定的目录中寻找索引节点,该索引节点要对应于denrty中给定的文件名
      6. struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
      7. //被系统调用link()调用,用来创建硬链接
      8. //硬链接名称由dentry参数指定,链接对象是dir目录中old_dentry目录项所代表的文件
      9. int (*link) (struct dentry *,struct inode *,struct dentry *);
      10. //被系统调用ulink()调用,从目录dir中删除由目录项dentry指定的索引节点对象
      11. int (*unlink) (struct inode *,struct dentry *);
      12. //被symlik()调用,创建符号链接
      13. int (*symlink) (struct inode *,struct dentry *,const char *);
      14. //被mknod()调用,创建新目录
      15. int (*mkdir) (struct inode *,struct dentry *,int);
      16. //被rmdir()调用,删除dir目录中的dentry目录项代表的文件
      17. int (*rmdir) (struct inode *,struct dentry *);
      18. //被mknod()调用,船舰特殊文件(设备文件,管道,套接字等)
      19. int (*mknod) (struct inode *,struct dentry *,int,dev_t);
      20. //移动文件
      21. int (*rename) (struct inode *, struct dentry *,
      22. struct inode *, struct dentry *);
      23. //readlink()调用,拷贝数据到特定的缓冲buffer中?
      24. //拷贝的数据来自dentry指定的符号链接,拷贝大小最大可达buflen字节
      25. int (*readlink) (struct dentry *, char __user *,int);
      26. void * (*follow_link) (struct dentry *, struct nameidata *);
      27. void (*put_link) (struct dentry *, struct nameidata *, void *);
      28. void (*truncate) (struct inode *);//修改文件大小
      29. int (*permission) (struct inode *, int);//检查访问权限
      30. int (*check_acl)(struct inode *, int);
      31. //被notify_change()调用,在修改索引节点后,通知发送了"改变事件"
      32. int (*setattr) (struct dentry *, struct iattr *);
      33. //在通知索引节点需要从磁盘中更新时,VFS会调用
      34. int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
      35. //VFS调用,给dentry指定的文件设置扩展属性
      36. int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
      37. //VFS调用,向value中拷贝给定文件的扩展属性name对应的数值
      38. ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
      39. //将特定文件的所有属性列表拷贝到一个缓冲列表中
      40. ssize_t (*listxattr) (struct dentry *, char *, size_t);
      41. //从文件中删除指定的属性
      42. int (*removexattr) (struct dentry *, const char *);
      43. void (*truncate_range)(struct inode *, loff_t, loff_t);
      44. long (*fallocate)(struct inode *inode, int mode, loff_t offset,
      45. loff_t len);
      46. int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
      47. u64 len);
      48. };

       

      9.目录项对象

       

      VFS把目录当作文件对待,一个完整路径中的每个组成部分都由一个索引节点对象标志。虽然可以用索引节点表示,但为了实际操作方便,引入目录项对象。完整路径的每一部分都是一个目录项对象,比如/bin/vi中/,bin,vi是三个目录项对象。

      VFS在执行目录操作时(需要的话)会现场创建目录项对象。

      目录项对象dentry结构体在 定义

       

      此处)折叠或打开

       

       

      1. struct dentry {
      2. atomic_t d_count; //使用计数
      3. /* protected by d_lock */
      4. unsigned int d_flags; //目录项标识
      5. /* per dentry lock */
      6. spinlock_t d_lock; //但目录项锁
      7. int d_mounted;
      8. /* Where the name belongs to - NULL is
      9. * negative */
      10. struct inode *d_inode; //相关联的索引节点
      11. /*
      12. * The next three fields are touched by __d_lookup. Place them here
      13. * so they all fit in a cache line.
      14. */
      15. struct hlist_node d_hash; /* lookup hash list */
      16. struct dentry *d_parent; /* parent directory */
      17. struct qstr d_name; //目录项名字
      18.
      19. struct list_head d_lru; /* LRU list *///未使用的链表
      20. /*
      21. * d_child and d_rcu can share memory
      22. */
      23. union {
      24. /* child of parent list */
      25. struct list_head d_child;//目录项内部形成的链表
      26. struct rcu_head d_rcu; //RCU加锁
      27. } d_u;
      28. struct list_head d_subdirs; /* our children *///子目录链表
      29. struct list_head d_alias; /* inode alias list *///索引节点别名链表
      30. unsigned long d_time; /* used by d_revalidate *///重置时间
      31. const struct dentry_operations *d_op;//目录项操作时间
      32. struct super_block *d_sb; /* The root of the dentry tree *///文件的超级块
      33. void *d_fsdata; /* fs-specific data *///文件系统特有数据
      34.
      35. unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
      36. };

       

      与超级块和索引节点不同,目录项对象没有对应的磁盘数据结构,VFS根据字符串形式的路径名现场创建它,而且由于目录项对象并非真正保存在磁盘上,所以目录项结构体没有是否被修改的标志。

      9.1 目录项状态

       

      目录项对象有三种有效状态:被使用、未被使用和负状态。

      (1)一个被使用的目录项对应一个有效的索引节点(d_inode指针),并且表明该对象存在一个或多个使用者(d_count为正值),一个目录项处于被使用状态,意味着它正被VFS使用并且指向有效数据,因此不能丢弃。

      (2)一个未被使用的目录项对应一个有效的索引节点(d_inode指向索引节点),但VFS当前并未使用(d_count为0),该目录项对象仍然指向一个有效对象,而且被保留在缓存中以便需要时使用。这样当需要它时,不必重新创建,这样路径查找更快。

      (3)负状态的目录项没有对应的有效索引节点,节点以及被删除或路径已经不正确了。但目录项仍然保留,以便快速解析以后的路径查询。

      目录项对象释放后也可以保存到slab对象缓存中。

      9.2 目录项缓存

       

      如果VFS层遍历路径名中的所有元素并将它们逐个解析成目录项对象,还要到达最深层目录,是一件非常费力的工作,会浪费大量时间。所以内核将目录项对象缓存在目录项缓存中

      dcache主要包括三个部分:

      (1)“被使用的”目录项链表,i_dentry项链接相关索引节点。因为一个索引节点可能有多个链接,所以就可能有多个目录项对象,因此用链表链接他们。

      (2)“最近被使用的”双向链表。该链表含有未被使用的或负状态的目录项对象。

      由于该链表总是在头部插入目录项,所以头节点目录项是最新的,内核通过删除节点回收内存时,会从链尾删除。

      (3)散列表和相应的散列函数,用来快速地将给定路径解析为相关目录项对象。

      散列表由数组dentry_hashtable表示,其中每一个元素都是一个指向相同键值的目录项对象链表的指针。

      实际的散列值由d_hash()函数计算,它是内核提供给文件系统的唯一的散列函数。

      dcache在一定意义上也提供了对索引节点的缓存,即icache。和目录项对象相关的索引节点不会被释放。因为目录项让相关索引节点的使用计数为正,这样确保相应索引节点保留在内存中。所以,只要路径名在缓存中找到,那么相应的索引节点肯定也在内存中缓存着。

       

      因为文件访问呈现空间和时间的局部性,所以对目录项和索引节点进程缓存非常有益。

      时间的局部性,是指程序可能会一次又一次地访问相同的文件,当同一个文件被访问时,所缓存的相关目录项和索引节点命中率高。

      空间局部性,是指程序可能在同一个目录下访问多个文件,因此一个文件对应的目录项缓存后命中率高,因为相关的文件可能在下次又被使用。

      10.目录项操作

       

      dentry_operation结构体指向VFS操作目录项的所有方法,在 定义

       

      此处)折叠或打开

      1. struct dentry_operations {
      2. int (*d_revalidate)(struct dentry *, struct nameidata *);
      3. int (*d_hash) (struct dentry *, struct qstr *);
      4. int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);
      5. int (*d_delete)(struct dentry *);
      6. void (*d_release)(struct dentry *);
      7. void (*d_iput)(struct dentry *, struct inode *);
      8. char *(*d_dname)(struct dentry *, char *, int);
      9. };

      int d_ revalidate(struct dentry *dentry, struct nameidata*name);

      判断目录对象是否有效,VFS准备从dcache中使用一个目录项时,会调用该函数,大部分时候设为NULL,因为dcache中的目录项总是有效的。

      int (*d_hash) (struct dentry * dentry, struct qstr * name);

      该函数为目录生成散列值,当目录项需要加入到散列表中时,VFS调用该函数。

      int (*d_compare) (struct dentry * dentry, struct qstr *name1, struct qstr *name2);

      多数文件系统使用VFS默认的操作,仅比较字符串。但有些系统,比如FAT,不区分大小写的,所以需要实现不区分大小写的字符串比较函数。

      int (*d_delete)(struct dentry *dentry);

      当目录项对象的d_count计数值等于0,VFS调用该函数

      void (*d_release)(struct dentry *);

      当目录项对象将要被释放时,VFS调用该函数

      void (*d_iput)(struct dentry *, struct inode *);

      当目录项丢失了索引节点时(索引节点被删除了),VFS调用,默认调用input()函数释放所有节点。

      11.文件对象

       

      文件对象,表示进程已打开的文件,进程直接处理的是文件,而不是超级块,索引节点或目录项。文件对象与我们熟悉的系统调用read()和write()对应。

      多个进程可以同时打开和操作同一个文件,所以同一个文件也可能存在多个对应的文件对象。文件对象仅仅是进程观点上已打开的实际文件,只有索引节点和目录项对象才是唯一的。

      文件对象在 定义

      此处)折叠或打开

      1. struct file {
      2. /*
      3. * fu_list becomes invalid after file_free is called and queued via
      4. * fu_rcuhead for RCU freeing
      5. */
      6. union {
      7. struct list_head fu_list; //文件对象链表
      8. struct rcu_head fu_rcuhead; //释放之后的RCU链表
      9. } f_u;
      10. struct path f_path; //包含目录项
      11. #define f_dentry f_path.dentry
      12. #define f_vfsmnt f_path.mnt
      13. const struct file_operations *f_op;//文件操作表
      14. spinlock_t f_lock; /* f_ep_links, f_flags, no IRQ *///单个文件结构锁
      15. atomic_long_t f_count; //文件对象的使用计数
      16. unsigned int f_flags; //打开文件时所指定的标志
      17. fmode_t f_mode; //文件的访问模式
      18. loff_t f_pos; //文件当前的位移量(文件指针)
      19. struct fown_struct f_owner; //拥有者通过信号进行异步I/O数据传送
      20. const struct cred *f_cred; //文件的信任状
      21. struct file_ra_state f_ra; //预读状态
      22.
      23. u64 f_version; //版本号
      24. #ifdef CONFIG_SECURITY
      25. void *f_security; //安全模块
      26. #endif
      27. /* needed for tty driver, and maybe others */
      28. void *private_data; //tty设备驱动的钩子
      29.
      30. #ifdef CONFIG_EPOLL
      31. /* Used by fs/eventpoll.c to link all the hooks to this file */
      32. struct list_head f_ep_links; //事件池链表
      33. #endif /* #ifdef CONFIG_EPOLL */
      34. struct address_space *f_mapping; //页缓存映射
      35. #ifdef CONFIG_DEBUG_WRITECOUNT
      36. unsigned long f_mnt_write_state; //调试状态
      37. #endif
      38. };

      文件对象实际上没有对应的磁盘数据,通过f_dentry指针指向相关的目录项对象,目录项会指向相关的索引节点,索引节点会记录文件是否为脏的。

      12.文件操作

      此处)折叠或打开

      1. /*
      2. * NOTE:
      3. * read, write, poll, fsync, readv, writev, unlocked_ioctl and compat_ioctl
      4. * can be called without the big kernel lock held in all filesystems.
      5. */
      6. struct file_operations {
      7. struct module *owner;
      8. //该函数用于更新偏移量指针,
      9. //由系统调用lleek()调用
      10. loff_t (*llseek) (struct file *, loff_t, int);
      11. //从给定文件的offset偏移处读取count字节到buf中
      12. //由系统调用read()调用
      13. ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
      14. //从给定buf中取出count字节数据,写入给定文件的offset偏移处,更新文件指针
      15. //由系统调用write()调用
      16. ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
      17. //从给定文件,以同步方式读取count字节的数据到buf中,
      18. //由系统调用aio_read()调用
      19. ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
      20. //以同步方式从给定buf中取出count字节数据,写入由iocb描述的文件中
      21. //由系统调用aio_write()调用
      22. ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
      23. //返回目录列表的下一个目录
      24. //由系统调用readdir()调用
      25. int (*readdir) (struct file *, void *, filldir_t);
      26. //该函数睡眠等待给定的文件活动
      27. //由系统调用poll()调用
      28. unsigned int (*poll) (struct file *, struct poll_table_struct *);
      29. //给设备发送命令参数对,进行设置操作
      30. //由系统调用ioctl调用,调用者必须持有BKL
      31. int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
      32. //功能与ioctl()类似,但不需要调用者持有BKL,如果用户空间调用ioctl()系统调用,
      33. //VFS可以调用unlocked_ioctl(),它与ioctl()实现一个即可,一般有限实现unlocked_ioctl()
      34. long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
      35. //是ioctl()函数的可移植变种,被32位应用程序用在64位系统上
      36. long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
      37. //将给定的文件映射到指定的地址空间上,
      38. //由系统调用mmap()调用
      39. int (*mmap) (struct file *, struct vm_area_struct *);
      40. //创建一个新的文件对象,并将它与相应索引节点对象关联
      41. //由系统调用open()调用
      42. int (*open) (struct inode *, struct file *);
      43. //当已打开文件的引用计数减少时,该函数被VFS调用,作用根据具体文件系统而定
      44. int (*flush) (struct file *, fl_owner_t id);
      45. //当文件最后一个引用被注销时,该函数被VFS调用
      46. int (*release) (struct inode *, struct file *);
      47. //将给定文件的所有缓存数据写回磁盘
      48. //由系统调用fsync()调用
      49. int (*fsync) (struct file *, struct dentry *, int datasync);
      50. //将iocb描述的文件所有缓存数据写回磁盘,
      51. //由系统调用aio_fsync()调用
      52. int (*aio_fsync) (struct kiocb *, int datasync);
      53. //用于打开或关闭异步I/O的通告信号
      54. int (*fasync) (int, struct file *, int);
      55. //给指定文件上锁
      56. int (*lock) (struct file *, int, struct file_lock *);
      57. ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
      58. unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
      59. int (*check_flags)(int);
      60. int (*flock) (struct file *, int, struct file_lock *);
      61. ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
      62. ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
      63. int (*setlease)(struct file *, long, struct file_lock **);
      64. };

       

      13.和文件系统相关的数据结构

      除了上面几种VFS基础对象外,内核还使用了另外一些标注数据结构来管理文件系统的其他相关数据。

      第一个是file_system_type,用来描述各种特定文件系统类型,比如ext3/4,UDF。

      在 定义

      此处)折叠或打开

      1. struct file_system_type {
      2. const char *name; //文件系统名字
      3. int fs_flags; //文件系统类型标志
      4. //从磁盘中读取超级块
      5. int (*get_sb) (struct file_system_type *, int,
      6. const char *, void *, struct vfsmount *);
      7. void (*kill_sb) (struct super_block *);//终止访问超级块
      8. struct module *owner; //文件系统模块
      9. struct file_system_type * next; //链表中下一个文件系统类型
      10. struct list_head fs_supers; //超级块对象链表
      11. //以下字段运行时使锁生效
      12. struct lock_class_key s_lock_key;
      13. struct lock_class_key s_umount_key;
      14.
      15. struct lock_class_key i_lock_key;
      16. struct lock_class_key i_mutex_key;
      17. struct lock_class_key i_mutex_dir_key;
      18. struct lock_class_key i_alloc_sem_key;
      19. };

      get_sb()函数从磁盘读取超级块,并且在文件系统被安装时,在内存中组装超级块对象,剩余的函数描述文件系统属性。

      每种文件系统不管被安装多少个实例到系统中,都只有一个file_system_type结构。当文件系统被实际安装时,有一个vfsmount结构体在安装点被创建。该结构体用来代表文件系统的实例,即一个安装点

      第二个结构体vfsmount,在 定义

      此处)折叠或打开

      1. struct vfsmount {
      2. struct list_head mnt_hash;
      3. struct vfsmount *mnt_parent; /* fs we are mounted on */
      4. struct dentry *mnt_mountpoint; /* dentry of mountpoint */
      5. struct dentry *mnt_root; /* root of the mounted tree */
      6. struct super_block *mnt_sb; /* pointer to superblock */
      7. struct list_head mnt_mounts; /* list of children, anchored here */
      8. struct list_head mnt_child; /* and going through their mnt_child */
      9. int mnt_flags;
      10. /* 4 bytes hole on 64bits arches */
      11. const char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */
      12. struct list_head mnt_list;
      13. struct list_head mnt_expire; /* link in fs-specific expiry list */
      14. struct list_head mnt_share; /* circular list of shared mounts */
      15. struct list_head mnt_slave_list;/* list of slave mounts */
      16. struct list_head mnt_slave; /* slave list entry */
      17. struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list */
      18. struct mnt_namespace *mnt_ns; /* containing namespace */
      19. int mnt_id; /* mount identifier */
      20. int mnt_group_id; /* peer group identifier */
      21. /*
      22. * We put mnt_count & mnt_expiry_mark at the end of struct vfsmount
      23. * to let these frequently modified fields in a separate cache line
      24. * (so that reads of mnt_flags wont ping-pong on SMP machines)
      25. */
      26. atomic_t mnt_count;
      27. int mnt_expiry_mark; /* true if marked for expiry */
      28. int mnt_pinned;
      29. int mnt_ghosts;
      30. #ifdef CONFIG_SMP
      31. int __percpu *mnt_writers;
      32. #else
      33. int mnt_writers;
      34. #endif
      35. };

      vfsmount结构还保存了在安装时指定的标志信息,该信息存储在mnt_flags域中

      14.和进程相关的数据结构

      每个进程多有自己的一组打开的文件,像跟文件系统,当前工作目录,安装点等。有三个将VFS层和系统的进程紧密联系在一起,它们分别是file_struct, fs_struct, namespace结构体。

      file_struct 结构体定义在 中,该结构体由进程描述符的files目录项指向,所有与单个进程相关的信息(如打开的文件及文件描述符)都包含在其中

      此处)折叠或打开

      1. /*
      2. * Open file table structure
      3. */
      4. struct files_struct {
      5. /*
      6. * read mostly part
      7. */
      8. atomic_t count; //结构的使用计数
      9. struct fdtable *fdt; //指向其他fd表的指针
      10. struct fdtable fdtab; //基fd表
      11. /*
      12. * written part on a separate cache line in SMP
      13. */
      14. spinlock_t file_lock ____cacheline_aligned_in_smp;
      15. int next_fd; //缓存下一个可用的fd
      16. struct embedded_fd_set close_on_exec_init;//exec()时关闭的文件描述符表
      17. struct embedded_fd_set open_fds_init;//打开的文件描述符链表
      18. struct file * fd_array[NR_OPEN_DEFAULT];//缺省的文件对象数组
      19. };

       

      第二个和进程相关的结构体是fs_struct,该结构由进程描述符的fs域指向,它包含文件系统和进程的相关信息,定义在 中

      此处)折叠或打开

      1. struct fs_struct {
      2. int users; //用户数目
      3. rwlock_t lock; //保护该结构体的锁
      4. int umask; //掩码
      5. int in_exec; //当前正执行的文件
      6. struct path root, pwd;//根目录路径和当前工作目录路径
      7. };

      第三个相关进程相关结构体是namespace,由进程描述符的mmt_namespace域指向,在 定义,大多数系统上只有一个命名空间,但CLONE_NEWS标志可以使这一功能失效。

      上述这些数据结构都是通过进程描述符连接起来的,对多数进程来说,它们的描述符都指向唯一的files_struct和fs_struct结构体。但对于那些使用CLONE_FILES或CLONE_FS创建的进程,会共享这两个结构体。所以多进程描述符可能指向同一个files_struct或fs_struct结构体,每个结构体都维护一个count域作为引用计数,防止在进程正使用时,该结构被撤销。

      小结:

      Linux支持了相当多种类的文件系统,从本地文件系统(ext3和ext4)到网络文件系统(NFS和Coda),Linux在标准内核中已支持的文件系统超过60种。VFS层提供给这些不同文件系统一个统一的实现框架,而且也提供了能和标准系统调用交互工作的统一接口。由于VFS层的存在,使得在Linux上实现新文件系统的工作变得简单起来,它可以轻松地使这些文件系统通过标准Unix系统调用而协同工作。

      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://blog.51cto.com/u_7784550/5676221,作者:luteresa,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:初学Oracle所需要知道的(启动关闭和配置)

      下一篇:Linux系统下使用wall命令发送广播消息中文乱码

      相关文章

      2025-05-14 10:33:25

      超级好用的C++实用库之网络

      在网络相关的项目中,我们经常需要去获取和设置设备的IP地址、子网掩码、网关地址、MAC地址等信息。这些信息一般与操作系统相关,在Windows系统和Linux系统上调用的接口是不一样的。

      2025-05-14 10:33:25
      Linux , 参数 , 地址 , 接口 , 网卡 , 返回值
      2025-05-14 10:33:16

      30天拿下Python之文件操作

      Python是一种高级编程语言,它提供了许多内置函数和模块来处理文件操作,主要包括:打开文件、读取文件、写入文件、关闭文件、获取目录列表等。

      2025-05-14 10:33:16
      Python , 使用 , 函数 , 文件 , 权限 , 目录
      2025-05-14 10:03:13

      超级好用的C++实用库之线程基类

      在C++中,线程是操作系统能够进行运算调度的最小单位。一个进程可以包含多个线程,这些线程共享进程的资源,比如:内存空间和系统资源,但它们有自己的指令指针、堆栈和局部变量等。

      2025-05-14 10:03:13
      Linux , void , Windows , 函数 , 操作系统 , 线程
      2025-05-13 09:51:17

      使用Kernel 2.6版本的Linux系统运行dbca创建数据库实例时报错ORA-27125

      使用Kernel 2.6版本的Linux系统运行dbca创建数据库实例时报错ORA-27125

      2025-05-13 09:51:17
      dbca , Linux , ORA
      2025-05-12 08:40:18

      C#目录文件监控

      C#目录文件监控

      2025-05-12 08:40:18
      控制台 , 源码 , 监控 , 目录 , 程序
      2025-05-12 08:40:18

      Linux+Docer 容器化部署之 Shell 语法入门篇 【Shell变量】

      Linux+Docer 容器化部署之 Shell 语法入门篇 【Shell变量】

      2025-05-12 08:40:18
      Linux , 变量
      2025-05-09 08:51:09

      Linux+Docer 容器化部署之 Shell 语法入门篇 【Shell基本运算符】

      Linux+Docer 容器化部署之 Shell 语法入门篇 【Shell基本运算符】

      2025-05-09 08:51:09
      Linux , Shell , 语法 , 运算符
      2025-05-09 08:51:09

      Linux+Docer 容器化部署之 Shell 语法入门篇 【Shell 替代】

      Linux+Docer 容器化部署之 Shell 语法入门篇 【Shell 替代】

      2025-05-09 08:51:09
      Linux , Shell , var
      2025-05-07 09:09:26

      【Linux 从基础到进阶】Linux中的用户认证与授权

      在Linux系统中,**用户认证(authentication)和授权(authorization)**是两个核心的安全机制,用来控制系统资源的访问和管理用户操作权限。用户认证确保登录的用户是合法的,授权则决定用户能够执行哪些操作。

      2025-05-07 09:09:26
      Linux , 密码 , 用户 , 认证
      2025-05-07 09:08:54

      【Linux】什么是Linux?

      【Linux】什么是Linux?

      2025-05-07 09:08:54
      Linux , 文件 , 权限
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5233969

      查看更多

      最新文章

      使用Kernel 2.6版本的Linux系统运行dbca创建数据库实例时报错ORA-27125

      2025-05-13 09:51:17

      Linux系统中Crontab的用法详解

      2025-05-07 09:08:42

      【Linux 从基础到进阶】IPv6配置与管理

      2025-05-06 09:18:49

      【Linux 从基础到进阶】RAID与LVM配置与管理

      2025-05-06 09:18:49

      操作系统实训复习笔记(2)

      2025-04-01 10:29:01

      Shell脚本实现日志老化管理:七天打包归档与三十天自动清除

      2025-03-21 06:56:46

      查看更多

      热门文章

      网络系统管理Linux环境——8.AppSrv之SSH

      2023-05-09 06:17:03

      网络系统管理Linux环境——15.StorageSrv之NFS

      2023-05-09 06:17:03

      网络系统管理Linux环境——12.AppSrv之MAIL(POSTFIX-SMTPS & DOVECOT-IMAPS)

      2024-06-28 06:18:03

      网络系统管理Linux环境——10.AppSrv之DNS

      2024-06-28 06:18:03

      Linux系统登录相关

      2023-05-16 09:44:45

      Linux系统配置pycharm

      2023-05-18 09:33:35

      查看更多

      热门标签

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

      相关产品

      弹性云主机

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

      天翼云电脑(公众版)

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

      对象存储

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

      云硬盘

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

      查看更多

      随机文章

      Linux服务器之SSH 密钥创建及密钥登录设置

      Linux系统中dd命令用法详解

      Linux 系统的安全加固

      【服务器数据恢复】Linux系统,EXT4文件系统下虚拟机误删除的数据恢复案例

      第六章 创建linux虚拟机和相关配置

      网络系统管理Linux环境——14.StorageSrv之DISK

      • 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号