文件描述符 3 在 vgcfgbackup 调用时泄漏。父 PID:bash

文件描述符 3 在 vgcfgbackup 调用时泄漏。父 PID:bash

我正在使用 bash 脚本对带有 lvm 的 ubuntu 机器进行备份,然后将其上传到 google drive,脚本每天通过 cron 运行,没有问题,但日志文件包含以下错误:

File descriptor 3 (/root/borg.sh) leaked on lvcreate invocation. Parent PID 27827: bash

这个错误到底是什么意思?它与 lvcreate/vgcfgbackup 或 bash 脚本本身有关吗?我找不到任何有用的信息,只有“调用时泄露”可能是无害的。

在 lvcreate 和 vgcfgbackup 中添加了 -vvv 的完整日志: http://dpaste.com/3FYVAC0

bash 脚本: http://dpaste.com/30NV1ZH

答案1

man lvm

在调用时,lvm 要求只有标准文件描述符 stdin、stdout 和 stderr 可用。如果发现其他文件描述符,则关闭它们并发出有关泄漏的警告消息。可以通过设置环境变量 LVM_SUPPRESS_FD_WARNINGS 来抑制此警告。

您可能在脚本中使用了文件描述符 3。LVM_SUPPRESS_FD_WARNINGS在调用之前,请在脚本中导出环境变量lvcreate

答案2

我的看法:

是的!我经常在cron工作中看到这种情况:crond(cron守护进程)运行他的脚本pipes为了在需要的时候开车去sendmail,他们打开了一些不寻常的文件描述符(输入/输出馈线)。

对这条消息感到厌倦,我做了一些测试...所以有一些意见/解决方案:

1. 使用LVM_SUPPRESS_FD_WARNINGS环境变量

作为伯尼的正确答案建议,最简单的解决方案是设置环境变量:LVM_SUPPRESS_FD_WARNINGS作为

LVM_SUPPRESS_FD_WARNINGS=1 lvs
LVM_SUPPRESS_FD_WARNINGS=1 lvcreate ...

或者简单来说:

export LVM_SUPPRESS_FD_WARNINGS=1
lvs
lvcreate ...

但是,有一种方法可以在运行它们之前满足 LVM 的要求!

2. 将 LVM 环境限制为仅需要文件描述符

然后,为了更好地理解:

创建一些有用的 FD

exec {dummyFd}<> <(: -)

适合read用作内置睡眠,样本替换为sleep 1.5

read -ru $dummyFd -t 1.5 _

好吧,如果我lvs

# lvs >/dev/null 
File descriptor 10 (pipe:[194609045]) leaked on lvs invocation. Parent PID 849375: -bash

尝试lvs通过关闭来无错误地运行不需要的FD在子 shell 中:

(exec {dummyFd}<&-;lvs) >/dev/null

将会完成这项工作!

在一个环形:

如何将 LVS 输出存储到有用的变量中?例如,我这样做是为了存储快照使用情况变成关联数组

declare -Ai lvStat='()'
while read -r lv vg attr size orig prct; do
    case $attr in
        s* ) printf -v prct %.2f ${prct%\%}
             lvStat[$lv/$vg]=${prct/.} ;;
    esac
done < <( exec {dummyFd}>&-; lvs )

我使用整数来存储带有两位小数的百分比值,只需删除小数点即可。所以我必须将测试值乘以 100:

for vol in "${!lvStat[@]}"; do
    (( ${lvStat["$vol"]} > 8000 )) &&
        printf 'Volume %s > 80%%: %8.2f%%\n' "$vol" \
            ${lvStat["$vol"]::-2}.${lvStat["$vol"]: -2}
done

整体包装全部关闭不需要的FD

以下是一点包装器关闭所有打开的 FD 的函数,但不会0STDIN1STDOUT2STDERR

closeFdWrapper4Lv()(
    allFileDescriptors=(/dev/fd/*)
    for fileDescriptor in ${allFileDescriptors[@]##*/}; do
        case $fileDescriptor in
            0|1|2 ) ;;
            *     ) exec {fileDescriptor}>&- ;;
        esac
    done
    "$@"
)

关心括号围绕功能而不是常规大括号!!!

然后你可以运行:

closeFdWrapper4Lv lvs
closeFdWrapper4Lv lvcreate ...

仍然可以使用你打开的文件描述符

read -ru $dummyFd -t 1.5 _

相关内容