【BSP開發經驗】簡易文件系統digicapfs實現方式

文章目錄

  • 背景
  • Linux vfs框架介紹
    • 數據結構
    • 系統調用
      • open
      • write
      • read
    • 總體框架
  • Linux 磁盤高速緩存機制
    • 標準文件訪問
    • 同步文件訪問
    • 異步文件訪問
    • buffer_head
  • 如何實現一個簡單的文件系統
    • blkdevfs
      • 注冊文件系統
      • 產生一個文件
      • 讓文件變得可讀可寫

背景

在新的分區升級啟動方案中需要分別實現兩個簡單的文件系統,其中一個文件系統作用是可以將存放digicap的塊設備變成可以掛載的設備,掛載后可以直接訪問digicap打包的所有文件,命名為digicapfs。另外一個文件系統的作用是可以將任意塊設備掛載為一個只有單個文件的文件系統,可以將寫入塊設備的讀寫操作轉化為對文件的讀寫。

文件系統是操作系統向用戶提供一套存取數據的抽象數據結構,方便用戶管理一組數據。文件系統在Linux操作系統)中的位置在下圖紅框中標出,如Ext2、Ext4等。而在windows中現在常用的文件系統為NTFS、exFAT等,想必大家在格式化U盤、硬盤的時候就經常見到了。

在這里插入圖片描述

為什么要用文件系統來存取數據呢?是為了圖個方便。試想如果沒有文件系統,放置在存儲介質(硬盤)中的數據將是一個龐大的數據主體,無法分辨一個數據從哪里停止,下一個數據又從哪里開始。通過將數據分為一塊一塊的,并為每一塊都賦予一個名字,數據將會很容易隔離和確定。當然這都是在邏輯上去劃分。既然是在邏輯上劃分,那總得有個依據,將劃分的結果落實下來。這時候我們就需要創建一系列的數據結構(包含數據和對此數據的一系列操作),來表示我們劃分的邏輯,這就是文件系統。

Linux vfs框架介紹

數據結構

首先,我們通過進程task_struct結構體中fs成員表示了進程可見根文件系統的根節點及當前工作目錄:

task_struct{...struct fs_struct *fs;          /進程目錄信息/struct files_struct *files;    /進程打開文件信息/...
}

fs_struct結構體定義在/include/linux/fs_struct.h頭文件:

struct fs_struct {int users;                     /結構體實例用戶數量/spinlock_t lock;seqcount_t seq;int umask;int in_exec;struct path root, pwd;        /進程根目錄和當前工作目錄/
};

path結構體實例,結構體定義如下:

struct path {struct vfsmount *mnt;     /目錄項所在文件系統掛載信息,vfsmount.mnt/struct dentry *dentry;    /目錄項指針/
};

root成員表示進程訪問內核根文件系統,通常為根文件系統的根節點,但也可以通過chroot()系統調用修改進程根目錄。進程以絕對路徑搜索文件時,從進程根目錄開始。pwd成員表示進程當前工作目錄。進程以相對路徑訪問文件時,將會從當前工作目錄開始查找。chdir()系統調用用于改變進程當前工作目錄。在前面介紹的VFS初始化中,將創建內核根文件系統,并設置內核線程的根目錄、當前工作目錄為根文件系統根目錄

files成員指向files_struct結構體實例,結構體定義在include/linux/fdtable.h頭文件:

struct files_struct {/** read mostly part*/atomic_t count;                 /*實例引用計數*/bool resize_in_progress;wait_queue_head_t resize_wait;  /*進程等待隊列*/struct fdtable __rcu *fdt;  /*fdtable結構體指針,初始值指向fdtab成員*/struct fdtable fdtab;       /*fdtable結構體成員*//** written part on a separate cache line in SMP*/spinlock_t file_lock ____cacheline_aligned_in_smp;/*下一個打開文件的文件描述符,初始值為0,每次分配描述符后設置*/unsigned int next_fd;/*執行execve()系統調用時關閉文件的位圖*/unsigned long close_on_exec_init[1];/*打開文件位圖*/unsigned long open_fds_init[1];unsigned long full_fds_bits_init[1];/*打開文件file指針數組*/struct file __rcu * fd_array[NR_OPEN_DEFAULT];
};
files_struct結構體主要成員簡介如下:
open_fds_init[1]:進程打開文件位圖,與打開文件file指針數組對應,每個比特位對應數組項是否為空,1表示數組項關聯了file實例
fdt:fdtable結構體指針,初始值指向fdtab成員
fd_array[]:file指針數組,數組項指向file實例,指針數組項索引為文件描述符,無符號整數。數組項數NR_OPEN_DEFAULT與整型數比特位數相同。
fdtab:fdtable結構體成員,用于管理文件位圖,其定義如下(include/linux/fdtable.h)
struct fdtable {unsigned int max_fds;    /fdtable能管理的打開文件最大數量,由位圖大小決定/struct file __rcu **fd;  /指向file指針數組的指針/unsigned long *close_on_exec;  /執行execve()系統調用時關閉文件的位圖/unsigned long *open_fds;  /進程打開文件位圖/unsigned long *full_fds_bits;struct rcu_head rcu;
};

文件位圖就是file指針數組對應的位圖,每位對應指針數組中一項,比特位位置就是數組項索引,即文件描述符

進程打開的文件由file結構體表示,結構體定義在include/linux/fs.h頭文件:

struct file {union {struct llist_node	fu_llist;           /*單鏈表成員*/struct rcu_head 	fu_rcuhead;} f_u;struct path		f_path;                   /*文件路徑信息*/struct inode		*f_inode;	              /*指向內核文件inode實例*/const struct file_operations	*f_op;    /*文件操作結構指針,通常在打開文件時設為inode->i_fop*/ /** Protects f_ep_links, f_flags.* Must not be taken from IRQ context.*/spinlock_t		f_lock;atomic_long_t		f_count;unsigned int 		f_flags;      /*系統調用傳遞的flags標記參數*/fmode_t			f_mode;           /*標記進程以何種模式打開文件*/struct mutex		f_pos_lock;loff_t			f_pos;            /*文件當前讀寫位置,相對于文件開頭處的字節偏移量*/struct fown_struct	f_owner;const struct cred	*f_cred;struct file_ra_state	f_ra;u64			f_version;
#ifdef CONFIG_SECURITYvoid			*f_security;
#endif/* needed for tty driver, and maybe others */void			*private_data;      /*文件私有數據指針,例如設備文件指向驅動程序定義的數據結構*/#ifdef CONFIG_EPOLL/* Used by fs/eventpoll.c to link all the hooks to this file */struct list_head	f_ep_links;struct list_head	f_tfile_llink;
#endif /* #ifdef CONFIG_EPOLL */struct address_space	*f_mapping; /*文件地址空間指針 */
} __attribute__((aligned(4)));

系統調用

在這里插入圖片描述

open(), read(), write() 等函數都是以 file descriptor 為對象。而實際上這件事牽扯到 3 個對象:

  1. 每個進程自己看到的 file descriptor (進程視角)
  2. open file table (系統視角)
  3. inode:文件真正的 inode (文件視角)

在這里插入圖片描述

open

open負責在內核生成與文件相對應的struct file元數據結構,并且與文件系統中該文件的struct inode進行關聯,裝載對應文件系統的操作回調函數,然后返回一個int fd給用戶進程。后續用戶對該文件的相關操作,會涉及到其相關的struct file、struct inode、inode->i_op、inode->i_fop和inode->i_mapping->a_ops等。

在讀寫文件之前,我們必須打開文件,從應用程序的角度來看,這是通過標準庫的open函數來完成的,該函數返回一個文件描述符,會調用fs/open.c中的sys_open函數,代碼流程如下所示:

在這里插入圖片描述

  1. PathWalk找到目標文件
  2. 構造并初始化inode
  3. 構造并初始化file

在這里插入圖片描述

