操作系统真象还原:创建文件系统

news2024/11/15 21:27:26

14.2 创建文件系统

14.2.1 创建超级块、i结点、目录项

超级块

/*
 * @Author: Adward-DYX 1654783946@qq.com
 * @Date: 2024-05-07 10:18:02
 * @LastEditors: Adward-DYX 1654783946@qq.com
 * @LastEditTime: 2024-05-07 11:24:50
 * @FilePath: /OS/chapter14/14.2/fs/super_block.h
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#ifndef __FS_SUPER_BLOCK_H
#define __FS_SUPER_BLOCK_H
#include "global.h"
#include "stdint.h"

/*超级块*/
struct super_block{
    uint32_t magic; //用来标识文件系统类型,支持多文件系统的操作系统通过此标志来识别文件系统的类型
    uint32_t sec_cnt;   //本分区总共的扇区数
    uint32_t inode_cnt; //本分区中ino数量
    uint32_t part_lba_base; //本分区的起始lba地址

    uint32_t block_bitmap_lba;  //块位图本身起始扇区地址
    uint32_t block_bitmap_sects; //扇区位图本身所占用的扇区数量

    uint32_t inode_bitmap_lba;  //i结点位图起始扇区lba地址
    uint32_t inode_bitmap_sects;    //i结点位图占用的扇区数量
    
    uint32_t inode_table_lba;   //i结点表起始扇区lba地址
    uint32_t inode_table_sects; //i结点表占用的扇区数量

    uint32_t data_start_lba;    //数据区开始的第一个扇区号
    uint32_t root_inode_no;    //根目录所在的i节点号
    uint32_t dir_entry_size;    //目录项大小

    uint8_t pad[460];   //加上460字节,凑足512字节1扇区的大小
}__attribute__ ((packed));

#endif // !__FS_SUPER_BLOCK_H

inode节点

/*
 * @Author: Adward-DYX 1654783946@qq.com
 * @Date: 2024-05-07 10:26:42
 * @LastEditors: Adward-DYX 1654783946@qq.com
 * @LastEditTime: 2024-05-07 10:35:50
 * @FilePath: /OS/chapter14/14.2/fs/inode.h
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#ifndef __FS_INODE_H
#define __FS_INODE_H

#include "stdint.h"
#include "list.h"

/*inode结构*/
struct inode{
    uint32_t i_no;  //inode编号
    /*当次inode是文件时,i_size是指文件大小,若是目录,则是指该目录下所有目录项大小之和*/
    uint32_t i_size;

    uint32_t i_open_cnts;   //记录此文件被打开的次数
    bool write_deny;    //写文件不能并行,进程写文件前检查此标识

    /* 咱们的块大小就是 1 扇区 ,i_sectors[0-11]是直接块,i_sectors[12]用来存储一级间接块指针*/
    /*不过稍微不同的是扇区大小是 512 字节,并且块地址用 4 字节来表示,因此咱们支持的一级间接块数量是 128 个,即咱们总共支持 128+12= 140 个块(扇区)*/
    uint32_t i_sectors[13];
    /*由于 inode 是从硬盘上保存的 , 文件被打开时, 肯定是先要从硬盘上载入其 inode,但硬盘比较
    慢, 为了避免下次再打开该文件时还要从硬盘上重复载入 inode,应该在该文件第一次被打开时就将其 inode
    加入到 内存缓存中,每次打开一个文件时,先在此缓冲中查找相关的 inode , 如果有就直接使用, 否则再从硬
    盘上读取 inode,然后再加入此缓存。 这个内存缓存就是“己打开的 inode 队列”*/
    struct list_elem inode_tag;
};

#endif // !__FS_INODE_H

目录

