[Linux]overlayroot后无法写入TF卡

1. 进入底层模式 (Chroot)
sudo overlayroot-chroot
2. 彻底清理 /etc/fstab (关键)
执行 vi /etc/fstab,删除或用 # 注释掉所有包含 0018-D0BC 或 /mnt/tfcard 的行。
原理:只要 fstab 里没有它,overlayroot 启动时就不会去“预占”这个目录,这是成功的核心。
3. 创建强力挂载脚本
执行 vi /usr/local/bin/mount-tf.sh,写入以下内容:
#!/bin/bash
# 等待硬件就绪和 overlayroot 初始化完成
sleep 10
# 强制创建物理目录
mkdir -p /mnt/tfcard
# 彻底清除可能存在的任何挂载(包括只读层残留)
umount -f /mnt/tfcard 2>/dev/null
umount -l /mnt/tfcard 2>/dev/null
# 执行物理挂载(加上参数确保读写)
mount -t exfat -o defaults,uid=1000,gid=1000,umask=000,noatime /dev/mmcblk1p1 /mnt/tfcard
赋予权限:chmod +x /usr/local/bin/mount-tf.sh

4. 创建 Systemd 服务文件
执行 vi /etc/systemd/system/mount-tfcard.service,写入:
[Unit]
Description=Mount TF Card for Overlayroot
After=multi-user.target
DefaultDependencies=no

[Service]
Type=idle
ExecStart=/usr/local/bin/mount-tf.sh
# 确保即使脚本退出,挂载依然保留
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
5. 启用并重启
在 chroot 环境内执行:
systemctl daemon-reload
systemctl enable mount-tfcard.service
exit
sudo reboot

///////////////////////////////////////////

要保证 mount-tfcard.service 在上电后自动运行,核心在于 Systemd 的注册机制 和 依赖关系控制。

你只需要在底层模式(chroot)下完成以下三个关键动作:

1. 必须包含 [Install] 区块
在你的 .service 文件末尾,必须有这段代码。它告诉系统:当执行“启用”命令时,要把这个服务挂载到哪个启动阶段(Target)。

代码段
[Install]
WantedBy=multi-user.target
multi-user.target:相当于传统的“运行级别 3”,是系统完成基础引导、进入多用户模式(命令行界面)的标志。

2. 执行启用命令 (最关键的一步)
仅仅写好文件是不够的,你必须在 sudo overlayroot-chroot 环境下运行以下命令:

Bash
# 重新加载系统服务配置
systemctl daemon-reload

# 设置开机自启
systemctl enable mount-tfcard.service
这一步做了什么?
它会在 /etc/systemd/system/multi-user.target.wants/ 目录下创建一个指向你 service 文件的软链接。上电后,系统扫描到这个链接,就会自动启动它。

3. 检查服务是否“真的”被设为自启
运行以下命令验证:

Bash
systemctl is-enabled mount-tfcard.service
如果输出 enabled,说明配置正确,上电会运行。

如果输出 disabled 或 static,说明 [Install] 部分有问题或没执行 enable。

4. 解决“运行了但没挂载成功”的问题
很多时候服务运行了,但因为执行太快报错。为了保证 100% 成功,请确保你的 [Service] 区块包含以下参数:

代码段
[Service]
Type=idle
ExecStart=/usr/local/bin/mount-tf.sh
# 即使脚本运行完退出了,也保持服务状态为 active,防止系统回收挂载点
RemainAfterExit=yes
Type=idle:这是 Systemd 的一个“必杀技”。它会等所有其他的启动任务(比如磁盘扫描、网络启动)全部彻底完成后,才最后运行你的脚本。这能有效避开 overlayroot 启动时的各种冲突。

总结:完整的检查清单
如果你已经按照之前的建议写好了文件,请按顺序执行:

sudo overlayroot-chroot

vi /etc/systemd/system/mount-tfcard.service (检查是否有 [Install] 部分)

systemctl daemon-reload

systemctl enable mount-tfcard.service

exit

sudo reboot

重启后,如果还没挂载,执行:
sudo systemctl status mount-tfcard.service
如果看到 Active: active (exited),说明它上电后确实运行了。此时如果还没挂载,那就不是“自动运行”的问题,而是脚本里的 mount 命令报错了(可能是 UUID 没对上或 /dev/mmcblk1p1 路径在那个瞬间还没生成)。

[linux]开机运行文件

//bp sudo vi /etc/rc.local

#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will “exit 0” on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

/usr/local/bin/load_module.sh

#xset s off
#xset -dpms

#while ! ip route | grep -q “default”; do
# echo “Waiting for default gateway…”
# sleep 1
# done

# echo “Default gateway is set.”

