09 - Mmap

mmod1.c

mmod1.c
/* Bufor pamięci jest tworzony oddzielnie dla każdego procesu, podczas 
   wywyołania open, i niszczony po zamknięciu pliku.
*/
 
#include <linux/module.h>
#include <linux/kernel.h>
 
/* Definicje związane z obsługą mmap */
#include <linux/mm.h>
#include <linux/slab.h>
 
/* Api debugfs */
#include <linux/debugfs.h>
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marcin Bis");
MODULE_DESCRIPTION("Pierwszy moduł");
 
/* Dane do których można dostać się przez mmap() */
struct mmap_info {
  char *data;     /* dane */
  int reference;   /* ile jest do nich odwolan */
};
 
/* Funkcje obsługują mapowanie i odmapowywanie pamięci 
   oraz ilość odwołań do niej */
void mmap_open(struct vm_area_struct *vma)
{
  struct mmap_info *info =
    (struct mmap_info *)vma->vm_private_data;
  info->reference++;
}
 
void mmap_close(struct vm_area_struct *vma)
{
  struct mmap_info *info =
    (struct mmap_info *)vma->vm_private_data;
  info->reference--;
}
 
/* Funkcja jest wywoływana podczas pierwszego dostępu do pamięci przez proces
   kiedy jeszcze nie jest ona przydzielona. Funkcja zajmuje się alokacją
   pamięci i współdzieleniem jej pomiędzy przestrzeń adresową procesu i jądra */
static int mmap_fault(struct vm_area_struct *vma,
                      struct vm_fault *vmf)
{
  struct page *page;
  struct mmap_info *info;
 
  /* sprawdzamy, czy dane znajdują się we właściwym miejscu */
  info = (struct mmap_info *)vma->vm_private_data;
  if (!info->data) {
    printk(KERN_ALERT "No data\n");
    return VM_FAULT_SIGBUS;
  }
 
  /* pobierz adres strony */
  page = virt_to_page(info->data);
 
  /* zwiększ licznik odwołań do tej strony */
  get_page(page);
 
  vmf->page = page;
  return 0;
}
 
/* struktura opsiująca operacje mmapowania */
struct vm_operations_struct mmap_vm_ops = {
  .open   = mmap_open,
  .close  = mmap_close,
  .fault = mmap_fault,
};
 
/* funckja obsługująca operację mmap na pliku */
int m_mmap(struct file *filp, struct vm_area_struct *vma)
{
  vma->vm_ops = &mmap_vm_ops;
  vma->vm_flags |= VM_RESERVED;
  /* prywatne dane pliku są przypisywane stronie pamięci */
  vma->vm_private_data = filp->private_data;
  mmap_open(vma);
  return 0;
}
 
/* obsługa operacji otwierania pliku */
int m_open(struct inode *inode, struct file *filp)
{
  /* alokacja pamięci */
  struct mmap_info *info =
    kmalloc(sizeof(struct mmap_info), GFP_KERNEL);
  info->data = (char *)get_zeroed_page(GFP_KERNEL);
  #define NAPIS "Hello from kernel, how do you hear me?\nThis is file: "
 
  memcpy(info->data, NAPIS, strlen(NAPIS));
  memcpy(info->data + strlen(NAPIS), filp->f_dentry->d_name.name,
                              strlen(filp->f_dentry->d_name.name));
  /* nowoutworzona struktura jest następnie przypisywana do pliku */
  filp->private_data = info;
  return 0;
}
 
/* obsługa operacji zamykania pliku */
int m_close(struct inode *inode, struct file *filp)
{
  struct mmap_info *info = filp->private_data;
  /* wypisujemy komunikat z aktualnym stanem bufora */
  printk(KERN_INFO
   "Mmap example module memory just after removal:\n%s\n------> ENDS HERE <------\n",
   info->data);
  /* zwolnienie pamięci */
  free_page((unsigned long)info->data);
  kfree(info);
  filp->private_data = NULL;
  return 0;
}
 
/* struktura opisująca operacje na pliku */
static const struct file_operations m_fops = {
  .open = m_open,
  .release = m_close,
  .mmap = m_mmap,
};
 
/* Podczas inicjowania modułu w systemie plików debugfs (aby nie dodawać kolejnych funckji),
   rejestrowany jest plik */
struct dentry *file1;
 
int __init mmod_init(void)
{
  file1 = debugfs_create_file("mmap_module_example", 0644, NULL, NULL, &m_fops);
  printk(KERN_INFO "Mmap example module loaded.\n");
  return 0;
}
module_init(mmod_init);
 
void __exit mmod_exit(void)
{
  debugfs_remove(file1);
  printk(KERN_INFO "Mmap example module unloading.\n");
}
module_exit(mmod_exit);

mmap_user.c

mmap_user.c
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
 
#define PAGE_SIZE 4096
 
int main (int argc, char **argv)
{
  int fd;
  fd = open("/sys/kernel/debug/mmap_module_example", O_RDWR);
  if (fd < 0) {
    printf("Nie moge otworzyc pliku.\n");
    return -1;
  }
 
  char *address = NULL;
  address = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
  if (address == MAP_FAILED) {
    printf("Nie udalo sie wykonac mmap.\n");
    return -1;
  }
 
  printf("teraz jest: %s\n", address);
  memcpy(address + 11, "*user*", 6);
  printf("Zmienilem.\n");
  printf("teraz jest: %s\n", address);
  close(fd);
 
  return 0;
}

