aboutsummaryrefslogtreecommitdiffstats
path: root/fs/file_table.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2011-03-13 03:51:11 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2011-03-15 02:21:45 -0400
commit1abf0c718f15a56a0a435588d1b104c7a37dc9bd (patch)
tree91a6fae3218686b9a945569a7fa7fad120f64e94 /fs/file_table.c
parentf2fa2ffc2046fdc35f96366d1ec8675f4d578522 (diff)
New kind of open files - "location only".
New flag for open(2) - O_PATH. Semantics: * pathname is resolved, but the file itself is _NOT_ opened as far as filesystem is concerned. * almost all operations on the resulting descriptors shall fail with -EBADF. Exceptions are: 1) operations on descriptors themselves (i.e. close(), dup(), dup2(), dup3(), fcntl(fd, F_DUPFD), fcntl(fd, F_DUPFD_CLOEXEC, ...), fcntl(fd, F_GETFD), fcntl(fd, F_SETFD, ...)) 2) fcntl(fd, F_GETFL), for a common non-destructive way to check if descriptor is open 3) "dfd" arguments of ...at(2) syscalls, i.e. the starting points of pathname resolution * closing such descriptor does *NOT* affect dnotify or posix locks. * permissions are checked as usual along the way to file; no permission checks are applied to the file itself. Of course, giving such thing to syscall will result in permission checks (at the moment it means checking that starting point of ....at() is a directory and caller has exec permissions on it). fget() and fget_light() return NULL on such descriptors; use of fget_raw() and fget_raw_light() is needed to get them. That protects existing code from dealing with those things. There are two things still missing (they come in the next commits): one is handling of symlinks (right now we refuse to open them that way; see the next commit for semantics related to those) and another is descriptor passing via SCM_RIGHTS datagrams. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/file_table.c')
-rw-r--r--fs/file_table.c53
1 files changed, 48 insertions, 5 deletions
diff --git a/fs/file_table.c b/fs/file_table.c
index eb36b6b17e26..3c16e1ca163e 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -276,11 +276,10 @@ struct file *fget(unsigned int fd)
276 rcu_read_lock(); 276 rcu_read_lock();
277 file = fcheck_files(files, fd); 277 file = fcheck_files(files, fd);
278 if (file) { 278 if (file) {
279 if (!atomic_long_inc_not_zero(&file->f_count)) { 279 /* File object ref couldn't be taken */
280 /* File object ref couldn't be taken */ 280 if (file->f_mode & FMODE_PATH ||
281 rcu_read_unlock(); 281 !atomic_long_inc_not_zero(&file->f_count))
282 return NULL; 282 file = NULL;
283 }
284 } 283 }
285 rcu_read_unlock(); 284 rcu_read_unlock();
286 285
@@ -289,6 +288,23 @@ struct file *fget(unsigned int fd)
289 288
290EXPORT_SYMBOL(fget); 289EXPORT_SYMBOL(fget);
291 290
291struct file *fget_raw(unsigned int fd)
292{
293 struct file *file;
294 struct files_struct *files = current->files;
295
296 rcu_read_lock();
297 file = fcheck_files(files, fd);
298 if (file) {
299 /* File object ref couldn't be taken */
300 if (!atomic_long_inc_not_zero(&file->f_count))
301 file = NULL;
302 }
303 rcu_read_unlock();
304
305 return file;
306}
307
292/* 308/*
293 * Lightweight file lookup - no refcnt increment if fd table isn't shared. 309 * Lightweight file lookup - no refcnt increment if fd table isn't shared.
294 * 310 *
@@ -313,6 +329,33 @@ struct file *fget_light(unsigned int fd, int *fput_needed)
313 *fput_needed = 0; 329 *fput_needed = 0;
314 if (atomic_read(&files->count) == 1) { 330 if (atomic_read(&files->count) == 1) {
315 file = fcheck_files(files, fd); 331 file = fcheck_files(files, fd);
332 if (file && (file->f_mode & FMODE_PATH))
333 file = NULL;
334 } else {
335 rcu_read_lock();
336 file = fcheck_files(files, fd);
337 if (file) {
338 if (!(file->f_mode & FMODE_PATH) &&
339 atomic_long_inc_not_zero(&file->f_count))
340 *fput_needed = 1;
341 else
342 /* Didn't get the reference, someone's freed */
343 file = NULL;
344 }
345 rcu_read_unlock();
346 }
347
348 return file;
349}
350
351struct file *fget_raw_light(unsigned int fd, int *fput_needed)
352{
353 struct file *file;
354 struct files_struct *files = current->files;
355
356 *fput_needed = 0;
357 if (atomic_read(&files->count) == 1) {
358 file = fcheck_files(files, fd);
316 } else { 359 } else {
317 rcu_read_lock(); 360 rcu_read_lock();
318 file = fcheck_files(files, fd); 361 file = fcheck_files(files, fd);