У меня есть скрипт bash, который используется rsync
для резервного копирования файлов в Archlinux. Я заметил, что rsync
не удалось скопировать файл из /sys
, хотя cp
работало просто отлично:
# rsync /sys/class/net/enp3s1/address /tmp
rsync: read errors mapping "/sys/class/net/enp3s1/address": No data available (61)
rsync: read errors mapping "/sys/class/net/enp3s1/address": No data available (61)
ERROR: address failed verification -- update discarded.
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1052) [sender=3.0.9]
# cp /sys/class/net/enp3s1/address /tmp ## this works
Интересно, почему происходит rsync
сбой, и можно ли скопировать файл с его помощью?
решение1
Во-первых /sys
, этопсевдофайловая система. Если вы посмотрите, /proc/filesystems
то найдете список зарегистрированных файловых систем, где довольно много есть nodev
впереди. Это указывает на то, что онипсевдофайловые системы. Это означает, что они существуют на работающем ядре как файловая система на базе ОЗУ. Кроме того, им не требуется блочное устройство.
$ cat /proc/filesystems
nodev sysfs
nodev rootfs
nodev bdev
...
При загрузке ядро монтирует эту систему и обновляет записи, когда это необходимо. Например, когда во время загрузки обнаруживается новое оборудование или udev
.
Обычно /etc/mtab
крепление можно найти по:
sysfs /sys sysfs rw,noexec,nosuid,nodev 0 0
Для хорошей статьи по теме прочитайте Патрик Мохел – Файловая система sysfs.
статистика файлов /sys
Если вы зайдете в каталог /sys
и сделаете , ls -l
то заметите, что все файлы имеют один размер. Обычно 4096 байт. Об этом сообщает sysfs
.
:/sys/devices/pci0000:00/0000:00:19.0/net/eth2$ ls -l
-r--r--r-- 1 root root 4096 Apr 24 20:09 addr_assign_type
-r--r--r-- 1 root root 4096 Apr 24 20:09 address
-r--r--r-- 1 root root 4096 Apr 24 20:09 addr_len
...
Далее вы можете сделать a stat
на файле и заметить еще одну отличительную особенность; он занимает 0 блоков. Также inode корня (stat /sys) равен 1. /stat/fs
обычно имеет inode 2. и т.д.
rsync против cp
Самым простым объяснением сбоя синхронизации псевдофайлов с помощью rsync, пожалуй, является пример.
Допустим, у нас есть файл с именем address
, который имеет размер 18 байт. Операция ls
or stat
файла сообщает о 4096 байтах.
rsync
- Открывает файловый дескриптор, fd.
- Использует fstat(fd) для получения такой информации, как размер.
- Установите для чтения размер байт, т.е. 4096. Это будетстрока 253кода, связанного@mattdm.
read_size == 4096
- Спросите; прочитайте: 4096 байт.
- Считывается короткая строка, т.е. 18 байт.
nread == 18
read_size = read_size - nread (4096 - 18 = 4078)
- Спросить; прочитать: 4078 байт
- Прочитано 0 байт (так как при первом чтении были израсходованы все байты в файле).
nread == 0
,строка 255- Невозможно прочитать
4096
байты. Обнулить буфер. - Ошибка установки
ENODATA
. - Возвращаться.
- Сообщить об ошибке.
- Повторить попытку. (Цикл выше).
- Неудача.
- Сообщить об ошибке.
- ОТЛИЧНО.
В ходе этого процесса он фактически считывает весь файл. Но из-за отсутствия доступного размера он не может проверить результат – таким образом, единственным вариантом является неудача.
ср
- Открывает файловый дескриптор, fd.
- Использует fstat(fd) для получения такой информации, как st_size (также использует lstat и stat).
Проверьте, не является ли файл разреженным. То есть, файл имеет дыры и т.п.
copy.c:1010 /* Use a heuristic to determine whether SRC_NAME contains any sparse * blocks. If the file has fewer blocks than would normally be * needed for a file of its size, then at least one of the blocks in * the file is a hole. */ sparse_src = is_probably_sparse (&src_open_sb);
Поскольку
stat
файл отчетов не имеет блоков, он классифицируется как разреженный.Пытается прочитать файл методом экстента-копирования (более эффективный способ копирования)нормальный разреженные файлы) и терпит неудачу.
- Копия разреженной копией.
- Начинается с максимального размера чтения MAXINT.
Обычно18446744073709551615
байты на 32-битной системе. - Запрос; прочитать 4096 байт. (Размер буфера, выделенного в памяти из статистической информации.)
- Считывается короткая строка, т.е. 18 байт.
- Проверьте, нужно ли отверстие, нет.
- Записать буфер в цель.
- Вычтите 18 из максимального размера считывания.
- Спросите; прочитайте 4096 байт.
- 0 байт, так как все данные были израсходованы при первом чтении.
- Возвращение успеха.
- Начинается с максимального размера чтения MAXINT.
- Все ОК. Обновите флаги для файла.
- ОТЛИЧНО.
решение2
Rsync имееткодкоторый специально проверяет, не обрезан ли файл во время чтения и выдает эту ошибку — ENODATA
. Я не знаюпочемуфайлы в /sys
ведут себя таким образом, но поскольку это не настоящие файлы, я думаю, это не слишком удивительно. Кажется, нет способа указать rsync пропустить эту конкретную проверку.
Я думаю, вам, вероятно, лучше не использовать rsync /sys
, а использовать специальные скрипты для выборочного извлечения нужной вам информации (например, адреса сетевой карты).
решение3
Возможно, это связано, но вызовы расширенных атрибутов не будут работать в sysfs:
[root@hypervisor eth0]# адрес lsattr
lsattr: Неподходящий ioctl для устройства при чтении флагов по адресу
[root@hypervisor eth0]#
Если посмотреть на мой strace, то можно увидеть, что rsync пытается по умолчанию извлечь расширенные атрибуты:
22964 <... getxattr возобновлен>, 0x7fff42845110, 132) = -1 ENODATA (Нет доступных данных)
Я пытался найти флаг, который нужно задать rsync, чтобы посмотреть, решит ли проблему пропуск расширенных атрибутов, но ничего не нашел ( --xattrs
превращает их внав пункте назначения).
решение4
Rsync обычно считывает информацию из файла, переносит содержимое файла или дельты во временный файл в целевом каталоге, а затем после проверки данных файла переименовывает его в имя целевого файла.
Я считаю, что проблема с sysfs в том, что все файлы отображаются как 4k (одна страница памяти), хотя они могут содержать всего несколько байт. Чтобы избежать копирования потенциально поврежденного файла в место назначения, rsync отменяет копирование, когда обнаруживает несоответствие между метаданными файла и тем, что было фактически скопировано.
По крайней мере, в rsync v3.0.6 этого поведения можно избежать с помощью переключателя --inplace
. Rsync все равно будет обнаруживать ошибки, но поскольку файлы назначения уже будут перезаписаны, то потенциально поврежденные файлы останутся там.
Обратите внимание, что побочным эффектом этого является то, что файлы в конечном итоге дополняются нулями до 4k, поскольку rsync считает, что файлы имеют такой размер. В большинстве случаев это не должно иметь значения, поскольку нулевые байты обычно игнорируются.