do_filp_open()函數要完成打開文件操作最重要、最繁重的工作,函數內需要創建文件file實例,遍歷文件路徑中每個分量,在內核根文件系統中搜索/創建對應的dentry和inode結構體實例,當到達最末尾分量時(文件名稱),將其inode實例(文件inode)與file實例建立關聯。因此,do_filp_open()函數執行的主要工作可概括為從路徑到節點,即由文件路徑確定文件inode實例,賦予file實例

write

用戶進程寫文件內容操作的系統調用為write(),其實現與讀操作非常相似,系統調用定義如下:
_vfs_write()函數內優先調用file->f_op->write()函數執行寫文件操作,如果沒有定義此函數則調用通用的同步寫函數**new_sync_write()**完成寫操作。同步寫操作通常是先將數據寫入文件內容緩存,然后在適當的時候同步(寫入)到介質文件系統

在這里插入圖片描述

read

read的讀邏輯中包含預期readahead的邏輯,其可以通過與fadvise的配合達到文件預取的效果。用戶進程讀文件內容的read()系統調用定義如下(/fs/read_write.c):

在這里插入圖片描述

總體框架

在這里插入圖片描述

進程1和進程2都打開同一文件,但是對應不同的file 結構體,因此可以有不同的File Status Flag和讀寫位置。file 結構體中比較重要的成員還有f_count,表示引用計數(Reference Count),如dup 、fork 等系統調用會導致多個文件描述符指向同一 個file 結構體,例如有fd1 和fd2 都引用同一個file 結構體,那么它的引用計數就是2,,當close(fd1) 時并不會釋放file 結構體,而只是把引用計數減到1,如果再close(fd2) ,引用計數 就會減到0同時釋放file 結構體,這才真的關閉了文件。

每個file 結構體都有一個指向dentry結構體的指針,“dentry”是directory entry(目錄項)的縮寫。 我們傳給open 、stat 等函數的參數的是一個路徑,如/home/akaedu/a ,需要根據路徑找到文件 的inode。為了減少讀盤次數,內核緩存了目錄的樹狀結構,稱為dentry cache,其中每個節點是一 個dentry結構體,只要沿著路徑各部分的dentry搜索即可,從根目錄/找到home 目錄,然后找 到akaedu目錄,然后找到文件a。dentry cache只保存最近訪問過的目錄項,如果要找的目錄項 在cache中沒有,就要從磁盤讀到內存中。

每個dentry結構體都有一個指針指向inode 結構體。inode 結構體保存著從磁盤inode讀上來的信 息。在上圖的例子中,有兩個dentry,分別表示/home/akaedu/a 和/home/akaedu/b ,它們都指向同 一個inode,說明這兩個文件互為硬鏈接。inode 結構體中保存著從磁盤分區的inode讀上來信息,,例如所有者、文件大小、文件類型和權限位等。每個inode 結構體都有一個指向inode_operations結 構體的指針,后者也是一組函數指針指向一些完成文件目錄操作的內核函數。

和file_operations 不同,inode_operations所指向的不是針對某一個文件進行操作的函數,而是影響文件和目錄布局的函數,例如添加刪除文件和目錄、跟蹤符號鏈接等等,屬于同一文件系統的 各inode 結構體可以指向同一個inode_operations結構體。 inode 結構體有一個指向super_block結構體的指針。super_block結構體保存著從磁盤分區的超級塊 讀上來的信息,例如文件系統類型、塊大小等。super_block結構體的s_root成員是一個指 向dentry的指針,表示這個文件系統的根目錄被mount 到哪里,在上圖的例子中這個分區 被mount 到/home 目錄下。

address_space結構體,一個address_space管理了一個文件在內存中緩存的所有pages。address_space 結構其中的一個作用就是用于存儲文件的 頁緩存,一個inode對應一個page cache對象,一個page cache對象包含多個物理page。詳細的可以參考Linux內核學習筆記(八)Page Cache與Page回寫
host:指向當前 address_space 對象所屬的文件 inode 對象(每個文件都使用一個 inode 對象表示)。
page_tree:用于存儲當前文件的 頁緩存。
tree_lock:用于防止并發訪問 page_tree 導致的資源競爭問題。
其對應詳細的數據結構如下圖所示

