Linux Audio

Check our new training course

Loading...
  1.. SPDX-License-Identifier: GPL-2.0
  2
  3===================================
  4File management in the Linux kernel
  5===================================
  6
  7This document describes how locking for files (struct file)
  8and file descriptor table (struct files) works.
  9
 10Up until 2.6.12, the file descriptor table has been protected
 11with a lock (files->file_lock) and reference count (files->count).
 12->file_lock protected accesses to all the file related fields
 13of the table. ->count was used for sharing the file descriptor
 14table between tasks cloned with CLONE_FILES flag. Typically
 15this would be the case for posix threads. As with the common
 16refcounting model in the kernel, the last task doing
 17a put_files_struct() frees the file descriptor (fd) table.
 18The files (struct file) themselves are protected using
 19reference count (->f_count).
 20
 21In the new lock-free model of file descriptor management,
 22the reference counting is similar, but the locking is
 23based on RCU. The file descriptor table contains multiple
 24elements - the fd sets (open_fds and close_on_exec, the
 25array of file pointers, the sizes of the sets and the array
 26etc.). In order for the updates to appear atomic to
 27a lock-free reader, all the elements of the file descriptor
 28table are in a separate structure - struct fdtable.
 29files_struct contains a pointer to struct fdtable through
 30which the actual fd table is accessed. Initially the
 31fdtable is embedded in files_struct itself. On a subsequent
 32expansion of fdtable, a new fdtable structure is allocated
 33and files->fdtab points to the new structure. The fdtable
 34structure is freed with RCU and lock-free readers either
 35see the old fdtable or the new fdtable making the update
 36appear atomic. Here are the locking rules for
 37the fdtable structure -
 38
 391. All references to the fdtable must be done through
 40   the files_fdtable() macro::
 41
 42	struct fdtable *fdt;
 43
 44	rcu_read_lock();
 45
 46	fdt = files_fdtable(files);
 47	....
 48	if (n <= fdt->max_fds)
 49		....
 50	...
 51	rcu_read_unlock();
 52
 53   files_fdtable() uses rcu_dereference() macro which takes care of
 54   the memory barrier requirements for lock-free dereference.
 55   The fdtable pointer must be read within the read-side
 56   critical section.
 57
 582. Reading of the fdtable as described above must be protected
 59   by rcu_read_lock()/rcu_read_unlock().
 60
 613. For any update to the fd table, files->file_lock must
 62   be held.
 63
 644. To look up the file structure given an fd, a reader
 65   must use either fcheck() or fcheck_files() APIs. These
 66   take care of barrier requirements due to lock-free lookup.
 67
 68   An example::
 69
 70	struct file *file;
 71
 72	rcu_read_lock();
 73	file = fcheck(fd);
 74	if (file) {
 75		...
 76	}
 77	....
 78	rcu_read_unlock();
 79
 805. Handling of the file structures is special. Since the look-up
 81   of the fd (fget()/fget_light()) are lock-free, it is possible
 82   that look-up may race with the last put() operation on the
 83   file structure. This is avoided using atomic_long_inc_not_zero()
 84   on ->f_count::
 85
 86	rcu_read_lock();
 87	file = fcheck_files(files, fd);
 88	if (file) {
 89		if (atomic_long_inc_not_zero(&file->f_count))
 90			*fput_needed = 1;
 91		else
 92		/* Didn't get the reference, someone's freed */
 93			file = NULL;
 94	}
 95	rcu_read_unlock();
 96	....
 97	return file;
 98
 99   atomic_long_inc_not_zero() detects if refcounts is already zero or
100   goes to zero during increment. If it does, we fail
101   fget()/fget_light().
102
1036. Since both fdtable and file structures can be looked up
104   lock-free, they must be installed using rcu_assign_pointer()
105   API. If they are looked up lock-free, rcu_dereference()
106   must be used. However it is advisable to use files_fdtable()
107   and fcheck()/fcheck_files() which take care of these issues.
108
1097. While updating, the fdtable pointer must be looked up while
110   holding files->file_lock. If ->file_lock is dropped, then
111   another thread expand the files thereby creating a new
112   fdtable and making the earlier fdtable pointer stale.
113
114   For example::
115
116	spin_lock(&files->file_lock);
117	fd = locate_fd(files, file, start);
118	if (fd >= 0) {
119		/* locate_fd() may have expanded fdtable, load the ptr */
120		fdt = files_fdtable(files);
121		__set_open_fd(fd, fdt);
122		__clear_close_on_exec(fd, fdt);
123		spin_unlock(&files->file_lock);
124	.....
125
126   Since locate_fd() can drop ->file_lock (and reacquire ->file_lock),
127   the fdtable pointer (fdt) must be loaded after locate_fd().
128