Subsecciones

6.3 ./arch/*

6.3.1 config.in

Se configura el menú de openMosix que se mostrarán en el front-end de configuración, invocado por ejemplo por el comando make menuconfig. Véase el código:

comment 'openMosix'
bool 'openMosix process migration support' CONFIG_MOSIX
if [ "$CONFIG_MOSIX" = "y" ]; then
        bool 'Support clusters with a complex network topology' CONFIG_MOSIX_TOPOLOGY
        if [ "$CONFIG_MOSIX_TOPOLOGY" = "y" ]; then
            int  'Maximum network-topology complexity to support (2-10)' CONFIG_MOSIX_MAXTOPOLOGY 4
        fi

        bool 'Stricter security on openMosix ports' CONFIG_MOSIX_SECUREPORTS
        int  'Level of process-identity disclosure (0-3)' CONFIG_MOSIX_DISCLOSURE 1
        #bool 'Create the kernel with a "-openmosix" extension' CONFIG_MOSIX_EXTMOSIX
        bool 'openMosix File-System' CONFIG_MOSIX_FS
        if [ "$CONFIG_MOSIX_FS" = "y" ]; then
           define_bool CONFIG_MOSIX_DFSA y
        fi
        bool 'Poll/Select exceptions on pipes' CONFIG_MOSIX_PIPE_EXCEPTIONS
        bool 'Disable OOM Killer' CONFIG_openMosix_NO_OOM
        bool 'Load Limit' CONFIG_MOSIX_LOADLIMIT
fi
endmenu

6.3.2 defconfig

Se guardarán todas las opciones del kernel seleccionadas por el usuario.

6.3.3 entry.S

Este fichero contiene todas las rutinas que manejan las llamadas a sistema. También implementa el gestor de interrupciones para los cambios de contexto en un switch de procesos.

#ifdef CONFIG_MOSIX
#include "mosasm.H"                   /*  libreria de codigo ensamblador de openMosix */  
#endif /* CONFIG_MOSIX */
Para pasar de modo sistema a modo usuario:
ENTRY(system_call)
        pushl %eax                      # save orig_eax
        SAVE_ALL
        GET_CURRENT(%ebx)
        testb $0x02,tsk_ptrace(%ebx)    # PT_TRACESYS
        jne tracesys
        cmpl $(NR_syscalls),%eax
        jae badsys
#ifdef CONFIG_MOSIX
        testl $(DTRACESYS1|DTRACESYS2),DFLAGS(%ebx)
        jne adjust_trace_before_syscall
adjusted_trace:
        testb $DREMOTE,DFLAGS(%ebx)
        je local_syscall
on_remote:
        pushl %eax
        call *SYMBOL_NAME(remote_sys_call_table)(,%eax,4)
        addl $4,%esp
        movl %eax,EAX(%esp)
        jmp ret_from_sys_call
local_syscall:
#endif /* CONFIG_MOSIX */
        call *SYMBOL_NAME(sys_call_table)(,%eax,4)
        movl %eax,EAX(%esp)             # save the return value
#ifdef CONFIG_MOSIX
        call SYMBOL_NAME(mosix_local_syscall)
#endif /* CONFIG_MOSIX */
ENTRY(ret_from_sys_call)
#ifdef CONFIG_MOSIX
        testl $(DTRACESYS1|DTRACESYS2),DFLAGS(%ebx)
        jne adjust_trace_before_syscall
ret_check_reschedule:
#endif /* CONFIG_MOSIX */
        cli                             # need_resched and signals atomic test
        cmpl $0,need_resched(%ebx)
        jne reschedule
        cmpl $0,sigpending(%ebx)
        jne signal_return
#ifdef CONFIG_MOSIX
straight_to_mosix:
        call SYMBOL_NAME(mosix_pre_usermode_actions)
        testl %eax,%eax
        jne ret_from_sys_call
#endif /* CONFIG_MOSIX */
restore_all:
        RESTORE_ALL

        ALIGN
signal_return:
        sti                             # we can get here from an interrupt handler
        testl $(VM_MASK),EFLAGS(%esp)
        movl %esp,%eax
        jne v86_signal_return
        xorl %edx,%edx
        call SYMBOL_NAME(do_signal)
