LINUX.ORG.RU

Реализация системного вызова ?


0

0

Здравствуйте !

Вопрос про реализацию системного вызова в 2.6.21.5 Создаю свой собственный вызов sys_copy - получает дескрипторы входного и выходного файлов. Должен осуществлять копирование между ними в пространстве ядра ... Но возвращает значение < 0. Пытаюсь для копирования использовать sys_read/sys_write (read/write) из fs/read_write.c

#include <linux/stat.h>

#include <linux/types.h>

#include <asm/unistd.h>

#include <linux/stat.h>

#include <linux/fcntl.h>

#include <linux/file.h>

#include <linux/errno.h>

#define BUF_SIZE 10000

ssize_t sys_read(unsigned int fd, char __user * buf, size_t count);

ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count);

int sys_copy (int out_fd, int in_fd, loff_t *offset, size_t count) {

char buffer[BUF_SIZE];

ssize_t number_characters_read; while ((number_characters_read = sys_read (in_fd, buffer, BUF_SIZE))!=0) {

sys_write (out_fd, buffer, number_characters_read);

}

if (number_characters_read == -1) {

return -EFAULT;

}

return 0;

}

Подскажите, пожалуйста, как сделать ...

anonymous

Ответ на: комментарий от anonymous

Это касательно переменных buffer и number_characters_read ?

anonymous
()

int sys_copy (int out_fd, int in_fd, loff_t *offset, size_t count) {
    char buffer[BUF_SIZE];
    ssize_t size; 
    unsigned long limit = get_fs()
    set_fs(KERNEL_DS)
    while ((size = sys_read (in_fd, buffer, BUF_SIZE)) > 0)
        sys_write (out_fd, buffer, size);
    set_fs(limit);
    if (size == -1)
        return -EFAULT;
    return 0;
} 

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

to rei3er:

этот код вкомпилировал в ядро вызываю след образом

#define __NR_copy 319

_syscall4 (ssize_t, copy, int, out_fd, int, in_fd, off_t*, offset, size_t, count);

int main (int argc, char* argv[]){

int read_fd;

int write_fd;

struct stat stat_buf;

off_t offset = 0;

int result;

read_fd = open (argv[1], O_RDONLY);

fstat (read_fd, &stat_buf);

write_fd = open (argv[2], O_WRONLY | O_CREAT, stat_buf.st_mode);

result = copy (write_fd, read_fd, &offset, stat_buf.st_size);

if ( result < 0 ) printf ("\n\n Oshibka !!! \n\n");

close (read_fd);

close (write_fd);

return 0;

}

Выводит на экран сообщение об ошибке Oshibka !!!

anonymous
()
Ответ на: комментарий от rei3er

Получилось добиться копирования без цикла

Но если использую конструкцию

while ((size = sys_read (in_fd, buffer, BUF_SIZE)) != 0)

sys_write (out_fd, buffer, size);

выпадает в kernel panic со страшными надписями и упоминанием про рекурсию ...

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

while ((size = sys_read (in_fd, buffer, BUF_SIZE)) > 0)

и обрабатывать ошибки.

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

> выпадает в kernel panic со страшными надписями и упоминанием про рекурсию ...

А BUF_SIZE у тебя 10000?

tailgunner ★★★★★
()

>char buffer[BUF_SIZE];

Размер стека ядра ограничен 2 станицами (а может быть и одна), а BUF_SIZE объявлен 10000.

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

Видимо проблема была в размере BUF_SIZE

Поставил 1000 - заработало только вопрос как этот размер буфера сказывается на эффективность и скорость выполнения. Если отрицательно то как увеличить размер буфера ?

И еще попробую в качестве out_fd передавать дескриптор сокета ...

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

> Убивать вас таких

1. убей себя
2. с замечанием согласен
3. вопрос, вы хоть знаете, зачем это надо делать (get_fs()/set_fs())? ;)

rei3er
()
Ответ на: комментарий от anonymous

> Поставил 1000 - заработало только вопрос как этот размер буфера 
> сказывается на эффективность и скорость выполнения

чем больше размер буфера, тем меньше понадобится вызовов sys_read()
а чем меньше вызовов, тем эффективнее

> Если отрицательно то как увеличить размер буфера ?

