Linux中tty与8250-uart的虐恋(包括双中断发送接收机制)

串口通用驱动文件在哪里?

drivers/tty/serial/

哪一个是正确的compatible

  • arch/arm64/boot/dts/rockchip/rk3568.dtsi
uart3: serial@fe670000 {compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart";reg = <0x0 0xfe670000 0x0 0x100>;interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;clocks = <&cru SCLK_UART3>, <&cru PCLK_UART3>;clock-names = "baudclk", "apb_pclk";reg-shift = <2>;reg-io-width = <4>;dmas = <&dmac0 6>, <&dmac0 7>;pinctrl-names = "default";pinctrl-0 = <&uart3m0_xfer>;status = "disabled";
};
static const struct of_device_id dw8250_of_match[] = {{ .compatible = "snps,dw-apb-uart" },{ .compatible = "cavium,octeon-3860-uart" },{ .compatible = "marvell,armada-38x-uart" },{ .compatible = "renesas,rzn1-uart" },{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, dw8250_of_match);
  • dw8250_platform_driver 属于platform_driver,相当于drv->probe
static struct platform_driver dw8250_platform_driver = {.driver = {.name		= "dw-apb-uart",.pm		= &dw8250_pm_ops,.of_match_table	= dw8250_of_match,.acpi_match_table = dw8250_acpi_match,},.probe			= dw8250_probe,.remove			= dw8250_remove,
};module_platform_driver(dw8250_platform_driver)

dw8250_probe

  • uart_add_one_port 把一个 已经初始化好的 uart_port 结构体 绑定到 已经注册好的 uart_driver 上,从而让它成为 Linux 内核可见的一个串口设备(/dev/ttySx/dev/ttyAMA0 等)
dw8250_probeuart_8250_port uartresource *regs = platform_get_resource//从设备树中获取 8250 控制器寄存器物理基地址uart_port *p = &uart.portdw8250_data *datap->handle_irq  = dw8250_handle_irqp->serial_in    = dw8250_serial_in;p->serial_out   = dw8250_serial_out;p->membase = devm_ioremap(dev, regs->start, resource_size(regs))//内存映射得在Linux用虚拟地址device_property_read_u32device_property_read_booldevm_clk_getdw8250_quirks(p, data)//特定平台配置和兼容性问题of_alias_get_id(np, "serial")p->serial_inp->serial_outdata->line = serial8250_register_8250_port(&uart)uart_add_one_portplatform_set_drvdata(pdev, data)

serial8250_init

  • uart_register_driver 先注册 driver
  • uart_register_driver “先填申报户口资料”,uart_add_one_port 是“依照资料给每块 UART 上户口”;只有上完户口,内核里才会出现对应的 /dev/tty* 设备
  • tty_register_driver创建 tty 设备节点(/dev/ttyS0ttyS1 …)
module_init(serial8250_init)serial8250_isa_init_ports//实现请求端口、添加和注册串口端口serial8250_init_portuart_8250_port port->ops = &serial8250_popsuart_register_driver(&serial8250_reg)//uart_driver 转 tty_driver 注册ttynormal = alloc_tty_driver(drv->nr)tty_set_operations(normal, &uart_ops)port->ops = &uart_port_ops//tty_port *port = &uart_state->porttty_register_driver(normal)put_tty_driver(normal)serial8250_isa_devs = platform_device_alloc("serial8250",PLAT8250_DEV_LEGACY)platform_device_add(serial8250_isa_devs)serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);platform_driver_register(&serial8250_isa_driver)
uart_driverstruct uart_state	*state;struct tty_port        portstruct uart_port   *uart_portstruct tty_driver	*tty_driver;
static struct uart_driver serial8250_reg = {.owner			= THIS_MODULE,.driver_name		= "serial",.dev_name		= "ttyS",.major			= TTY_MAJOR,.minor			= 64,.cons			= SERIAL8250_CONSOLE,
};
static const struct tty_operations uart_ops = {.install	= uart_install,.open		= uart_open,.close		= uart_close,.write		= uart_write,.put_char	= uart_put_char,.flush_chars	= uart_flush_chars,.write_room	= uart_write_room,.chars_in_buffer= uart_chars_in_buffer,.flush_buffer	= uart_flush_buffer,.ioctl		= uart_ioctl,.throttle	= uart_throttle,.unthrottle	= uart_unthrottle,.send_xchar	= uart_send_xchar,.set_termios	= uart_set_termios,.set_ldisc	= uart_set_ldisc,.stop		= uart_stop,.start		= uart_start,.hangup		= uart_hangup,.break_ctl	= uart_break_ctl,.wait_until_sent= uart_wait_until_sent,
#ifdef CONFIG_PROC_FS.proc_show	= uart_proc_show,
#endif.tiocmget	= uart_tiocmget,.tiocmset	= uart_tiocmset,.get_icount	= uart_get_icount,
#ifdef CONFIG_CONSOLE_POLL.poll_init	= uart_poll_init,.poll_get_char	= uart_poll_get_char,.poll_put_char	= uart_poll_put_char,
#endif
};
static const struct tty_port_operations uart_port_ops = {.carrier_raised = uart_carrier_raised,.dtr_rts	= uart_dtr_rts,.activate	= uart_port_activate,.shutdown	= uart_tty_port_shutdown,
};

uart_ops serial8250_popsuart_port 什么区别

uart_8250_portuart_8250_dma *dmauart_8250_ops *opsuart_port port(*serial_in)(*serial_out)(*set_termios)(*set_ldisc)(*handle_irq)uart_state  *statetty_port   portuart_port   *uart_portuart_ops *ops(*startup)(*start_tx)(*stop_tx)(*stop_rx)(*ioctl)
static const struct uart_ops serial8250_pops = {.tx_empty	= serial8250_tx_empty,.set_mctrl	= serial8250_set_mctrl,.get_mctrl	= serial8250_get_mctrl,.stop_tx	= serial8250_stop_tx,.start_tx	= serial8250_start_tx,.throttle	= serial8250_throttle,.unthrottle	= serial8250_unthrottle,.stop_rx	= serial8250_stop_rx,.enable_ms	= serial8250_enable_ms,.break_ctl	= serial8250_break_ctl,.startup	= serial8250_startup,.shutdown	= serial8250_shutdown,.set_termios	= serial8250_set_termios,.set_ldisc	= serial8250_set_ldisc,.pm		= serial8250_pm,.type		= serial8250_type,.release_port	= serial8250_release_port,.request_port	= serial8250_request_port,.config_port	= serial8250_config_port,.verify_port	= serial8250_verify_port,
#ifdef CONFIG_CONSOLE_POLL.poll_get_char = serial8250_get_poll_char,.poll_put_char = serial8250_put_poll_char,
#endif
};
  • univ8250_setup_irq硬件中断号都没有(port->irq == 0,常见于早期板级代码或虚拟端口),则完全采用 纯轮询
  • 如果硬件中断号有效,就调用 serial_link_irq_chain() 把普通中断处理链挂到该 IRQ 上,包括注册 serial8250_interrupt()
static const struct uart_8250_ops univ8250_driver_ops = {.setup_irq	= univ8250_setup_irq,.release_irq	= univ8250_release_irq,
};

serial_in serial_out 读取发送 如何 实现的?

  • ALTERNATIVE 是内核提供的一个宏,利用 ELF .altinstructions 段 机制
  • 在内核启动早期 会扫描这个段,根据 ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE 的布尔值,把 ldrb 原地 patchldarb,或者在不需要时保持 ldrb,保证 读操作之前的所有读写都不能重排到它之后,用于解决 Device-nGRE/Device-nGnRE 映射上可能出现的加载乱序或重试 bug
serial_in(struct uart_8250_port *up, int offset)up->port.serial_in(&up->port, offset);dw8250_serial_inreadb(p->membase + (offset << p->regshift))readb_relaxedasm volatile(ALTERNATIVE("ldrb %w0, [%1]","ldarb %w0,[%1]",ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE): "=r" (val) : "r" (addr));serial_out(struct uart_8250_port *up, int offset, int value)up->port.serial_out(&up->port, offset, value);dw8250_serial_outwriteb(value, p->membase + (offset << p->regshift))writeb_relaxedasm volatile("strb %w0, [%1]" : : "rZ" (val), "r" (addr))

dw8250_handle_irq -> serial8250_handle_irq

  • serial8250_handle_irq 真正处理函数
univ8250_setup_irqrequest_irqserial8250_interruptp->handle_irq  = dw8250_handle_irqdw8250_handle_irqserial8250_handle_irqif (iir & UART_IIR_NO_INT) //  把假中断挡在门外serial_port_in(port, UART_LSR) //一次读出所有线路/错误状态位skip_rx = true //自动 RTS/CTS 硬件流控把 RX 堵住//只要有数据 (`DR`) 或 Break (`BI`) 并且未被上一阶段跳过,就处理接收dma_err = handle_rx_dma(up, iir) //先尝试 DMA 接收 status = serial8250_rx_chars(up, status) //DMA 失败或无 DMA落到 PIO 接收serial8250_modem_status(up)//读取 `UART_MSR` 寄存器,检测 CTS/DSR/RI/DCD 变化  //CTS 变高/低、载波丢失等事件上报 TTYserial8250_tx_chars(up)//serial8250_tx_chars把 TTY 环形缓冲区里的字节写入UART TXFIFOpr_err //现 Overrun/Parity/Frame/Break 错误,就打印一行提示

UART_LSR 是什么寄存器?

  • Line Status Register(线路状态寄存器)一次读即可得到发送/接收单元当前状态
#define UART_LSR	5	/* In:  Line Status Register */
bit7  UART_LSR_FIFOE  FIFO 数据错误
bit6  UART_LSR_TEMT   发送移位器+发送保持器都空
bit5  UART_LSR_THRE   发送保持器 空(可继续写下一个字节)
bit4  UART_LSR_BI     Break 中断
bit3  UART_LSR_FE     帧错误
bit2  UART_LSR_PE     奇偶错误
bit1  UART_LSR_OE     Overrun 错误
bit0  UART_LSR_DR     接收数据就绪

up->dma->txchan 是什么?

  • 发送 DMA 通道:由 dma_request_slave_channel_compat()DMA Engine 子系统 申请得到
  • 不为 NULL → 用 DMA 搬数据到 UART
  • NULL → 退回到传统 PIOCPU 轮询)方式发送

