LINUX.ORG.RU

Узнать количество ссылок на файл


0

1

Можно ли узнать количество ссылок на файл? Я что-то сразу не могу найти как. Да, про stat(2) я в курсе, но результат st_nlink содержит только ссылки внутри FS, а мне нужно обязательно знать, открыт ли файл кем-либо ещё.

★★★★★

>открыт ли файл кем-либо ещё

lsof ?

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

Вопрос не в шелле узнать, не сканиерованием /proc, а какую функцию из программы позвать. Сорри, что сразу не сказал. Можно, конечно, fuser из программы позвать, но как-то это не очень прямо...

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

> не сканиерованием /proc, а какую функцию из программы позвать

В таких случаях обычно советуют скопипастить исходник lsof или fuser.

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

В таких случаях обычно советуют скопипастить исходник lsof или fuser.

Которые как раз сканированием /proc и занимаются :)

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

> Которые как раз сканированием /proc и занимаются :)

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

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

> Как раз это - правильные альтернативы.

ОМГ. У нас разные понятия о правильно работающих программах...

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

А что, по-вашему было бы лучше, если бы помимо /proc существовал список из 100500 различных сис. вызовов? Это уже мастдай какой-то получится...

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

Мне достаточно ещё одного поля в структуре, которая возвращается fstat(2). Оно там было бы очень даже логично. Раз уж я могу открыть этот файл, то могу знать открыт ли он кем-либо ещё. Аргумента про мастдай и стотыщпиццот применительно к моему вопросу не понял.

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

Аргумента про мастдай и стотыщпиццот применительно к моему вопросу не понял.

Это я говорил к тому, что вам, например, нужно посмотреть, кем файл открыт; кому-то - найти процесс по имени; кому-то - найти процесс по pid'у; и т.д, и т.п. Если все это делать через ioctl'ы или доп. структуры, получится черт знает что. Тем более, что за работу fstat отвечает модуль ФС, а за учет открытых файлов - само ядро. Хитро как-то получается...

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

> Хитро как-то получается...

Чего такого особо хитрого получается? Ядру так или иначе надо держать файл на диске, даже если на него нет линков в ФС, но есть открытые файлы. Значит, оно ведёт учёт открытых файлов и запускает механизм сборки мусора на ФС, когда удаляется последняя ссылка на файл с учётом открытых файлов. Значит, сама информация есть. Просто не экспортируется в юзерспейс. И чтобы мне её получить, предлагается сканировать /proc, в котором придётся проанализировать совсем не мало файлов. Допустим, что мне надо найти информацию не про один файл, а про 15 тыщ в каталоге, это уже совсем не детское сканирование получается. Да, можно сделать hash join информации из /proc и списка файлов из каталога, но это всё кривизна. Просто не предусмотрен нормальный интерфейс для моего случая. Это я и хотел выяснить, поскольку не смог найти информации. И это мне несколько обидно, поскольку я знаю, что нужная информация в ядре есть.

Теперь, я так понимаю, ты объяснишь мне, что у меня кривая задача...

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

Задача у вас совершенно не кривая. Просто нужно выбрать правильный метод ее решения. Если бы мне нужно было определить, какой из файлов заданной директории в данный момент открыт ядром, я бы прошелся по /proc, выискивая файлы из данной директории (например, при помощи strstr), собрал бы их в кучу, отсортировал бы и вывел. Не так уж это и сложно, тем более, что все, что нужно, уже есть: смотрите исходники lsof и т.п.

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

> Не так уж это и сложно...

Да, ёлки. Я хотел в деструкторе объекта проверять надо ли грохать файл совсем. В рамках этого деструктора я не собирался собирать весь мусор из каталога, но, либо неэффективность N*M, либо сборка мусора отдельным процессом. Как работает fuser/lsof я посмотрел strace-ом давно, там полное сканирование /proc. Делать это на каждый файл просто зверски неэффективно.

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

> Значит, оно ведёт учёт открытых файлов и запускает

механизм сборки мусора на ФС, когда удаляется последняя

ссылка на файл с учётом открытых файлов.



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

Значит, сама информация есть. Просто не экспортируется в

юзерспейс.



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

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

> похоже, у вас неправильное представдение о ссылке на файл. во всяком случае, «ссылка на файл с учётом открытых» путает разные вещи.

У меня «классическое» представление в юниксовом смысле о ссылке на файл, в котором за последние 20 лет у меня не было повода усомниться. Ты первый, кто ставит это представление под сомнение.

Если нельзя узнать сколько раз был inode открыт, как узнать, что его можно удалить?

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

> У меня «классическое» представление

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

