LinuxForum.Fans
Тема

Разработка ФС

Автор: Fat-Zer 31 сообщений 20169 просмотров
#128143

Не посоветуете, что почитать о разработке ФС вообще и под линукс в частности? В идеале было бы найти какую-нить статью, где во всех подробностях расписывается код кокой-нить ext2.

Сейчас читаю "Linux: азбука ядра" и "Linux device drivers".

И ещё посоветуйте какой-нить форум, где есть кернелхакеры, можно даже на языке потенциального противника, а то сдаётся мне, что вопросов у меня будет ещё много и они будут не совсем в тему данного сообщества.

#128178

я вот не понимаю, что вам не почитать-бы код самой ext2? что непонятно - спрашивайте. например у меня. Кстати, к ядру это не имеет отношения. к девайсам тоже, дело в том, что ext2 можно развернуть где угодно - хоть на флешке, хоть на CDROM'е, хоть в любом другом файле.

#128180

Термо, плюсануть хотел, но лениво ;)

#128183

у меня отключено ибо нех! :D

#128348

прежде всего я не понимаю с чего начать разбираться... я плохо представляю какие части вынесены в vfs, как фс регистрируется в системе? что берёт на себя vfs, что драйверы блочных устройств, а что надо реализовывать в самом модуле ФС.

#128656
Fat-Zer написал:
какие части вынесены в vfs

что значит v?

#128663
drBatty написал:
что значит v?

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

#129085

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

Итак функция инициализации:
fs/ext2/super.c struct file_system_type ext2_fs_type; init_ext2_fs(void)

Показать
text

static struct file_system_type ext2_fs_type = {
    .owner        = THIS_MODULE,
    .name        = "ext2",
    .get_sb        = ext2_get_sb, // указатель на функцию возвращающую суперблок
    .kill_sb    = kill_block_super,  // соответственно функция убивающая суперблок
    .fs_flags    = FS_REQUIRES_DEV,
};