UART_IIR_THRI 是什么?

  • UART_IIR_THRI = “Transmit Holding Register Empty Interrupt”
  • 当发送 FIFO(或保持寄存器)里的最后一个字节被移位器取走后,硬件置位 THREUART_LSR bit5),并同时把 UART_IIR_THRI 填进 IIR,表示“你可以继续写下一个字节了”

为什么 p->handle_irq dw8250_handle_irq 要兼顾 DesignWare UART “假超时”和“BUSY”处理?什么是 DesignWare UART ?

  • DesignWare UART(官方文档中称为 DW_apb_uart)是 Synopsys公司推出的、基于 AMBA APB 总线的可综合 IP 核,目标是给 SoC 提供一套 兼容传统 16550/8250 的通用异步串行收发器(UART
  • dw8250_handle_irq 复用了 8250 核心逻辑,又补上了芯片特有的“假超时”和“BUSY”处理
阶段作用
读取 IIR获知当前中断类型
DesignWare UART RX TIMEHO​UT 假中断检查USR/LSR/RFL,必要时空读 UART_RX 清假超时
标准中断交给 serial8250_handle_irq()
DesignWare UART BUSY 中断USRBUSY状态
结束返回已处理标志

自动 RTS/CTS 流控是什么?

自动 RTS/CTS 流控 = 硬件级双向握手,用两根线 RTS(Request To Send) CTS(Clear To Send)自动启停对方的发送,防止 FIFO 溢出。

  • RTS 由 本地 UART 输出:
    “我准备好接收了,你可以发”。
  • CTS 由 对方 UART 输出:
    “我准备好了,你可以发”。

工作方式(全双工场景):

  • 本地接收侧

    • 当本地 RX FIFO 快满(可编程阈值)时,UART 自动把 RTS 拉高 → 对方看到 RTS=1 就 暂停发送
    • FIFO 被读空后,RTS 自动拉低 → 对方继续发。
  • 本地发送侧

    • 只有检测到 CTS=0(对方准备好)时,UART 才会把 TX FIFO 里的数据真正发出;
    • CTS=1 则硬件暂停发送

dma初始化位置在哪里?两个函数是什么?

serial8250_startupserial8250_do_startupserial8250_request_dmadma->txchan = dma_request_slave_channel_compatdma->tx_addr = dma_map_single
serial8250_initserial8250_isa_init_portsserial8250_set_defaultsup->dma->tx_dma = serial8250_tx_dmaup->dma->rx_dma = serial8250_rx_dma
  • serial8250_tx_dma
struct uart_8250_dma *dma = p->dma;                // 拿到 DMA 私有结构
struct circ_buf *xmit = &p->port.state->xmit;      // 指向 TTY 层的发送环形缓冲区
struct dma_async_tx_descriptor *desc;               // DMA 描述符
int ret;                                            // 返回值if (dma->tx_running)                                // 如果上一次 DMA 还没完成,直接退出return 0;if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) {   // 上层已暂停或缓冲区为空serial8250_rpm_put_tx(p);                       // 发送端置空闲,降低功耗return 0;
}dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);  // 计算本次可搬的字节数
#ifdef CONFIG_ARCH_ROCKCHIP
if (dma->tx_size < MAX_TX_BYTES) {                  // Rockchip:字节数太少就别 DMA,用 PIOret = -EBUSY;goto err;
}
#endifdesc = dmaengine_prep_slave_single(                 // 构造 DMA 描述符dma->txchan,                                // 发送通道dma->tx_addr + xmit->tail,                  // 源地址:环形缓冲区尾指针dma->tx_size,                               // 长度DMA_MEM_TO_DEV,                             // 方向:内存 -> 设备DMA_PREP_INTERRUPT | DMA_CTRL_ACK);         // 完成后中断 + 立即应答
if (!desc) {                                        // 描述符申请失败ret = -EBUSY;goto err;
}dma->tx_running = 1;                                // 置标志:DMA 正在跑
desc->callback = __dma_tx_complete;                 // DMA 完成回调
desc->callback_param = p;                           // 回调参数:uart_8250_port 指针dma->tx_cookie = dmaengine_submit(desc);            // 把描述符提交给 DMA 引擎dma_sync_single_for_device(                         // 刷新 cache,确保 DMA 看到最新数据dma->txchan->device->dev,dma->tx_addr, UART_XMIT_SIZE, DMA_TO_DEVICE);dma_async_issue_pending(dma->txchan);               // 真正启动 DMA 传输if (dma->tx_err) {                                  // 如果之前出过错dma->tx_err = 0;                                // 清错误if (p->ier & UART_IER_THRI) {                   // 关 THRE 中断,避免 PIO 与 DMA 冲突p->ier &= ~UART_IER_THRI;
#ifdef CONFIG_ARCH_ROCKCHIPp->ier &= ~UART_IER_PTIME;
#endifserial_out(p, UART_IER, p->ier);}
}
return 0;                                           // 成功启动 DMAerr:
dma->tx_err = 1;                                    // 记录错误,下次退到 PIO
return ret;
  • serial8250_rx_dma