#ifdef CONFIG_MOSIX
        jmp straight_to_mosix
#else
        jmp restore_all
#endif /* CONFIG_MOSIX */

        ALIGN
v86_signal_return:
        call SYMBOL_NAME(save_v86_state)
        movl %eax,%esp
        xorl %edx,%edx
        call SYMBOL_NAME(do_signal)
#ifdef CONFIG_MOSIX
        jmp straight_to_mosix
#else
        jmp restore_all
#endif /* CONFIG_MOSIX */

        ALIGN
tracesys:
        movl $-ENOSYS,EAX(%esp)
        call SYMBOL_NAME(syscall_trace)
#ifdef CONFIG_MOSIX
adjust_trace_before_syscall:            # only arrive here with DTRACESYS(1|2)
        testl $DDEPUTY,DFLAGS(%ebx)
        jne straight_to_mosix           # no mess with signals/syscalls/tracesys
        testl $DREMOTE,DFLAGS(%ebx)
        je no_need_to_unsync
        call wait_for_permission_to_continue
no_need_to_unsync:
        testl $DTRACESYS2,DFLAGS(%ebx)
        jne second_tracesys             # skipping system-call
        orl $DTRACESYS2,DFLAGS(%ebx)    # next time we skip the system-call
        movl $-ENOSYS,EAX(%esp)
        movl ORIG_EAX(%esp),%eax
        cmpl $(NR_syscalls),%eax
        jae second_tracesys             # prevent system-call out of range trick
        jmp adjusted_trace              # now do the system-call
second_tracesys:                        # note: "syscall_trace" clears the flags
#else
        movl ORIG_EAX(%esp),%eax
        cmpl $(NR_syscalls),%eax
        jae tracesys_exit
        call *SYMBOL_NAME(sys_call_table)(,%eax,4)
        movl %eax,EAX(%esp)             # save the return value
tracesys_exit:
#endif /* CONFIG_MOSIX */
        call SYMBOL_NAME(syscall_trace)
        jmp ret_from_sys_call
badsys:
        movl $-ENOSYS,EAX(%esp)
        jmp ret_from_sys_call

        ALIGN
ENTRY(ret_from_intr)
        GET_CURRENT(%ebx)
ret_from_exception:
        movl EFLAGS(%esp),%eax          # mix EFLAGS and CS
        movb CS(%esp),%al
        testl $(VM_MASK | 3),%eax       # return to VM86 mode or non-supervisor?
#ifdef CONFIG_MOSIX
        jne ret_check_reschedule
#else
        jne ret_from_sys_call
#endif /* CONFIG_MOSIX */
        jmp restore_all

        ALIGN
reschedule:
        call SYMBOL_NAME(schedule)    # test
        jmp ret_from_sys_call

6.3.4 i387.c

Guarda el contexto de los registros eprtenecientes al coprocesador i387.

6.3.5 ioport.c

Este fichero gestiona un mapa de bits que corresponden a los permisos que posee un proceso sobre los dispositivos de E/S.



static void set_bitmap()



Configura la máscara de permisos, esto no difiere del codigo del kernel vanilla de Linux. Al mapa bitmap se guarda el valor turn_on.

static void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value)
{
        int mask;
        unsigned long *bitmap_base = bitmap + (base >> 5);
        unsigned short low_index = base & 0x1f;
        int length = low_index + extent;

        if (low_index != 0) {
                mask = (~0 << low_index);
                if (length < 32)
                                mask &= ~(~0 << length);
                if (new_value)
                        *bitmap_base++ |= mask;
                else
                        *bitmap_base++ &= ~mask;
                length -= 32;
        }

        mask = (new_value ? ~0 : 0);
        while (length >= 32) {
                *bitmap_base++ = mask;
                length -= 32;
        }

        if (length > 0) {
                mask = ~(~0 << length);
                if (new_value)
                        *bitmap_base++ |= mask;
                else
                        *bitmap_base++ &= ~mask;
        }
}



asmlinkage int sys_ioperm()



Esta función modifica los permisos de E/S para el proceso en curso. Se invocará cuando un proceso deba dejar de mapear memoria del dispositivo de E/S o, en el caso de openMosix, cuando un proceso migrado quiera acceder a un dispositivo que se encuentre local al UHN.

asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
{
        struct thread_struct * t = &current->thread;             /*proceso en curso */
        struct tss_struct * tss = init_tss + smp_processor_id();

        if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32))
                return -EINVAL;
        if (turn_on && !capable(CAP_SYS_RAWIO))
                return -EPERM;
#ifdef CONFIG_MOSIX                                               /* si openmosix debe devolver el */           
        if(turn_on && !mosix_go_home_for_reason(1, DSTAY_FOR_IOPL))
                return(-ENOMEM);                                  /* proceso a su UHN por razones de E/S */
#endif /* CONFIG_MOSIX */
        /* Si el proceso aun no habia invocado a ioperm() se carga el mapa en memoria */
        if (!t->ioperm) {
                memset(t->io_bitmap,0xff,(IO_BITMAP_SIZE+1)*4);
                t->ioperm = 1;
        }

        /* se deberan copiar las modificaciones a los threads y TSS */
        /* TSS -Task State Segment. Es un segmento especifico en arquitecturas
        x86 para guardar contextos hardware */
        set_bitmap(t->io_bitmap, from, num, !turn_on);
        if (tss->bitmap == IO_BITMAP_OFFSET) { 
                set_bitmap(tss->io_bitmap, from, num, !turn_on);
        } else {
                memcpy(tss->io_bitmap, t->io_bitmap, IO_BITMAP_BYTES);
                tss->bitmap = IO_BITMAP_OFFSET; /* Activa el mapa modificado en el TSS */
        }

        return 0;
}

6.3.6 offset.c

Este fichero proporciona rutinas a las librerrías utilizadas en entry.S para las operaciones específicas de openMosix. Como:

6.3.7 ptrace.c

Configura y gestiona los registros SSE i FXSR de las arquitecturas Intel x86, a partir del P III-. SSE es el acrónimo de Streaming SIMD Extensions y mejora el rendimiento de la arquitectura Intel en 4 vesantes:

6.3.8 signal.c

En este fichero se maneja todo lo referente a las señales qe el sistema puede enviar a los procesos. El parche openMosix debe hacer considerables modificaciones, puesto que en los procesos migrados -procesos divididos en remote y deputy- la comunicación también debe ser posible, además de transparente. Igualmente tiene que ser posible hacer llegar a remote el señal para informarle de su vuelta, etc.



int copy_siginfo_to_user()



Para que el área de usuario esté informado del estado de los señales, controlado por el área de kernel, se le debe pasar la información sobre el mapa de interrupciones.

En procesos migrados esto es importante, puesto que supone una comunicación entre remote y deputy.

int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
{
        if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
                return -EFAULT;
        if (from->si_code < 0)
                return __copy_to_user(to, from, sizeof(siginfo_t));
        else {
#ifdef CONFIG_MOSIX
                int sz = offsetof(struct siginfo, _sifields);

                switch(from->si_code >> 16)
                {
                        case __SI_FAULT >> 16:
                                sz += sizeof(to->_sifields._sigfault);
                                break;
                        case __SI_CHLD >> 16:
                                sz += sizeof(to->_sifields._sigchld);
                                break;
                        case __SI_MIGRATION >> 16:
                                sz += sizeof(to->_sifields._sigmig);
                                break;
                        default:
                                sz += sizeof(to->_sifields._kill);
                                break;
                }
                return(__copy_to_user(to, from, sz));
#else
                int err;

                err = __put_user(from->si_signo, &to->si_signo);
                err |= __put_user(from->si_errno, &to->si_errno);
                err |= __put_user((short)from->si_code, &to->si_code);
                /* First 32bits of unions are always present.  */
                err |= __put_user(from->si_pid, &to->si_pid);
                switch (from->si_code >> 16) {
                case __SI_FAULT >> 16:
                        break;
                case __SI_CHLD >> 16:
                        err |= __put_user(from->si_utime, &to->si_utime);
                        err |= __put_user(from->si_stime, &to->si_stime);
                        err |= __put_user(from->si_status, &to->si_status);
                default:
                        err |= __put_user(from->si_uid, &to->si_uid);
                        break;
                }
                return err;
#endif /* CONFIG_MOSIX */
        }
}



