Analysis of linux kernel file_operations structure

Transfer from: https://blog.csdn.net/whatday/article/details/100631472

struct module *owner

The first file_operations member is not an operation at all; it is a pointer to the module that owns this structure. This member is used to prevent the module from being unloaded while its operation is still in use. Almost all the time, it is simply initialized to THIS_MODULE, a macro defined in <linux/module.h>.

loff_t (*llseek) (struct file *, loff_t, int);

The llseek method is used to change the current read/write position in the file, and the new position is used as a (positive) return value. The loff_t parameter is a "long offset", and is at least 64 bits wide even on a 32-bit platform. The error is caused by a Negative return value indication. If this function pointer is NULL, the seek call will modify the position counter in the file structure (described in the "file structure" section) in a potentially unpredictable way.

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

Used to get data from the device. A null pointer at this position causes the read system call to fail with -EINVAL("Invalid argument"). A non-negative return value represents the number of bytes successfully read (the return value is a " signed size" type, usually an integer type native to the target platform).

ssize_t (*aio_read)(struct kiocb *, char __user *, size_t, loff_t);

Initiate an asynchronous read - a read operation that may not end before the function returns. If this method is NULL, all operations will be performed by read instead (synchronously).

ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

Send data to the device. If NULL, -EINVAL is returned to the program that called the write system call. If non-negative, the return value represents the number of bytes successfully written.

ssize_t (*aio_write)(struct kiocb *, const char __user *, size_t, loff_t *);

Initialize an asynchronous write on the device.

int (*readdir) (struct file *, void *, filldir_t);

For device files, this member should be NULL; it is used to read directories and is only useful for file systems.

unsigned int (*poll) (struct file *, struct poll_table_struct *);

The poll method is the backend of three system calls: poll, epoll, and select, which are used to query whether the reading or writing of one or more file descriptors will block. The poll method should return a bit mask indicating whether it is non-blocking Reading or writing is possible, and, possibly, information is provided to the kernel to sleep the calling process until I/O becomes possible. If the poll method of a driver is NULL, the device is assumed to be readable and writable without blocking .

int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);

The ioctl system call provides a method of issuing device-specific commands (for example, formatting a track of a floppy disk, which is neither read nor write). In addition, several ioctl commands are recognized by the kernel without having to reference the fops table. If the device does not provide an ioctl method, For any undefined request (-ENOTTY, "The device has no such ioctl"), the system call returns an error.

int (*mmap) (struct file *, struct vm_area_struct *);

mmap is used to request the device memory to be mapped into the process address space. If this method is NULL, the mmap system call returns -ENODEV.

int (*open) (struct inode *, struct file *);

Although this is often the first operation performed on the device file, the driver is not required to declare a corresponding method. If this item is NULL, the device has been opened successfully, but your driver will not be notified.

int (*flush) (struct file *);

The flush operation is called when the process closes the copy of its device file descriptor; it should execute (and wait for) any unfinished operation of the device. This must not be confused with the fsync operation requested by the user query. Currently, flush is rarely used Used in the drive; SCSI tape drives use it, for example, to ensure that all written data is written to the tape before the device is closed. If flush is NULL, the kernel simply ignores the request of the user application.

int (*release) (struct inode *, struct file *);

Refer to this operation when the file structure is released. Like open, release can be NULL.

int (*fsync) (struct file *, struct dentry *, int);

This method is the backend of the fsync system call, which is called by the user to refresh any pending data. If this pointer is NULL, the system call returns -EINVAL.

int (*aio_fsync)(struct kiocb *, int);

This is the asynchronous version of the fsync method.

int (*fasync) (int, struct file *, int);

This operation is used to notify the device of the change of its FASYNC flag. Asynchronous notification is an advanced topic, described in Chapter 6. This member can be NULL if the driver does not support asynchronous notification.

int (*lock) (struct file *, int, struct file_lock *);

The lock method is used to implement file locking; locking is an essential feature for regular files, but device drivers almost never implement it.

ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);

ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);

These methods implement divergent/convergent read and write operations. Applications occasionally need to do a single read or write operation containing multiple memory areas; these system calls allow them to do so without having to make additional copies of the data. If these function pointers are NULL , read and write methods are called (maybe more than once).

ssize_t (*sendfile)(struct file *, loff_t *, size_t, read_actor_t, void *);

This method implements the read of the sendfile system call, using the least copy to move data from one file descriptor to another. For example, it is used by a web server that needs to send the contents of a file to a network connection. Device drivers often make sendfile NULL.

ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);

sendpage is the other half of sendfile; it is called by the kernel to send data, one page at a time, to the corresponding file. The device driver does not actually implement sendpage.

unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);

The purpose of this method is to find a suitable location in the address space of the process to map to the memory segment on the underlying device. This task is usually performed by memory management code; this method exists in order to enable the driver to force any special devices that may have Alignment request. Most drivers can set this method to NULL. [ 10 ]

int (*check_flags)(int)

This method allows the module to check the flags passed to the fnctl(F_SETFL...) call.

int (*dir_notify)(struct file *, unsigned long);

This method is called when the application uses fcntl to request directory change notification. It is only useful for file systems; the driver does not need to implement dir_notify.

The scull device driver implements only the most important device methods. Its file_operations structure is initialized as follows:

struct file_operations scull_fops = {
 .owner =  THIS_MODULE, 
 .llseek =  scull_llseek, 
 .read =  scull_read, 
 .write =  scull_write, 
 .ioctl =  scull_ioctl, 
 .open =  scull_open, 
 .release =  scull_release,  
};  

Guess you like

Origin blog.csdn.net/qq_45467083/article/details/111473216