unsigned int rfl, i = 0, fcr = 0, cur_index = 0;    // 局部变量
unsigned char buf[MAX_FIFO_SIZE];                   // 临时缓存,放本次接收字节
struct uart_port *port = &p->port;                  // 方便引用
struct tty_port *tty_port = &p->port.state->port;   // TTY 端口
struct dma_tx_state state;                          // DMA 状态结构
struct uart_8250_dma *dma = p->dma;                 // DMA 私有结构fcr = UART_FCR_ENABLE_FIFO | UART_FCR_T_TRIG_10 | UART_FCR_R_TRIG_11; // 开 FIFO,设高触发
serial_port_out(port, UART_FCR, fcr);               // 立即写到硬件do {                                                // 轮询直到 DMA 余量是整 burst 倍数dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);cur_index = dma->rx_size - state.residue;       // 已搬运字节
} while (cur_index % dma->rxconf.src_maxburst);     // 对齐到 burst 大小rfl = serial_port_in(port, UART_RFL_16550A);        // 读出 FIFO 当前字节数
while (i < rfl)                                     // 把 FIFO 里剩余字节全部读出buf[i++] = serial_port_in(port, UART_RX);__dma_rx_complete(p);                               // 复位 DMA 描述符,准备下一轮tty_insert_flip_string(tty_port, buf, i);           // 把 i 个字节塞进 TTY flip buffer
p->port.icount.rx += i;                             // 统计接收字节
tty_flip_buffer_push(tty_port);                     // 通知上层“有数据可读”if (fcr)                                            // 恢复原始 FCR 设置serial_port_out(port, UART_FCR, p->fcr);
return 0;