asmlinkage int sys_sigreturn()



Envía el señal para mandar de regreso el remote.

asmlinkage int sys_sigreturn(unsigned long __unused)
{
        struct pt_regs *regs = (struct pt_regs *) &__unused;
#ifdef CONFIG_MOSIX
        struct sigframe *frame;
#else
        struct sigframe *frame = (struct sigframe *)(regs->esp - 8);
#endif /* CONFIG_MOSIX */
        sigset_t set;
        int eax;

#ifdef CONFIG_MOSIX
        mosix_obtain_registers(BIT_OF_REGISTER(esp));
        frame = (struct sigframe *)(regs->esp - 8);
#endif /* CONFIG_MOSIX */
La estructura sigframe contiene:

char *pretcode;
int sig;
struct sigcontext sc;
struct _fpstate fpstate;
unsigned long extramask[_NSIG_WORDS-1];
char retcode[8];

        if (verify_area(VERIFY_READ, frame, sizeof(*frame)))   /* verifica la correcta lectura al remoto */
                goto badframe;
        if (__get_user(set.sig[0], &frame->sc.oldmask)
            || (_NSIG_WORDS > 1
                && __copy_from_user(&set.sig[1], &frame->extramask,
                                    sizeof(frame->extramask))))
       /* con una correcta comunicacion, copia desde el remoto al UHN */
                goto badframe;

        sigdelsetmask(&set, ~_BLOCKABLE);
        spin_lock_irq(&current->sigmask_lock);   /* bloquea la seccion critica con semaforos */
        current->blocked = set;                  /* aplica la mascara de los registros al proceso en curso */
                                                 /* los registros bloquean el proceso, para recibir el senal */
        recalc_sigpending(current);              /* desbloquea la proteccion */
        spin_unlock_irq(&current->sigmask_lock);
        
#ifdef CONFIG_MOSIX
        if(current->mosix.dflags & DDEPUTY)
        {
                if (mosix_deputy_restore_sigcontext(&frame->sc, &eax))   
                /* restaura el contexto de los registros en el deputy */
                        goto badframe;
        }  /* si no se recupera bien el registro eax */
        else
#endif /* CONFIG_MOSIX */
        if (restore_sigcontext(regs, &frame->sc, &eax))
                goto badframe;
        return eax;

badframe:
        force_sig(SIGSEGV, current);
        /* en caso de que no se proceda satisfactoriamente, se envia SIGSEGV para abortar*/
        return 0;
}



asmlinkage int handle_signal()



Esta rutina atiende a las señales que recibe un proceso.