#sudo ip route del default via 192.168.43.1 dev usb0

//sp

#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will “exit 0” on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
/usr/local/bin/load_module.sh

#while ! ip route | grep -q “default”; do
# echo “Waiting for default gateway…”
# sleep 1
# done

# echo “Default gateway is set.”

#sudo ip route del default via 192.168.43.1 dev usb0

//bp /usr/local/bin/load_module.sh

#!/bin/bash

source /etc/profile
source ~/.bash_profile

chmod 777 /dev/spidev3.0
sleep 1
insmod /home/orangepi/wlanuav.ko rtw_country_code=”CN”
#sleep 1
#sudo iw dev wlx7822884b2787 set type AP
#sleep 2
#nmcli dev set wlx7822884b2787 managed no
#sleep 2
#sudo /usr/sbin/hostapd /usr/sbin/1.config -B
#sleep 2
#sudo ifconfig wlx7822884b2787 192.168.16.7
sleep 1

#while ! ip route | grep -q “default”; do
# echo “Waiting for default gateway…”
# sleep 1
# done
# echo “Default gateway is set.”

#sudo ip route del default via 192.168.43.1 dev usb0
#sleep 8
sudo /usr/sbin/openvpn –config /home/orangepi/baseport.ovpn –daemon
sleep 20
su – orangepi -c “/home/orangepi/bp” &

//sp

#!/bin/bash
sleep 1
insmod /home/orangepi/wlanuav.ko rtw_country_code=”CN”
sleep 1
sudo iw dev wlx7822884b2786 set type AP
sleep 2
nmcli dev set wlx7822884b2786 managed no
sleep 2
sudo /usr/sbin/hostapd /usr/sbin/1.config -B
sleep 2
sudo ifconfig wlx7822884b2786 192.168.16.1
sleep 2
sudo openvpn –config /home/orangepi/skyport.ovpn –daemon
sleep 2
echo “autorun init done”

[linux]设置网卡自动连接并设置固定IP

sudo nmcli connection add type wifi ifname wlx7822884b2787 con-name rtlwap ssid rtlwap
sudo nmcli connection modify rtlwap wifi-sec.key-mgmt wpa-psk
sudo nmcli connection modify rtlwap wifi-sec.psk mqdqxyg1qy
sudo nmcli connection modify rtlwap ipv4.addresses 192.168.16.7/24
sudo nmcli connection modify rtlwap ipv4.gateway 192.168.16.1
sudo nmcli connection modify rtlwap ipv4.dns “8.8.4.4,114.114.114.114”
sudo nmcli connection modify rtlwap ipv4.method manual
sudo nmcli connection modify rtlwap connection.autoconnect yes

sudo nmcli connection up rtlwap ifname wlx7822884b2787

// 这一个是测试的 不用sudo nmcli device wifi connect rtlwap password mqdqxyg1qy ifname wlx7822884b2787

[Linux] 清理Vmware垃圾

sudo dd if=/dev/zero of=/bigemptyfile bs=1M
sudo rm -f /bigemptyfile
sudo sync

WIN+S
以管理员身份打开命令提示符(CMD)或 PowerShell。 导航到该目录,或者直接使用完整路径。

D:
cd D:\Program Files (x86)\VMware\VMware Workstation
vmware-vdiskmanager -k “F:\Ubuntu22.04-cl10.vmdk”

——————————————————————
执行压缩命令:
语法:vmware-vdiskmanager -k “你的虚拟机磁盘文件完整路径”

假设你的虚拟机磁盘文件(.vmdk)放在 D:\Virtual Machines\Ubuntu\Ubuntu.vmdk,则命令如下:
cmd

“C:\Program Files (x86)\VMware\VMware Workstation\vmware-vdiskmanager.exe” -k “D:\Virtual Machines\Ubuntu\Ubuntu.vmdk”

等待执行完成。 你会看到类似以下的输出:
text

Defragmenting: 100% done.
Shrink: 100% done.

The disk shrinking operation has completed successfully.

[Linux]开机自运行脚本

sudo vi /usr/local/bin/load_module.sh

//skyport的
#!/bin/bash
sleep 1
insmod /home/orangepi/wlanuav.ko rtw_country_code=”CN”
sleep 1
sudo iw dev wlx7822884b2786 set type AP
sleep 2
nmcli dev set wlx7822884b2786 managed no
sleep 2
sudo /usr/sbin/hostapd /usr/sbin/1.config -B
sleep 2
sudo ifconfig wlx7822884b2786 192.168.16.1
sleep 2
sudo openvpn –config /home/orangepi/skyport.ovpn –daemon
sleep 2
echo “autorun init done”

//baseport的

