linux文件管理(inode、文件描述符表、文件表)

2024-04-12 01:58
文章标签 linux 管理 描述符 inode

本文主要是介绍linux文件管理(inode、文件描述符表、文件表),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、inode(索引节点)
(1)  理解inode,要从文件储存说起。
文件储存在硬盘上,硬盘的最小存储单位叫做"扇区"(Sector)。每个扇区储存512字节(相当于0.5KB)。操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个"块"(block)。这种由多个扇区组成的"块",是文件存取的最小单位。“块"的大小,最常见的是4KB,即连续八个 sector组成一个 block。


(2) 通常情况下,文件系统会将文件的实际内容和属性分开存放:

文件的属性保存在 inode 中(i 节点)中,每个 inode 都有自己的编号。每个文件各占用一个 inode。不仅如此,inode 中还记录着文件数据所在 block 块的编号;
文件的实际内容保存在 block 中(数据块),类似衣柜的隔断,用来真正保存衣物。每个 block 都有属于自己的编号。当文件太大时,可能会占用多个 block 块。
另外,还有一个 super block(超级块)用于记录整个文件系统的整体信息,包括 inode 和 block 的总量、已经使用量和剩余量,以及文件系统的格式和相关信息等。
如图所示:文件系统先格式化出 inode 和 block 块,假设某文件的权限和属性信息存放到 inode 4 号位置,这个 inode 记录了实际存储文件数据的 block 号有 4 个,分别为 2、7、13、15,由此,操作系统就能快速地找到文件数据的存储位置。

note:

每个inode都有一个号码,操作系统用inode号码来识别不同的文件。Unix/Linux系统内部不使用文件名,而使用inode号码来识别文件。对于系统来说,文件名只是inode号码便于识别的别称或者绰号。表面上,用户通过文件名,打开文件。实际上,系统内部这个过程分成三步:首先,系统找到这个文件名对应的inode号码;其次,通过inode号码,获取inode信息;最后,根据inode信息,找到文件数据所在的block,读出数据。

(3) 联系平时实践,大家格式化硬盘(U盘)时发现有:快速格式化和底层格式化。快速格式化非常快,格式化一个32GB的U盘只要1秒钟,普通格式化格式化速度慢。这两个的差异?其实快速格式化就是只删除了U盘中的硬盘内容管理表(其实就是inode),真正存储的内容没有动。这种格式化的内容是有可能被找回的。

(4) inode本质上是一个结构体,定义如下

struct inode {
        struct hlist_node       i_hash;              /* 哈希表 */
        struct list_head        i_list;              /* 索引节点链表 */
        struct list_head        i_dentry;            /* 目录项链表 */
        unsigned long           i_ino;               /* 节点号 */
        atomic_t                i_count;             /* 引用记数 */
        umode_t                 i_mode;              /* 访问权限控制 */
        unsigned int            i_nlink;             /* 硬链接数 */
        uid_t                   i_uid;               /* 使用者id */
        gid_t                   i_gid;               /* 使用者id组 */
        kdev_t                  i_rdev;              /* 实设备标识符 */
        loff_t                  i_size;              /* 以字节为单位的文件大小 */
        struct timespec         i_atime;             /* 最后访问时间 */
        struct timespec         i_mtime;             /* 最后修改(modify)时间 */
        struct timespec         i_ctime;             /* 最后改变(change)时间 */
        unsigned int            i_blkbits;           /* 以位为单位的块大小 */
        unsigned long           i_blksize;           /* 以字节为单位的块大小 */
        unsigned long           i_version;           /* 版本号 */
        unsigned long           i_blocks;            /* 文件的块数 */
        unsigned short          i_bytes;             /* 使用的字节数 */
        spinlock_t              i_lock;              /* 自旋锁 */
        struct rw_semaphore     i_alloc_sem;         /* 索引节点信号量 */
        struct inode_operations *i_op;               /* 索引节点操作表 */
        struct file_operations  *i_fop;              /* 默认的索引节点操作 */
        struct super_block      *i_sb;               /* 相关的超级块 */
        struct file_lock        *i_flock;            /* 文件锁链表 */
        struct address_space    *i_mapping;          /* 相关的地址映射 */
        struct address_space    i_data;              /* 设备地址映射 */
        struct dquot            *i_dquot[MAXQUOTAS]; /* 节点的磁盘限额 */
        struct list_head        i_devices;           /* 块设备链表 */
        struct pipe_inode_info  *i_pipe;             /* 管道信息 */
        struct block_device     *i_bdev;             /* 块设备驱动 */
        unsigned long           i_dnotify_mask;      /* 目录通知掩码 */
        struct dnotify_struct   *i_dnotify;          /* 目录通知 */
        unsigned long           i_state;             /* 状态标志 */
        unsigned long           dirtied_when;        /* 首次修改时间 */
        unsigned int            i_flags;             /* 文件系统标志 */
        unsigned char           i_sock;              /* 可能是个套接字吧 */
        atomic_t                i_writecount;        /* 写者记数 */
        void                    *i_security;         /* 安全模块 */
        __u32                   i_generation;        /* 索引节点版本号 */
        union {
                void            *generic_ip;         /* 文件特殊信息 */
        } u;
};
可以用stat命令,查看某个文件的inode信息:

二、文件描述符表
(1)  每个进程在Linux内核中都有一个task_struct结构体来维护进程相关的信息,称为进程描述符(Process Descriptor),而在操作系统理论中称为进程控制块 (PCB,Process Control Block)。

struct task_struct {
 ...
/* open file information */
 struct files_struct *files;
 ...
};
task_struct中有一个指针(struct files_struct *files)指向files_struct结构体(如下所示),称为文件描述符表(我认为这个定义不确切,暂时还没找到这个说法的来源),记录该进程打开的所有文件。该表中有一个域(struct file * fd_array[NR_OPEN_DEFAULT]),为数组,该数组的每个元素指向已打开的文件的指针(已打开的文件在内核中用file 结构体表示,文件描述符表中的指针指向file 结构体)。

  struct files_struct
  {
  atomic_t count; //引用计数   累加
  struct fdtable *fdt;
  struct fdtable fdtab;
  spinlock_t file_lock ____cacheline_aligned_in_smp;
  int next_fd; 
  struct embedded_fd_set close_on_exec_init; 
  struct embedded_fd_set open_fds_init; 
  struct file * fd_array[NR_OPEN_DEFAULT]; //文件描述符数组
  };
struct file
{
    mode_t f_mode;//表示文件是否可读或可写,FMODE_READ或FMODE_WRITE
    dev_ t  f_rdev ;// 用于/dev/tty
    off_t  f_ops;//当前文件位移
    unsigned short f_flags;//文件标志,O_RDONLY,O_NONBLOCK和O_SYNC
    unsigned short f_count;//打开的文件数目
    unsigned short f_reada;
    struct inode *f_inode;//指向inode的结构指针
    struct file_operations *f_op;//文件操作索引指针
}
(2)  用户程序不能直接访问内核中的文件描述符表,而只能使用文件描述符表的索引 (即0、1、2、3这些数字),这些索引就称为文件描述符(File Descriptor),用int 型变量保存。

文件描述符(本质上是个数字)是open系统调用内部由操作系统自动分配的,操作系统分配这个fd时也不是随意分配,操作系统规定,fd从0开始依次增加。linux中文件描述符表是个数组(不是链表),所以这个文件描述符表其实就是一个数组,fd是index,文件表指针是value
当我们去open时,内核会从文件描述符表中挑选一个最小的未被使用的数字给我们返回。也就是说如果之前fd已经占满了0-9,那么我们下次open得到的一定是10.(但是如果上一个fd得到的是9,下一个不一定是10,这是因为可能前面更小的一个fd已经被close释放掉了)
fd中0、1、2已经默认被系统占用了,因此用户进程得到的最小的fd就是3了。
linux内核占用了0、1、2这三个fd是有用的,当我们运行一个程序得到一个进程时,内部就默认已经打开了3个文件,这三个文件对应的fd就是0、1、2。这三个文件分别叫stdin(标准输入)、stdout(标准输出)、stderr(标准错误)。标准输入一般对应的是键盘,标准输出一般是LCD显示器(可以理解为:1对应LCD的设备文件)
printf函数其实就是默认输出到标准输出stdout上了。stdio中还有一个函数叫fpirntf,这个函数就可以指定输出到哪个文件描述符中。
三、文件表
struct file
{
    mode_t f_mode;//表示文件是否可读或可写,FMODE_READ或FMODE_WRITE
    dev_ t  f_rdev ;// 用于/dev/tty
    off_t  f_ops;//当前文件位移
    unsigned short f_flags;//文件标志,O_RDONLY,O_NONBLOCK和O_SYNC
    unsigned short f_count;//打开的文件数目
    unsigned short f_reada;
    struct inode *f_inode;//指向inode的结构指针
    struct file_operations *f_op;//文件索引指针
}
内核为所有打开文件维护一张文件表项,每个文件表项包含内容可以由以上结构体看出,其中比较重要的内容有:

a. 文件状态(读 写 添写 同步 非阻塞等)

b. 当前文件偏移量

c. 指向该文件i节点(i节点)的指针

d. 指向该文件操作的指针(file_operations )

file_operations 结构体在linux内核2.6.5定义如下所示:

struct file_operations 
{
 
  struct module *owner;
 
  loff_t(*llseek) (struct file *, loff_t, int);
 
  ssize_t(*read) (struct file *, char __user *, size_t, loff_t *);
 
  ssize_t(*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
 
  ssize_t(*write) (struct file *, const char __user *, size_t, loff_t *);
 
  ssize_t(*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);
 
  int (*readdir) (struct file *, void *, filldir_t);
 
  unsigned int (*poll) (struct file *, struct poll_table_struct *);
 
  int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
 
  int (*mmap) (struct file *, struct vm_area_struct *);
 
  int (*open) (struct inode *, struct file *);
 
  int (*flush) (struct file *);
 
  int (*release) (struct inode *, struct file *);
 
  int (*fsync) (struct file *, struct dentry *, int datasync);
 
  int (*aio_fsync) (struct kiocb *, int datasync);
 
  int (*fasync) (int, struct file *, int);
 
  int (*lock) (struct file *, int, struct file_lock *);
 
  ssize_t(*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
 
  ssize_t(*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
 
  ssize_t(*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void __user *);
 
  ssize_t(*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
 
  unsigned long (*get_unmapped_area) (struct file *, unsigned long,
 
         unsigned long, unsigned long,
 
         unsigned long);
 
};
 

 

总结:

 

 

https://blog.51cto.com/13574131/2064574

https://www.jianshu.com/p/0520d6b76318

 

http://www.ruanyifeng.com/blog/2011/12/inode.html

https://www.cnblogs.com/how-are-you/p/5699257.html

https://blog.csdn.net/jnu_simba/article/details/8806654

https://blog.csdn.net/luotuo44/article/details/17474099

https://www.cnblogs.com/wanghetao/archive/2012/05/28/2521675.html

https://blog.csdn.net/u010944778/article/details/45077565
————————————————
版权声明:本文为CSDN博主「wwwlyj123321」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wwwlyj123321/article/details/100298377

这篇关于linux文件管理(inode、文件描述符表、文件表)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/895793

相关文章

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

软考系统规划与管理师考试证书含金量高吗?

2024年软考系统规划与管理师考试报名时间节点: 报名时间:2024年上半年软考将于3月中旬陆续开始报名 考试时间:上半年5月25日到28日,下半年11月9日到12日 分数线:所有科目成绩均须达到45分以上(包括45分)方可通过考试 成绩查询:可在“中国计算机技术职业资格网”上查询软考成绩 出成绩时间:预计在11月左右 证书领取时间:一般在考试成绩公布后3~4个月,各地领取时间有所不同

安全管理体系化的智慧油站开源了。

AI视频监控平台简介 AI视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒,省去繁琐重复的适配流程,实现芯片、算法、应用的全流程组合,从而大大减少企业级应用约95%的开发成本。用户只需在界面上进行简单的操作,就可以实现全视频的接入及布控。摄像头管理模块用于多种终端设备、智能设备的接入及管理。平台支持包括摄像头等终端感知设备接入,为整个平台提

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

【Linux 从基础到进阶】Ansible自动化运维工具使用

Ansible自动化运维工具使用 Ansible 是一款开源的自动化运维工具,采用无代理架构(agentless),基于 SSH 连接进行管理,具有简单易用、灵活强大、可扩展性高等特点。它广泛用于服务器管理、应用部署、配置管理等任务。本文将介绍 Ansible 的安装、基本使用方法及一些实际运维场景中的应用,旨在帮助运维人员快速上手并熟练运用 Ansible。 1. Ansible的核心概念

Linux服务器Java启动脚本

Linux服务器Java启动脚本 1、初版2、优化版本3、常用脚本仓库 本文章介绍了如何在Linux服务器上执行Java并启动jar包, 通常我们会使用nohup直接启动,但是还是需要手动停止然后再次启动, 那如何更优雅的在服务器上启动jar包呢,让我们一起探讨一下吧。 1、初版 第一个版本是常用的做法,直接使用nohup后台启动jar包, 并将日志输出到当前文件夹n