Newsgroup: it.comp.os.linux.development
Titolo: syscall

Ciao a tutti.
Ho un problema con una nuova syscall che sto realizzando :
tale syscall dovrebbe fondere in maniera atomica le operazioni compiute da
lseek e read.
Nesun problema sulla scrittura del codice (eccettuato, forse, qualche crisi
schizofrenica nella comprensione del codice della lock_kernel() :-)) ).
Il problema è un altro :
ho fatto l'update alla sys_call_table entry.S, inserendo la stringa relativa
alla nuova chiamata di sistema, e ho aggiornato il contenuto del file
<linux/unistd.h>.
Il proto della func l'ho messo in <unistd.h>.
quando vado a compilare un programma tester, il linker mi dà il seguente
errmsg:
undefined reference to atomic_read ecc...ecc...
Ho capito che manca qualcosa che serve a fatrgli trovare la funzione.
Ma che cosa???
Grazie a chi saprà rispondermi
@LeX
#define __TRUE__ "C is BETTER"

lseek e read.
Non mi sembra una cosa furba. Spiega cosa vuoi fare, probabilmente c'e`
un sistema piu` semplice.
-- 
ciao, |
Marco | * The Internet is full. Go away.  -- Joel Furr *
      | (Ri)scoprire fidonet: 
http://bbs.mi.linux.it

 un sistema piu` semplice.
Quello che devo fare è esattamente quello che hai letto.
il fatto che ti sembri furbo o meno.... mi sembra che esuli dall'argomento
della discussione.
@LeX


Ma che cosa???
Ho avuto anch'io lo stesso problema quando ho voluto implemetare
una mlockall(int flags, pid_t pid) :-)
Credo che quello che manchi sia la definizione di una macro del tipo:
_syscall3(ssize_t, atomic_read, int, fd, void, *buf, size_t, count);
Sempre che la tua nuova atomic_read() sia di 3 argomenti, altrimenti
devi definirla come _syscall4, _syscall5 eccetera.
Al limite puoi anche definirla nei sorgenti dei programmi che la
usano. Almeno io, come faccia glibc non l'ho capito :-)
-- 
Lorenzo
"Given enough eyeballs, all bugs are shallow", Linus'Law
(address rot13 encoded)

 ha scritto nel messaggio
news:slrn8kjr2k...@localhost.localdomain...



Dunque aspetta un po'...
A parte che come consiglio è mitico... ma spiegami come faccio ad usarla,
dove devo definirla, che parametri prende, ecc.ecc...
Insomma, se puoi, illustrami tutto quello che sai sulle _syscall?.
Grazie in anticipo :)))))
@LeX

tipo quello che dici tu....
Si, la definizione della macro, ma e` generica, devi specificarla.
Ovviamente lo dovrebbero fare gli include di glibc ma:
1) Non ho la minima idea come lo faccia :-)
2) E` bastato che lo facessi io, e funziona...
Per specificarla fai come ho detto nell'altro articolo.
Consiglio:
Se e` possibile, implementa la nuova chiamata con un modulo caricabile.
E` meno invasivo e piu` comodo.
Non si puo` modularizzare tutto, vedi nel tuo caso se i simboli
esportati dal kernel (/proc/ksyms) ti bastano.
Se non ti bastano, o li esporti tu, ma sicuramente Linus ti lanciera`
qualche fulmine e "sporcheresti" ancor di piu` il kernel, oppure
devi per forza patchcare il kernel e ricompilare tutto.


