shmget() ENOSPC-vel elszáll virtuozzo virtualizált környezetben

 ( abszint | 2010. december 10., péntek - 22:14 )

Hello,

adott egy 32 bites virtuozzo-val virtualizált gép, amelyen a

int ret = shmget(0xXXXXXXXX, YYYYYYYY, IPC_CREAT|IPC_EXCL|0660);

parancs ENOSPC-vel elszáll. A sysctl-ben beállítottam a
kernel.shmmax = 4294967295
kernel.shmall = 268435456
paramétereket, és ulimit sincs.

100MB memóriát szeretnék lefoglalni, van szabadon 1.5 GIGA. Swap nincs a géphez.

Virtuozzo specifikus dolog lehet? Találkozott már valaki ilyennel?

Ui: 0 shm segment és 0 szemafor van használva, biztos nem az fogyott el

Hozzászólás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

Virtuozzo/OpenVZ specifikus - nezd meg user beancounters (/proc/user_beancounters) tartalmat, valoszinuleg tullepted a vm limitjet. vzctl set $VEID --shmpages X segitsegevel beallithatod mennyi shm legyen elerheto a vm-en belul.

http://wiki.openvz.org/Resource_shortage
http://wiki.openvz.org/Shmpages#shmpages

Helló, itt a kimenet:


uid resource held maxheld barrier limit failcnt
shmpages 5940 16042 19567 19567 3

Ezek szerint 20 ezer page, azaz kemény 80 mega SHM van engedélyezve. Sajnos a szolgáltató nem fogja miattam átállítani, nincs valami módszer a kliens oldalról a memória rovására az shm növelésére?

Nem tudom, hogy hogyan működik ez a virtualizáló izé, de elképzelhető, hogy az shm memóriaterület globális erőforrás (azaz az összes virtuális gép ugyanabból a keretből dolgozik), ezért kénytelenek korlátozni a használatot, hogy mindenkinek jusson.

subscribe

Virtualizációtól függetlenül javaslom az alábbit. Feltételezem, hogy a memóriát szülő-gyerek viszonyban osztod meg (*).

shmget() helyett használj mmap()-et. A lényeg az, hogy ne anonim mapping-et használj (mint az shmget), hanem regular file backed mapping-et. A különbség nagyjából csak annyi, hogy nem a swap lesz a backing store, hanem egy reguláris file. Ezt ajánlom:

  1. fd = open(tmpfname, O_RDWR | O_CREAT | O_EXCL, (mode_t)0); -- A nullás mód nem tévedés.
  2. unlink(tmpfname);
  3. pgsiz = sysconf(_SC_PAGE_SIZE);
  4. posix_fallocate(fd, 0, fsiz = (YYYYYYYY + pgsiz - 1) / pgsiz * pgsiz); -- felkerekítve lapméretre. Bár alaposabban nézegetve az mmap() speckóját, ez valószínűleg nem is kell.
  5. addr = mmap(0, fsiz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  6. close(fd);
  7. fork();

Attól, hogy a címtartomány alatt egy reguláris file van, nem a swap, még semmivel sem valószínűbb a diszkre írogatás. (Ha tudod, milyen minta szerint fogják a processzek elérni a tartományt, akkor adhatsz tippet az OS-nek, lásd posix_madvise().)

A fenti hatására a file nagyon rövid ideig lesz látható a filerendszerben (és idegen uid-ok számára azalatt is megnyithatatlan lesz, és azonos euid számára is tipp lesz a nullás mód), onnantól kezdve csak mapping referenciák lesznek a file-ra. Ha az összes hivatkozó processz leáll (rendesen, vagy kilövik), a file területe automatikusan fel fog szabadulni, ráadásul az OS-nek még csak nem is szükséges kiírnia a diszkre a tartomány tartalmát (az _exit()-ben automatikusan bennefoglalt munmap() hatására ezt meg kellene tennie egyébként, úgy gondolom). Az mmap()-ra tehát most nem úgy kell tekinteni, hogy byte-tömb-ként akarunk használni egy file-t, hanem úgy, hogy odateszünk egy ideiglenes "swap file"-t egy osztott memóriatartomány mögé.

(*) Ha a memóriát nem ilyen viszonyban lévő processzek között osztod meg, akkor ugye az shmget()-et is úgy használod valószínűleg, hogy az összes processzben ftok()-kal eljutsz ugyanahhoz a kulcshoz ugyanabból a file-ból, majd shmget()-tel eljutsz az azonosítóhoz, majd shmat()-tal rácsatlakozol. (Feltéve, hogy az egész előtt egy dedikált processz létrehozta a szegmenst.) Ugyanezt megteheted mmap()-pel is: (a) a backing store-t adó file-t nem törlöd le, hanem tartósan megőrzöd, vagy (b) a backing store-t adó file-t letörlöd ugyan, de egy dedikált daemon processzben egyetlen fd referenciát nyitva tartasz rá. Ehhez a daemon-hoz hozzácsatlakoznak a többiek egy unix domain socket-en, amin keresztül a daemon SCM_RIGHTS-szal átküldi az fd-t ("interprocess dup()"). Ezután minden processz maga végrehajthatja az mmap()-et és a close()-t. Remélhetőleg azért a megosztásra nem így van szükséged, hanem szülő-gyerek viszonyban.