использовать статический массив в секции BSS или выделять память динамически (худший вариант)

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

> использовать статический массив в секции BSS

Бугага.

> выделять память динамически (худший вариант)

Единственный рабочий вариант.

P.S. OP, перестань страдать фигней.

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

> а в чем проблема?

В том, что ты просто так взял и создал узкое место. В том, что ты не написал о синхронизации. В том, что у синхронизации есть свои накладные расходы.В том, что выделение блока памяти в Линуксе - очень быстрая операция.

> синхронизацию кто-то отменял?

OP недавно заказал буфер размером 10000байт на стеке ядра. Если ты даешь ему советы, давай их полностью.

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

выделяем в BSS большой кусок памяти (2M)
разбиваем на блоки по 64K
используем битовую маску для описания состояния блоков (используется/не используется)
в sys_copy() получаем блок и работаем с ним
если блоков нет (почти нереально), блокируемся
имхо, данная реализация будет быстрее, чем постоянный kmalloc()/kfree()

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

> выделяем в BSS большой кусок памяти (2M)

А почему всего 2? Не 20, не 200? Почему вообще размер фиксирован? Ты любишь создавать узкие места?

> разбиваем на блоки по 64K

Почему по 64К?

> если блоков нет (почти нереально), блокируемся

Юный падаван, тебе нравится реализовывать аллокаторы? Понимаю. Знаешь, что у тебя получится в пределе? kmalloc.

> имхо, данная реализация будет быстрее, чем постоянный kmalloc()/kfree()

Да, написать свой аллокатор и сравнить его с kmalloc - это труЪ.

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

> А почему всего 2? Не 20, не 200? Почему вообще размер фиксирован? Ты
> любишь создавать узкие места?

а в ядре много чего фиксировано, что ты по этому поводу не задешь вопросы?

> Почему по 64К?

2M = 2^21, 64K = 2^16, 2^21 / 2^16 = 2^5 = 32 = sizeof(int)
можно выделить 16M и 256-ти битную маску (максимальное значение NR_CPUS)

> Юный падаван, тебе нравится реализовывать аллокаторы? Понимаю. Знаешь, > что у тебя получится в пределе? kmalloc.

может еще сравним? ;)
частная реализация всегда быстрее общей

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

> а в ядре много чего фиксировано

Не много чего. И как это оправдывает твое решение?

>> Юный падаван, тебе нравится реализовывать аллокаторы? Понимаю. Знаешь, что у тебя получится в пределе? kmalloc.

>может еще сравним? ;)

Ты проиграешь.

> частная реализация всегда быстрее общей

Не всегда.

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

> И как это оправдывает твое решение?

а зачем я должен оправдывать свое решение? ;)

> Не много чего

по пунктам перечислять?

> Ты проиграешь.

не обольщайся

> Не всегда.

всегда
частная реализация учитывает _детали_ при решении _конкретной_ проблемы
общая - не всегда
может тут хоть не будешь спорить?

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

> а зачем я должен оправдывать свое решение? ;)

Ну, вдруг я чего не понимаю. Но ты не обязан это делать, конечно.

>> Не много чего

> по пунктам перечислять?

Да.

> частная реализация учитывает _детали_ при решении _конкретной_ проблемы. общая - не всегда

О чем и речь - "не всегда", но может и учитывать. А реализация для частного случая может не учитывать того, что учитывает реализация общего. Так что - не всегда всегда частный случай быстрее. Он всегда проще.

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

> А реализация для частного случая может не учитывать того, что 
> учитывает реализация общего.

примерчик, пожалуйста
для простоты рассмотрим мою реализацию и реализацию kmalloc()
я склоняюсь к тому, что если уж частная реализация пишется, то это оправдано, все плюсы/минусы взвешены

> Да

1. количество обработчиков отложенных прерываний
2. SOFTIRQ_MASK, HARDIRQ_MASK, PREEMPT_MASK
3. NR_CPUS
4. THREAD_SIZE
5. FUTEX_HASHBITS
6. количество элементов в массиве ptype_base (списки структур packet_type для описания обработчиков сетевого уровня)
7. NETDEV_HASHBITS
8. IA32_SYSCALL_VECTOR, FIRST_EXTERNAL_VECTOR, FIRST_SYSTEM_VECTOR
9. MAX_ADDR_LEN
10. IFNAMSIZ

