Что такое файловый дескриптор

Где хранится файловый дескриптор и что из себя представляет? Как просмотреть список файловых дескрипторов для процесса? Что такое таблица файловых дескрипторов? Типы файлов в Unix. Утилиты и команды: lsof, fuser, ulimit, strace, pstree, top, pidof, pgrep.

В этот раз я решила разобраться, что из себя представляет файловый дескриптор. Ниже — небольшой конспект рассмотренной информации. К сожалению, так и не удалось запустить утилиту Crash(M1), для анализа дампов ядра. Оказалось, что утилита существует только на Solaris, а в наличии только Debian. Поэтому, рассмотреть систему файловых дескрипторов изнутри не получилось.

 

Типы файлов в Unix

Помимо каталогов и обычных файлов для хранения информации, файловая система может содержать следующие виды файлов:

  • Специальный файл устройства
  • Именованный канал
  • Символьная ссылка
  • Сокет

Пример:

Директория dev (от devices) содержит файлы почти всех возможных в unix типов, поэтому она идеальна для примера. Первый символ в строке «crw-rw-rw-» — обозначает тип файла. Типы файлов могут принимать следующие значения:

  • — для обычного файла,
  • d для каталога,
  • b для блочного устройства,
  • c для символьного устройства,
  • l для символической ссылки,
  • p для FIFO,
  • s для гнезда (socket).

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

Файловая подсистема операционной системы UNIX имеет специальный уровень абстракции для обработки запросов к файлам — переключатель файловых систем или виртуальная файловая система (VFS). VFS предоставляет пользователю стандартный набор функций (интерфейс) для работы с файлами, вне зависимости от места их расположения и принадлежности к разным файловым системам.

vfs

Рисунок http://www.openspin.org/materials/courses/admin/ch01s02.html

Задача VFS — по полному имени файла найти его местоположение в дереве файловой системы,
определить её тип в этом месте дерева и «переключить», т. е. передать файл на дальнейшую обработку драйверу конкретной файловой системы. Такой подход позволяет использовать практически неограниченное количество различных файловых систем на одном компьютере под управлением одной операционной системы, а пользователь даже не будет знать, что файлы физически находятся на разных носителях информации.

 

Системные вызовы для взаимодействия с файлами

Некоторые системные вызовы для работы с файлами:

fd=open(name,how,j) Открыть файл для чтения, записи, или для чтения и записи
fd=creat(name,mode) Создать новый файл
s=close(fd) Закрыть открытый файл
n=read(fd,buffer,nbytes) Прочитать данные из файла в буфер
n=write(fd,buffer,nbytes) Записать данные из буфера в файл
position=lseek(fd,offset,whence) Переместить указатель в файле
s=stat(name,&buf) Получить информацию о состоянии файла
s=fstat(fd,&buf) Получить информацию о состоянии файла
s=pipe(&fd[0]) Создать канал
s=fcntl(fd,cmd,…) Блокировка файла

 

Что такое файловый дескриптор

Успешный вызов creat(), open() или pipe() — возвращают небольшое неотрицательное целое число, которое называют дескриптором файла. Если произошла ошибка, то системный вызов вернет -1. Системные вызовы creat() и open() возвращают наименьший неиспользуемый в данный момент дескриптор файла.

Информация об открытых файлах хранится в ядре системы UNIX. Значение, возвращаемое open(), является индексом в таблице файловых дескрипторов.

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

При запуске shell, например при логине или при запуске командой sh, открывается новая shell-сессия, внутри которой создаются псевдофайлы символьных ссылок на устройства
ввода-вывода /dev/stdin, /dev/stdout и /dev/stderr, в которые потоки ввода-вывода можно перенаправлять так же, как в обычные текстовые файлы. Когда под оболочкой запускается программа, в системе создается новый процесс, который является для этой оболочки дочерним процессом, следовательно, получает копию таблицы дескрипторов своего родителя (то есть все открытые файлы родительского процесса).

Таким образом, когда программа начинает свое выполнение, файлы с дескрипторами 0, 1 и 2 уже открыты для стандартного ввода, вывода и потока сообщений об ошибках. При этом, программа даже не знает, что открытые ею файлы, строго говоря, файлами не являются.

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

Системный вызов close() закрывает файл. При завершении процесса все открытые файлы (кроме файлов с дескрипторами 0, 1 и 2) автоматически закрываются. Однако, если файлы не закрывать самостоятельно, то соответствующие дескрипторы могут не освобождаться, что приводит к превышению лимита открытых файлов.

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

Системный вызов read(), позволяет читать данные из файла. Системный вызов read() читает данные в «сыром» виде, то есть как последовательность байт, без какой-либо интерпретации.

Для записи данных в файл используется системный вызов write(). В принципе write() выполняет процедуру, обратную
read(): записывает count байтов из буфера buffer в файл с дескриптором fd, возвращая количество записанных байтов или -1 в случае ошибки.

