как я понял, в ядро вкомпилливается только EXT4. но можно засунуть и лишь EXT2, например для встроенных систем без HDD.
не верю я чего-то... при сборке ядра всё же собирается отдельно. Есть пруфлинк или идеи, как это проверить?
как я понял, в ядро вкомпилливается только EXT4. но можно засунуть и лишь EXT2, например для встроенных систем без HDD.
не верю я чего-то... при сборке ядра всё же собирается отдельно. Есть пруфлинк или идеи, как это проверить?
ещё вопрос... как иноды адресуют информацию на диске? и есть ли различия в структуре инодов для каталогов/устройств/труб итп?
а теперь.... следующий кусок кода на разбор...
fs/ext2/super.c static int ext2_get_sb()
static int ext2_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
return get_sb_bdev(fs_type, flags, dev_name, data, ext2_fill_super, mnt);
}
ничего примечательного... важно что передаём указатель на функцию ext2_fill_super().
похоже оно занимается чтением суперблока с блочного устройства... хотя собственно чтения я тут не заметил:
fs/super.c static int get_sb_bdev()
int get_sb_bdev(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data,
int (*fill_super)(struct super_block *, void *, int),
struct vfsmount *mnt)
{
struct block_device *bdev;
struct super_block *s;
fmode_t mode = FMODE_READ;
int error = 0;
if (!(flags & MS_RDONLY)) //если не ридонли, то разрешаем запись
mode |= FMODE_WRITE;
bdev = open_bdev_exclusive(dev_name, mode, fs_type); //открываем блочное устройство
if (IS_ERR(bdev)) // ошибка при ахтунге
return PTR_ERR(bdev);
/*
* once the super is inserted into the list by sget, s_umount
* will protect the lockfs code from trying to start a snapshot
* while we are mounting
*/
mutex_lock(&bdev->bd_fsfreeze_mutex);
if (bdev->bd_fsfreeze_count > 0) { // не очень понятно, что мы тут проверяем.. что за замороженные процессы...
mutex_unlock(&bdev->bd_fsfreeze_mutex);
error = -EBUSY;
goto error_bdev;
}
s = sget(fs_type, test_bdev_super, set_bdev_super, bdev); // собственно ищет и создаёт суперблок
mutex_unlock(&bdev->bd_fsfreeze_mutex);
if (IS_ERR(s))
goto error_s;
// не понятно, кто бы мог это установить... похоже где-то в тёмной части c test в sget
if (s->s_root) {
if ((flags ^ s->s_flags) & MS_RDONLY) {
deactivate_locked_super(s);
error = -EBUSY;
goto error_bdev;
}
/*
* s_umount nests inside bd_mutex during
* __invalidate_device(). close_bdev_exclusive()
* acquires bd_mutex and can't be called under
* s_umount. Drop s_umount temporarily. This is safe
* as we're holding an active reference.
*/
up_write(&s->s_umount);
close_bdev_exclusive(bdev, mode);
down_write(&s->s_umount);
} else {
char b[BDEVNAME_SIZE];
s->s_flags = flags; // устанавливаем флаги
s->s_mode = mode; // режим
strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id)); // заменяем имя
sb_set_blocksize(s, block_size(bdev)); // устанавливаем размер блока
error = fill_super(s, data, flags & MS_SILENT ? 1 : 0); //!!!калл-бек в модуль ФС
if (error) {
deactivate_locked_super(s);
goto error;
}
s->s_flags |= MS_ACTIVE;
bdev->bd_super = s;
}
simple_set_mnt(mnt, s);
return 0;
error_s:
error = PTR_ERR(s);
error_bdev:
close_bdev_exclusive(bdev, mode);
error:
return error;
}
fs/super.c struct super_block *sget()
/**
* sget - find or create a superblock
* @type: filesystem type superblock should belong to
* @test: comparison callback
* @set: setup callback
* @data: argument to each of them
*/
struct super_block *sget(struct file_system_type *type,
int (*test)(struct super_block *,void *),
int (*set)(struct super_block *,void *),
void *data)
{
struct super_block *s = NULL;
struct super_block *old;
int err;
retry:
spin_lock(&sb_lock);
if (test) {// если нам передали указатель на функцию тестирования суперблока, то проходим по всем спискам суперблоков для ФС и перепроверяем их(если не ошибыюсь)
list_for_each_entry(old, &type->fs_supers, s_instances) {
if (!test(old, data))
continue;
if (!grab_super(old))
goto retry;
if (s) {
up_write(&s->s_umount);
destroy_super(s);
s = NULL;
}
down_write(&old->s_umount);
if (unlikely(!(old->s_flags & MS_BORN))) {
deactivate_locked_super(old);
goto retry;
}
return old;
}
}
if (!s) { // если указатель на суперблок ==нулю(а это скорей всего так), то пытаемся его создать
spin_unlock(&sb_lock);
s = alloc_super(type);
if (!s)
return ERR_PTR(-ENOMEM);
goto retry;
}
err = set(s, data); // калл-бек
if (err) {
spin_unlock(&sb_lock);
up_write(&s->s_umount);
destroy_super(s);
return ERR_PTR(err);
}
s->s_type = type; // начинаем заполнение структуры... устанавливаем тип ФС
strlcpy(s->s_id, type->name, sizeof(s->s_id)); //устанавливаем ID ФС суперблока
list_add_tail(&s->s_list, &super_blocks); //добавляет новый суперблок в конец списка СБ
list_add(&s->s_instances, &type->fs_supers); // добавляет суперблок в список суперблоков ФС
spin_unlock(&sb_lock);
get_filesystem(type); //!!! похоже подгружает модуль для ФС (поправте меня)!!!
return s;
}
в общем не понятно , что за тёмное дело с test делается...
и вроде там может возникнуть ситуация, когда спинблокировку второй раз пытаемя захватить... oO
и ещё get_filesystem не совсем уверен, что делает
в следуещем посте рассмотрю ext2_fill_super()
не верю я чего-то... при сборке ядра всё же собирается отдельно. Есть пруфлинк или идеи, как это проверить?
ИМХО проще всего попробовать собрать ядро без 2 и 3, и потом mkfs.ext2.
ИМХО проще всего попробовать собрать ядро без 2 и 3, и потом mkfs.ext2.
А разве mkfs не полностью в юзерспейсе работает и от модулей ФС ядра вообще не зависит? А вот монтировать он точно отказывается (помню в первый раз, когда собирал, отключил ext2 и /boot не монтировался...) конечно можно смонтировать 2 как 3(или 4)... но это уже история обратной совместимости.
[added] Только что попробовал создать рейзер4, хотя в ядре им и не пахнет... получилось, смонтировать само собой - фейл... Итого: создание ФС не зависит от ядра ни как
код ext2_fill_super() расписывать нет больше ни желание, ни необходимости, ибо эта зараза занимает без малого четыре сотни строк. Так что опишу просто основные действия/данные, на что ИМХО стоит обратить внимание:
fs/ext2/super.c static int ext2_fill_super()
static int ext2_fill_super(struct super_block *sb, void *data, int silent)
// sb - структура суперблока, которую заполняем
// data - данные, которые передали транзитом (А кстати откуда эти данные пришли и что это такое?)
// судя по всему это опции монтирования в виде простой текстовой строки...
{
struct buffer_head * bh; // заголовок буфера чтения
struct ext2_sb_info * sbi; // указатель на эти данные, специфические для ФС будет хранится в суперблоке
struct ext2_super_block * es; // структура суперблока, так, как она хранится на диске
// ...
if (blocksize != BLOCK_SIZE) { // перещёт смешения, если суперблок находится не на границе блока устройства
logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize;
offset = (sb_block*BLOCK_SIZE) % blocksize;
} else {
logic_sb_block = sb_block;
}
if (!(bh = sb_bread(sb, logic_sb_block))) { // собственно создание и чтение в буффер суперблока
ext2_msg(sb, KERN_ERR, "error: unable to read superblock");
goto failed_sbi;
}
// ...
// потом уставливаем дефолтные значения
// правим их в зависимости от опций монтирования
// проверка, не попытались ли мы использовать какие-то неподдерживаемые опции
// копирование разнообразных параметров в sbi
// ...
// что-то про группы, фрагменты итп... в общем в этом разбираться бесполезно,
// пока более-менее не освоюсь в структуре ФС
// ...
// !а вот это очень важно!
sb->s_op = &ext2_sops; // установка структуры-списка операций над ФС
sb->s_export_op = &ext2_export_ops; // не столь важные операции
sb->s_xattr = ext2_xattr_handlers; // операции над доп. атрибутами
// ...
root = ext2_iget(sb, EXT2_ROOT_INO); // чтение инода корня ФС
// ...
sb->s_root = d_alloc_root(root);
// ...
ext2_write_super(sb); // не совсем понял, зачем нам записывать суперблок после того, как мы его загрузили
return 0;
// ... обработка ошибок
}
fs/ext2/super.c static const struct super_operations ext2_sops
static const struct super_operations ext2_sops = {
.alloc_inode = ext2_alloc_inode, // выделяем инод в кеше
.destroy_inode = ext2_destroy_inode, // соответственно уничтожаем инод
.write_inode = ext2_write_inode, // сохранение инода на диск
.evict_inode = ext2_evict_inode, // пока не понял (???) может удаление
.put_super = ext2_put_super, // освобождение суперблока
.write_super = ext2_write_super, // запись суперблока на диск
.sync_fs = ext2_sync_fs, // записывает грязный суперблок надиск (вычитал в книжке, сильно в этом сомневаюсь)
.statfs = ext2_statfs, // получение статистики ФС
.remount_fs = ext2_remount, // перемонтирование ФС
.show_options = ext2_show_options, // тоже пока загадка
#ifdef CONFIG_QUOTA
.quota_read = ext2_quota_read,
.quota_write = ext2_quota_write,
#endif
};
заметил, что переопределяются не все операции(например нет read_inode). Некоторые из них доступны по-умолчанию? где это можно увидеть?
Ещё: как рейзер упаковывает хвосты и мелкие файлы?
ЗЫ: наткнулся на статью о ext2(pdf), вроде это как раз то что нужно было.
ЗЗЫ: ещё хотелось бы что-нить почитать о структуре самой ФС ext2
Только что попробовал создать рейзер4, хотя в ядре им и не пахнет... получилось, смонтировать само собой - фейл... Итого: создание ФС не зависит от ядра ни как
зависит. вопрос в том, модулем оно, или в самом ядре. mkfs естественно умеет и так и так.
А вот монтировать он точно отказывается (помню в первый раз, когда собирал, отключил ext2 и /boot не монтировался...)
ну ещё-бы! именно для того и делают /boot в EXT2, что-бы их поняли старинные загрузчики. т.е. прежде всего загрузчик должен прочитать ядро, потом ядро монтирует корневой раздел, потом оттуда грузятся модули.
Сейчас это всё не играет никакой роли, ибо и загрузчики, и ядра поддерживают EXT4.
Вы можете проверить, настоящая-ли у вас EXT2 - достаточно посмотреть, затирает-ли она нулями координаты блоков данных. EXT2 не затирает, а EXT3 без журнала - не затирает. Разница существенная, ибо на EXT3 без журнала не работает undelete.
создание ФС конечно от ядра и не должно зависить, но вот сможете-ли вы смонтировать вашу EXT2, или нет... И является-ли эта EXT2 действительно 2?...
data - данные, которые передали транзитом (А кстати откуда эти данные пришли и что это такое?)
это как раз самое интересное. Вот эти данные:
# tune2fs -l /dev/sda3
.sync_fs = ext2_sync_fs, // записывает грязный суперблок надиск (вычитал в книжке, сильно в этом сомневаюсь)
"грязный" в том смысле, что например произошло создание файла, и соответственно число свободных инодов уменьшилось. дело в том, что суперблок обычно расположен далеко от данных, и что-бы лишний раз не дёргать головками, запись в суперблок откладывается до выполнения этой функции. Она выполняется либо ядром, когда нечего делать, либо во время размонтирования носителя.
.show_options = ext2_show_options, // тоже пока загадка
в зависимости от версии ФС не все фичи могут быть доступны, например ACL, которая по умолчанию выключена. Но её можно и включить. Естественно необходим механизм для проверки этого.
ещё хотелось бы что-нить почитать о структуре самой ФС ext2
где-то у меня валялось годное описание, поищу...
зависит. вопрос в том, модулем оно, или в самом ядре. mkfs естественно умеет и так и так.
в том то и идея... оно вообще выпилено из ядра (и модуль не собран, само собой).
Вы можете проверить, настоящая-ли у вас EXT2 - достаточно посмотреть, затирает-ли она нулями координаты блоков данных. EXT2 не затирает, а EXT3 без журнала - не затирает. Разница существенная, ибо на EXT3 без журнала не работает undelete.
не совсем согласен: затирание - дело драйвера. Если драйвер ext2 не знает о том, что нужно затирать нулями, то за него магическая сила это делать не будет...
создание ФС конечно от ядра и не должно зависить, но вот сможете-ли вы смонтировать вашу EXT2, или нет... И является-ли эта EXT2 действительно 2?...
вопрос не совсем понятен у extX в том и прелесть, что они обладают совместимостью во всех направлениях(и обратной и прямой). А то что (у меня) 2 - это действительно 2 я уверен(как минимум работает человеческий undelete)
"грязный" в том смысле, что например произошло создание файла, и соответственно число свободных инодов уменьшилось. дело в том, что суперблок обычно расположен далеко от данных, и что-бы лишний раз не дёргать головками, запись в суперблок откладывается до выполнения этой функции. Она выполняется либо ядром, когда нечего делать, либо во время размонтирования носителя.
это понятно... просто ёкнуло, что должны сбрасываться ещё и буферы данных... сейчас вспомнил, что буферизация данных находится на уровне устройств.
это как раз самое интересное. Вот эти данные:
# tune2fs -l /dev/sda3
интересно, но не то... это текстовая строка, в которой, как минимум, может находится "sb=N" (N - смещение с которого читаем суперблок). Вопрос был откуда она по коду приходит (есть предположение, что она идёт из mount). Это было в той части, которую я опустил.
unsigned long sb_block = get_sb_block(&data);
fs/ext2/super.c static unsigned long get_sb_block()
static unsigned long get_sb_block(void **data)
{
unsigned long sb_block;
char *options = (char *) *data;
if (!options || strncmp(options, "sb=", 3) != 0)
return 1; /* Default location */
options += 3;
sb_block = simple_strtoul(options, &options, 0);
if (*options && *options != ',') {
printk("EXT2-fs: Invalid sb specification: %s\n",
(char *) *data);
return 1;
}
if (*options == ',')
options++;
*data = (void *) options;
return sb_block;
}
а то что вы назвали должно содержаться в es или sbi(если смотреть по коду)
понял, правда тут, наверное в зависимости от того как модуль собран зависит...в зависимости от версии ФС не все фичи могут быть доступны, например ACL, которая по умолчанию выключена. Но её можно и включить. Естественно необходим механизм для проверки этого.
где-то у меня валялось годное описание, поищу...
заранее спасибо.
для полноты картины не хватало:
include/linux/fs.h struct super_block
struct super_block {
struct list_head s_list; /* Keep this first */ // заголовок списка суперблоков
dev_t s_dev; /* search index; _not_ kdev_t */ // пока не ясно что это
unsigned char s_dirt; // флаг грязности инода
unsigned char s_blocksize_bits; // ???
unsigned long s_blocksize; // размер блока данных
loff_t s_maxbytes; /* Max file size */
struct file_system_type *s_type; // указатель на тип ФС ()
const struct super_operations *s_op; // список доступных операций
const struct dquot_operations *dq_op; // операции связанные с квотами
const struct quotactl_ops *s_qcop; // в ту же степь
const struct export_operations *s_export_op; //ещё какие-то операции
unsigned long s_flags; // флаги какие-то
unsigned long s_magic; // что за магическое число до сих пор не понимаю... (похоже или UUID, или уникальный для каждого типа ФС)
struct dentry *s_root; // указатель на структуру связанную с корнем
struct rw_semaphore s_umount; // видимо блокировка отмонтирования при работе с ФС
struct mutex s_lock; // а это бокировка на монопольный доступ к ФС
int s_count; // ???
atomic_t s_active; // ???
#ifdef CONFIG_SECURITY
void *s_security;
#endif
const struct xattr_handler **s_xattr; // тоже операции/обработчики чего-то связанного с xattr'ами
struct list_head s_inodes; /* all inodes */
struct hlist_head s_anon; /* anonymous dentries for (nfs) exporting */
#ifdef CONFIG_SMP
struct list_head __percpu *s_files;
#else
struct list_head s_files; // список открытых файлов
#endif
/* s_dentry_lru and s_nr_dentry_unused are protected by dcache_lock */
struct list_head s_dentry_lru; /* unused dentry lru */
int s_nr_dentry_unused; /* # of dentry on lru */
struct block_device *s_bdev; // блочное устройство, ассоциированное с ФС
struct backing_dev_info *s_bdi; // ???
struct mtd_info *s_mtd; // ???
struct list_head s_instances; // ???
struct quota_info s_dquot; /* Diskquota specific options */
int s_frozen; // ???
wait_queue_head_t s_wait_unfrozen; // ???
char s_id[32]; /* Informational name */
void *s_fs_info; /* Filesystem private info */
fmode_t s_mode; // ???
/* Granularity of c/m/atime in ns.
Cannot be worse than a second */
u32 s_time_gran; // надо понять, что такое грунул[ярность/ирование]
/*
* The next field is for VFS *only*. No filesystems have any business
* even looking at it. You had been warned.
*/
struct mutex s_vfs_rename_mutex; /* Kludge */
/*
* Filesystem subtype. If non-empty the filesystem type field
* in /proc/mounts will be "type.subtype"
*/
char *s_subtype;
/*
* Saved mount options for lazy filesystems using
* generic_show_options()
*/
char *s_options; // опа на...
};
[quote=Fat-Zer]
.show_options = ext2_show_options, // тоже пока загадка
в зависимости от версии ФС не все фичи могут быть доступны, например ACL, которая по умолчанию выключена. Но её можно и включить. Естественно необходим механизм для проверки этого.[/quote]
и всё таки оно показывает только опции монтирования... в текстовом виде(см. последний член структуры)
вопрос не совсем понятен у extX в том и прелесть, что они обладают совместимостью во всех направлениях(и обратной и прямой). А то что (у меня) 2 - это действительно 2 я уверен(как минимум работает человеческий undelete)
а у меня не работает...
unsigned char s_blocksize_bits; // ???
ЕМНИП это тоже что и размер блока, только для скорости оно как-то по другому записано. вроде-бы там логарифм от 2, для того-что-бы скажем сдвинуть число влево на 12, и получить из числа блоков байты. (12 == log2(4096))
// что за магическое число до сих пор не понимаю... (похоже или UUID, или уникальный для каждого типа ФС)
это тип FS. если команде mount не указать ФС (auto), то она читает суперблок, и если в нужном месте число 0xEF53, она предполагает, что это какая-то EXT. Это не очень надёжно конечно, с вероятностью 1/65536 она может принять данные скажем из NTFS как EXT, и соответственно напишет "инвалидный суперблок".
int s_count; // ???
скорее всего это счётчик свободных блоков. надо дальше по коду смотреть...
struct mtd_info *s_mtd; // ???
ЕМНИП когда и как монтировалась ФС в посл. раз.
и всё таки оно показывает только опции монтирования... в текстовом виде(см. последний член структуры)
ну значит так...
[quote=Fat-Zer]
вопрос не совсем понятен у extX в том и прелесть, что они обладают совместимостью во всех направлениях(и обратной и прямой). А то что (у меня) 2 - это действительно 2 я уверен(как минимум работает человеческий undelete)
а у меня не работает...[/quote]
был не прав:
ext2 монтируется как ext[2,4]
ext3 монтируется как ext[2,3,4]
ext4 монтируется как ext4 только
эксперементы:
[63516.350370] EXT3-fs (loop0): error: no journal found. mounting ext3 over ext2?
[63531.752337] EXT4-fs (loop0): mounted filesystem without journal. Opts: (null)
[64834.130508] EXT2-fs (loop0): warning: mounting ext3 filesystem as ext2
[64986.218178] EXT3-fs: barriers not enabled
[64986.218209] kjournald starting. Commit interval 5 seconds
[64986.218242] EXT3-fs (loop0): using internal journal
[64986.218246] EXT3-fs (loop0): mounted filesystem with writeback data mode
[65001.334499] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: (null)
[65775.969452] EXT2-fs (loop0): error: couldn't mount because of unsupported optional features (240)
[65782.602635] EXT3-fs (loop0): error: couldn't mount because of unsupported optional features (240)
дали почитать талмуд Бовет, Чезати "Ядро Linux" - книжка ответила почти на все вопросы. drBatty, спасибо за помощь.