/*
 * @Author: Adward-DYX 1654783946@qq.com
 * @Date: 2024-05-07 10:35:58
 * @LastEditors: Adward-DYX 1654783946@qq.com
 * @LastEditTime: 2024-05-07 15:41:12
 * @FilePath: /OS/chapter14/14.2/fs/dir.h
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#ifndef _FS_DIR_H
#define _FS_DIR_H
#include "stdint.h"
#include "inode.h"
#include "fs.h"
#include "global.h"

#define MAX_FILE_NAME_LEN 16    //最大文件名长度

/*目录结构*/
struct dir{
    struct inode* inode;
    uint32_t dir_pos;   //记录在目录内的偏移
    uint8_t dirr_buf[512];  //目录的数据缓存
};

/*目录项结构*/
struct dir_entry{
    char filename[MAX_FILE_NAME_LEN];   //普通文件或目录名称
    uint32_t i_no;  //普通文件或目录对应的inode编号
    enum file_types f_type; //文件类型
};

#endif // !_FS_DIR_H

注:目录的数据结构struct dir只会存在于内存之中,因为它管理的是对一个目录文件的操作(比如打开一个目录文件,就会在内存中创建这样一个结构体)。

文件类型的定义

/*
 * @Author: Adward-DYX 1654783946@qq.com
 * @Date: 2024-05-07 11:06:32
 * @LastEditors: Adward-DYX 1654783946@qq.com
 * @LastEditTime: 2024-05-07 15:29:03
 * @FilePath: /OS/chapter14/14.2/fs/fs.h
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#ifndef _FS_FS_H
#define _FS_FS_H
#include "stdint.h"

#define MAX_FILES_PER_PART 4096 //每个分区所支持最大创建的文件数
#define BITS_PER_SECTOR 4096    //每扇区的位数
#define SECTOR_SIZE 512 //扇区字节大小
#define BLOCK_SIZE SECTOR_SIZE  //块字节大小

/*文件类型*/
enum file_types{
    FT_UNKNOWN, //不支持的文件类型
    FT_REGULAR, //普通文件
    FT_DIRECTORY    //目录
};

void filesys_init(void);
#endif // !_FS_FS_H

14.2.2 创建文件系统

这里书上的创建的文件系统有一定的问题,我这里直接是学习的另外一个博主的地址如下:《操作系统真象还原》 第十四章 文件系统-CSDN博客

其代码如下:

#include "stdint.h"
#include "fs.h"
#include "inode.h"
#include "ide.h"
#include "memory.h"
#include "super_block.h"
#include "dir.h"
#include "stdio-kernel.h"
#include "string.h"



