LINUX.ORG.RU

Операция read в ядре


0

0

Добрый день.

Ядро Linux 2.6.17 процессор sh4.

Есть модуль который переопределяет функию readpage структуры:

static struct address_space_operations my_asops = {
    readpage:   my_iop_readpage
};
Функцию readpage дергает ядро, в тот момент когда необходимо начитать страницу (struct page) в кэше. Реализация функции readpage в my_module просто дергает функцию read файловой системы:
char *buf;
struct file *filp;
filp->f_op->read(filp, buf, readlen,&(filp->f_pos))
Вопрос: является ли функция read (скажем ext2) синхронной?

Судя по исходному коду ядра вызов передается do_sync_read (отсюда делаю вывод, что функция синхронная). Но происходит следующее, если запустить на исполнение програму, обращение к которой перехватывает мой модуль,то можно заметить, что при наличии в коде модуля, задержек (например printk), страницы (struct page) заполняются данными и програма успешно запускаются. Если убрать все задержки то при первом запуске програма падает с SEGFAULT при втором BUS ERROR (либо наоборот порядок не известен), при третьем успешно запускается.

Если функция read асинхронная то насколько я понимаю при недоступности данных она должна вернуть некий код (что-то типа EAGAIN), но read все время возвращает кол-во прочитанных данных.



Последнее исправление: irishka (всего исправлений: 1)

>read(filp, buf, readlen, &(filp->f_pos))

Чёто я недогоню, что это за read такой? В каком хедере объявляется?

golodranez ★★★★
()

>Если убрать все задержки то при первом запуске програма падает с SEGFAULT при втором BUS ERROR (либо наоборот порядок не известен), при третьем успешно запускается.

Тебе не кажется, что даже два запуска будут длиться гораздо дольше, чем printk()? Странно как-то.

BUS ERROR - это что за ошибка?

golodranez ★★★★
()

Сделай массив в памяти и посмотри, правильно ли читаются данные, чтобы исключить влияние printk(). Поставь membar, может поможет.

frey ★★
()

-filp->f_op->read(filp, buf, readlen,&(filp->f_pos))
+buf=kmalloc(readlen, GFP_KERNEL);
+filp=get_filp();
+if (filp) {
+loff_t pos = file_pos_read(file);
+vfs_read(filp, buf, readlen, &pos);
+file_pos_write(file, pos);
+}

а вообще посмотри на системный вызов sys_read

xydo ★★
()
Ответ на: комментарий от xydo

но есть такая штука: она не гарантирует, что будет прочитано именно readlen байт. надо обрабатывать возвращаемое значение.

xydo ★★
()
Ответ на: комментарий от xydo

тест: записывала magic number в buf перед чтением и проверяла чтобы не было magic number после чтения таким образом данные точно считывались. Но исполняемые файлы все равно падают.

irishka
() автор топика
Ответ на: комментарий от irishka

еще раз: она не гарантирует, что будет прочитано именно readlen байт.
для одаренных: она может прочитать меньше.
если у вас это не обрабатывается, самое время добавить...
вообще, хотелось бы увидеть весь код. думаю, там есть, что фиксить...

xydo ★★
()
Ответ на: комментарий от irishka

> тест: записывала magic number в buf перед чтением и проверяла чтобы не было magic number после чтения таким образом данные точно считывались. Но исполняемые файлы все равно падают.

Это как бы намекает, что дело не в асинхронности.

tailgunner ★★★★★
()
Ответ на: комментарий от irishka

для начала создайте тупо модуль, который при загрузке будет выводить содержимое какого-нибудь текстового файла на stdout текущего приложения.
так вы отладите способ чтения файлов из пространства ядра (штука, кстати, весьма нетривиальная).

xydo ★★
()

> Реализация функции readpage в my_module просто

дергает функцию read файловой системы


так не может быть. как минимум a_ops->readpage()
должна обеспечить последующий unlock_page() и
PG_uptodate. иначе напр do_generic_file_read() просто
«повиснет» в lock_page().

что-то не то у вас, лучше код покажите целиком.

является ли функция read (скажем ext2) синхронной?


f_op->read() «синхронна», да.


как это часто бывает, складывается впечатление, что
вы пытаетесь сделать то, что делать бы и не стоило ;)

idle ★★★★★
()
Ответ на: комментарий от xydo

Структура my_file просто хранит (struct file*) на исходный файл.

static struct address_space_operations asops = {
    readpage:   iop_readpage
};

static int iop_readpage(struct file * filp, struct page * page) 
{
  struct dentry *dentry = filp->f_dentry;
  struct inode *inode = dentry->d_inode;
  char *buf;
  int ret = -1;
  unsigned long offset, avail, readlen;
  struct my_file *my_filp;
  my_filp = (struct my_file *)filp->private_data;

  int result = -EIO;

  inode->i_atime = CURRENT_TIME;
  get_page(page);
  buf = page_address(page);
  offset = page->index << PAGE_CACHE_SHIFT;
  if(offset < inode->i_size)
  {
          ssize_t n;
          avail = inode->i_size-offset;
          readlen = min(avail, PAGE_SIZE);
          if (offset != my_filp->source_file->f_pos){
                loff_t seek_res = 0;
                LLSEEK(my_filp->source_file, offset, SEEK_SET, seek_res);
                if (seek_res < 0 ) {
                goto file_seek_failed;
            };

          }
	
	if ( !my_filp->source_file || !my_filp->source_file->f_op->read || (n = my_filp->source_file->f_op->read(my_filp->source_file, buf, readlen, &(my_filp->source_file->f_pos))) != readlen ) {
                printk( KERN_ERR "read_content:source file read failed n=%d\n", n );
                goto ret;
          }

         if(n == readlen)
          {
                  filp->f_pos = my_filp->source_file->f_pos;
                  if (readlen < PAGE_SIZE){
                        memset((void *)((char *)buf+readlen),0,PAGE_SIZE-readlen);
                    set_bit(PG_uptodate, &page->flags);
                  result = 0;
          }
          else if(n < 0)
                  result = n;
ret:
  if(result > 0)
  {
          memset((char *)buf, 0, PAGE_SIZE);
          SetPageError(page);
  }

  unlock_page(page);
  free_page((unsigned long)buf);
  return result;

file_seek_failed:
    return -1;
}
irishka
() автор топика
Ответ на: комментарий от xydo

Спасибо всем. Нашла проблемму. Необходимо было дернуть функцию void flush_dcache_page(struct page *page) после записи данных на страницу. Помог анализ исходников squashfs.

irishka
() автор топика
Ответ на: комментарий от irishka

ой.

с таким форматированием я этот код читать не могу.
он, кажется, и компилиолваться не должен, но я поверю
на слово...

inode->i_atime = CURRENT_TIME;


зачем?

get_page(page);


зачем? caller must have a reference.

free_page((unsigned long)buf);


ик. тогда уж put_page(page) или page_cache_release()

buf = page_address(page);

...


f_op->read(..., buf, ...)



не понимаю, как это работает без set_fs(KERNEL_DS)

LLSEEK(..., offset, ...)

... WINDOW ...


f_op->read(..., &(my_filp->source_file->f_pos))



а теперь представьте, что в этом окне другой thread
сделает то же самое, или просто поменяет ->f_pos ?
и, кстати, зачем вообще seek ?


ну, и по прежнему непонятно, для чего все это нужно.

idle ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.