как узнать, что его можно удалить?


что значит удалить? и откуда.

ладно, на эту тему можно долго разговаривать (и,
кстати, я в fs/ далеко не эксперт).

вот пример. файл (inode) вообще никем не открыт.
но in-kernel inode вполне жив и в файле есть еще
не сохраненные после последнего close() изменения.

у нас просто нету counter'a который бы считал,
сколько раз он был открыт. если это как-то можно
узнать - я буду очень сильно удивлен. на i_count,
насколько я понимаю, полагаться нельзя.

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

> что значит удалить? и откуда.

По порядку. Есть ФС. Есть файл. Есть инод. Есть счётчик линков на это инод. ФС должна удалить инод и связанное с ним содержимое физически с диска в момент, когда на инод нет ни одной ссылки (нет ни одной записи в директориях, указывающей на этот инод) _и_ он не открыт ни одним процессом, т.е. нет ни одного файл хендла, который его бы удерживал. Верно?

файл (inode) вообще никем не открыт. но in-kernel inode вполне жив и в файле есть еще не сохраненные после последнего close() изменения.

В данном случае это всего лишь особенности реализации. ФС так или иначе должна знать, есть ли открытые хендлы на инод или нет, иначе она не знает, можно ли проводить уборку мусора.

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

> Есть счётчик линков на это инод.

где? какой??? вот есть st_nlink, да. как только он
станет нулем - файл можно удалять.

_и_ он не открыт ни одним процессом


да почему, файл может быть удален и при этом открыт.

ФС так или иначе должна знать, есть ли открытые хендлы


ну елки. ну, как минимум, для этого dcache надо прочесать.

уборку мусора.


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

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

> вот есть st_nlink, да. как только он станет нулем - файл можно удалять.

Ой, если бы.

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

Ну, это не нормальная ситуация, и лечится с помощью fsck.

да почему, файл может быть удален и при этом открыт.

Ну проведи эксперимент. Есть какой-либо файл. Открой его. Сделай unlink. А теперь внимание: в файл можно писать и читать, и он будет занимать место на диске, пока не будет закрыт последний файлхендл на него. Его можно использовать как некоторое хранилище информации между процессами, которое будет автоматически удалено как только закроются все хендлы на него. Например, процессы завершатся нормальным или аварийным образом. Это, в общем-то, известный приём.

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

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

> вот есть st_nlink, да. как только он станет нулем - файл

> можно удалять.




Ой, если бы.



верь мне.

> да почему, файл может быть удален и при этом открыт.



Ну проведи эксперимент.



не надо, я и так знаю, серьезно ;)

в файл можно писать и читать, и он будет занимать

место на диске



конечно! это я и имел в виду когда сказал «и при этом открыт».
но файл уже удален. можно создать новый с тем же именем.

я об этом заговорил как раз потому, что ты постоянно (как
мне кажется) путаешь разные вещи. забудь про ->i_nlink
вообще, это не имеет (почти) никакого значения в данном
контексте.

> но она может вообще никогда не произойти.



Ну, это не нормальная ситуация, и лечится с помощью fsck.



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

вот смотри. процесс делает close(open(FILE, ...)).
все. этот файл никем не открыт.

но. dentry по прежнему болтается в кэше, и может там
оставаться вечно. просто не имеет смысл его чистить пока
у нас хватает памяти/etc.

в каком-то смысле этот FILE все еще открыт. dentry->d_inode
создает reference (те, увеличивает счетчик) на inode.

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

еще раз. я уже говорил, что я забыл почти все, что я знал
про fs/. я могу ошибаться, но если существут просто способ
узнать сколько раз inode открыт - я буду очень удивлен.

все, устал ;)

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

> где? какой??? вот есть st_nlink, да. как только он станет нулем - файл можно удалять.

Нет.

да почему, файл может быть удален и при этом открыт

До тех пор, пока есть ссылки на данный vnode, файл физически удалён не будет (и будет продолжать занимать место на диске).

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

да екарный бабай.

ну почитайте же, что я написал в предыдущем посте.

файл физически удалён не будет


да! данные удалены не будут. и inode будет жить. но
файл уже удален. можно создать новый с тем же именем.

неужели это не понятно?

зы: про «физически» вообще немножко не в тему.

всё. я отсюда ухожу ;)

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

> верь мне.

Сфигали? 8))

теперь. глядя вот на этот inode, мы не можем сразу сказать,

открыт ли сответствующий ему файл или нет.

еще раз. я уже говорил, что я забыл почти все, что я знал

про fs/. я могу ошибаться, но если существут просто способ узнать сколько раз inode открыт - я буду очень удивлен.