stud in assembler che lancino la sys call?? Tu per aggiungere mlockall non
No. Ma ribadisco che quasi sicuramente aggiungere una system call e` il
modo sbagliato per fare quello che devi fare, qualunque cosa sia.



Esempio, volevo fare una mlockall2(int flags, int pid).
Tra prentesi, non ho ancora capito perche` gli ingegneri dello
standard POSIX si siano inventati una mlockall senza la selezione
del pid...
Ho patchato il kernel e l'ho implementata, non e` stato difficile.
L'ho aggiunta a entry.S e a linux/asm/unistd.h
Per fare una cosa piu` portabile bisognerebbe anche patchare tutti
gli altri entry.S e linux/asm/unistd.h delle altre architetture
ma... andavo di fretta :-)
A questo punto l'unico problema e` trovare un modo per chiamarla
da un programma. Glibc (con gli include) deve saperla riconoscere
come syscall e sostituire la chiamata con un:
mov eax, __NR_mlockall2
int 0x80
Alrimenti dobbiamo farlo a mano, e non ci va.
Il problema e` che non avevo capito (tutt'ora) qual'e` il meccanismo
che usa glibc. Sapevo solo che usava una macro.
In verita` se uno guarda in /usr/include/unistd.h puo` trovare per
esempio:
extern __pid_t __getpid __P ((void));
Immagino che quel __P sia una qualche macro per la syscall ma non
so dove la definisce ne come la definisce.
In ogni caso si trattava di modificare gli include della glibc
per una sola chiamata, non standard, per un solo programma!
Mi sembrava un sacrilegio...
Dopo essermi sbattuto per un po` senza riuscirci ho tentato l'ultima
soluzione.
Visto che <asm/unistd.h> oltre a definire i numeri delle entry definisce
anche la macro delle syscall (_syscallX), mi e` bastato includerlo
nel programma e specificare la macro per la mia syscall.
Questo e` il codice di mlock.c, il programma in userspace che usa
le nuove chimate di sistema:
(Non vi affrettate a criticare il codice, lo so che e` lo sport
 preferito di ogni programmatore ma questo caso e` solo un banale
 esempio :)
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/mman.h>
#include <asm/unistd.h> /* Ecco l'include... */
#define BOOL int
#define FALSE 0
#define TRUE  1
/* ... e le macro */
_syscall2(int, mlockall2, int, flags, pid_t, pid);
_syscall1(int, munlockall2, pid_t, pid);
int main(int argc, char *argv[])
{
        int pid;
	BOOL unlock = FALSE;
	int c;
 
	if (argc < 2) {
	        printf("Usage: mlock [-u] -p <pid>\n");
		exit(1);
        }
        while (1) {
                c = getopt(argc, argv, "up:");
                if (c == -1)
                        break;
                switch (c) {
                case 'u':
                        unlock = TRUE;
                        break;
	        case 'p':
	                pid = atoi(optarg);
	                break;
	        case 'V':
	                printf("Version 0.90\n");
			exit(1);
		}
        }
	if (unlock) {
                if (munlockall2(pid) == -1)
		        perror("unlockall2");
	} else {
	        if (mlockall2(MCL_CURRENT | MCL_FUTURE, pid) == -1)
                        perror("mlockall2");
	}
	return 0;
}
=======================================================
Nel tuo caso dipende da come hai definito la tua atomic_read(2).
Mi spiego, se il numero e il tipo degli argomenti della tua syscall
e` uguale a quello della read(2), puoi fare cosi`:
_syscall3(ssize_t, atomic_read, int, fd, void, *buf, size_t, count);
            .^         .^       .^   .^
Tipo di  __/          /        /    /
ritorno             /        /    /
           Nome __/        /    /
	                 /    /
Tipo primo argomento __/    /
                          /
Argomento, ecc ecc    __/
Ti adatti la macro secondo come hai definito la tua atomic_read(2)
e la usi.
E` tutto :-)


 del pid...
Perchè la mlockall agisce sul processo chiamante, e quindi il pid non
serve a niente.
Ciao,
Fabio Alemagna




