Как ОС производит запись на внешнюю память на уровне железа?

Прочитал несколько источников но полноценной информации так и не нашел. Хочу понять как происходит фактическая запись.

  1. Правильно ли я понимаю что мы адресуем номера блоков (например по 4Кб)? т.е. мы все равно храним какое то конечное кол-во адресов свободных блоков?
  2. Получается что ОС не адресует конкретные байта (как в случае с ОЗУ страницы+смещение из за чего возникает ограничения в 32х например 4Гб оперативки), а только отправляет на устройство (например ссд) команду что сейчас я буду выполняеть запись. Находит свободный блок данных (который он у себя где то сохранил в момент старта) и говорит запиши в этот блок следующие данные и шлет по 64 бита столько данных сколько вмешает блок (например 4Кб) или меньше, а дальше находит следующий блок, или если кончаются данные шлет команду окончания записи?
  3. Не могу найти информацию из за чего именно возникает ограничение на максимальный размер файла если любой файл это бесконечное кол-во связанных блоков?

Ответы (2 шт):

Автор решения: KoVadim
  1. Да, система хранит в каком то виде номер условного блока. Размер блока также определяется характеристиками устройства. Это может быть как 4 кб, так и мегабайт. Например, в жестких дисках используется система цилиндр, головка, сектор. Вначале это были прям реальные "координаты", сейчас уже нет и контроллер диска может сообщать о сотнях дисков и головок, а потом сам уже транслирует в реальные данные.

  2. В случае диска или других внешних устройств обычно очень неудобно адресовать байтом, поэтому берут более крупные единицы. В случае ОЗУ ограничение в 4 гигабайта возникло из за того, что шина адреса (которая позволяет адресовать конкретный байт) хранилась в 32битном регистре. а 2 в 32 - это 4 гигабайта. Сейчас, в 64 битных системах на самом деле не используются все 64 бита для адреса, а обычно порядка 48 (что все равно очень и очень много - 256 терабайт, но это пока)). Но тут тоже есть один момент. Если раньше с памятью работали "побайтно", то в какой то момент поняли, что можно скорость поднять в два раза, если шину данных сделать не 8 бит, а 16 и читать по два байта за раз. Все равно, в многих случаях это второй байт все равно нужно прочитать. Сейчас, на сколько я знаю, читают по 64 байта за раз, даже если по факту нужно 1 байт. На этом базируются многие оптимизации.

Тут возможно интересно, как именно это происходит на "очень низком уровне". И тут есть много разных протоколов. С памятью обычно работают по параллельной шине - то есть для каждого бита есть свой проводок и обычно это происходит так. Вначале процессор (а если точнее - контроллер памяти, который сейчас обычно находится в процессоре) выставляет на шине адреса нужный адрес, а потом, по отдельному проводку дает сигнал "чтения/записи". Память выставляет на шине данных нужные данные (или забирает для записи) и выставляет свой флажек на отдельном проводе. Зачем эти заморочки с отдельным проводом? а тут нужно вспомнить физику. При скорости света 300000 км/с и тактовой частоте 3 ггц (округлим для красоты), получается, что 310^8 м/с / 310^9 тк/с = 0.1 м на такт - свет проходит 10 см за один такт процессора! а 10 см - это вполне себе длина проводника на материнской плате от процессора до памяти. Так что за один такт сигнал может "не дойти/не установится в нормальном виде" (да, это грубо, но вдаваться в электрические процессы, которые происходят на плате в этот момент и читать курс по электрическим цепям, который учат в техническом вузе пару лет я не буду).

Если же взять что то другое, например, USB, то там последовательная передача. Если очень условно упростить все, то изменяя напряжение, кодируются 1 и 0, контроллеры с двух сторон договариваются о скорости и признаках начала и конца передачи пакета. И собственно, изменяя напряжение и передаются данные. Размер пакета разный, в той же википедии https://ru.wikipedia.org/wiki/USB можно посмотреть графики как это все меняется. И тут часто приходится играться либо маленькая скорость и надежно, или большая, но шалит. Ищут золотую середину.

  1. А как возникает ограничение на размер файла. А очень просто. Есть такая штука как файловая система. Она хранит имена файлов, разную метаинформацию (время создания, права) и также - начало (адрес) файла. Выше уже я приводил систему "адресации" файла на диске. Но там были просто числа. Но допустим, что автор файловой системы выделил 4 байта под хранение адреса начала и решил хранить побайтно (странно, но допустим). В таком случае, файл не может начаться дальше, чем за 4 гигабайта от начала (да, размер нужно тоже хранить и тут появляется ограничение на размер). И если под размер тоже отвести 4 байта, то получается, что размер файла не может быть больше 4 гигабайт. И на весь диск нельзя будет использовать больше 8 гигабайт.

Поэтому, придумали хранить/адресовать небольшими кусками - от 512 байт до 4-8 кб. Если сделать меньше - придется выделять больше места под хранения адреса и размера, если сделать больше - то в некоторых блоках (кусках) в конце будет неиспользуемое место (если файл к примеру 128 байт, а блок 8 кб, то почти весь блок будет пуст...).