在這里插入圖片描述

Linux 磁盤高速緩存機制

緩存I/O又被稱作標準I/O,目前大多數操作系統中的文件系統的默認I/O操作都是緩存I/O。在Linux的緩存I/O機制中,數據先從磁盤復制到內核空間的緩沖區,然后從內核空間緩沖區復制到應用程序的地址空間。緩存I/O使用操作系統內核緩沖區,在一定程度上分離了應用程序空間與實際的物理設備,它能夠減少讀取磁盤的次數,進而提高I/O效率。
?? 讀操作:操作系統檢查內核的緩沖區有沒有需要的數據,如果已經緩存了,那么就直接從緩存中返回;否則從磁盤中讀取,然后緩存在操作系統的緩存中。

讀取: 硬盤 ->內核緩沖區 -> 用戶緩沖區
?? 寫操作:將數據從用戶空間復制到內核空間的緩存中。這時對用戶程序來說寫操作就已經完成,至于什么時候再寫到磁盤中由操作系統決定,除非顯示地調用了sync同步命令。
寫入: 用戶緩沖區->內核緩沖區 ->硬盤
正常的系統調用read/write的流程如下:

read: 硬盤 ->內核緩沖區 -> 用戶緩沖區
write: 數據會從用戶地址空間拷貝到操作系統內核地址空間的page cache中,這時write就會直接返回,操作系統會在恰當的時候將其刷至磁盤。
?? 緩存I/O的缺點:數據在傳輸過程中需要在應用程序地址空間和緩存之間進行多次數據拷貝操作,這些數據拷貝操作所帶來的CPU以及內存開銷是非常大的。

標準文件訪問

在 Linux 操作系統中中,通過兩個系統調用( read() 和 write())來實現文件訪問。。當應用程序調用 read() 系統調用讀取一塊數據的時候,如果該塊數據已經在內存中了,那么就直接從內存中讀出該數據并返回給應用程序;如果該塊數據不在內存中,那么數據會被從磁盤 上讀到頁高緩存中去,然后再從頁緩存中拷貝到用戶地址空間中去。如果一個進程讀取某個文件,那么其他進程就都不可以讀取或者更改該文件;對于寫數據操作來 說,當一個進程調用了 write() 系統調用往某個文件中寫數據的時候,數據會先從用戶地址空間拷貝到操作系統內核地址空間的頁緩存中去,然后才被寫到磁盤上(圖1)。但是對于這種標準的訪問文件的 方式來說,在數據被寫到頁緩存中的時候,write() 系統調用就算執行完成,并不會等數據完全寫入到磁盤上。在Linux 中稱為延遲寫機制( deferred writes )。

在這里插入圖片描述

同步文件訪問

同步訪問文件的方式與上述標準訪問文件方式相類似,這兩種方法最大區別就是:同步訪問文件的時候,寫數據的操作是在數據完全被寫回磁盤上才算完成的(圖2);而標準訪問文件方式的寫數據操作是在數據被寫到頁高速緩沖存儲器中的時候就算執行完成了。

在這里插入圖片描述

異步文件訪問

Linux 異步訪問文件其本質思想:進程發出數據傳輸請求之后,進程不會被阻塞,也不用等待任何操作完成,進程可以在數據傳輸的時候繼續執行其他的操作(圖5)。相比于同步訪問文件的方式來說,異步訪問文件的方式可以提高應用程序的效率,并且提高系統資源利用率。
在這里插入圖片描述

buffer_head

正常的文件訪問都是先寫入內存緩存并不會直接落盤,buffer_head就是實現這個操作的關鍵。

buffer_head是磁盤塊的一個抽象,一個buffer_head對應一個磁盤塊,buffer_head中保存對應的磁盤號

buffer_head把page與磁盤塊聯系起來,由于page和磁盤塊的大小可能不一樣,所以一個page可能管理多個buffer_head
這里假設page大小4K,塊大小為1K, buffer_head,page和磁盤塊關系如下:

在這里插入圖片描述

如何實現一個簡單的文件系統

blkdevfs

以blkdevfs為例 先看一下如何實現一個簡單的文件系統

編寫文件系統涉及一些基本數據結構。需要建立一個結構,4個操作表,如下所示。

文件系統類型結構(file_system_type);
超級塊操作表(super_operations);
索引結點操作表(inode_operations);
頁緩沖區表(address_space_operations);
文件操作表(file_operations)。

以上基本數據結構和操作函數,貫穿了整個文件系統的主要過程,下面具體分析這幾個結構和文件系統實現的要點。
一個通常意義上的文件系統驅動可以單獨被編譯成模塊動態加載,也可以被直接編譯到內核中,為了調試的方便,本文中的文件系統采用動態加載的方式實現。實現一個文件系統必須遵照內核的一些“規則”,以下我將以遞進的順序闡述文件系統的實現過程。
文件系統既然基于可加載內核模塊,自然也需要實現module_init以及mocule_exit,就從module_init函數開始入手。
首先,必須建立一個文件系統類型(file_system_type)來描述文件系統,它含有文件系統的名稱、類型標志以及get_sb()等操作。當安裝文件系統時,系統會對該文件系統進行注冊,即填充file_system_type結構,然后調用get_sb()函數來建立該文件系統的超級塊。
對于特定的文件系統, 該文件系統的所有的superblock 都存在于file_sytem_type中的fs_supers鏈表中,而所有的文件系統,都存在于file_systems鏈表中。通過調用register_filesystem接口來注冊文件系統,將一個新的文件系統類型加入到鏈表中。

在這里插入圖片描述

注冊文件系統

int register_filesystem(struct file_system_type * fs)
注冊成功以后,需要對文件系統進行掛載,因為是基于內存的文件系統,沒有實際的磁盤,無法使用命令進行掛載,所以在模塊初始化的時候使用內核函數kern_mount進行掛載。掛載主要完成的任務是調用file_system_type中的 mount方法,通過該方法獲取該文件系統的根目錄dentry,同時也獲取super_block.。file_system_type的mount方法kernel也提供了已經實現的函數:mount_single,mount_pseudo等。
接下來創建若干文件和目錄,用于后面進行讀寫操作。創建文件和目錄會在向內核申請inode、dentry結構體,并且對其中的主要成員變量進行初始化。

在這里插入圖片描述

當實現完成這個數據結構之后,就可以直接mount一個塊設備了。

在mount的時候 blkdevfs具有這樣的調用流程

.mount
  ->blkdevfs_mount
    ->blkdevfs_fill_supper

在blkdevfs_fill_supper中必須要填充一個全局的supper_block,和一個象征著掛載第一級目錄的root_inode。

上圖是blkdevfs_fill_supper 的具體實現。

產生一個文件

完成上面的步驟之后因為對于根目錄的inode和file_inde_operations都還沒有實現,所以雖然文件系統可以成功掛載但是還是無法進行任何操作,ls看不到任何文件。

所以下一步需要產生一個文件。

需要填充兩個結構體。
在這里插入圖片描述

這兩個結構體就是目錄的主要操作接口

其中

blkdevfs_iterate的作用主要就是查找該目錄下存在的文件

blkdevfs_lookup的作用在于查找每一個文件的基本信息,如果該文件對應的inode還沒有生成則需要生成該文件對應的inode

因為只會實現一個單文件的文件系統所以這兩個函數的實現就變得非常簡單

當你在目錄中第一次運行ls的時候,就會先后調用iterate和lookup,之后再調用ls就只會調用iterate。

讓文件變得可讀可寫

通過上面的實現我們可以發現當運行ls的時候你掛載的文件系統就可以顯示出一個文件就像這樣:

在這里插入圖片描述

但是僅僅是這樣這個文件系統還是沒有作用的我們需要讓這個文件系統變得可讀可寫。

和目錄的操作一樣 為了讓你的文件變得具有作用也要實現兩個結構體分別是:

在這里插入圖片描述