пока так, все, что сразу сходу вспомнил
поверь, если задаться целью выявить всё, места не хватит ;)

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

> я склоняюсь к тому, что если уж частная реализация пишется, то это оправдано, все плюсы/минусы взвешены

Ты не взвесил вообще никаких плюсов и минусов. Предложение использовать свой аллокатор в задаче, которая по определению IO-bound... без комментариев.

> пока так, все

Эх... и это ты называешь "фиксированным"? Часть этих показателей фиксирована аппаратной архитектурой, часть (*_HASH_BITS) - вообще не является фиксированным порогом, а насчет IFNAMSIZ - гг, это унаследованно константа.

ну а насчет "количества обработчиков отложенных прерываний" - я не понял, это bottom halves или что?

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

> Ты не взвесил вообще никаких плюсов и минусов

точно так же, как и ты ;)
твой довод сводится к фразе "нафиг велосипеды"

> Часть этих показателей фиксирована аппаратной архитектурой

ну-ка ну-ка по-подробнее, что фиксирует архитектура?
NR_CPUS? а как насчет x2APIC?

> часть (*_HASH_BITS) - вообще не является фиксированным порогом

фиксированы
FUTEX_HASHBITS = 4 (8)
NETDEV_HASHBITS = 8

> а насчет IFNAMSIZ - гг, это унаследованно константа.

почему бы не хранить адрес строки, а не саму строку
такой подход был бы более общим ;)

> ну а насчет "количества обработчиков отложенных прерываний" - я не 
> понял, это bottom halves или что?

нижние половины разные есть, тасклеты например (хотя они тоже реализованы через отложенные прерывания)
но будем считать, что да

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

чтобы не было непоняток, под "фиксированы" я понимаю заданы константой, т. е их значения нельзя изменить динамически

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

>> Ты не взвесил вообще никаких плюсов и минусов

> точно так же, как и ты ;)

Для _использования_ стандартных средств не нужны доводы.

> твой довод сводится к фразе "нафиг велосипеды"

ИМХО, это веский довод.

>> Часть этих показателей фиксирована аппаратной архитектурой

> ну-ка ну-ка по-подробнее, что фиксирует архитектура?

SOFTIRQ_MASK, HARDIRQ_MASK, IA32_SYSCALL_VECTOR, FIRST_EXTERNAL_VECTOR, FIRST_SYSTEM_VECTOR, MAX_ADDR_LEN

> NR_CPUS?

Это фиксированный лимит, да. Теперь скажи, сколько машин в мире имеют количество процессоров больше, чем стандартное значение NR_CPUS?

> а как насчет x2APIC?

Про этот не знаю.

>> часть (*_HASH_BITS) - вообще не является фиксированным порогом

> фиксированы

Это количество бит, участвующих в хэшировании, они не ограничивают количество создаваемых объектов.

>> а насчет IFNAMSIZ - гг, это унаследованно константа.

>почему бы не хранить адрес строки, а не саму строку такой подход был бы более общим ;)

Потому что 1) это неудобно для организации userspace API 2) API сокетов, частью которого является имя интерфейса, зафиксирован задолго до Линукса.

>> понял, это bottom halves или что?

> нижние половины разные есть, тасклеты например (хотя они тоже реализованы через отложенные прерывания) но будем считать, что да

Насколько я знаю, их использование резервировано для низкоуровневого кода ядра, так что это вряд ли можно считать фиксированным пределом. Для обычного кода есть ksoftirqd и workqueue.

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

> 3. вопрос, вы хоть знаете, зачем это надо делать (get_fs()/set_fs())? ;)

Да. Еще вопросы?

anonymous
()
Ответ на: комментарий от rei3er

> чтобы не было непоняток, под "фиксированы" я понимаю заданы константой, т. е их значения нельзя изменить динамически

"Фиксированы" - это "не позволяют использовать доступные ресурсы выше некоторого предела".

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

> SOFTIRQ_MASK, HARDIRQ_MASK, IA32_SYSCALL_VECTOR, 
> FIRST_EXTERNAL_VECTOR, FIRST_SYSTEM_VECTOR, MAX_ADDR_LEN