mmod2.c

mmod2.c
/* Implementacja pamięci współdzielonej - bufor jest alokowany przy ładowaniu modułu. */
 
#include <linux/module.h>
#include <linux/kernel.h>
 
/* Definicje związane z obsługą mmap */
#include <linux/mm.h>
#include <linux/slab.h>
 
/* Api debugfs */
#include <linux/debugfs.h>
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marcin Bis");
MODULE_DESCRIPTION("Mmap moduł");
 
/* Dane do których można dostać się przez mmap() */
struct mmap_info {
  char *data;     /* dane */
  int reference;  /* ile jest do nich odwolan */
};
 
struct mmap_info *info = NULL;
 
/* Funkcje obsługują mapowanie i odmapowywanie pamięci 
   oraz ilość odwołań do niej */
void mmap_open(struct vm_area_struct *vma)
{
  struct mmap_info *linfo =
    (struct mmap_info *)vma->vm_private_data;
  linfo->reference++;
}
 
void mmap_close(struct vm_area_struct *vma)
{
  struct mmap_info *linfo =
    (struct mmap_info *)vma->vm_private_data;
  linfo->reference--;
}
 
/* Funkcja jest wywoływana podczas pierwszego dostępu do pamięci przez proces
   kiedy jeszcze nie jest ona przydzielona. Funkcja zajmuje się alokacją
   pamięci i współdzieleniem jej pomiędzy przestrzeń adresową procesu i jądra */
static int mmap_fault(struct vm_area_struct *vma,
                      struct vm_fault *vmf)
{
  struct page *page;
  struct mmap_info *linfo;
 
  /* sprawdzamy, czy dane znajdują się we właściwym miejscu */
  linfo = (struct mmap_info *)vma->vm_private_data;
  if (!linfo->data) {
    printk(KERN_ALERT "No data\n");
    return VM_FAULT_SIGBUS;
  }
 
  /* pobierz adres strony */
  page = virt_to_page(linfo->data);
 
  /* zwiększ licznik odwołań do tej strony */
  get_page(page);
 
  vmf->page = page;
  return 0;
}
 
/* struktura opsiująca operacje mmapowania */
struct vm_operations_struct mmap_vm_ops = {
  .open   = mmap_open,
  .close  = mmap_close,
  .fault = mmap_fault,
};
 
/* funckja obsługująca operację mmap na pliku */
int m_mmap(struct file *filp, struct vm_area_struct *vma)
{
  vma->vm_ops = &mmap_vm_ops;
  vma->vm_flags |= VM_RESERVED;
  /* prywatne dane pliku (w których znajduje się już wskaźnik na strukturę
     ze współdzielonymi danymi, są przypisywane stronie pamięci */
  vma->vm_private_data = filp->private_data;
  mmap_open(vma);
  return 0;
}
 
/* obsługa operacji otwierania pliku */
int m_open(struct inode *inode, struct file *filp)
{
  filp->private_data = info;
  return 0;
}
 
/* obsługa operacji zamykania pliku */
int m_close(struct inode *inode, struct file *filp)
{
  filp->private_data = NULL;
  return 0;
}
 
/* struktura opisująca operacje na pliku */
static const struct file_operations m_fops = {
  .open = m_open,
  .release = m_close,
  .mmap = m_mmap,
};
 
/* Podczas inicjowania modułu w systemie plików debugfs (aby nie dodawać kolejnych funckji),
   rejestrowany jest plik */
struct dentry *file1;
 
static int __init mmod_init(void)
{
  /* alokacja pamięci */
  info = kmalloc(sizeof(struct mmap_info), GFP_KERNEL);
  info->data = (char *)get_zeroed_page(GFP_KERNEL);
 
  file1 = debugfs_create_file("shm_module_example", 0644, NULL, NULL, &m_fops);
 
  printk(KERN_INFO "Mmap shm example module loaded.\n");
  return 0;
}
module_init(mmod_init);
 
static void __exit mmod_exit(void)
{
  printk(KERN_INFO "Mmap shm example module unloading.\n");
  debugfs_remove(file1);
  free_page((unsigned long)info->data);
  kfree(info);
}
module_exit(mmod_exit);

shm_user.c

shm_user.c
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
 
#define PAGE_SIZE 4096
 
int main (int argc, char **argv)
{
  int fd;
  fd = open("/sys/kernel/debug/shm_module_example", O_RDWR);
  if (fd < 0) {
    printf("Nie moge otworzyc pliku.\n");
    return -1;
  }
 
  char *address = NULL;
  address = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
  if (address == MAP_FAILED) {
    printf("Nie udalo sie wykonac mmap.\n");
    return -1;
  }
 
  printf("teraz jest: %d\n", *address);
  (*address)++;
  close(fd);
 
  return 0;
}

Makefile

Makefile
obj-m += mmod1.o
obj-m += mmod2.o
 
all:
	make -C /lib/modules/$(shell uname -r)/build \
		SUBDIRS=$(shell pwd) modules
	$(CC) -o mmap_user mmap_user.c
	$(CC) -o shm_user shm_user.c
 
clean:
	make -C /lib/modules/$(shell uname -r)/build \
		SUBDIRS=$(shell pwd) clean
	rm -f mmap_user shm_user
ostatnio zmienione: 2011/06/16 15:58