/* 格式化分区,也就是初始化分区的元信息,创建文件系统 */
static void partition_format(struct partition* part) {
    /* 为方便实现,一个块大小是一扇区 */
    uint32_t boot_sector_sects = 1;	  
    uint32_t super_block_sects = 1;
    uint32_t inode_bitmap_sects = DIV_ROUND_UP(MAX_FILES_PER_PART, BITS_PER_SECTOR);	   // I结点位图占用的扇区数.最多支持4096个文件
    uint32_t inode_table_sects = DIV_ROUND_UP(((sizeof(struct inode) * MAX_FILES_PER_PART)), SECTOR_SIZE);
    uint32_t used_sects = boot_sector_sects + super_block_sects + inode_bitmap_sects + inode_table_sects;
    uint32_t free_sects = part->sec_cnt - used_sects;  

    /************** 简单处理块位图占据的扇区数 ***************/
    uint32_t now_total_free_sects = free_sects; // 定义一个现在总的可用扇区数
    uint32_t prev_block_bitmap_sects = 0; // 之前的块位图扇区数
    uint32_t block_bitmap_sects = DIV_ROUND_UP(now_total_free_sects, BITS_PER_SECTOR); // 初始估算
    uint32_t block_bitmap_bit_len;

    while (block_bitmap_sects != prev_block_bitmap_sects) {
        prev_block_bitmap_sects = block_bitmap_sects;
        /* block_bitmap_bit_len是位图中位的长度,也是可用块的数量 */
        block_bitmap_bit_len = now_total_free_sects - block_bitmap_sects;
        block_bitmap_sects = DIV_ROUND_UP(block_bitmap_bit_len, BITS_PER_SECTOR);
    }
    /*********************************************************/
    
    /* 超级块初始化 */
    struct super_block sb;
    sb.magic = 0x19590318;
    sb.sec_cnt = part->sec_cnt;
    sb.inode_cnt = MAX_FILES_PER_PART;
    sb.part_lba_base = part->start_lba;

    sb.block_bitmap_lba = sb.part_lba_base + 2;	 // 第0块是引导块,第1块是超级块
    sb.block_bitmap_sects = block_bitmap_sects;

    sb.inode_bitmap_lba = sb.block_bitmap_lba + sb.block_bitmap_sects;
    sb.inode_bitmap_sects = inode_bitmap_sects;

    sb.inode_table_lba = sb.inode_bitmap_lba + sb.inode_bitmap_sects;
    sb.inode_table_sects = inode_table_sects; 

    sb.data_start_lba = sb.inode_table_lba + sb.inode_table_sects;  //数据区的起始就是inode数组的结束
    sb.root_inode_no = 0;
    sb.dir_entry_size = sizeof(struct dir_entry);

    printk("%s info:\n", part->name);
    printk("   magic:0x%x\n   part_lba_base:0x%x\n   all_sectors:0x%x\n   inode_cnt:0x%x\n   block_bitmap_lba:0x%x\n   block_bitmap_sectors:0x%x\n   inode_bitmap_lba:0x%x\n   inode_bitmap_sectors:0x%x\n   inode_table_lba:0x%x\n   inode_table_sectors:0x%x\n   data_start_lba:0x%x\n", sb.magic, sb.part_lba_base, sb.sec_cnt, sb.inode_cnt, sb.block_bitmap_lba, sb.block_bitmap_sects, sb.inode_bitmap_lba, sb.inode_bitmap_sects, sb.inode_table_lba, sb.inode_table_sects, sb.data_start_lba);

    struct disk* hd = part->my_disk;
    /*******************************
     * 1 将超级块写入本分区的1扇区 *
     ******************************/
    ide_write(hd, part->start_lba + 1, &sb, 1);
    printk("   super_block_lba:0x%x\n", part->start_lba + 1);

    /* 找出数据量最大的元信息,用其尺寸做存储缓冲区*/
    uint32_t buf_size = (sb.block_bitmap_sects >= sb.inode_bitmap_sects ? sb.block_bitmap_sects : sb.inode_bitmap_sects);
    buf_size = (buf_size >= sb.inode_table_sects ? buf_size : sb.inode_table_sects) * SECTOR_SIZE;
    uint8_t* buf = (uint8_t*)sys_malloc(buf_size);	// 申请的内存由内存管理系统清0后返回
    
    /**************************************
     * 2 将块位图初始化并写入sb.block_bitmap_lba *
     *************************************/
    /* 初始化块位图block_bitmap */
    buf[0] |= 0x01;       // 第0个块预留给根目录,位图中先占位
    uint32_t block_bitmap_last_byte = block_bitmap_bit_len / 8; //计算出块位图最后一字节的偏移
    uint8_t  block_bitmap_last_bit  = block_bitmap_bit_len % 8; //计算出块位图最后一位的偏移
    uint32_t last_size = SECTOR_SIZE - (block_bitmap_last_byte % SECTOR_SIZE);	     // last_size是位图所在最后一个扇区中,不足一扇区的其余部分

    /* 1 先将位图最后一字节到其所在的扇区的结束全置为1,即超出实际块数的部分直接置为已占用*/
    memset(&buf[block_bitmap_last_byte], 0xff, last_size);
    
    /* 2 再将上一步中覆盖的最后一字节内的有效位重新置0 */
    uint8_t bit_idx = 0;
    while (bit_idx < block_bitmap_last_bit) {
        buf[block_bitmap_last_byte] &= ~(1 << bit_idx++);
    }
    ide_write(hd, sb.block_bitmap_lba, buf, sb.block_bitmap_sects);

    /***************************************
     * 3 将inode位图初始化并写入sb.inode_bitmap_lba *
     ***************************************/
    /* 先清空缓冲区*/
    memset(buf, 0, buf_size);
    buf[0] |= 0x1;      // 第0个inode分给了根目录
    /* 由于inode_table中共4096个inode,位图inode_bitmap正好占用1扇区,
        * 即inode_bitmap_sects等于1, 所以位图中的位全都代表inode_table中的inode,
        * 无须再像block_bitmap那样单独处理最后一扇区的剩余部分,
        * inode_bitmap所在的扇区中没有多余的无效位 */
    ide_write(hd, sb.inode_bitmap_lba, buf, sb.inode_bitmap_sects);

    /***************************************
     * 4 将inode数组初始化并写入sb.inode_table_lba *
     ***************************************/
    /* 准备写inode_table中的第0项,即根目录所在的inode */
    memset(buf, 0, buf_size);  // 先清空缓冲区buf
    struct inode* i = (struct inode*)buf; 
    i->i_size = sb.dir_entry_size * 2;	 // .和..
    i->i_no = 0;   // 根目录占inode数组中第0个inode
    i->i_sectors[0] = sb.data_start_lba;	     // 由于上面的memset,i_sectors数组的其它元素都初始化为0 
    ide_write(hd, sb.inode_table_lba, buf, sb.inode_table_sects);
    
    /***************************************
     * 5 将根目录初始化并写入sb.data_start_lba
     ***************************************/
    /* 写入根目录的两个目录项.和.. */
    memset(buf, 0, buf_size);
    struct dir_entry* p_de = (struct dir_entry*)buf;

    /* 初始化当前目录"." */
    memcpy(p_de->filename, ".", 1);
    p_de->i_no = 0;
    p_de->f_type = FT_DIRECTORY;
    p_de++;

    /* 初始化当前目录父目录".." */
    memcpy(p_de->filename, "..", 2);
    p_de->i_no = 0;   // 根目录的父目录依然是根目录自己
    p_de->f_type = FT_DIRECTORY;

    /* sb.data_start_lba已经分配给了根目录,里面是根目录的目录项 */
    ide_write(hd, sb.data_start_lba, buf, 1);

    printk("   root_dir_lba:0x%x\n", sb.data_start_lba);
    printk("%s format done\n", part->name);
    sys_free(buf);
}