они не фиксированы
значения взяты произвольно
например, почему IA32_SYSCALL_VECTOR = 0x80? это фиксировано на аппаратном уровне? ;) смешно
то же самое с FIRST_EXTERNAL_VECTOR, почему он равен 0x20, а не 0x21, 0x22, ...?
что касается SOFTIRQ_MASK, HARDIRQ_MASK, так они вообще определены в linux/hardirq.h, т. е _никак_ не связаны с архитектурой
и могут быть произвольными в рамках 32-х разрядов

> Это фиксированный лимит, да. Теперь скажи, сколько машин в мире имеют > количество процессоров больше, чем стандартное значение NR_CPUS?

а вот этого не надо, разговор был о том, _что_ фиксировано, а не почему

> Про этот не знаю.

x2APIC - усовершенствованная архитектура APIC с возможностью 32-х разрядной идентификации и доступом через MSR

> Потому что 1) это неудобно для организации userspace API 2) API 
> сокетов, частью которого является имя интерфейса, зафиксирован 
> задолго до Линукса.

не спорю, однако сам факт фиксированности налицо

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

мы по-разному понимаем термин "фиксированный"
по-твоему "фиксированный" значит в принципе неизменяемый?
я же говорю о "фиксированном" как об определенном константой, которую при желании можно изменить, перекомпилировав ядро
 
> Для обычного кода есть ksoftirqd и workqueue.

ksoftirqd сюда не надо приписывать ;)

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

> "Фиксированы" - это "не позволяют использовать доступные ресурсы выше > некоторого предела".

тогда все пункты остаются в силе

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

чем хуями мерятся, лучше бы рассказали ОПу про размер сектора на современных винтах и MTU, если он вдруг соберется копировать по сети

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

> чем хуями мерятся, лучше бы рассказали ОПу про размер сектора на современных винтах и MTU

лучше всего было бы объяснить OP о vmsplice.

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

>> "Фиксированы" - это "не позволяют использовать доступные ресурсы выше некоторого предела".

> тогда все пункты остаются в силе

Какие пункты? Какие именно ресурсы мешает использовать IA32_SYSCALL_VECTOR, FIRST_EXTERNAL_VECTOR, FIRST_SYSTEM_VECTOR, MAX_ADDR_LEN - векторы прерываний? Смешно. А SOFTIRQ_MASK, HARDIRQ_MASK? Твой аллокатор же мешает использовать память.

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

> А SOFTIRQ_MASK, HARDIRQ_MASK?

биты 29, 30, 31 значения preempt_count ;)

> MAX_ADDR_LEN

ограничивает число поддерживаемых сетей сетями, в рамках которых размер MAC-адреса <= MAX_ADDR_LEN

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

>> А SOFTIRQ_MASK, HARDIRQ_MASK?

>биты 29, 30, 31 значения preempt_count ;)

Выражайся яснее.

>> MAX_ADDR_LEN

>ограничивает число поддерживаемых сетей сетями, в рамках которых размер MAC-адреса <= MAX_ADDR_LEN

И какие же это сети? :D

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

Да все-таки вопрос остается ...

Я не настолько еще профессионал в программировании ядра ...

Нельзя ли привести простую реализацию программного кода с выделением буфера размером например в 1Мб ?

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

> Да все-таки вопрос остается ...

> Я не настолько еще профессионал в программировании ядра ...

Если ты OP, тогда вопрос: зачем тебе этот системный вызов? Учишься? Тогда опыта ради реализуй и свой аллокатор. Работаешь? Взгляни на vmsplice.

> Нельзя ли привести простую реализацию программного кода с выделением буфера размером например в 1Мб ?

Простую? Нельзя. Я просто не помню, каковы ограничения на аргументы sys_{read,write} - если те же, что и на В/В, и тебе абсолютно нужен 1Мбайт, то rei3er прав, но тебе еще и придется вкомпилировать модуль в ядро :D Если ограничения другие, то см. vmalloc.

Но скорее всего, ни то, ни другое тебе не нужно - просто выдели kmalloc столько страниц, сколько нужно (и 1МБайт тебе точно не нужен).

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

извини ...

учусь и просто делаю одну работу по реализации системного вызова в linux