這兩個結構體需要在第一次創建inode的時候完成填充。其中file_operations中填充的函數都是通用的,系統已經完成了具體實現,那么我們需要做些什么呢。

我們需要實現aops接口

在這里插入圖片描述

這個結構體也是在lookup 第一次創建Inode的時候進行填充,它是用于管理文件(struct inode)映射到內存的頁面(struct page)的,其實就是每個file都有這么一個結構,將文件系統中這個file對應的數據與這個file對應的內存綁定到一起;與之對應,address_space_operations 就是用來操作該文件映射到內存的頁面,比如把內存中的修改寫回文件、從文件中讀入數據到頁面緩沖等。

在read 這個文件的時候 blkdevfs具有這樣的調用流程
在這里插入圖片描述

mpage_readpage是系統實現的一個通用的讀取一個page的接口,而readpage會調用文件系統提供的函數指針。

這個函數實現的功能十分簡單,就是將想要訪問的page進行map操作。

如此這個簡單的文件系統就可以讀了,寫也是類似的。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/13710.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/13710.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/13710.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

OGG幾何內核-BRepBuilderAPI_MakeEdge學習

OGG幾何內核fork自OCCT 7.7.0, BRepBuilderAPI_MakeEdge是幾何內核的一個重要和基礎的功能,也十分復雜,因為要支持line、circle、ellipse,parabola,hyperbola,circle,beziercurve,b…

springboot常用的注解

啟動注解(Spring Boot 應用的入口注解)@SpringBootApplication @SpringBootApplication 是一個注解,它是 Spring Boot 應用的入口注解,用于表示一個應用程序的主類。這個注解通常被放置在包含 main() 方法的類上。@SpringBootApplication 是一個組合注解,整合了以下三個注…

亞馬遜測評還能做嗎?

只能說測評不是唯一的手段,但是推銷量的一把好手。首先測評能讓listing快速成長,短期內有望成為爆款,速度快,利潤高,回款快。相對其他推廣,測評無疑是有效,省培養listing的方法。其次新品前期太…

設計模式六大原則

開閉原則:對修改封閉,對拓展開放。 單一職責原則:類的功能要專一。 里氏代換原則:子類繼承父類的時候,除添加新的方法完成新增功能外,盡量不要重寫父類方法。 依賴倒轉原則:類要依賴接口&…

Hsql每日一題 | day01