static void
handle_signal(unsigned long sig, struct k_sigaction *ka,
              siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
{
#ifdef CONFIG_MOSIX
        mosix_obtain_registers(
           BIT_OF_REGISTER(orig_eax)|BIT_OF_REGISTER(eax)|BIT_OF_REGISTER(eip));
#endif /* CONFIG_MOSIX */
        /* si se esta ejecutando una llamada a sistema, como es una se~nal */
        if (regs->orig_eax >= 0) {
                /* en este caso se informa al proceso, a traves del registro eax */
                switch (regs->eax) {
                        case -ERESTARTNOHAND:
                                regs->eax = -EINTR;
                                break;

                        case -ERESTARTSYS:
                                if (!(ka->sa.sa_flags & SA_RESTART)) {
                                        regs->eax = -EINTR;
                                        break;
                                }
                        /* fallthrough */
                        case -ERESTARTNOINTR:
                                regs->eax = regs->orig_eax;
                                regs->eip -= 2;
                }
        }

        /* Set up the stack frame */
#ifdef CONFIG_MOSIX
   /* si el proceso no es un proceso Linux completo, sino un deputy, se lo
trata como debe hacerse, mediante una llamada a mosix_deputy_setup_frame().
La mayor diferencia es que el deputy carece de segmento de datos para
almacenar esta informacion*/
        if(current->mosix.dflags & DDEPUTY)
                mosix_deputy_setup_frame(sig, ka, *info, oldset);
        else
#endif /* CONFIG_MOSIX */
        if (ka->sa.sa_flags & SA_SIGINFO)
                setup_rt_frame(sig, ka, info, oldset, regs);
        else
                setup_frame(sig, ka, oldset, regs);

        if (ka->sa.sa_flags & SA_ONESHOT)
                ka->sa.sa_handler = SIG_DFL;

        if (!(ka->sa.sa_flags & SA_NODEFER)) {
                spin_lock_irq(&current->sigmask_lock);   /* se bloquea la recepcion de interrupciones para el proceso */
                sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
                sigaddset(&current->blocked,sig);        /* se actualiza el estado de las interrupciones del proceso */
                recalc_sigpending(current);              /* se atiende a las interrupciones pendientes */
                spin_unlock_irq(&current->sigmask_lock); /* se desbloquea */ 
        }
}

6.3.9 vm86.c

Se gestiona la ejecución de los procesos en emulación vm86. La mayor aportación de código openMosix en esta sección se debe a que aún no se permite la ejecución de tales procesos estando migrados, es un aspecto que debe controlarse.



asmlinkage int save_v86_state()



Guarda el estado del proceso en emulación. Se le indica la opción de bloqueo para que PPM no intente migrarlo.

struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs)
{
        struct tss_struct *tss;
        struct pt_regs *ret;
        unsigned long tmp;

#ifdef CONFIG_MOSIX
        if(current->mosix.dflags & DREMOTE)
                panic("remote save_v86");
#endif /* CONFIG_MOSIX */
        if (!current->thread.vm86_info) {
                printk("no vm86_info: this is BAD\n");
                do_exit(SIGSEGV);
        }
        set_flags(regs->eflags, VEFLAGS, VIF_MASK | current->thread.v86mask);
        tmp = copy_to_user(&current->thread.vm86_info->regs,regs, VM86_REGS_SIZE1);
        tmp += copy_to_user(&current->thread.vm86_info->regs.VM86_REGS_PART2,
                &regs->VM86_REGS_PART2, VM86_REGS_SIZE2);
        tmp += put_user(current->thread.screen_bitmap,&current->thread.vm86_info->screen_bitmap);
        if (tmp) {
                printk("vm86: could not access userspace vm86_info\n");
                do_exit(SIGSEGV);
        }
        tss = init_tss + smp_processor_id();
#ifdef CONFIG_MOSIX
        lock_mosix();   /* ptrace checks saved_esp0 under the mosix-lock */
#endif /* CONFIG_MOSIX */
        tss->esp0 = current->thread.esp0 = current->thread.saved_esp0;
        current->thread.saved_esp0 = 0;
        ret = KVM86->regs32;
#ifdef CONFIG_MOSIX
        unlock_mosix();
        task_lock(current);
        current->mosix.stay &= ~DSTAY_FOR_86;    /* se marca la opcion de bloqueo del proceso */
        task_unlock(current);
#endif /* CONFIG_MOSIX */
        return ret;
}



asmlinkage int sys_vm86old()



En caso de tratarse de un proceso en emulación y de haberse iniciado la migración antes de percatarse de tal condición, se manda el señal para volver el proceso al UHN indicando la razón DSTAY_FOR_86.

asmlinkage int sys_vm86old(struct vm86_struct * v86)
{
        struct kernel_vm86_struct info; 
        struct task_struct *tsk;
        int tmp, ret = -EPERM;

#ifdef CONFIG_MOSIX
        if(!mosix_go_home_for_reason(1, DSTAY_FOR_86))
        {
                ret = -ENOMEM;
                goto out;
        }
#endif /* CONFIG_MOSIX */
        tsk = current;
        if (tsk->thread.saved_esp0)
                goto out;
        tmp  = copy_from_user(&info, v86, VM86_REGS_SIZE1);
        tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2,
                (long)&info.vm86plus - (long)&info.regs.VM86_REGS_PART2);
        ret = -EFAULT;
        if (tmp)
                goto out;
        memset(&info.vm86plus, 0, (int)&info.regs32 - (int)&info.vm86plus);
        info.regs32 = (struct pt_regs *) &v86;
        tsk->thread.vm86_info = v86;
        do_sys_vm86(&info, tsk);
        ret = 0;        /* we never return here */
out:
        return ret;
}



asmlinkage int sys_ioperm()




miKeL a.k.a.mc2 2004-09-06