diff options
author | Dipankar Sarma <dipankar@in.ibm.com> | 2005-09-09 16:04:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-09 16:57:55 -0400 |
commit | ab2af1f5005069321c5d130f09cce577b03f43ef (patch) | |
tree | 73a70ba486f522cd9eeeef376ede2b5a1c1b473b /fs/fcntl.c | |
parent | 6e72ad2c581de121cc7e772469e2a8f6b1fd4379 (diff) |
[PATCH] files: files struct with RCU
Patch to eliminate struct files_struct.file_lock spinlock on the reader side
and use rcu refcounting rcuref_xxx api for the f_count refcounter. The
updates to the fdtable are done by allocating a new fdtable structure and
setting files->fdt to point to the new structure. The fdtable structure is
protected by RCU thereby allowing lock-free lookup. For fd arrays/sets that
are vmalloced, we use keventd to free them since RCU callbacks can't sleep. A
global list of fdtable to be freed is not scalable, so we use a per-cpu list.
If keventd is already handling the current cpu's work, we use a timer to defer
queueing of that work.
Since the last publication, this patch has been re-written to avoid using
explicit memory barriers and use rcu_assign_pointer(), rcu_dereference()
premitives instead. This required that the fd information is kept in a
separate structure (fdtable) and updated atomically.
Signed-off-by: Dipankar Sarma <dipankar@in.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/fcntl.c')
-rw-r--r-- | fs/fcntl.c | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/fs/fcntl.c b/fs/fcntl.c index bfecc6238083..d2f3ed8acd93 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/security.h> | 16 | #include <linux/security.h> |
17 | #include <linux/ptrace.h> | 17 | #include <linux/ptrace.h> |
18 | #include <linux/signal.h> | 18 | #include <linux/signal.h> |
19 | #include <linux/rcupdate.h> | ||
19 | 20 | ||
20 | #include <asm/poll.h> | 21 | #include <asm/poll.h> |
21 | #include <asm/siginfo.h> | 22 | #include <asm/siginfo.h> |
@@ -64,8 +65,8 @@ static int locate_fd(struct files_struct *files, | |||
64 | if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) | 65 | if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) |
65 | goto out; | 66 | goto out; |
66 | 67 | ||
67 | fdt = files_fdtable(files); | ||
68 | repeat: | 68 | repeat: |
69 | fdt = files_fdtable(files); | ||
69 | /* | 70 | /* |
70 | * Someone might have closed fd's in the range | 71 | * Someone might have closed fd's in the range |
71 | * orig_start..fdt->next_fd | 72 | * orig_start..fdt->next_fd |
@@ -95,9 +96,15 @@ repeat: | |||
95 | if (error) | 96 | if (error) |
96 | goto repeat; | 97 | goto repeat; |
97 | 98 | ||
99 | /* | ||
100 | * We reacquired files_lock, so we are safe as long as | ||
101 | * we reacquire the fdtable pointer and use it while holding | ||
102 | * the lock, no one can free it during that time. | ||
103 | */ | ||
104 | fdt = files_fdtable(files); | ||
98 | if (start <= fdt->next_fd) | 105 | if (start <= fdt->next_fd) |
99 | fdt->next_fd = newfd + 1; | 106 | fdt->next_fd = newfd + 1; |
100 | 107 | ||
101 | error = newfd; | 108 | error = newfd; |
102 | 109 | ||
103 | out: | 110 | out: |
@@ -163,7 +170,7 @@ asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) | |||
163 | if (!tofree && FD_ISSET(newfd, fdt->open_fds)) | 170 | if (!tofree && FD_ISSET(newfd, fdt->open_fds)) |
164 | goto out_fput; | 171 | goto out_fput; |
165 | 172 | ||
166 | fdt->fd[newfd] = file; | 173 | rcu_assign_pointer(fdt->fd[newfd], file); |
167 | FD_SET(newfd, fdt->open_fds); | 174 | FD_SET(newfd, fdt->open_fds); |
168 | FD_CLR(newfd, fdt->close_on_exec); | 175 | FD_CLR(newfd, fdt->close_on_exec); |
169 | spin_unlock(&files->file_lock); | 176 | spin_unlock(&files->file_lock); |