Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
What does opening a file actually do on Linux?
When we talk about opening a file in Linux, the process varies depending on the programming language and API being used. However, most high-level languages eventually call either the C library functions or directly invoke the Linux open() system call. This article focuses on what happens at the kernel level when a file is opened in C on a Linux system.
The sys_open() System Call
At the heart of file opening is the sys_open() system call. When you call open() in C, it eventually triggers this kernel function found in fs/open.c:
int sys_open(const char *filename, int flags, int mode) {
char *tmp = getname(filename);
int fd = get_unused_fd();
struct file *f = filp_open(tmp, flags, mode);
fd_install(fd, f);
putname(tmp);
return fd;
}
This function orchestrates several key operations to safely open a file and return a file descriptor to the user space.
Step-by-Step File Opening Process
1. getname() - Copying the Filename
The getname() function copies the filename from user space to kernel space. This is necessary because kernel code cannot directly access user memory. Found in fs/namei.c:
#define __getname() kmem_cache_alloc(names_cachep, SLAB_KERNEL)
#define putname(name) kmem_cache_free(names_cachep, (void *)(name))
char *getname(const char *filename) {
char *tmp = __getname(); /* allocate some memory */
strncpy_from_user(tmp, filename, PATH_MAX + 1);
return tmp;
}
2. get_unused_fd() - Finding a File Descriptor
This function searches for an available slot in the process's file descriptor table and marks it as in use:
int get_unused_fd(void) {
struct files_struct *files = current->files;
int fd = find_next_zero_bit(files->open_fds,
files->max_fdset, files->next_fd);
FD_SET(fd, files->open_fds); /* in use now */
files->next_fd = fd + 1;
return fd;
}
3. filp_open() - Creating the File Structure
This function performs the core work of resolving the filename to an inode and creating a struct file object:
struct file *filp_open(const char *filename, int flags, int mode) {
struct nameidata nd;
open_namei(filename, flags, mode, &nd);
return dentry_open(nd.dentry, nd.mnt, flags);
}
It uses the filesystem to look up the inode corresponding to the filename and creates a file structure containing essential information about the file.
4. fd_install() - Linking Everything Together
The final step stores the file structure in the process's file descriptor table:
void fd_install(unsigned int fd, struct file *file) {
struct files_struct *files = current->files;
files->fd[fd] = file;
}
Memory Management
After successful installation, putname() frees the temporary kernel memory allocated by getname(). The system call then returns the file descriptor, which applications can use with functions like read(), write(), and close().
Conclusion
Opening a file in Linux involves multiple kernel functions working together to safely transition from user space to kernel space, allocate resources, and establish the necessary data structures. The returned file descriptor serves as a handle for all subsequent file operations, maintaining the abstraction between user applications and the underlying filesystem implementation.