为什么叫“8250”驱动?

  • 历史原因:Intel1981 年推出了 NMOS 8250 UART 芯片,用来给早期 IBM PC/XT 提供串口 COM1/COM2
  • 后续 1645016550A1675016850 等芯片都把 寄存器布局 做成了 8250 的超集,于是 Linux 就把支持这一系列芯片的驱动统称为 8250 驱动

tty8250驱动是什么关系?

  • 用户空间对 tty 设备文件进行操作时,实际上是在调用对应的 tty_fops 中的操作函数
应用层│├── read()/write()/ioctl()│
tty 层(tty_io.c, n_tty.c, tty_port.c)│   ① 负责线路规程、回显、缓冲、termios├── tty_struct├── tty_port└── tty_ldisc│
serial_core(serial_core.c)│   ② 把“tty 端口”与“uart_driver”粘合在一起└── uart_driver / uart_port│
8250 驱动族(8250_core.c, 8250_port.c, 8250_dw.c …)│   ③ 真正把字节写进 UART 寄存器└── struct uart_ops│
硬件 UART(16550, DesignWare, QCOM …)

tty 如何调用 8250

open("/dev/ttyS0",)tty_open()tty_port_open(struct tty_port *port, struct tty_struct *tty,struct file *filp)port->ops->activateuart_port_activateuart_startupretval = uport->ops->startup(uport);uart_state->uart_port->ops->startupuart_ops.startupserial8250_startup