下面再写一个函数filesys_init遍历所有分区,如果该分区没有文件系统就调用partition_format来创建文件系统

/*在磁盘上搜索文件系统,若没有则格式化分区创建文件系统*/
void filesys_init(void){
    uint8_t channel_no = 0, dev_no, part_idx = 0;
    /*sb_buf用来存储从硬盘上读入的超级块*/
    struct super_block* sb_buf = (struct super_block*)sys_malloc(SECTOR_SIZE);
    
    if(sb_buf == NULL){
        PANIC("alloc memory failed!");
    }
    printk("searching  filesystem.......\n");
    while(channel_no < channel_cnt){
        dev_no = 0;
        while(dev_no<2){
            if(dev_no == 0){    //跨过裸盘hd60M.img
                dev_no++;
                continue;
            }
            struct disk* hd = &channels[channel_no].devices[dev_no];
            struct partition* part = hd->prim_parts;
            while(part_idx < 12){   //4个主分区+8个逻辑分区
                if(part_idx == 4){  //开始处理逻辑分区
                    part = hd->logic_parts;
                }

                /**
                 * channels数组是全局变量,默认值为0,disk属于其嵌套结构,
                 * partition又为disk的嵌套结构,因此partition中的成员默认也为0
                 * 若partition未初始化,则partition中的成员扔为0
                 * 下面处理存在的分区
                */
               if(part->sec_cnt!=0){    //如果分区存在
                    memset(sb_buf,0,SECTOR_SIZE);

                    /*独处分区的超级块,更具魔数是否正确判断是否存在文件系统*/
                    ide_read(hd,part->start_lba+1,sb_buf,1);

                    /*只支持自己的文件系统,若磁盘上已经有文件系统就不在格式化了*/
                    if(sb_buf->magic == 0x19590318){
                        printk("%s has filesystem\n",part->name);
                    }else{  //其他文件系统不支持,一律按无文件系统处理
                        printk("formatting %s`s partition %s........\n",hd->name,part->name);
                        partition_format(part);
                    }
                }
                part_idx++;
                part++; //下一分区
            }
            dev_no++;//下一磁盘
        }
        channel_no++;//下一通道
    }
    sys_free(sb_buf);
    /*确定默认操作的分区*/
    char default_part[8] = "sdb1";
    /*挂载分区*/
    list_traversal(&partition_list,mount_partition,(int)default_part);
}
14.2.3 挂载分区

