dadv: (Default)
[personal profile] dadv

В продолжение темы. Дальше только для пользователей FreeBSD.

1. Для демонстрации идеи начнем с "Hello, World!"

#include <sys/syscall.h>

#define MESG    "Hello, world!\n"
#define MESG_SZ (sizeof(MESG)-1)

int syscall(const int n, ...);

#define _exit(a)       syscall(SYS_exit, a)
#define write(a, b, c) syscall(SYS_write, a, b, c)

int errno;

int main() {
  write(1, MESG, MESG_SZ);
  _exit(0);
  return 0; /* make compiler happy */
}
Написанная в таком стиле программа является строгим кодом на C (собирается gcc -ansi -pedantic -Wall без замечаний), не использует и не требует сервиса libc, общаясь с ядром FreeBSD непосредственно через системные вызовы и под FreeBSD 8.0/i386 компилируется в статический бинарник размером в 512 байт:

gcc -Os -ansi -pedantic -Wall -I/usr/src/lib/libc/i386 -nostartfiles -nodefaultlibs -nostdlib -s -static -O99 -fomit-frame-pointer -Wl,--entry=main,--gc-section -o hello hello.c /usr/src/lib/libc/i386/sys/syscall.S /usr/src/lib/libc/i386/sys/cerror.S /usr/src/lib/libc/sys/__error.c

Цена - отсутствие переносимости на другие OS.

2. FreeBSD, как и другие OS, наравне с "традиционными" файловыми системами на разделах дисков умеет использовать заранее подготовленные файл-образы файловых систем, сначала "подключая" (attach) образы, что создает в каталоге /dev новое "устройство", соответствующее файл-образу, а затем монтируя его как любое другое устройство. К сожалению, система загрузки FreeBSD пока не предоставляет готового сервиса по "подключению" произвольного количества образов средствами loader без загрузки их полностью в память (есть штатный метод с загрузкой - директивами mfsroot_* в /boot/loader.conf).

А всего-навсего надо-то один системный вызов (MDIOCATTACH) на образ, а дальше монтировать можно уже штатно через /etc/fstab. Актуальность такого сервиса проявляется при создании "встроенных" решений для аппаратных систем с небольшим размером носителя (флеша) и RAM (необязательно на архитектуре i386). Можно было бы сжать файловую систему при помощи geom_uzip, "аттачить" её перед стартом /sbin/init как /dev/md0.uzip и прописать в /etc/fstab монтирование /dev/md0.uzip в качестве корня вместо действительного носителя. И не читать только для этого весь образ в дефицитную память.

Если быть педантичным, то есть способ обойтись штатными средствами: использовать /rescue/sh для запуска shell-скрипта перед вызовом /sbin/initloader есть и такая возможность), он подробно описан в статье http://wiki.freebsd.org/AvgLiveCD. Но для встроенных решений у него есть очевидный недостаток - он зависит от наличия /rescue/sh на загрузочном носителе, а этот файл (crunched binary) в FreeBSD 8.0 занимает чуть больше 4Mb. Для LiveCD это ничто, но встроенные системы могут иметь ненамного больше флеша. И ради одного системного вызова для них это может быть слишком большим оверхедом.

3. Наилучшим решением было бы расширить функциональность загрузчика и обучить его передавать в ядро информацию о необходимости подключать указанные в loader.conf файл-образы перед запуском /sbin/init, а также научить ядро использовать эту информацию и следовать её инструкциям. Но это относительно крупные изменения в системе.

Более легковесным (и полностью рабочим) решением будет маленький статический бинарник mdtab, созданный по описанной в пункте 1 технологии. Бинарник умеет прочитать свой конфиг /boot/mdtab.conf, в котором каждая строка описывает один файл-образ и состоит из двух полей, разделенных пробельными символами: имени сжатого geom_uzip-образа и точки монтирования. Затем он подключает и сразу монтирует (r/o) образ файловой системы. Размер бинарника для 8.0 получается менее 3Kb. Его можно запускать и в multiuser как любое другое приложение, а кроме того, можно использовать директиву init_path="/boot/mdtab" в loader.conf. В этом случае mdtab запускается ядром вместо /sbin/init с PID=1 и тогда он при окончании работы вместо _exit() запускает /sbin/init через execve, прозрачно передавая ему аргументы и environment.

Исходный код mdtab и Makefile для сборки доступны тут: http://www.grosbein.net/freebsd/mdtab-0.1.tgz

Пример /boot/mdtab.conf для одного образа на всю систему:
# Монтировать образ поверх корневой fs
/root.uzip      /
В образ надо убрать все файлы и каталоги, кроме /boot и /dev. При таком варианте после загрузки ядра (и монтирования им корневой файловой системы и devfs) mdtab смонтирует образ "поверх" рута и скроет доступ к /boot и /dev. При этом devfs будет автоматически повторно смонтирована одним из системных rcNG-скриптов при загрузке.

Можно сделать чуть иначе, монтируя образ не напрямую поверх рута, а в каталог /tree. В этом варианте нужно в корне наделать симлинков типа /usr -> /tree/usr (и так далее для всех подкаталогов корня, кроме /boot и /dev). При такой настройке остается доступ к /boot и /dev тоже не будет монтироваться дважды.

Date: 2010-06-27 10:43 (UTC)
From: [identity profile] dadv.livejournal.com
last pid: 41621;  load averages:  0.05,  0.12,  0.08   up 14+22:02:52  17:42:37
31 processes:  1 running, 30 sleeping
CPU:     % user,     % nice,     % system,     % interrupt,     % idle
Mem: 65M Active, 307M Inact, 95M Wired, 11M Cache, 59M Buf, 7524K Free
Swap: 

  PID USERNAME      THR PRI NICE   SIZE    RES STATE    TIME   WCPU COMMAND