serve a niente.
Grazie, lo sapevo :-)
Tuttavia una mlockall con selezione del pid sarebbe stata molto piu`
flessibile, permettendo di lockare la memoria da un'altro processo.


modo sbagliato per fare quello che devi fare, qualunque cosa sia.
Non sempre Marco, ci sono casi in cui avere una syscall consente
di risolvere certi problemi in modo pulito e ordinato, senza trucchi.
Se poi riesci ad implementarla con un modulo allora e` il massimo.
Del resto anche Linux ne ha diverse di chiamate non standard.
Ne approfitto per chiederti un tuo parere sulla ipotetica
mlockall2(int flags, int pid) e sul perche` la mlockall(2)
non abbia la (secondo me) utilissima selezione del pid, visto
che non ci sono problemi di sicurezza in quanto la chiamata
la puo` fare solo root.
Non mi risulta esista un modo "pulito" per lockare la memoria
da un altro processo, se c'e` mi piacerebbe saperlo :-)


 flessibile, permettendo di lockare la memoria da un'altro processo.
I processi per definizione hanno spazi di indirizzamento diversi proprio
per evitare che un processo possa maneggiare la memoria di un altro...
Se vuoi che un processo possa lockare la sua memoria è giusto che lo
sappia, non credi? :)
Puoi dirglielo di fare spedendogli un messaggio, tramite pipe, SysV IPC,
socket...
Saluti,
Fabio Alemagna

socket...
In linea teorica si, sono d'accordo.
Nella pratica pero` una simile chiamata potrebbe essere utile
perche` ti da la flessibilita` (un)lockare la memoria di un processo
da un'altro processo, con gli opputuni privilegi di root ovviamente,
in situazioni particolari che potrebbero verificarsi.
In altre parole hai un controllo maggiore sul sistema senza perdere
niente, neanche in sicurezza visto che le chiamate le puo` fare
solo root. Pensa all'utilita` di una munlockall(int pid) per esempio
in situazioni di "memory pressure". Potrebbe essere vitale forzare
una munlockall per liberare memoria piu` utile ad altri processi
senza ucciderli.
Ripeto, in teoria sono d'accordo ma nella pratica ci si scontra
con problemi inaspettati, tipo che Linux uccide processi a caso,
quindi anche processi root, in situazioni di out of memory.
Solamente i processi che non generano page fault riescono a
sopravvivere, cioe` quelli che hanno la memoria lockata.
Non basta dire "compra piu` memoria" perche` e` una soluzione
parziale al problema che puo` benissimo riverificarsi.
Anche limitare le risorse dei processi utenti puo` non essere
la miglior soluzione perche` quello che serve e` un meccanismo
di controllo sicuro e certo, indipendente da questi fattori.
Insomma, se e` possibile fare #kill -9 `pidof inetd per esempio,
perche` non dovrebbe essere possibile forzare il lock o l'unlock
della memoria di un processo che e` una cosa meno drammatica?


 ha scritto nel messaggio
Dire che sei un mito č poco!!!
Paolo... mi sa che ora č il caso di metterci al lavoro sul serio :)))
Mi sa che non abbiamo piů scuse :))
@LeX
#define __TRUE__ "C is Better"

da un altro processo, se c'e` mi piacerebbe saperlo :-)
Non mi risulta nemmeno che esista la necessita` di fare una cosa simile.
Se veramente non puoi modificare il programma ti avevo gia` spiegato
come fare la stessa cosa molto piu` semplicemente con LD_PRELOAD.


come fare la stessa cosa molto piu` semplicemente con LD_PRELOAD.
Stavo pensando, se uso LD_PRELOAD per intercettare getpid()
che viene eseguita sempre all'inizio, qualsiasi chiamata a
getpid() seguente sara` "sporcata" dal codice che ci metto in
piu` (la mlockall).
Si puo` sganciare la libreria in LD_PRELOAD subito dopo aver
fatto quello che mi serve?
Forse ho capito male?


piu` (la mlockall).
static int flag = 0;
int getpid (void) {
    if (!flag) {
	if (mlockall(MCL_CURRENT | MCL_FUTURE) < 0) {
	    perror("mlockall");
	    abort;
	}
	flag = 1;
    }
    return (*o_getpid) ();