Linux 内核所在的分区是默认分区,自系统启动后就以该分区为默认分区,该分区的根目录是固定存在的,要想使用其他新分区的话,需要用 mount 命令手动把新的分区挂载到默认分区的某个目录下,这就是上面所说的“拿”出来。尽管其他分区都有自己的根目录,但是默认分区的根目录才是所有分区的父目录,因此挂载分区之后,整个路径树就像一串葡萄。分区不用的时候还可以通过 umount 命令卸载,这就是上面所说的“收”起来。

挂载分区的实质是把该分区文件系统的元信息从硬盘上读出来加载到内存中,这样硬盘资源的变化都用内存中元信息来跟踪,如果有写操作,及时将内存中的元信息同步写入到硬盘以持久化 。

struct partition* cur_part; //默认情况下操作的是那个分区

/*在分区链表中找到名为part_name的分区,并将其赋值给cur_part*/
static bool mount_partition(struct list_elem* pelem, int arg){
    char* part_name = (char*)arg;
    struct partition* part = elem2entry(struct partition, part_tag, pelem);
    if(!strcmp(part->name,part_name)){
        cur_part = part;
        struct disk* hd = cur_part->my_disk;

        /*sb_buf用来存储从硬盘上读入的超级块*/
        struct super_block* sb_buf = (struct super_block*)sys_malloc(SECTOR_SIZE);

        /*在内存中创建分区cur_part的超级块*/
        cur_part->sb = (struct super_block*)sys_malloc(sizeof(struct super_block));
        if(cur_part->sb == NULL){
            PANIC("alloc memory failed!");
        }

        /*读入超级块*/
        memset(sb_buf, 0, SECTOR_SIZE);
        ide_read(hd, cur_part->start_lba+1,sb_buf,1);

        /*把sb_buf中的超级块的信息复制到分区的超级块sb中*/
        memcpy(cur_part->sb,sb_buf,sizeof(struct super_block));

        /********************* 将硬盘上的块位图读入到内存中 ***************************************/
        cur_part->block_bitmap.bits = (uint8_t*)sys_malloc(sb_buf->block_bitmap_sects * SECTOR_SIZE);
        if(cur_part->block_bitmap.bits == NULL)
            PANIC("alloc memory failed!");
        
        cur_part->block_bitmap.btmp_bytes_len = sb_buf->block_bitmap_sects * SECTOR_SIZE;

        /*从硬盘上读入块位图到分区的block_bitmao.bits*/
        ide_read(hd,sb_buf->block_bitmap_lba,cur_part->block_bitmap.bits,sb_buf->block_bitmap_sects);
        /********************************************************************************************/
    
        /********************* 将硬盘上的inode位图读入到内存中 ***************************************/
        cur_part->inode_bitmap.bits = (uint8_t*)sys_malloc(sb_buf->inode_bitmap_sects * SECTOR_SIZE);
        if(cur_part->inode_bitmap.bits == NULL)
            PANIC("alloc memory failed!");
        cur_part->inode_bitmap.btmp_bytes_len = sb_buf->inode_bitmap_sects * SECTOR_SIZE;

        /*从硬盘上读入inode位图到分区的inode_bitmap.bits*/
        ide_read(hd,sb_buf->inode_bitmap_lba,cur_part->inode_bitmap.bits,sb_buf->inode_bitmap_sects);
        /********************************************************************************************/

        list_init(&cur_part->open_inodes);
        printk("mount %s done!\n", part->name);
        
        /**
         * 此处返回true是为了迎合主调函数list_traversal的实现
         * 与函数本身功能无关
         * 只有返回true时list_traversal才会停止遍历
         * 减少了后面元素无意义的遍历
        */
        return true;
    }
    return false;   //使得list_traversal继续遍历
}