35178 transmission    2  54    0 33632K 24928K kqread 115:33 15.87% transmissio
41617 root            1  50    0  3620K  1384K wait     0:00  0.20% login
 1071 root            4  44    0  3224K   200K rpcsvc  13:30  0.00% nfsd
  922 bind            4  44    0 35748K 25692K kqread   6:11  0.00% named
 1272 root            1  44    0  4740K  1340K select   2:14  0.00% ntpd
 1100 root            1  44    0  9972K  3836K select   1:46  0.00% mpd5
 1327 root            1  50    0  5144K  1236K select   1:01  0.00% sshd
 1337 root            1  44    0  5928K  1732K select   0:41  0.00% sendmail
  830 root            1  44    0  3280K   648K select   0:16  0.00% syslogd
 1350 root            1  44    0  3308K   520K nanslp   0:07  0.00% cron
  941 root            1  44    0  3308K  1016K select   0:03  0.00% rpcbind
 1342 smmsp           1  44    0  5928K  1212K pause    0:01  0.00% sendmail
 1069 root            1  44    0  3224K   536K select   0:00  0.00% nfsd
41538 eugen           1  44    0  4600K  2036K ttyin    0:00  0.00% tcsh
41618 eugen           1  46    0  4600K  2076K pause    0:00  0.00% tcsh
 1059 root            1  44    0  3280K  1108K select   0:00  0.00% mountd

Date: 2010-06-27 10:47 (UTC)
From: [identity profile] blacklion.livejournal.com
last pid: 79559;  load averages:  0.59,  0.61,  0.63 up 47+14:58:49  14:45:14
36 processes:  1 running, 35 sleeping
CPU: 13.6% user,  0.0% nice, 18.3% system, 10.5% interrupt, 57.6% idle
Mem: 328M Active, 53M Inact, 96M Wired, 9012K Cache, 60M Buf, 7652K Free
Swap:

  PID USERNAME  THR PRI NICE   SIZE    RES STATE    TIME   WCPU COMMAND
26058 rtorrent    1 100    0   398M   118M select 113.1H 16.31% rtorrent
  888 root        1  98    0  3372K   688K select  74.1H  6.05% natd
 1020 bind        4   4    0 40812K 10080K kqread   7:30  0.15% named
58795 rtorrent    1  96    0  3536K   904K select  18:03  0.00% screen
 1153 root        1   8   r0  3268K   260K nanslp  13:04  0.00% watchdogd
 1104 root        1  96    0  7964K  1052K select  11:31  0.00% nmbd
 1195 root        1  96    0  4672K   692K select   6:48  0.00% ntpd
 1144 dhcpd       1  96    0  3128K   336K select   5:08  0.00% dhcpd
 1126 www         1   4    0  5068K   876K kqread   3:18  0.00% lighttpd
 1220 root        1  96    0  5876K   768K select   2:46  0.00% sendmail
 1214 root        1  96    0  5752K   656K select   2:20  0.00% sshd
 1119 nutmon      1   8    0  4792K   508K nanslp   2:05  0.00% upsmon
  955 root        1  96    0  3184K   512K select   0:54  0.00% syslogd
 1264 root        1  96    0  3288K   404K select   0:50  0.00% hostapd
 1232 root        1   8    0  3212K   452K nanslp   0:25  0.00% cron
 1108 root        1  96    0 10160K   432K select   0:19  0.00% smbd
  379 _dhcp       1  96    0  3128K   412K select   0:16  0.00% dhclient
 1030 root        1  96    0  3212K   308K select   0:06  0.00% rpcbind
 1226 smmsp       1  20    0  5876K   576K pause    0:05  0.00% sendmail
79457 rtorrent    1  96    0  3496K  1228K RUN      0:03  0.00% top
  363 root        1  96    0  3128K   268K select   0:01  0.00% dhclient
79445 rtorrent    1  96    0  8428K  2188K select   0:00  0.00% sshd
79443 root        1   4    0  8428K  2052K sbwait   0:00  0.00% sshd
58798 rtorrent    1  20    0  5500K   220K pause    0:00  0.00% tcsh
79447 rtorrent    1  20    0  5500K  1160K pause    0:00  0.00% tcsh
79454 rtorrent    1  20    0  5500K  1184K pause    0:00  0.00% tcsh
79450 rtorrent    1  20    0  3536K  1004K pause    0:00  0.00% screen
  772 root        1  96    0  1888K    16K select   0:00  0.00% devd
 1282 root        1   5    0  3184K   180K ttyin    0:00  0.00% getty
 1258 root        1  96    0  3240K   224K select   0:00  0.00% inetd
 1117 root        1  -8    0  4792K   240K piperd   0:00  0.00% upsmon
  113 root        1  20    0  1380K   136K pause    0:00  0.00% adjkerntz
 1129 root        1  20    0 10160K   224K pause    0:00  0.00% smbd

Date: 2010-06-27 10:54 (UTC)
From: [identity profile] dadv.livejournal.com
60M свободно (Inact+Free), вполне можно жить и не заморачиваться - если конечно rtorrent не жалуется на недостаток памяти. Лично я ограничиваю скорость раздачи на 2 мегабита, чтобы не устраивать себе DDoS :-) Рейтинга больше семи мне вполне хватает.

Date: 2010-06-27 11:15 (UTC)
From: [identity profile] blacklion.livejournal.com
rTorrent работает через mmap() он регшулярно жалуется что ему 32-х битного адресного пространства не хватает :)
А вот скорость отдачи на это не влияет (влияет на процессор)...

Profile

dadv: (Default)
Choose your future

July 2024

M T W T F S S
12 34567
891011121314
15161718192021
22232425262728
293031    

Tags

Style Credit

Powered by Dreamwidth Studios