Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the principle of realizing inotify function in Linux?

2025-02-27 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >

Share

Shulou(Shulou.com)06/01 Report--

Today, I will talk to you about the implementation principle of inotify function in Linux, which may not be well understood by many people. In order to make you understand better, the editor has summarized the following content for you. I hope you can get something according to this article.

1. Main functions of inotify

It is a mechanism used by the kernel to notify user space programs of file system changes.

As we all know, the Linux desktop system has many unsatisfactory aspects compared with MAC or Windows. In order to improve this situation, the open source community proposes that the kernel should provide some mechanisms in the user state, so that the user state can know what happened to the kernel or underlying hardware devices in time, so that they can better manage the devices and provide better services to users, such as hotplug, udev and inotify. Hotplug is a mechanism by which the kernel notifies user-mode applications of some events on hot-swappable devices. Desktop systems can use it to manage devices effectively. Udev dynamically maintains device files under / dev. Inotify is a file system change notification mechanism. Events such as file additions and deletions can immediately let users know that this mechanism is introduced by the famous desktop search engine project beagle. And has been applied in Gamin and other projects.

two。 User interface

In user mode, inotify is used through three system calls and file I / operations on the returned file descriptor. The * step of using inotify is to create an inotify instance:

Int fd = inotify_init ()

Each inotify instance corresponds to a separate sorted queue.

The change event of the file system is called an object management of watches. Each watch is a tuple (target, event mask), the target can be a file or directory, and the event mask represents the inotify event that the application wants to focus on, and each bit corresponds to an inotify event. The Watch object is referenced by the watch descriptor, and the watches is added by the pathname of the file or directory. The directory watches returns events that occur on all files in that directory.

The following function adds a watch:

Int wd = inotify_add_watch (fd, path, mask)

Fd is the file descriptor returned by inotify_init (), path is the path name of the monitored target (that is, file name or directory name), mask is the event mask, and the event represented by each is defined in the header file linux/inotify.h. You can modify the event mask in the same way, that is, change the inotify event that you want to be notified. Wd is the watch descriptor.

The following function deletes a watch:

Int ret = inotify_rm_watch (fd, wd)

Fd is the file descriptor returned by inotify_init (), and wd is the watch descriptor returned by inotify_add_watch (). Ret is the return value of the function.

File events are represented by an inotify_event structure, which is obtained through the file descriptor returned by inotify_init () using the usual file reading function read:

Struct inotify_event {_ _ s32 wd; / * watch descriptor * / _ _ U32 mask; / * watch mask * / _ _ U32 cookie; / * cookie to synchronize two events * / _ _ U32 len / * length (including nulls) of name * / char name [0]; / * stub for possible name * /}

The wd in the structure is the watch descriptor of the monitored target, mask is the event mask, len is the length of the name string, name is the path name of the monitored target, the name field of this structure is a pile, it only references the file name for the user, the file name is longer, it actually follows the structure, and the file name will be filled with 0 so that the next event structure can be aligned with 4 bytes. Note that len also counts the number of filled bytes.

Multiple events can be obtained at a time through a read call, as long as the buf provided is large enough.

Size_t len = read (fd, buf, BUF_LEN)

Buf is an array pointer of inotify_event structure. BUF_LEN specifies the total length to be read, and the buf size should be at least not less than BUF_LEN. The number of events returned by this call depends on the BUF_LEN and the length of the filename in the event. Len is the number of bytes actually read, that is, the total length of the obtained event.

You can use select () or poll () on the file descriptor fd returned by the function inotify_init (), or you can use the ioctl command FIONREAD on fd to get the length of the current queue. Close (fd) removes all watch added to the fd and does the necessary cleanup.

Int inotify_init (void); int inotify_add_watch (int fd, const char * path, _ _ U32 mask); int inotify_rm_watch (int fd, _ _ U32 mask)

3. Kernel implementation principle

In the kernel, each inotify instance corresponds to an inotify_device structure:

Struct inotify_device {wait_queue_head_t wq; / * wait queue for iBank o * / struct idr idr; / * idr mapping wd-> watch * / struct semaphore sem; / * protects this bad boy * / struct list_head events; / * list of queued events * / struct list_head watches; / * list of watches * / atomic_t count; / * reference count * / struct user_struct * user; / * user who opened this dev * / unsigned int queue_size / * size of the queue (bytes) * / unsigned int event_count; / * number of pending events * / unsigned int max_events; / * maximum number of events * / U32 last_wd; / * the last wd allocated * /}

D_list points to the list of all inotify_device, i_list points to the list of all monitored inode, count is the reference count, dev points to the inotify_device structure corresponding to the inotify instance where the watch is located, inode points to the inode,wd to be monitored by the watch is the descriptor assigned to the watch, and mask is the event mask of the watch, indicating which file system events it is interested in.

The structure inotify_device is created when inotify_init () is called in user mode and is released when the file descriptor returned by inotify_init () is closed. The structure inotify_watch is created when inotify_add_watch () is called in user mode and released when inotify_rm_watch () or close (fd) is called in user mode.