cat /proc/interrupts

![[Pasted image 20250814173636.png]]

cat /proc/tty/drivers

![[Pasted image 20250814145902.png]]

cat /proc/tty/ldiscs

  • 行规程

![[Pasted image 20250814152218.png]]

有了early boot of_platform_default_populate_init,为什么serial8250_init需要platform_device_add?

  • 因为serial8250_isa_devs 并不是“从设备树里解析出来的普通串口”,而是 8250/16550 驱动为了兼容 ISA/Legacy UART 专门创建的一个“虚拟”平台设备

  • 给“非设备树、非 ACPI”的老式串口一个统一的 platform_device 句柄

  • 那些固定地址(0x3F8、0x2F8…)的 ISA UART 在设备树里往往根本没有节点,或者节点被禁用

  • 驱动必须手动把它们包装成一个 platform_device,才能继续沿用 platform_driverprobe 流程

  • 驱动注册时如果找不到任何 device 就会无事可做;因此驱动自己先 platform_device_alloc() / platform_device_add() 创建一个名字为 "serial8250"、ID 为 PLAT8250_DEV_LEGACY 的设备,确保 serial8250_isa_driver 能匹配到它并进入 probe

platform_device_add调用 bus 匹配,drv 进行 probe

  • serial8250_initplatform_device_add()device_add()bus_probe_device()__device_attach()bus_for_each_drv()__device_attach_driver()driver_match_device()bus_type->match()
  • __device_attach_driver()driver_probe_device -> really_probe -> drv->probe
__device_attach_driverdriver_match_devicebus_type->match()driver_probe_devicedrv->probe
  • 参考文档43
    module_platform_driver 与 module_init_module platform driver-CSDN博客

  • 参考文档44
    uart驱动学习-CSDN博客

  • 参考45
    深入浅出UART驱动开发与调试:从基础调试到虚拟驱动实现-CSDN博客

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

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

相关文章

GitHub 仓库代码上传指南