结果如下:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1925994.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

P14-磁通量、高斯定理

高斯定理&#xff1a; 由于磁感线是闭合的&#xff0c;因此对于任一闭合曲面来说&#xff0c;有多少条磁感线进入闭合曲面&#xff0c;就一定有多少条磁感线穿出该闭合曲面。也就是说&#xff0c;通过任意闭合曲面的磁通量必等于零&#xff0c;称为磁场的高斯定理或磁通连续定…

前端面试题(CSS篇六)

一、浏览器如何判断是否支持 webp 格式图片 &#xff08;1&#xff09;宽高判断法。通过创建image对象&#xff0c;将其src属性设置为webp格式的图片&#xff0c;然后在onload事件中获取图片的宽高&#xff0c;如果能够获取&#xff0c;则说明浏览器支持webp格式图片。如果不能…

【pbootcms】新环境搭建环境安装时发生错误

【pbootcms】新环境搭建环境安装时发生错误 提示一下内容&#xff1a; 登录请求发生错误&#xff0c;您可按照如下方式排查: 1、试着删除根目录下runtime目录,刷新页面重试 2、检查系统会话文件存储目录是否具有写入权限; 3、检查服务器环境pathinfo及伪静态规则配置; 先按照…

OWASP 移动应用 2024 十大安全风险

1. OWASP 移动应用 2024 十大安全风险 开放全球应用程序安全项目 &#xff08;OWASP&#xff09; 是一个非营利性基金会&#xff0c;致力于提高软件的安全性。自 2014、2016 年两次发布了移动应用的十大风险后&#xff0c;今年再次发布2024版。这对移动应用软件的检查工具有着…

css画半圆画圆弧

利用border-radius和border完成&#xff1a; <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>test</title> <style> .semicircle {width: 100px;height: 50px;border-radius: 0 0 50px 50px;background:…

IDEA社区版使用Maven archetype 创建Spring boot 项目