Both directories and files correspond to an inode structure in the kernel, and the inotify system adds two fields to the inode structure:

Struct inotify_watch {struct list_head dumblist; / * entry in inotify_device's list * / struct list_head ilistings; / * entry in inode's list * / atomic_t count; / * reference count * / struct inotify_device * dev; / * associated device * / struct inode * inode; / * associated inode * / s32 wd; / * watch descriptor * / U32 mask; / * event mask for this watch * /}

D_list points to the list of all inotify_device, i_list points to the list of all monitored inode, count is the reference count, dev points to the inotify_device structure corresponding to the inotify instance where the watch is located, inode points to the inode,wd to be monitored by the watch is the descriptor assigned to the watch, and mask is the event mask of the watch, indicating which file system events it is interested in.

The structure inotify_device is created when inotify_init () is called in user mode and is released when the file descriptor returned by inotify_init () is closed. The structure inotify_watch is created when inotify_add_watch () is called in user mode and released when inotify_rm_watch () or close (fd) is called in user mode.

Both directories and files correspond to an inode structure in the kernel, and the inotify system adds two fields to the inode structure:

# ifdef CONFIG_INOTIFY struct list_head inotify_watches; / * watches on this inode * / struct semaphore inotify_sem; / * protects the watches list * / # endif

Inotify_watches is a watch list on a monitored target, and whenever a user calls inotify_add_watch (), the kernel creates an inotify_watch structure for the added watch and inserts it into the inotify_watches list of the corresponding inode of the monitored target. Inotify_sem is used to synchronize access to inotify_watches lists. When one of the events mentioned in the * * section occurs in the file system, the corresponding file system code will display the call fsnotify_* to report the corresponding event to the inotify system, where the * number is the corresponding event name. The current implementation includes:

Fsnotify_move, the file is moved from one directory to another fsnotify_nameremove, the file is deleted from the directory fsnotify_inoderemove, self-deleted fsnotify_create, creates a new file fsnotify_mkdir, creates a new directory fsnotify_access, the file is read fsnotify_modify, the file is written fsnotify_open, the file is opened fsnotify_close, the file is closed fsnotify_xattr, the file's extended properties are modified fsnotify_change, there is an exception when the file is modified or the original data is modified This is inotify_unmount_inodes, which is called to notify the umount event to the inotify system when the file system is umount.

All the notification functions mentioned above call inotify_inode_queue_event (inotify_unmount_inodes calls inotify_dev_queue_event directly). This function first determines whether the corresponding inode is monitored, which is achieved by checking whether the inotify_watches list is empty. If it is found that inode is not being monitored, do nothing, return immediately, otherwise, iterate through the inotify_watches list to see whether the current file operation event is monitored by a watch, if so. Call inotify_dev_queue_event, otherwise, return. The function inotify_dev_queue_event first determines whether the event is a repeat of the previous event, if so, discards the event and returns, otherwise, it determines whether the inotify instance, that is, the event queue of inotify_device, overflows, and if it overflows, it generates an overflow event, otherwise it generates a current file operation event, which is built by kernel_event, and kernel_event will create an inotify_kernel_event structure. The structure is then inserted into the events event list of the corresponding inotify_device, and then wakes up the wait queue pointed to by the wq waiting in the inotify_device structure. User-mode processes that want to monitor file system events hang on the waiting queue wq when they call read on the inotify instance (that is, the file descriptor returned by inotify_init ()) but when there is no event.

4. Use the example

Here is an example of using inotify to monitor file system events:

# include # include # include _ syscall0 (int, inotify_init) _ syscall3 (int, inotify_add_watch, int, fd, const char *, path, _ _ U32, mask) _ syscall2 (int, inotify_rm_watch, int, fd, _ _ U32, mask) char * monitored_files [] = {". / tmp_file", ". / tmp_dir", "/ mnt/sda3/windows_file"}; struct wd_name {int wd Char * name;}; # define WD_NUM 3 struct wd_name wd_ array [WD _ NUM] Char * event_array [] = {"File was accessed", "File was modified", "File attributes were changed", "writtable file closed", "Unwrittable file closed", "File was opened", "File was moved from X", "File was moved to Y", "Subfile was created", "Subfile was deleted", "Self was deleted", "Self was moved", " "Backing fs was unmounted", "Event queued overflowed", "File was ignored"} # define EVENT_NUM 16 # define MAX_BUF_SIZE 1024 int main (void) {int fd; int wd; char buffer [1024]; char * offset = NULL; struct inotify_event * event; int len, tmp_len; char strbuf [16]; int I = 0; fd = inotify_init (); if (fd

< 0) { printf("Fail to initialize inotify.\n"); exit(-1); } for (i=0; imask & IN_ISDIR) { memcpy(strbuf, "Direcotory", 11); } else { memcpy(strbuf, "File", 5); } printf("Object type: %s\n", strbuf); for (i=0; iwd != wd_array[i].wd) continue; printf("Object name: %s\n", wd_array[i].name); break; } printf("Event mask: X\n", event->

Mask); for (iTuno; imask & (1)

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Servers

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report