Linux kernel struct file

File management in the Linux kernel¶

This document describes how locking for files (struct file) and file descriptor table (struct files) works.

Up until 2.6.12, the file descriptor table has been protected with a lock (files->file_lock) and reference count (files->count). ->file_lock protected accesses to all the file related fields of the table. ->count was used for sharing the file descriptor table between tasks cloned with CLONE_FILES flag. Typically this would be the case for posix threads. As with the common refcounting model in the kernel, the last task doing a put_files_struct() frees the file descriptor (fd) table. The files (struct file) themselves are protected using reference count (->f_count).

In the new lock-free model of file descriptor management, the reference counting is similar, but the locking is based on RCU. The file descriptor table contains multiple elements — the fd sets (open_fds and close_on_exec, the array of file pointers, the sizes of the sets and the array etc.). In order for the updates to appear atomic to a lock-free reader, all the elements of the file descriptor table are in a separate structure — struct fdtable. files_struct contains a pointer to struct fdtable through which the actual fd table is accessed. Initially the fdtable is embedded in files_struct itself. On a subsequent expansion of fdtable, a new fdtable structure is allocated and files->fdtab points to the new structure. The fdtable structure is freed with RCU and lock-free readers either see the old fdtable or the new fdtable making the update appear atomic. Here are the locking rules for the fdtable structure —

    All references to the fdtable must be done through the files_fdtable() macro:

struct fdtable *fdt; rcu_read_lock(); fdt = files_fdtable(files); . if (n max_fds) . . rcu_read_unlock();
struct file *file; rcu_read_lock(); file = lookup_fd_rcu(fd); if (file) < . >. rcu_read_unlock();
rcu_read_lock(); file = files_lookup_fd_rcu(files, fd); if (file) < if (atomic_long_inc_not_zero(&file->f_count)) *fput_needed = 1; else /* Didn't get the reference, someone's freed */ file = NULL; > rcu_read_unlock(); . return file;
spin_lock(&files->file_lock); fd = locate_fd(files, file, start); if (fd >= 0) < /* locate_fd() may have expanded fdtable, load the ptr */ fdt = files_fdtable(files); __set_open_fd(fd, fdt); __clear_close_on_exec(fd, fdt); spin_unlock(&files->file_lock); .

Источник

Читайте также:  Switch to gui linux

Linux Device Drivers, Second Edition by

Get full access to Linux Device Drivers, Second Edition and 60K+ other titles, with a free 10-day trial of O’Reilly.

There are also live events, courses curated by job role, and more.

The file Structure

struct file , defined in , is the second most important data structure used in device drivers. Note that a file has nothing to do with the FILE s of user-space programs. A FILE is defined in the C library and never appears in kernel code. A struct file , on the other hand, is a kernel structure that never appears in user programs.

The file structure represents an open file . (It is not specific to device drivers; every open file in the system has an associated struct file in kernel space.) It is created by the kernel on open and is passed to any function that operates on the file, until the last close . After all instances of the file are closed, the kernel releases the data structure. An open file is different from a disk file, represented by struct inode .

In the kernel sources, a pointer to struct file is usually called either file or filp (“file pointer”). We’ll consistently call the pointer filp to prevent ambiguities with the structure itself. Thus, file refers to the structure and filp to a pointer to the structure.

The most important fields of struct file are shown here. As in the previous section, the list can be skipped on a first reading. In the next section though, when we face some real C code, we’ll discuss some of the fields, so they are here for you to refer to.

Читайте также:  Форматирование загрузочной флешки linux

The file mode identifies the file as either readable or writable (or both), by means of the bits FMODE_READ and FMODE_WRITE . You might want to check this field for read/write permission in your ioctl function, but you don’t need to check permissions for read and write because the kernel checks before invoking your method. An attempt to write without permission, for example, is rejected without the driver even knowing about it.

The current reading or writing position. loff_t is a 64-bit value ( long long in gcc terminology). The driver can read this value if it needs to know the current position in the file, but should never change it ( read and write should update a position using the pointer they receive as the last argument instead of acting on filp->f_pos directly).

These are the file flags, such as O_RDONLY , O_NONBLOCK , and O_SYNC . A driver needs to check the flag for nonblocking operation, while the other flags are seldom used. In particular, read/write permission should be checked using f_mode instead of f_flags . All the flags are defined in the header .

struct file_operations *f_op;

The operations associated with the file. The kernel assigns the pointer as part of its implementation of open , and then reads it when it needs to dispatch any operations. The value in filp->f_op is never saved for later reference; this means that you can change the file operations associated with your file whenever you want, and the new methods will be effective immediately after you return to the caller. For example, the code for open associated with major number 1 ( /dev/null , /dev/zero , and so on) substitutes the operations in filp->f_op depending on the minor number being opened. This practice allows the implementation of several behaviors under the same major number without introducing overhead at each system call. The ability to replace the file operations is the kernel equivalent of “method overriding” in object-oriented programming.

Читайте также:  Linux установить сертификат сервера

The open system call sets this pointer to NULL before calling the open method for the driver. The driver is free to make its own use of the field or to ignore it. The driver can use the field to point to allocated data, but then must free memory in the release method before the file structure is destroyed by the kernel. private_data is a useful resource for preserving state information across system calls and is used by most of our sample modules.

The directory entry (dentry) structure associated with the file. Dentries are an optimization introduced in the 2.1 development series. Device driver writers normally need not concern themselves with dentry structures, other than to access the inode structure as filp->f_dentry->d_inode .

The real structure has a few more fields, but they aren’t useful to device drivers. We can safely ignore those fields because drivers never fill file structures; they only access structures created elsewhere.

Get Linux Device Drivers, Second Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.

Источник

Оцените статью
Adblock
detector