Некоторые файловые системы научились и это обходить. Насколько мне известно, NTFS может хранить два мелких файла в одном блоке.

Из этого возникает интересная штука. Если к примеру, размер диска 1 мб, а сектор 1 кб (цифры просто такие, что бы легче считать), то больше 1024 файлов на таком диске не сохранить (а на самом деле меньше - нужно ещё файловую систему сохранить где то. В компьютерах укнц размер файла вообще указывался в блоках для экономии места. И никто не знал, там 1 байт или 2. Блоки были по 512 байт. И на хранение имени файла, даты, размера, позиции уходило 14 байт. да, именно 14 байт (попробуйте на досуге это все втиснуть, имя файла было 6 символов + 3 для расширения, диски были по 400 и 800 кб).

Собственно, многие файловые системы и отличаются тем, как именно они размешают всю необходимую информацию.

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


пойдем ещё глубже. А как сама запись происходит. Тут целое поле изобретений и новаций. К примеру, в случае с дисками вначале все было просто - магнитная головка просто намагничивала правильным образом небольшой кусок диска, а когда нужно было считывать, то проверяла эту намагниченность (кассетные плееры работают почти также!) Потом захотелось писать больше - начали придумывать, как упаковать и тут началось. И писали не один бит, а к примеру 2 сразу, просто используя 4 степени намагниченности (в ssd применяют этот же трюк). А потом начали писать прям слой поверх другого слоя. Да, при этом возникают ошибки при считывании, но применяются специальные методики для восстановления данных (почитать - коды Рида-Соломона. Если кратко, то пишем 8 бит полезной информации и 3 сверху контрольных. Если повредился один бит - то его можно восстановить, зная контрольные. Где выгода? а теперь можно записывать условно в два раза плотнее, даже зная, что один бит всегда повреждается. Дико? возможно, но когда цена вопроса миллионы и миллиарды прибыли, и не так сделаешь. (тот же western digital регулярно ловят на том, что он "недоговариает " о том, какую именно он систему использует внутри, а иногда, в той же серии просто меняет ее, удешевляя себе производство, а люди ругаются, так как обнаруживают это по косвенным признакам, а иногда и по существенным (например, падением скорости чтения, так как контроллер занимается восстановлением данных) честность/законность такого оставим на совести производителей).

→ Ссылка
Автор решения: Alex Krass

Получается что ОС не адресует конкретные байта (как в случае с ОЗУ страницы+смещение из за чего возникает ограничения в 32х например 4Гб оперативки), а только отправляет на устройство (например ссд) команду что сейчас я буду выполняеть запись. Находит свободный блок данных (который он у себя где то сохранил в момент старта) и говорит запиши в этот блок следующие данные и шлет по 64 бита столько данных сколько вмешает блок (например 4Кб) или меньше, а дальше находит следующий блок, или если кончаются данные шлет команду окончания записи?

У нас есть ограничения на уровне самого аппаратного обеспечения (железа) и ограничения на уровне реализации работы с этим железом. Поэтому их стоит рассматривать вместе.

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

Это ограничение так же решалось аппаратными средствами, на процессорах с поддержкой PAE ограничение в 4Гб оперативной памяти преодолевается для 32-битных систем.

https://wasm.in/blogs/stranichnaja-adresacija-pae.476/

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

С оперативной памятью закончили.

Внешняя память не проектируется на максимальную скорость, а проектируется на хранение информации. Здесь мы уже не ограничены задачей передавать весь адрес за один заход и управление происходит последовательными командами. А значит, аппаратное ограничение как в оперативной памяти тут отсутствует.

Не могу найти информацию из за чего именно возникает ограничение на максимальный размер файла если любой файл это бесконечное кол-во связанных блоков?

В случае с той же FAT32, на уровне драйвера устройства происходит тоже самое, что и с оперативной памятью. Она проектировалась очень давно и тоже требует передачи адреса одним блоком в виде 32-битного числа. Вот и все, это требование самой реализации файловой системы.

Это ограничение не аппаратное, а значит его можно преодолеть, таким образом появляется exFat, который просто снимает эти программные ограничения и исправляет проблемы старой системы.

Правильно ли я понимаю что мы адресуем номера блоков (например по 4Кб)? т.е. мы все равно храним какое то конечное кол-во адресов свободных блоков?

Да, пространство разбивается на блоки различной длины, но мы сами можем определять размеры этих блоков и способы работы с ним. Тут уже работа инженеров, как они хотят работать с файловой системой. Можно заранее разметить весь объем тома, а можно придумать систему, которая будет динамически расширять как адресное пространство, так и файловое пространство. Различных решений в данном случае очень много.

https://timeweb.com/ru/community/articles/tipy-faylovyh-sistem-ih-prednaznachenie-i-otlichiya

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

Если хочется чего-то более подробного, то можно прочитать про систему iNode в Unix.

https://www.techspot.com/article/2377-file-system-explainer/

https://www.researchgate.net/publication/38107261_A_Hardware_Filesystem_Implementation_with_Multidisk_Support

→ Ссылка