Для изменения текущей позиции чтения-записи используется системный вызов lseek(). В случае удачного завершения, lseek() возвращает значение установленной «новой» позиции относительно начала файла. В случае ошибки возвращается -1.

 

Таблица файловых дескрипторов

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

Поля структуры user, связанные с файловым дескриптором:

  • u_ofile — Указатель на системную файловую таблицу
  • u_pofile — Флаги файлового дескриптора

Содержимое таблицы дескрипторов процесса можно посмотреть с помощью утилиты crash(1M).
Команда user покажет содержимое u-area процесса. Например, для текущего командного интерпретатора мы получим следующую информацию:

 

Утилиты и команды, для получения информации о файловых дескрипторах

pfiles и lsof

pfiles (Solaris) — выводит список открытых файлов, дескрипторов, сокетов указанным процессом.

lsof (от англ. LiSt of Open Files) — утилита, служащая для вывода информации о том, какие файлы используются теми или иными процессами.

Небольшой отрывок из документации на lsof:

 

fuser

fuser — утилита, идентифицирующая процессы, которые используют указанные файлы или сокеты.

 

ulimit

Утилита ulimit устанавливает ограничения на общесистемные ресурсы. Позволяет обеспечивать контроль над ресурсами для оболочки и процессов, запущенных под ее управлением, если это возможно. Данная утилита в строена в интерпретатор bash.

-S Установить мягкие ограничения для указанных ресурсов (Change and report the soft limit associated with a resource).
-H Установить жесткие ограничения для указанных ресурсов (Change and report the hard limit associated with a resource).
-a Сообщить о текущих ограничениях по всем ресурсам (All current limits are reported).
-c Максимальный размер создаваемых файлов (The maximum size of core files created).
-d Максимальный размер сегмента данных процесса (The maximum size of a process’s data segment).
-e Максимальный планируемый приоритет («nice»).
-f Максимальный размер файла, записываемого с помощью оболочки и ее потомками (The maximum size of files created by the shell, default option).
-i Максимальное количество ожидающих сигналов.
-l Максимальный размер памяти, который может быть зарезервирован (The maximum size that may be locked into memory).
-m Максимальный размер в памяти (The maximum resident set size).
-n Максимальное количество открытых файловых дескрипторов (The maximum number of open file descriptors). Многие unix системы не позволяют изменять значения данного ресурса.
-p Размер канала (pipe size) в 512-байтных блоках (нельзя изменять во многих операционных системах).
-q Максимальное количество байт в очереди сообщений POSIX.
-r Максимальный планируемый приоритет в реальном времени.
-s Максимальный размер стека (The maximum stack size).
-t Максимальная загрузка процессора в секундах (The maximum amount of cpu time in seconds).
-u Максимальное количество процессов доступных одновременно одному пользователю (The maximum number of processes available to a single user).
-v Максимальный размер виртуальной памяти доступный оболочке (The maximum amount of virtual memory available to the process).
-x Максимальное количество файловых блоков.

 

truss и strace

truss (Solaris) — аналог strace.

Strace — это утилита, которая отслеживает системные вызовы, которые представляют собой механизм трансляции, обеспечивающий интерфейс между процессом и операционной системой (ядром).

strace — трассировка системных вызовов команды program (очень полезна для отслеживания попыток программы открыть конфиг/библиотеку и т.п.).

  • -e write — указать параметр фильтрации, в данном примере — отслеживать системные вызовы write (часто используется open)
  • -f — отслеживать системные вызовы потомков (желательно использовать)
  • -o file — вывод трассировки в файл file

 

ptree и pstree

ptree (Solaris) — аналог pstree.

pstree — команда отображает дерево запущенных процессов.

 

top

top – показать все запущенные процессы в интерактивном режиме (с возможностью сортировки по загрузке ЦП/памяти/т.п.) :

  • h — справка о программе
  • k — уничтожить процесс
  • n — число отображаемых процессов
  • u — сортировать по имени пользователя
  • M — сортировать по объему ОЗУ
  • P — сортировать по загрузке ЦП
  • r — изменить приоритет выполнения
  • q — выход

 

pidof

pidof — программа в операционной системе Linux, находящая идентификатор процесса (PID) работающего процесса(ов) по имени программы и выводящая его на стандартный вывод.

 

pgrep

pgrep — ищет процессы по их именам и другим атрибутам.

 

Полезные ссылки, использованые материалы

wm-help.net: Файловая таблица

opennet.ru: НИЗКОУРОВНЕВЫЙ ВВОД-ВЫВОД

citforum.ru: CRASH(1M) — изучение образа системы

valera.asf.ru: Дескрипторы файлов

ccfit.nsu.ru: Что же делает вызов open(2)

Что такое файловый дескриптор: 1 комментарий

Комментарии запрещены.