文章目录 🛠️ 一、环境准备 🧱 二、创建 GitHub 仓库 ⚙️ 三、本地代码上传流程 首次上传 更新已有代码 🔐 四、认证问题解决(必看!) 方案 1:个人访问令牌(PAT) 方案 2:SSH 密钥(推荐长期使用) ⚡ 五、常见错误处理 🏆 六、最佳实践建议 💎 高级技巧 🛠…

介绍一下 自动驾驶 感知多任务训练模型设计

自动驾驶感知多任务训练模型是指在一个统一的模型架构中&#xff0c;同时完成自动驾驶场景下的多个感知任务&#xff08;如目标检测、语义分割、深度估计、车道线检测等&#xff09;的模型设计。其核心目标是通过特征共享和任务协同&#xff0c;在提升单任务性能的同时&#xf…

huggingface文件下载过慢/中断怎么办

huggingface上汇集了各个大模型和预训练模型的权重文件&#xff0c;但是访问huggingface需要连接外网&#xff0c;即时连接外网之后下载仍然过慢甚至会出现中断&#xff0c;因此本文将使用两种方法教你解决上述问题。 文章目录1.使用国内镜像下载2.使用Python脚本自动化下载1.使…

Spring Boot + Redis Sentinel (一主两从)测试案例

&#x1f680; Spring Boot Redis Sentinel 完整测试案例 &#x1f3f7;️ 标签&#xff1a;Redis 、Redis Sentinel、Spring Boot 实战 &#x1f4da; 目录导航 &#x1f4dd; 前言&#x1f3d7;️ Redis Sentinel 架构说明&#x1f4e6; Docker Compose 搭建 Redis 哨兵环境…

力扣-295.数据流的中位数