Мы не можем знать, открыт ли файл или нет, мы можем знать сумму ссылок (т.е. сколько раз этот файл открыли, не закрыв на настоящий момент + кол-во хардлинков, грубо говоря). И, вообще говоря, в данном контексте правильнее говорить не об inode, а о vnode (или как там оно в линуксе называется?), для инода имеет смысл только кол-во хардлинков (st_nlink в struct stat), который к вопросу имеет весьма опосредованное отношение.

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

> да! данные удалены не будут. и inode будет жить. но файл уже удален. можно создать новый с тем же именем.

Файл - это не имечко c иконочкой в папочке. В данном контексте файл - это структура в ядре. Пока есть ссылки на vnode - он есть и файл существует.

всё. я отсюда ухожу ;)

Да иди уже...

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

> Мы не можем знать, открыт ли файл или нет, мы можем знать сумму ссылок (т.е. сколько раз этот файл открыли, не закрыв на настоящий момент + кол-во хардлинков, грубо говоря).

Да, про это я и спрашиваю. Вычесть st_nlink не проблема.

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

> но файл уже удален.

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

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

> Да, про это я и спрашиваю. Вычесть st_nlink не проблема.

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

Удалена может быть запись в директории,


это я и имел в виду. и вот это как раз связано с nlink.
если == 0, файл можно удалять (чуть точнее, он уже удален).

но все остальные данные в ФС в целости и сохранности


кто с этим спорит. я же об этом тоже говорил, и inode
живехонек (и да, в linux'е это называется inode, а не
vnode).

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

> кто с этим спорит. я же об этом тоже говорил, и inode живехонек (и да, в linux'е это называется inode, а не vnode).

Тогда я не понимаю что ты не понимаешь в моём вопросе.

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

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

Ну вот здесь как раз начинается непонимание. Логически, st_nlink + «количество не закрытых хендлов на файл» == 0 как раз определяют можно ли удалять inode и всю остальную информацию в ФС. Меня интересует «количество незакрытых хендлов».

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

> Почему бы не написать в lklm?

А смысл? Если такого API до сих пор не было, ты представляешь сколько надо усилий, чтобы его продвинуть, убедить, что оно необходимо?

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

> Тогда я не понимаю что ты не понимаешь в моём вопросе.

вопрос я понимаю. и уже много раз на него отвечал.

дело не в том, что нужная тебе инормация не
экспортируется в user-space, ее просто нет.

точнее, нет простого способа узнать, сколько раз
этот файл (in-kernel inode) открыт их user-space.

еще раз! насколько я знаю.

Логически, st_nlink + «количество не закрытых хендлов на файл»


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

можно ли удалять inode и всю остальную информацию в ФС.


вот здесь, наверное, была путаница. скорее всего, под
«inode» ты понимаешь метаданные типа ext3_inode/etc.

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

я тебе встречный вопрос задам. что тебе непонятно в
примере с close(open(FILE)) в
http://www.linux.org.ru/jump-message.jsp?msgid=5574921&cid=5581271
?

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

> я тебе встречный вопрос задам. что тебе непонятно в примере с close(open(FILE))

Мне непонятно какое он имеет отношение к моему вопросу. Ну создали и выбросили хендл, ну замусорили кеш. Это не имеет отношения к другим открытым хендлам, которые не дают удалить информацию об inode с диска.

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

API тебе точно не дадут такого сделать ;)

но вопрос про «как узнать» ты вполне можешь задать.
пусть меня поправят, если есть простой способ.

но его нету ;) ну, давай, еще пример приведу. вот,
процесс делает fork(). посмотри на dup_fd(). мы
просто делаем get_file(), inode никаким способом
про это узнать не может.

конечно, в этом случае, мы можем сказать, что
«открытие» из потомков не считается (struct file
is shared), но я не знаю, что именно тебе нужно.

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

> Это не имеет отношения к другим открытым хендлам,

которые не дают удалить информацию об inode


еще раз. глядя на inode, не видно разницы. то ли
он кем-то открыт, то ли dentry болтается в dcache.

насколько я понимаю.

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

Нет в ядре никакого open count для инодов.
Есть i_count который просто учитывает все ссылки на данную иноду, но поскольку struct file на самом деле не ссылается напрямую на inode, а только через struct dentry, то из него open count вычислить не удастся. В struct dentry есть свой счетчик ссылок, d_count, но он, опять же учитывает все ссылки включая прочие внутриядерные, и внутри dcache.

