6
votes

Comment fournir une fonctionnalité d'extension-on-écriture pour des fichiers mappés en mémoire sous Linux?

Je travaille sur le portage du code d'AIX à Linux. Parties du code Utilisez le shmat () appel système pour créer de nouveaux fichiers. Lorsqu'il est utilisé avec shm_map en mode helditable, on peut étendre le fichier au-delà de sa longueur d'origine (de zéro, dans mon cas):

Lorsqu'un fichier est mappé sur un segment, le fichier est référencé en accédant au segment. Le système de pagination mémoire s'occupe automatiquement des E / S physique. Les références au-delà de la fin du fichier font que le fichier soit étendu aux incréments de la taille de la page. Le fichier ne peut pas être étendu au-delà de la limite de segment suivante.

(un "segment" dans Aix est une partie de l'espace d'adressage de 256 Mo et une "page" est généralement de 4 Ko.)

Ce que je voudrais comme à faire sous Linux est ce qui suit:

  • Réservez une grande partie de l'espace d'adresses (il n'est pas nécessaire d'être aussi gros que 256 Mo, ce ne sont pas de tels fichiers volumineux)
  • Configurez les bits de protection de la page de sorte qu'un segfault soit généré sur le premier accès à une page qui n'a pas été touchée avant
  • sur une défaillance de la page, effacez le bit "Cause un défaut de page" et allouez la mémoire commise pour la page, permettant ainsi à l'écriture (ou à la lecture) qui a provoqué la faute de la page de continuer
  • Lors de la fermeture de la zone de mémoire partagée, écrivez les pages modifiées dans un fichier

    Je sais que je peux le faire sous Windows avec le Fonction VirtualProtect , le bit de protection de la mémoire Page_GUARD et a Handler des exceptions structurées . Quelle est la méthode correspondante sur Linux de faire de même? Y a-t-il peut-être un meilleur moyen de mettre en œuvre cette fonctionnalité de prolongation sur Linux?

    J'ai déjà envisagé:

    • en utilisant mmap () avec une taille de grande ish fixe, mais je ne peux pas dire à quel point le fichier a été écrit par le code de l'application
    • Allocation d'une zone de mémoire partagée anonyme de grande taille de l'ISH, mais encore une fois, je ne peux pas dire à quel point la région a été écrite
    • MMAP () Par lui-même ne semble pas fournir une installation pour étendre la longueur du fichier de support

      Naturellement, je voudrais le faire avec seulement des modifications minimales au code de l'application.


0 commentaires

3 Réponses :


0
votes

J'ai envisagé des choses similaires moi-même et je n'ai trouvé aucun moyen pour mmap () pour étendre le fichier de support.

Actuellement, je prévois d'essayer deux alternatives:

  • gérez manuellement la flux de fichiers, en prolongeant moi-même et mremap () 'ING APRESSE
  • Créez un fichier clairsemé et espérons que la machine virtuelle allouerait des secteurs nécessaires lors de la rinçage des pages sales.

    Honnêtement, je ne pense pas que les fichiers rares fonctionnent, mais ça vaut la peine d'essayer.


0 commentaires

3
votes

Allouer un gros tampon mais vous aimez, puis utilisez MProtect () * Call System pour rendre la queue du tampon en lecture seule et enregistrez un gestionnaire de signal pour SIGSEGV pour noter où dans les écrivies précédentes et utilisez MProtect () encore une fois pour activer les écrivies.


0 commentaires

5
votes

Ceci est très em> similaire à un devoir je l'ai fait. Fondamentalement, j'avais une liste de "pages" et une liste de "cadres", avec des informations associées. Utilisation de SIGSEGV CODE> J'attrape des défauts et modifierais les bits de protection de la mémoire si nécessaire. Je vais inclure des parties que vous pouvez trouver utiles.

Créer la cartographie. Initialement, il n'a pas d'autorisations. H3> xxx pré>

manutention d'installation h3> xxx pré>

gestionnaire d'exception h3> xxx

Protection croissante H3>
int w_protect_mapping(void *addr, size_t num_pages, w_prot_t protection)
{
    int prot;

    switch (protection) {
    case PROTECTION_NONE:
        prot = PROT_NONE;
        break;
    case PROTECTION_READ:
        prot = PROT_READ;
        break;
    case PROTECTION_WRITE:
        prot = PROT_READ | PROT_WRITE;
        break;
    }

    if (mprotect(addr, num_pages * w_get_page_size(), prot) < 0)
        return FALSE;

    return TRUE;
}


1 commentaires

Excellent, merci! C'est une structure très similaire à ce que j'ai fait auparavant sous Windows.