题目链接 295.数据流的中位数 class MedianFinder {PriorityQueue<Integer> left;//队头最大PriorityQueue<Integer> right;//队头最小public MedianFinder() {left new PriorityQueue<>(new Comparator<Integer>() {Overridepublic int compare(In…

【数据分享】2014-2023年长江流域 (0.05度)5.5km分辨率的每小时日光诱导叶绿素荧光SIF数据

而今天要说明数据就是2014-2023年长江流域 &#xff08;0.05度&#xff09;5.5km分辨率的每小时日光诱导叶绿素荧光SIF数据。数据介绍一、数据集概况&#xff1a;长江流域植被动态的 “每小时快照”本文分享的核心数据集为2014 年 9 月至 2023 年 9 月长江流域日光诱导叶绿素荧…

计算机二级 Web —— HTML 全面精讲(含真题实战)

例题来源: web.code2ji.cn 0. HTML 基础与全局常识 0.1 HTML 是什么 HTML&#xff08;HyperText Markup Language&#xff09;是网页结构语言&#xff0c;用“标签”描述内容、层次与含义。 0.2 基本文档骨架&#xff08;必须熟练&#xff09; <!DOCTYPE html> <…

Linux中的日志管理

注&#xff1a;在 centos7/Rocky9 中&#xff0c;系统日志消息由两个服务负责处理&#xff1a;systemd-journald 和 rsyslog一、常见日志文件的作用实验一&#xff1a;测试查看暴力破解系统密码的IP地址步骤一&#xff1a;故意输错密码3次&#xff0c;在日志文件中查看步骤二&a…

C++ 性能优化擂台:挑战与突破之路

一、引言&#xff08;一&#xff09;C 在性能关键领域的地位在当今数字化时代&#xff0c;C 语言凭借其高效性、灵活性和对硬件的直接操控能力&#xff0c;在众多对性能要求极高的领域中占据着举足轻重的地位。无论是构建高性能的游戏引擎&#xff0c;实现金融领域毫秒级响应的…

五、Elasticsearch在Linux的安装部署

五、Elasticsearch在Linux的安装部署 文章目录五、Elasticsearch在Linux的安装部署1.Elasticsearch的作用2.安装0. 安装前准备1.使用包管理器安装&#xff08;推荐&#xff0c;自动服务化&#xff09;Ubuntu / DebianRHEL / CentOS / Rocky / Alma2. 使用 tar.gz 安装&#xff…

Kubernetes集群部署全攻略

目录 一、 服务器环境及初始化 1、架构分析 2、初始化 2.1、清空Iptales默认规则及关闭防火墙 2.2、关闭SELINUX 2.3、关闭Swap交换空间 2.4、设置主机名 2.5、编写hosts文件 2.6、设置内核参数 二、安装Docker环境 1、安装Docker 1.1、配置阿里源 1.2、安装docke…

Ceph存储池详解

Ceph 存储池&#xff08;Pool&#xff09;详解 Ceph 的 存储池&#xff08;Pool&#xff09; 是逻辑存储单元&#xff0c;用于管理数据的分布、冗余和访问策略。它是 Ceph 存储集群的核心抽象&#xff0c;支持 对象存储&#xff08;RGW&#xff09;、块存储&#xff08;RBD&…

使用 Docker 部署 PostgreSQL

通过 Docker 部署 PostgreSQL 是一种快速、高效的方式&#xff0c;适用于开发和测试环境。 步骤 1&#xff1a;拉取 PostgreSQL 镜像 运行以下命令从 Docker Hub 拉取最新的 PostgreSQL 镜像&#xff1a; docker pull postgres 如果需要其他的镜像&#xff0c;可以指定版本…

P1886 滑动窗口 /【模板】单调队列【题解】

P1886 滑动窗口 /【模板】单调队列 题目描述 有一个长为 nnn 的序列 aaa&#xff0c;以及一个大小为 kkk 的窗口。现在这个窗口从左边开始向右滑动&#xff0c;每次滑动一个单位&#xff0c;求出每次滑动后窗口中的最小值和最大值。 例如&#xff0c;对于序列 [1,3,−1,−3,5,3…

河南萌新联赛2025第(五)场:信息工程大学补题

文章目录[TOC](文章目录)前言A.宇宙终极能量调和与多维时空稳定性验证下的基础算术可行性研究B.中位数C.中位数1F.中位数4G.简单题H.简单题I.Re:从零开始的近世代数复习&#xff08;easy&#xff09;K.狂飙追击L.防k题前言 这次萌新联赛考到了很多数学知识 A.宇宙终极能量调和…

SuperMap GIS基础产品FAQ集锦(20250804)

一、SuperMap iServer 问题1&#xff1a;iServer的名称和logo怎么自定义&#xff1f; 11.3.0 【解决办法】参考&#xff1a;https://blog.csdn.net/supermapsupport/article/details/144744640 问题2&#xff1a;iServer 刷新工作空间&#xff0c;当数据库是 PostGIS 时&#x…

AWS CloudFormation批量删除指南:清理Clickstream Analytics堆栈

概述 在AWS环境管理中,经常会遇到需要批量删除CloudFormation堆栈的情况。本文记录了一次完整的Clickstream Analytics堆栈清理过程,包括遇到的问题和解决方案,希望能为其他开发者提供参考。 背景 我们的AWS账户中部署了多个Clickstream Analytics解决方案的CloudFormati…

redis中分布式锁的应用

我们之前讲了秒杀模块的实现&#xff0c;使用了sychronized互斥锁&#xff0c;但是在集群模式下因为不同服务器有不同jvm&#xff0c;所以synchronized互斥锁失效了。 redis实现秒杀超卖问题的解决方案&#xff1a;(仅限于单体项目)-CSDN博客 这时就要找到一个多台服务器都能…

【科研绘图系列】R语言绘制微生物丰度和基因表达值的相关性网络图

文章目录 介绍 加载R包 数据下载 导入数据 数据预处理 画图 系统信息 参考 介绍 【科研绘图系列】R语言绘制微生物丰度和基因表达值的相关性网络图 加载R包 library(tidyverse) library(ggsignif) library(RColorBrewer) library(dplyr) library(reshape2) library(grid

Pycharm现有conda环境有对应env,但是添加后没反应

一、系统环境 二、异常现象 Pycharm现有conda环境有对应env&#xff1a; anaconda3的envs下也确实存在这个环境&#xff1a; 但是添加后没反应&#xff08;点击确认后&#xff0c;yolov7环境没有出现在列表中&#xff09;&#xff1a; 但是我之前在别的机子添加是没问题的。 …