static int __init init_ext2_fs(void) { int err = init_ext2_xattr(); // инициализация дополнительных атрибутов... пока не интересно if (err) return err; err = init_inodecache(); // а вот тут начинаются проблемы... не понимаю, что за кеш, а самое главное как из этого кеша вытаскиваются иноды (см. дальше) if (err) goto out1; err = register_filesystem(&ext2_fs_type); // регистрация файловой системы if (err) goto out; return 0; // всякие откаты на случай ошибок out: destroy_inodecache(); out1: exit_ext2_xattr(); return err; }

сначала посмотрим на ргистрацию ФC
fs/filesystem.c register_filesystem(struct file_system_type * fs)

Показать
text

/**
 *    register_filesystem - register a new filesystem
 *    @fs: the file system structure
 *
 *    Adds the file system passed to the list of file systems the kernel
 *    is aware of for mount and other syscalls. Returns 0 on success,
 *    or a negative errno code on an error.
 *
 *    The &struct file_system_type that is passed is linked into the kernel 
 *    structures and must not be freed until the file system has been
 *    unregistered.
 */
 
int register_filesystem(struct file_system_type * fs)
{
    int res = 0;
    struct file_system_type ** p;

BUG_ON(strchr(fs->name, '.')); if (fs->next) return -EBUSY; INIT_LIST_HEAD(&fs->fs_supers); //обнуление списка суперблоков write_lock(&file_systems_lock); p = find_filesystem(fs->name, strlen(fs->name)); // ещет по имени, не добавлена ли уже такая fs

if (*p) res = -EBUSY; else *p = fs; // добавление ФС в хвост списка (хитрый финт см. функцию find_filesystem) write_unlock(&file_systems_lock); return res; }

! указатель на начало списка ФС хранится в глобальной переменно *file_systems

include/linux/fs.h struct file_system_type

Показать
text

struct file_system_type {
    const char *name; //имя
    int fs_flags;
    int (*get_sb) (struct file_system_type *, int,
               const char *, void *, struct vfsmount *);
    void (*kill_sb) (struct super_block *); 
    struct module *owner; //модуль, владеющий ФС, видимо для дебага, или если модуль выгружают, чтобы ФС тоже автоматом выгружалась...
    struct file_system_type * next; // следующая ФС в списке
    struct list_head fs_supers; //заголовок списка суперблоков
//....
// тут ещё какие-то блокировки...
};

// to be continued...

#129089

а теперь функция, инициализирующая кеш инодов oO
fs/filesystem.c init_inodecache(); init_once(void *foo)

Показать
text

// вызывается калбеком откуда-то из кеша...
static void init_once(void *foo)
{
    struct ext2_inode_info *ei = (struct ext2_inode_info *) foo;
    // тип инода ext2 для представления в памяти
    rwlock_init(&ei->i_meta_lock);
#ifdef CONFIG_EXT2_FS_XATTR
    init_rwsem(&ei->xattr_sem);
#endif
    mutex_init(&ei->truncate_mutex);
    inode_init_once(&ei->vfs_inode); //забивает инод значениями по умолчанию
}

static int init_inodecache(void) { // пока понятия не имею как работают кеши и с чем их едят... // но тут он, очевидно, создаётся ext2_inode_cachep = kmem_cache_create("ext2_inode_cache", sizeof(struct ext2_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), init_once); if (ext2_inode_cachep == NULL) return -ENOMEM; return 0; }

описатель структуры:
fs/ext2/ext2.h struct ext2_inode_info

Показать
text

/*
 * second extended file system inode data in memory
 */
// часть полей и коментариев пропущено
struct ext2_inode_info {
    __le32    i_data[15];
    __u32    i_flags;
    __u32    i_faddr;
    __u8    i_frag_no;
    __u8    i_frag_size;
    __u16    i_state;
    __u32    i_file_acl;
    __u32    i_dir_acl;
    __u32    i_dtime;
    __u32    i_block_group;
    struct ext2_block_alloc_info *i_block_alloc_info;

__u32 i_dir_start_lookup; rwlock_t i_meta_lock;

struct mutex truncate_mutex; struct inode vfs_inode; // инод vfs struct list_head i_orphan; /* unlinked but open inodes */ };

приведу описатель структуры что б было
include/linux/fs.h struct inode

Показать
text

struct inode {
    struct hlist_node    i_hash;
    struct list_head    i_list;        /* backing dev IO list */
    struct list_head    i_sb_list;
    struct list_head    i_dentry;
    unsigned long    i_ino;
    atomic_t        i_count;
    unsigned int    i_nlink;
    uid_t        i_uid;
    gid_t        i_gid;
    dev_t        i_rdev;
    unsigned int    i_blkbits;
    u64        i_version;
    loff_t        i_size;
#ifdef __NEED_I_SIZE_ORDERED
    seqcount_t        i_size_seqcount;
#endif
    struct timespec    i_atime;
    struct timespec    i_mtime;
    struct timespec    i_ctime;
    blkcnt_t        i_blocks;
    unsigned short       i_bytes;
    umode_t        i_mode;
    spinlock_t    i_lock;    /* i_blocks, i_bytes, maybe i_size */
    struct mutex    i_mutex;
    struct rw_semaphore    i_alloc_sem;
    const struct inode_operations    *i_op;
    const struct file_operations    *i_fop;    /* former ->i_op->default_file_ops */
    struct super_block    *i_sb;
    struct file_lock    *i_flock;
    struct address_space    *i_mapping;
    struct address_space    i_data;
#ifdef CONFIG_QUOTA
    struct dquot        *i_dquot[MAXQUOTAS];
#endif
    struct list_head    i_devices;
    union {
        struct pipe_inode_info    *i_pipe;
        struct block_device    *i_bdev;
        struct cdev        *i_cdev;
    };

__u32 i_generation;

#ifdef CONFIG_FSNOTIFY __u32 i_fsnotify_mask; /* all events this inode cares about */ struct hlist_head i_fsnotify_marks; #endif

unsigned long i_state; unsigned long dirtied_when; /* jiffies of first dirtying */

unsigned int i_flags;

atomic_t i_writecount; #ifdef CONFIG_SECURITY void *i_security; #endif #ifdef CONFIG_FS_POSIX_ACL struct posix_acl *i_acl; struct posix_acl *i_default_acl; #endif void *i_private; /* fs or device private pointer */ };

kmem_cache_create полностью приводить не буду, напишу только, что он делает с возвращаемым значением:
mm/slab.c struct kmem_cache *kmem_cache_create ()

Показать
text

struct kmem_cache *
kmem_cache_create (const char *name, size_t size, size_t align,
    unsigned long flags, void (*ctor)(void *))
{
    size_t left_over, slab_size, ralign;
    struct kmem_cache *cachep = NULL, *pc;
    gfp_t gfp;
//....

cachep = kmem_cache_zalloc(&cache_cache, gfp); if (!cachep) goto oops;

//....

/* * Determine if the slab management is 'on' or 'off' slab. * (bootstrapping cannot cope with offslab caches so don't do * it too early on. Always use on-slab management when * SLAB_NOLEAKTRACE to avoid recursive calls into kmemleak) */ if ((size >= (PAGE_SIZE >> 3)) && !slab_early_init && !(flags & SLAB_NOLEAKTRACE)) /* * Size is large, assume best to place the slab management obj * off-slab (should allow better packing of objs). */ flags |= CFLGS_OFF_SLAB;

size = ALIGN(size, align);

left_over = calculate_slab_order(cachep, size, align, flags);

if (!cachep->num) { printk(KERN_ERR "kmem_cache_create: couldn't create cache %s.\n", name); kmem_cache_free(&cache_cache, cachep); cachep = NULL; goto oops; } slab_size = ALIGN(cachep->num * sizeof(kmem_bufctl_t) + sizeof(struct slab), align);

/* * If the slab has been placed off-slab, and we have enough space then * move it on-slab. This is at the expense of any extra colouring. */ if (flags & CFLGS_OFF_SLAB && left_over >= slab_size) { flags &= ~CFLGS_OFF_SLAB; left_over -= slab_size; }

if (flags & CFLGS_OFF_SLAB) { /* really off slab. No need for manual alignment */ slab_size = cachep->num * sizeof(kmem_bufctl_t) + sizeof(struct slab);

#ifdef CONFIG_PAGE_POISONING /* If we're going to use the generic kernel_map_pages() * poisoning, then it's going to smash the contents of * the redzone and userword anyhow, so switch them off. */ if (size % PAGE_SIZE == 0 && flags & SLAB_POISON) flags &= ~(SLAB_RED_ZONE | SLAB_STORE_USER); #endif }

cachep->colour_off = cache_line_size(); /* Offset must be a multiple of the alignment. */ if (cachep->colour_off < align) cachep->colour_off = align; cachep->colour = left_over / cachep->colour_off; cachep->slab_size = slab_size; cachep->flags = flags; cachep->gfpflags = 0; if (CONFIG_ZONE_DMA_FLAG && (flags & SLAB_CACHE_DMA)) cachep->gfpflags |= GFP_DMA; cachep->buffer_size = size; cachep->reciprocal_buffer_size = reciprocal_value(size);

if (flags & CFLGS_OFF_SLAB) { cachep->slabp_cache = kmem_find_general_cachep(slab_size, 0u); /* * This is a possibility for one of the malloc_sizes caches. * But since we go off slab only for object size greater than * PAGE_SIZE/8, and malloc_sizes gets created in ascending order, * this should not happen at all. * But leave a BUG_ON for some lucky dude. */ BUG_ON(ZERO_OR_NULL_PTR(cachep->slabp_cache)); } cachep->ctor = ctor; cachep->name = name;

if (setup_cpu_cache(cachep, gfp)) { __kmem_cache_destroy(cachep); cachep = NULL; goto oops; }

/* cache setup completed, link it into the list */ list_add(&cachep->next, &cache_chain); oops: if (!cachep && (flags & SLAB_PANIC)) panic("kmem_cache_create(): failed to create slab `%s'\n", name); if (slab_is_available()) { mutex_unlock(&cache_chain_mutex); put_online_cpus(); } return cachep; }

приведу kmem_cache
mm/slab.c struct kmem_cache

Показать
text

struct kmem_cache {
    unsigned int size, align;
    unsigned long flags;
    const char *name;
    void (*ctor)(void *);
};

если кто знает, может разжевать что такое кеш и с чем его едят?

#129090

у кэша во все времена было два значения
а) наличность (наличные деньги)
б) некие промежуточные результаты или данные, которые требуются постоянно в процессе работы
читали это?
http://www.interface.ru/home.asp?artId=8660
вдруг поможет...

#129217

ну не читать-же каждый раз иноды с диска? вот они и лежат в памяти - читаются ОДИН раз. причём сразу блоком, ЕМНИП в 4096байт (один инод сейчас в 256 байт). это и называется "кеширование".
кстати, иноды создаются 1 раз при форматировании, их очень много - сотни тысяч, и даже миллионы. Потому читать их ВСЕ невозможно. Приходится читать по мере запросов. В FAT'е читалась вся таблица. В NTFS похоже, но там обычно таблица инодов непрерывная (MFT), и лежит точно в центре диска. В EXT таблица разорвана на куски, и куски разбросаны по всей поверхности. Причём координаты таблиц инодов никогда не меняются, и записаны они в суперблоках (которые тоже равномерно разбросаны по всему разделу. но нужен только один, первый суперблок, остальные для резерва).

#129227
Fat-Zer написал:
приведу описатель структуры что б было

что-то добавили, что-то убавили... это EXT4?

#129334

спасибо... понял при чём здесь кеш, оказалось всё достаточно просто и логично... просто одна книжка ввела в заблуждение.

drBatty написал:
[quote=Fat-Zer]приведу описатель структуры что б было

что-то добавили, что-то убавили... это EXT4?[/quote]
это из include/linux/fs.h, т.е. одна структура для всех ФС... похоже для представления инода в памяти...

#129495
Fat-Zer написал:
это из include/linux/fs.h, т.е. одна структура для всех ФС... похоже для представления инода в памяти...

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

Как я понял, сейчас есть только EXT4, EXT2 и EXT3 получаются из четвёрки отключением некоторых фич.

Получается, что при чтении инода он теперь кардинально переделывается (ЕМНИП раньше он просто тупо читался, и структура была точно такой-же).

Я вот что подумал: дело в том, что у ядра имеется СВОЯ, личная память. Мало того, ВСЕ алгоритмы внутри ядра имеют гарантированное потребление памяти. К примеру, внутри ядра не применяется qsort(), причина проста - qsort() имеет худший случай - когда время исполнения и объём памяти равен N*N - если N равно например 1000000, то N*N = 10^12, что приведёт даже для 32х битных систем к потреблению как минимум 10^14 байт. (кстати в венде не так. потому она иногда виснет, а иногда просто падает. Редко, но бывает). Проблема в том, что инодов может потребоваться ОЧЕНЬ много, потому просто так этот кеш в ядро не запихаешь. Однако, несколько лет таки запихали. ИМХО как раз это и привело к трудноуловимому глюку. ИМХО этот "глюк" так и не исправили, просто число файлов увеличилось не так быстро, как память :lol:

А линух как тормозил, так и сейчас тормозит при копировании файлов, если этих файлов много. ИЧСХ, область памяти ядра скрыта даже от рута, и невидима - получается так, что кажется, что памяти хватает, но на самом деле, её недостаточно. Как доказал Кнут ещё в середине прошлого века, любая система будет сильно тормозить при нехватке памяти. Вот мы и имеем - кажется (даже руту), что памяти достаточно, но её не хватает. Ядро судорожно гоняет данные с места на место, при этом загрузка памяти 70%, загрузка CPU 0%, но всё тупит и тормозит. Это принципиально не лечится. Ядро венды ввести в такой режим ещё проще, просто мало кому это нужно. А вот в линуксе мы имеем отличную EXT, которая поддерживает огромное количество файлов сразу, чем усиленно пользуются кодеры...

#129841

что это было?
это тоже необходимо знать? :o :o :o

#129924
сантехник написал:
что это было?
это тоже необходимо знать?

если вы собираетесь разрабатывать ФС - да. smile

#129962

в линуксе этих фс.. черт ногу сломает.
зачем усложнять себе жись?

#129975
drBatty написал:
Как я понял, сейчас есть только EXT4, EXT2 и EXT3 получаются из четвёрки отключением некоторых фич.

почему? в дереве сырцов отдельно лежат fs/ext2/, fs/ext3/, fs/ext4/ и содержимое в них достаточно сильно(если не полностью) различается.

drBatty написал:
Получается, что при чтении инода он теперь кардинально переделывается (ЕМНИП раньше он просто тупо читался, и структура была точно такой-же).

это тоже достаточно логично... всё таки поддерживаем не одну ФС...

drBatty написал:
К примеру, внутри ядра не применяется qsort(), причина проста - qsort() имеет худший случай - когда время исполнения и объём памяти равен N*N - если N равно например 1000000, то N*N = 10^12, что приведёт даже для 32х битных систем к потреблению как минимум 10^14 байт.

это по времени худший случай О(n^2), а памяти он используется не более O(n). да и улучшить можно: если глубина рекурсии достигает опасного n, то вызываем какой-нить пузырёк для подмассивов.

drBatty написал:
ИМХО как раз это и привело к трудноуловимому глюку.

можно поподробней, а то я этого не застал smile

drBatty написал:
ИЧСХ, область памяти ядра скрыта даже от рута, и невидима - получается так, что кажется, что памяти хватает, но на самом деле, её недостаточно.

о_О вот эту строчку не переварил... не представляю, как такое может быть(то что скрыта от рута, да и как вообще неучтённая память может быть...) oO

сантехник написал:
в линуксе этих фс.. черт ногу сломает.
зачем усложнять себе жись?

ни кто за вами бегать с палкой и заставлять использовать что-то конкретное не будет. а зачем - как минимум самообразование.

#130049
Fat-Zer написал:
почему? в дереве сырцов отдельно лежат fs/ext2/, fs/ext3/, fs/ext4/ и содержимое в них достаточно сильно(если не полностью) различается.

как я понял, в ядро вкомпилливается только EXT4. но можно засунуть и лишь EXT2, например для встроенных систем без HDD.

Fat-Zer написал:
это тоже достаточно логично... всё таки поддерживаем не одну ФС...

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

Fat-Zer написал:
это по времени худший случай О(n^2), а памяти он используется не более O(n). да и улучшить можно: если глубина рекурсии достигает опасного n, то вызываем какой-нить пузырёк для подмассивов.

ну O(N) это обычно тоже ОЧЕНЬ много. Учитывая, что рассчитывают таки на log2(N).

Fat-Zer написал:
да и улучшить можно: если глубина рекурсии достигает опасного n, то вызываем какой-нить пузырёк для подмассивов.

проще не парится, а взять другую сортировку, ЕМНИП так и было сделано. (используется метод Шелла).

Fat-Zer написал:
можно поподробней, а то я этого не застал

недавно было. совпало по времени со сменой hda на sda (у меня во всяком случае). Там при операциях с файлами всё жутко тупило, мышкой по кнопке нельзя было кликнуть. А загрузка около 0.
многие не застали - этот глюк проявлялся как-то рандомно - типа на дистре XYZ и мамке ABC есть, а на другой мамке/дистре - нету.

Fat-Zer написал:
вот эту строчку не переварил... не представляю, как такое может быть(то что скрыта от рута, да и как вообще неучтённая память может быть...)

да говорю-же: глюк. Рут спрашивает ядро: "сколько памяти?", ядро отвечает 100. И нагло врёт. :(

сантехник написал:
в линуксе этих фс.. черт ногу сломает.
зачем усложнять себе жись?

для более эффективного использования инструмента надо знать его свойства. Что-бы было ясно, когда применить шило, когда отвёртку, а когда - лом.

Войдите или зарегистрируйтесь, чтобы ответить.