1.新建new project 2.选择Maven Archetype 3.命名name 4.选择存储地址 5.选择jdk版本 6.Archetype使用webapp 7.create创建项目 创建好长这样。 检查一下自己的Maven是否是自己的。 没问题的话就开始增添java包。 [有的人连resources包也没有&#xff0c;那就需要自己添…

5、Hacker_Kid-v1.0.1

中等难度 目标root权限 先进行一波IP地址发现 netdiscover -i eth0 -r 192.168.1.1/24 发现存在的靶机ip 进行一波端口的探测 发现是一个apache的服务和一个tornado的网站 这里有个细节部分&#xff0c;53端口常见的情况都是走的udp协议做的域名解析&#xff0c;这里查询出来…

manim学习笔记04:使用manim,表示向量和加法。

manim学习笔记04&#xff1a;使用manim&#xff0c;表示向量和加法。 一&#xff0c;相关定义 1.有向线段&#xff1a; 规定若线段 AB的端点为起点为A&#xff0c;B为终点&#xff0c;则线段就具有了从起点 A到终点 B的方向和长度。具有方向和长度的线段叫做有向线段。 接下…

多个版本JAVA切换(学习笔记)

多个版本JAVA切换 很多时候&#xff0c;我们电脑上会安装多个版本的java版本&#xff0c;java8&#xff0c;java11&#xff0c;java17等等&#xff0c;这时候如果想要切换java的版本&#xff0c;可以按照以下方式进行 1.检查当前版本的JAVA 同时按下 win r 可以调出运行工具…

牛客周赛51

思路&#xff1a;求a mod 上b后的值为amodb, 求gcd(b, amodb)即可 int gcd(int a,int b){return b ? gcd(b, a % b) : a; }void solve(){string a;cin >> a;int b;cin >> b;int amodb 0;for(auto c : a){amodb (amodb * 10 (c - 0)) % b;}cout << gcd(b…

Access denied for user ‘root‘@‘localhost‘ (using password: YES)解决办法

在Spring配置数据源时&#xff0c;当使用Spring容器加载druid.properties数据库连接池配置文件时&#xff0c;容易碰到create connection SQLException, url: jdbc:mysql://127.0.0.1:3306/mydbs, errorCode 1045, state 28000 java.sql.SQLException: Access denied for user …

【 香橙派 AIpro评测】烧系统运行部署LLMS大模型体验Jupyter Lab AI 应用样例(新手入门)

文章目录 一、引言⭐1.1下载镜像烧系统⭐1.2开发板初始化系统配置远程登陆&#x1f496; 远程ssh&#x1f496;查看ubuntu桌面&#x1f496; 远程向日葵 二、部署LLMS大模型2.1 快速启动&#x1f496;拉取代码&#x1f496;下载mode数据&#x1f496;启动模型对话 三、体验 内置…

JavaScript 如何中止Promise

目录 方法 1&#xff1a;使用新的 Promise.withResolvers() 方法 2&#xff1a;使用 AbortController 在 JavaScript 中&#xff0c;你可能已经知道如何取消请求&#xff1a;对于 XHR 可以使用 xhr.abort() &#xff0c;对于 fetch 可以使用 signal 。但是你如何取消一个普通…

网络技术相关知识概念

网络技术&#xff1a; 进程&#xff08;Process&#xff09; 定义&#xff1a;进程是程序的一次执行过程&#xff0c;它有自己的内存空间和系统资源&#xff08;资源独立&#xff09;。特性&#xff1a; 每个进程都有唯一的PID&#xff08;进程ID&#xff09;。进程间通信&am…

6、evil box one

低—>中 目标&#xff1a;获取root权限以及2个flag 主机发现 靶机 192.168.1100.40 或者使用fping -gaq 192.168.100.1/24发现主机使用ping的方式。 端口扫描 发现开放了22和80 可以使用-A参数&#xff0c;-A参数会得到更多的扫描细节 访问80端口就是一个apache的基本的…

微服务-注册中心

一. 分布式系统架构与微服务 分布式系统架构和微服务是现代软件开发中常见的两种概念&#xff0c;它们通常结合使用来构建灵活、可扩展和高效的应用程序。 分布式系统架构&#xff1a; 分布式系统架构是指将一个单一的应用程序或服务拆分成多个独立的部分&#xff0c;这些部分…

讲讲 JVM 的内存结构(附上Demo讲解)

讲讲 JVM 的内存结构 什么是 JVM 内存结构&#xff1f;线程私有程序计数器​虚拟机栈本地方法栈 线程共享堆​方法区​注意永久代​元空间​运行时常量池​直接内存​ 代码详解 什么是 JVM 内存结构&#xff1f; JVM内存结构分为5大区域&#xff0c;程序计数器、虚拟机栈、本地…

50、haproxy+keepalive+nginx

keepalivehaproxy 客户端&#xff1a;192.168.168.21haproxy1&#xff1a;192.168.168.43haproxy2&#xff1a;192.168.168.44vip&#xff1a;192.168.168.100nginx1:192.168.168.31nginx2:192.168.168.32haproxykeepalive做高可用nginx做后台haproxy1haproxy2一起操作&#x…

实验发现AI提高了个人创造力,但降低了整体创造力

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

从链表中移除在数组中存在的节点 | 力扣题解

⭐简单说两句⭐ ✨ 正在努力的小叮当~ &#x1f496; 超级爱分享&#xff0c;分享各种有趣干货&#xff01; &#x1f469;‍&#x1f4bb; 提供&#xff1a;模拟面试 | 简历诊断 | 独家简历模板 &#x1f308; 感谢关注&#xff0c;关注了你就是我的超级粉丝啦&#xff01; &a…