前言 就一直向前走吧,沿途的花終將綻放~ 題目:找出連續活躍3天及以上的用戶 create table t_useractive(uid string,dt string );insert into t_useractive values(A,2023-10-01),(A,2023-10-02),(A,2023-10-03),(A,2023-10-04),(B,2023-10-01),(B…

代碼隨想錄打卡第38天:動態規劃解決編輯距離和回文串

1.72編輯距離 1.問題描述 找到其中需要進行操作的最少次數。 2.問題轉換 大體思路可以參照前面的兩個字符串的刪除操作。添加操作可以將其看做是一個另類的刪除操作,所以最后全部都可以看做是一個刪除操作 3.解題思路 每一個位置的word1[i]和word2[j]都有兩種…

RTOS原理和應用總結

RTOS的作用 RTOS一般應用在中低端處理器當中,這里舉一個筆者日常開發遇到的案例來說明RTOS的作用。 假設你有一個設備,這個設備的外圍硬件很多,假設有LED、一個網口、若干RS232等等。 在沒有RTOS的時候,我們用裸機編程來寫&…

HTML5 多媒體應用技術

目錄 多媒體元素 audio元素video元素多媒體事件與JavaScript交互音頻和視頻軌道(Track)媒體API MediaElement APIMediaSource Extensions (MSE)Encrypted Media Extensions (EME)Web Audio API

數據庫同步軟件,天不生PanguSync萬古如長夜

在信息時代的海洋中,數據是那永不熄滅的燈塔,照亮了科技發展的航道。然而,隨著數據的膨脹和應用場景的多樣化,如何確保這些寶貴資源在不同平臺、不同設備間實時更新、保持一致性,便成了一道亟待解決的難題。于是&#…

Android File Transfer for mac(強大的安卓文件傳輸工具) 直裝版

Android File Transfer是一款專門為Mac用戶設計的軟件,它用于在Android設備與Mac之間傳輸文件。這款軟件提供了簡單直觀的操作界面,使用戶能夠輕松地在Android設備和Mac之間傳輸和管理文件。 下載地址:https://www.macz.com/mac/7099.html?i…

使用python實現socket進行消息傳輸-demo

Socket 是什么 Socket 是一種在計算機網絡中用于實現進程間通信的一種機制。它是網絡編程中的重要概念,通過它可以在不同的計算機之間進行數據傳輸和通信。Socket 可以用于實現各種網絡應用,包括客戶端-服務器模型、P2P 應用等。基本上,Sock…

自動駕駛決策規劃算法——二次規劃

自動駕駛決策規劃算法第二章第二節(中) 參考線算法_嗶哩嗶哩_bilibili 動態規劃開辟的凸空間如下,兩條橙色線之間: 黃色的點就意味著L的上下界,物理意義是當軌跡ss1時,L的范圍應該是(Lmin1,Lmax1)之間,這個范圍就是開辟…

學習日記.1

今天就是配置了droidbot的環境。主要的知識來源是GitHub - xieincz/droidbot: A lightweight test input generator for Android. Similar to Monkey, but with more intelligence and cool features! 看readme,注意只需要platform就好,sdk太大不用下載…

《Ai企業知識庫》-模型實踐-rasa開源學習框架-基礎理論-02

rasa官網 Conversational AI Platform | Superior Customer Experiences Start Here rasa簡介: Rasa是一個開源的機器學習框架,專門用于構建自動化的文本和語音對話系統,即聊天機器人。它允許開發者和企業創建定制化的對話體驗&#xff0c…

ubuntu設置root開機登錄,允許root用戶ssh遠程登錄

ubuntu與centos系統不同,默認root開機不能登錄。 1、輸入一下命令創建root密碼,根據提示輸入新密碼 sudo passwd root 2、打開gdm-autologin文件,將auth required pam_succeed_if.so user ! root quiet_success這行注釋掉,這行就…

el-upload 上傳多個視頻

<el-form-item label"視頻" prop"video_url"><el-uploadclass"upload-demo"ref"uploadRef":multiple"true":on-change"handleChange":before-remove"beforeRemove":before-upload"before…

Flutter 中的 EditableText 小部件:全面指南

Flutter 中的 EditableText 小部件&#xff1a;全面指南 在Flutter中&#xff0c;EditableText是一個低級別的文本編輯組件&#xff0c;它提供了構建自定義文本編輯界面的能力。與TextField和TextFormField不同&#xff0c;EditableText提供了更多的靈活性&#xff0c;允許開發…

【LinuxC語言】鏈接文件

文章目錄 前言一、inode索引節點inode的作用為什么inode重要 二、文件鏈接的定義文件鏈接是什么硬鏈接&#xff08;Hard Link&#xff09;軟鏈接&#xff08;符號鏈接&#xff0c;Symbolic Link&#xff09;硬鏈接圖示&#xff1a;軟鏈接圖示&#xff1a; 硬鏈接應用場景限制和…

五步定位性能瓶頸

一、著手測試前的準備&#xff1a;優化數據流向與系統架構分析 在進行性能測試或系統優化之前&#xff0c;明確數據流向和系統架構的細節是至關重要的步驟。這不僅能夠幫助識別潛在的瓶頸&#xff0c;還能確保測試用例設計的全面性與針對性。以下是關鍵步驟和方法&#xff1a;…

實現本地訪問云主機,以及在云主機搭建FTP站點

前言 云計算是一種基于互聯網的計算模式&#xff0c;通過網絡提供按需訪問的計算資源和服務。核心概念是把計算能力視作一種公共資源&#xff0c;用戶可以根據自身需求動態分配和管理這些資源。 云主機 ECS (Elastic Compute Server)是一種按需獲取的云端服務器&#xff0c;提…