#!/bin/bash
chmod 777 /dev/spidev3.0
sleep 1
insmod /home/orangepi/wlanuav.ko rtw_country_code=”CN”
#sleep 1
#sudo iw dev wlx7822884b2787 set type AP
#sleep 2
#nmcli dev set wlx7822884b2787 managed no
#sleep 2
#sudo /usr/sbin/hostapd /usr/sbin/1.config -B
#sleep 2
#sudo ifconfig wlx7822884b2787 192.168.16.7
sleep 1
sudo openvpn –config /home/orangepi/baseport.ovpn –daemon
sleep 1

sudo chmod +x /usr/local/bin/load_module.sh

sudo vi /etc/rc.local

在 exit 0 之前添加:
——————————–
/usr/local/bin/load_module.sh

while ! ip route | grep -q “default”; do
echo “Waiting for default gateway…”
sleep 1
done

echo “Default gateway is set.”

sudo ip route del default via 192.168.43.1 dev usb0
—————————————–
sudo chmod +x /etc/rc.local

[linux]定时器异步通知

—————————–驱动————————————
/*
*file name: misc_device.c
*/

#include #include #include #include #include #include #include #include #include #include #include #include

#include #include

#include #include

#define MISC_MINOR 255

/* imx6uirq设备结构体 */
struct imx6uirq_dev{
struct fasync_struct *async_queue; /* 异步相关结构体 */
};

struct imx6uirq_dev imx6uirq; /* irq设备 */

// 定义定时器
static struct timer_list my_timer;

void my_timer_handler(struct timer_list *t) {

if(imx6uirq.async_queue)
{
// printk(KERN_INFO “timenow =: %ld\n”, jiffies);
kill_fasync(&imx6uirq.async_queue, SIGIO, POLL_IN); /* 释放SIGIO信号 */

}

mod_timer(&my_timer, jiffies + msecs_to_jiffies(1999));
// 重新启动定时器,例如每2秒触发一次

}

static int my_timer_init(void) {
// 初始化定时器
timer_setup(&my_timer, my_timer_handler, 0);

// 设置定时器的首次触发时间,例如 1 秒后
mod_timer(&my_timer, jiffies + msecs_to_jiffies(1000));

printk(KERN_INFO “定时器模块已初始化。\n”);
return 0;
}

static void my_timer_exit(void) {
// 删除定时器,防止再次触发
del_timer(&my_timer);
printk(KERN_INFO “定时器模块已卸载。\n”);
}

static int hello_open(struct inode *inode, struct file *filp)
{
printk(“misc open!\n”);
return 0;
}

static ssize_t hello_write(struct file *filp, const char __user *buf,size_t cnt, loff_t *offt)
{
int ret = 0;
unsigned char data[16];

printk(“misc write\n”);
ret = copy_from_user(data, buf, cnt);
if(ret != 0)
printk(“hello misc write failed\n”);

return ret;
}

static ssize_t hello_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
int ret = 0;
unsigned char data[4] = {0x12, 0x03, 0x56, 0x11};

printk(“misc read\n”);

ret = copy_to_user(buf, &data, sizeof(data));
if(ret != 0)
printk(“hello misc read failed\n”);

return ret;
}

int imx6uirq_fasync(int fd, struct file *filp, int on)
{
return fasync_helper(fd, filp, on, &imx6uirq.async_queue);
}

static int imx6uirq_release(struct inode *inode, struct file *filp)
{
return imx6uirq_fasync(-1, filp, 0);
}

/*
* file operations
*/
struct file_operations hello_fops = {

.owner = THIS_MODULE,
.write = hello_write,
.read = hello_read,
.open = hello_open,
.fasync = imx6uirq_fasync,
.release = imx6uirq_release,
};

/*
* misc description
*/
struct miscdevice hello_misc = {
.minor = MISC_MINOR,
.name = “my-timer”,
.fops = &hello_fops,
};

static int hello_init(void)
{
int ret = 0;

printk(” Hello World enter\n”);

ret = misc_register(&hello_misc);
if(ret != 0)
printk(“hello misc register failed!”);

my_timer_init();
return 0;
}

static void hello_exit(void)
{
my_timer_exit();
printk(” Hello World exit\n “);
misc_deregister(&hello_misc);
}

module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE(“Dual BSD/GPL”);
MODULE_DESCRIPTION(“A simple Hello World Module”);

—————————–应用—————————————–

#include “stdio.h”
#include “unistd.h”
#include “sys/types.h”
#include “sys/stat.h”
#include “fcntl.h”
#include “stdlib.h”
#include “string.h”
#include “poll.h”
#include “sys/select.h”
#include “sys/time.h”
#include “linux/ioctl.h”
#include “signal.h”

static int fd = 0; /* 文件描述符 */