Единственный близкий по духу счетчик, это inode->i_writecount, который работает в двух ипостасях. Если значение в нем положительное, то столько раз файл был открыт для записи (+ столько truncate на нем сейчас идет), если же значение в нем отрицательное, то столько у данной иноды прикреплено mmap областей с выставленным флагом VM_DENYWRITE.

Ну а раз в ядре такого счетчика open handles нет, то и в юзрспейс, понятное дело, не так то это просто получить.

Кстати с i_nlink тоже не все просто. Например i_nlink=1 для каталога означает «сколько-то линков есть, но сколько точно - нам неизвестно» ;)

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

> Ну а раз в ядре такого счетчика open handles нет, то и в юзрспейс, понятное дело, не так то это просто получить.

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

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

> If the inode use count hits zero, the inode is then freed and may also be destroyed.

Я так понимаю, это оно. Если я правильно понял, то i_count это внутренний счётчик ядра на то, сколько раз используется инода ядром, верно? Если i_count == 0 и i_nlink == 0, то это условие для удаление иноды с диска, так? Кажется я дошёл до сути. Значение i_count можно получить только если зачем либо эту иноду читали.

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

Да, это оно.
Про «читали» мысль не понял. i_count - это чисто in-memory reference counter.

когда оно равно нулю - мы можем сунуть иноду в lru или просто выкинуть из памяти, а если при этом nlink == 0, то просто выкидываем из памяти с удалением с диска.

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

Да, я так и понял. Мне нужен именно i_count. А вернее, знать, i_count == 0, или вообще эту иноду пока никто не открывал.

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

В том-то и беда, что даже если ее никто не открывал, просто сделав на нее stat, ты ее прочитаешь с диска и i_Cunt e нее будет не 0

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

> Да, я так и понял.

я вот не уверен ;) и, на всякий случай, i_nlink все-таки
здесь не при чем.

Мне нужен именно i_count.


вот с самого же начала я твержу, что он не поможет.

i_count == 0, или вообще эту иноду пока никто не открывал.


green уже сказал, что fstat() никогда не увидит i_count == 0.
но это, все-таки, не беда. мы могли бы сделать syscall,
который не считывал бы с диска.

короче. все что можно было сделать (с практической точки
зрения), это написать syscall, возвращающий одно из двух
значений: МАМОЙ_КЛЯНУСЬ_ОН_НИКЕМ_НЕ_ОТКРЫТ и, второе,
А_ХРЕН_ЕГО_ЗНАЕТ.

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

</thread>

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

> inode->i_writecoun

столько раз файл был открыт для записи

(+ столько truncate на нем сейчас идет)



green, ну это неправда. разумеется, sys_truncate()
get_write_access(). и по понятным причинам, мы ведь,
в сущности, открываем файл для записи, так что это
одно и то же.

но сам по себе do_truncate() этого не требует, и
никак на это счетчик не полагается. те, например,
sys_ftruncate() этот счетчик не трогает (он и так
больше нуля если FMODE_WRITE).

выставленным флагом VM_DENYWRITE


сказал бы проще, в этот файл запрещено писать из-за
exec. MAP_DENYWRITE/VM_DENYWRITE user-space'у недоступен
и не виден.


но я не за этим зашел, спросить хочу...

i_nlink=1 для каталога означает «сколько-то линков есть

но сколько точно - нам неизвестно» ;)



хм. а это в каких случаях? просто интересно.


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

truncate не требует открытого file handle, а вопрос был именно про них ;)

i_nlink=1 используется, например, когда в каталоге создаешь больше подкаталогов чем поместится в тип данных для i_nlink для этой конкретной файлухи. То есть для ext3/4 и reiserfs, больше чем 32k подкаталогов (в любой момент времени жизни этого каталога в прошлом) сбросит i_nlink в 1, и даже если потом часть подкаталогов удалить - то поскольку мы незнаем сколько там подкаталогов, то счетчик из этого значения уже никуда не изменится.

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

> То есть для ext3/4 и reiserfs, больше чем 32k подкаталогов

(в любой момент времени жизни этого каталога в прошлом)

сбросит i_nlink в 1



хмм. это точно? про reiserfs вообще ничего не знаю, но
вот я смотрю в fs/ext2 и ничего такого не вижу.

->write_inode() и ext2_iget() ничего «интересного» с
ext2_inode->i_links_count не делают, просто пишут/читают
->i_count.

ext2_dir_inode_operations->mkdir/link/rename всегда
проверяют ->i_nlink < EXT2_LINK_MAX, иначе EMLINK.

может, это раньше так было, или я что-то упустил ?

(напомню, я в fs/ не разбираюсь, у меня даже ctags
туда не смотрит ;)

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