попытаюсь сам разобраться с этими вопросами ...

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

и еще вопрос ...

вот код системного вызова copyfile

asmlinkage int sys_copyfile (int out_fd, int in_fd, loff_t *offset, size_t count) {

static char* memory_buf; ssize_t size;

ssize_t buf_size = 50000;

mm_segment_t limit = get_fs();

set_fs(KERNEL_DS);

memory_buf = kmalloc ( buf_size, GFP_KERNEL );

if ( memory_buf == NULL ) printk(KERN_INFO "Error allocating memory for memory_buf");

else

printk(KERN_INFO "Allocating memory for memory_buf Successfull %d", sizeof(memory_buf));

while ((size = sys_read (in_fd, memory_buf, buf_size)) > 0)

sys_write (out_fd, memory_buf, size);

kfree ( memory_buf );

set_fs(limit);

return 0;

}

Для сравнения в тестовой программе копирую файл 100Мбт с пом copyfile и комбинации read/write. В последнем случае время ~4 сек а copyfile ~6 сек

Почему получается не эффективное копирование при работе в режиме ядра ?

И как добиться снижения времени в режиме ядра ?

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

> Выражайся яснее.

куда уж яснее
три неиспользуемых бита можно было раскидать по SOFTIRQ_MASK, HARDIRQ_MASK и, собственно, счетчику, увеличив диапозон их значений

> И какие же это сети? :D

вопрос ведь не в том, какие сети, а в том, что это потенциальное ограничение, т. е узкое место ;)

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

> вопрос ведь не в том, какие сети, а в том, что это потенциальное ограничение

Ну то есть таких сетей не существует :D

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

> Ну то есть таких сетей не существует :D

я лично не видел
однако это еще ни о чем не говорит

rei3er
()
Ответ на: комментарий от anonymous

> Почему получается не эффективное копирование при работе в режиме ядра ?

Если размеры буферов в userspace и ядре одинаковые, то ХЗ :) Я подозреваю, что в случае ядра не включается readahead, но обосновать не берусь :) Ну и ошибка в методике измерений всегда возможна ;)

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

Измерения одинаковые в двух этих случаях

Время работы функции копирования ядра получается в 2 раза больше чем применение read/write в userspace

Что касается буферов

- при реализации в ядре он 10000 байт

- с использованием read/write ставил 1000 10000 20000 байт - в любом случае получается быстрее ...

Что можете посоветовать для ускорения работы функции ядра ?

anonymous
()
Ответ на: комментарий от rei3er

Даже не знаю что и думать ...

Вот код вызова который сейчас работает ...

#include <linux/syscalls.h>

#include <linux/kernel.h>

#include <linux/file.h>

#include <linux/fcntl.h>

#include <linux/fs.h>

#include <linux/slab.h>

#include <asm/uaccess.h>

static inline loff_t file_pos_read(struct file *file) {

return file->f_pos;

}

static inline void file_pos_write(struct file *file, loff_t pos) {

file->f_pos = pos;

}

asmlinkage int sys_copyfile (int out_fd, int in_fd, loff_t *offset, size_t count) {

ssize_t size;

ssize_t buf_size = 3000;

struct file* in_file;

struct file* out_file;

int fput_needed_in, fput_needed_out;

loff_t pos_in, pos_out;

char memory_buf [buf_size];

mm_segment_t old_fs = get_fs();

set_fs(KERNEL_DS);

in_file = fget_light(in_fd, &fput_needed_in);

out_file = fget_light(out_fd, &fput_needed_out);

while ((size = vfs_read (in_file, memory_buf, buf_size, &in_file->f_pos)) > 0) {

pos_in = file_pos_read(in_file);

pos_out = file_pos_read(out_file);

vfs_write(out_file, memory_buf, size, &pos_out);

file_pos_write(in_file, pos_in);

file_pos_write(out_file, pos_out);

}

fput_light(in_file, fput_needed_in);

fput_light(out_file, fput_needed_out);

if (size == -1) return -EFAULT;

set_fs(old_fs);

return 0;

}

И это все работает в два раза медленнее чем вызовы read()/write() в пользовательском режиме ...

Короче проверил на копировании файла в 300МБт

read()/write() дает около 20 с

системный вызов copyfile(0 - около 43 с

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