/*
* SIGIO信号处理函数
* @param – signum : 信号值
* @return : 无
*/
static void sigio_signal_func(int signum)
{
int err = 0;
unsigned int keyvalue = 0;
printf(“sigio signal!\r\n”);
}

/*
* @description : main主程序
* @param – argc : argv数组元素个数
* @param – argv : 具体参数
* @return : 0 成功;其他 失败
*/
int main(int argc, char *argv[])
{
int flags = 0;
char *filename;

if (argc != 2) {
printf(“Error Usage!\r\n”);
return -1;
}

filename = argv[1];
fd = open(filename, O_RDWR);
if (fd < 0) { printf("Can't open file %s\r\n", filename); return -1; } /* 设置信号SIGIO的处理函数 */ signal(SIGIO, sigio_signal_func); fcntl(fd, F_SETOWN, getpid()); /* 设置当前进程接收SIGIO信号 */ flags = fcntl(fd, F_GETFL); /* 获取当前的进程状态 */ fcntl(fd, F_SETFL, flags | FASYNC); /* 设置进程启用异步通知功能 */ while(1) { sleep(2); } close(fd); return 0; }

[linux]misc简单驱动

/*
*file name: misc_device.c
*/

#include #include #include #include #include #include #include #include #include #include #include #include

#define MISC_MINOR 255

static int hello_open(struct inode *inode, struct file *filp)
{
printk(“misc open!\n”);
return 0;
}

static ssize_t hello_write(struct file *filp, const char __user *buf,size_t cnt, loff_t *offt)
{
int ret = 0;
unsigned char data[16];

printk(“misc write\n”);
ret = copy_from_user(data, buf, cnt);
if(ret != 0)
printk(“hello misc write failed\n”);

return ret;
}

static ssize_t hello_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
int ret = 0;
unsigned char data[4] = {0x12, 0x03, 0x56, 0x11};

printk(“misc read\n”);

ret = copy_to_user(buf, &data, sizeof(data));
if(ret != 0)
printk(“hello misc read failed\n”);

return ret;
}

/*
* file operations
*/
struct file_operations hello_fops = {

.owner = THIS_MODULE,
.write = hello_write,
.read = hello_read,
.open = hello_open,
};

/*
* misc description
*/
struct miscdevice hello_misc = {
.minor = MISC_MINOR,
.name = “hello-misc”,
.fops = &hello_fops,
};

static int hello_init(void)
{
int ret = 0;

printk(” Hello World enter\n”);

ret = misc_register(&hello_misc);
if(ret != 0)
printk(“hello misc register failed!”);

return 0;
}

static void hello_exit(void)
{
printk(” Hello World exit\n “);
misc_deregister(&hello_misc);
}

module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE(“Dual BSD/GPL”);
MODULE_DESCRIPTION(“A simple Hello World Module”);

[linux]GPIO 设备树

在/节点下添加
aledspx: aledspx {
compatible = “agpio-leds”;
pinctrl-names = “default”;
pinctrl-0 =<&aleds_gpio>;

led@1 {
gpios = <&gpio0 RK_PC1 GPIO_ACTIVE_HIGH>;
label = “astatus_led”;
};
};

pinctr中加入
awork-led {
aleds_gpio: aleds-gpio {
rockchip,pins = <0 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>;
};
};

——————————————————————-
多个IO可这样写
leds: leds {
compatible = “gpio-leds”;
pinctrl-names = “default”;
pinctrl-0 =<&leds_gpio>;

led = <&gpio0 RK_PC0 GPIO_ACTIVE_LOW>;
ledb = <&gpio0 RK_PC1 GPIO_ACTIVE_LOW>;
ledc = <&gpio0 RK_PC2 GPIO_ACTIVE_LOW>;

};

pinctr:

work-led {
leds_gpio: leds-gpio {
rockchip,pins = < 0 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>,
< 0 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>,
< 0 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
};
};

—————————–也可以这样写————————————
leds: leds {
compatible = “gpio-leds”;
pinctrl-names = “default”;
pinctrl-0 =<&leds_gpio>;

led@1 {
gpios = <&gpio0 RK_PC0 GPIO_ACTIVE_HIGH>;
label = “status_led”;
linux,default-trigger = “heartbeat”;
};
leda {
gpios = <&gpio0 RK_PC1 GPIO_ACTIVE_HIGH>;
label = “astatus_led”;
};
ledb {
gpios = <&gpio0 RK_PC2 GPIO_ACTIVE_HIGH>;
label = “bstatus_led”;
};
};

pinctr:

work-led {
leds_gpio: leds-gpio {
rockchip,pins = < 0 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>,
< 0 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>,
< 0 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
};
};

编译设备树