forked from Minki/linux
[PATCH] merge locate_fd() and get_unused_fd()
New primitive: alloc_fd(start, flags). get_unused_fd() and get_unused_fd_flags() become wrappers on top of it. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
a1bc6eb4b4
commit
1027abe882
85
fs/fcntl.c
85
fs/fcntl.c
@ -49,73 +49,6 @@ static int get_close_on_exec(unsigned int fd)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* locate_fd finds a free file descriptor in the open_fds fdset,
|
|
||||||
* expanding the fd arrays if necessary. Must be called with the
|
|
||||||
* file_lock held for write.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int locate_fd(unsigned int orig_start, int cloexec)
|
|
||||||
{
|
|
||||||
struct files_struct *files = current->files;
|
|
||||||
unsigned int newfd;
|
|
||||||
unsigned int start;
|
|
||||||
int error;
|
|
||||||
struct fdtable *fdt;
|
|
||||||
|
|
||||||
spin_lock(&files->file_lock);
|
|
||||||
repeat:
|
|
||||||
fdt = files_fdtable(files);
|
|
||||||
/*
|
|
||||||
* Someone might have closed fd's in the range
|
|
||||||
* orig_start..fdt->next_fd
|
|
||||||
*/
|
|
||||||
start = orig_start;
|
|
||||||
if (start < files->next_fd)
|
|
||||||
start = files->next_fd;
|
|
||||||
|
|
||||||
newfd = start;
|
|
||||||
if (start < fdt->max_fds)
|
|
||||||
newfd = find_next_zero_bit(fdt->open_fds->fds_bits,
|
|
||||||
fdt->max_fds, start);
|
|
||||||
|
|
||||||
error = expand_files(files, newfd);
|
|
||||||
if (error < 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If we needed to expand the fs array we
|
|
||||||
* might have blocked - try again.
|
|
||||||
*/
|
|
||||||
if (error)
|
|
||||||
goto repeat;
|
|
||||||
|
|
||||||
if (start <= files->next_fd)
|
|
||||||
files->next_fd = newfd + 1;
|
|
||||||
|
|
||||||
FD_SET(newfd, fdt->open_fds);
|
|
||||||
if (cloexec)
|
|
||||||
FD_SET(newfd, fdt->close_on_exec);
|
|
||||||
else
|
|
||||||
FD_CLR(newfd, fdt->close_on_exec);
|
|
||||||
error = newfd;
|
|
||||||
|
|
||||||
out:
|
|
||||||
spin_unlock(&files->file_lock);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dupfd(struct file *file, unsigned int start, int cloexec)
|
|
||||||
{
|
|
||||||
int fd = locate_fd(start, cloexec);
|
|
||||||
if (fd >= 0)
|
|
||||||
fd_install(fd, file);
|
|
||||||
else
|
|
||||||
fput(file);
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
asmlinkage long sys_dup3(unsigned int oldfd, unsigned int newfd, int flags)
|
asmlinkage long sys_dup3(unsigned int oldfd, unsigned int newfd, int flags)
|
||||||
{
|
{
|
||||||
int err = -EBADF;
|
int err = -EBADF;
|
||||||
@ -194,10 +127,15 @@ asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd)
|
|||||||
asmlinkage long sys_dup(unsigned int fildes)
|
asmlinkage long sys_dup(unsigned int fildes)
|
||||||
{
|
{
|
||||||
int ret = -EBADF;
|
int ret = -EBADF;
|
||||||
struct file * file = fget(fildes);
|
struct file *file = fget(fildes);
|
||||||
|
|
||||||
if (file)
|
if (file) {
|
||||||
ret = dupfd(file, 0, 0);
|
ret = get_unused_fd();
|
||||||
|
if (ret >= 0)
|
||||||
|
fd_install(ret, file);
|
||||||
|
else
|
||||||
|
fput(file);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,8 +260,11 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
|
|||||||
case F_DUPFD_CLOEXEC:
|
case F_DUPFD_CLOEXEC:
|
||||||
if (arg >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
|
if (arg >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
|
||||||
break;
|
break;
|
||||||
get_file(filp);
|
err = alloc_fd(arg, cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0);
|
||||||
err = dupfd(filp, arg, cmd == F_DUPFD_CLOEXEC);
|
if (err >= 0) {
|
||||||
|
get_file(filp);
|
||||||
|
fd_install(err, filp);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case F_GETFD:
|
case F_GETFD:
|
||||||
err = get_close_on_exec(fd) ? FD_CLOEXEC : 0;
|
err = get_close_on_exec(fd) ? FD_CLOEXEC : 0;
|
||||||
|
61
fs/file.c
61
fs/file.c
@ -6,6 +6,7 @@
|
|||||||
* Manage the dynamic fd arrays in the process files_struct.
|
* Manage the dynamic fd arrays in the process files_struct.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/time.h>
|
#include <linux/time.h>
|
||||||
@ -432,3 +433,63 @@ struct files_struct init_files = {
|
|||||||
},
|
},
|
||||||
.file_lock = __SPIN_LOCK_UNLOCKED(init_task.file_lock),
|
.file_lock = __SPIN_LOCK_UNLOCKED(init_task.file_lock),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* allocate a file descriptor, mark it busy.
|
||||||
|
*/
|
||||||
|
int alloc_fd(unsigned start, unsigned flags)
|
||||||
|
{
|
||||||
|
struct files_struct *files = current->files;
|
||||||
|
unsigned int fd;
|
||||||
|
int error;
|
||||||
|
struct fdtable *fdt;
|
||||||
|
|
||||||
|
spin_lock(&files->file_lock);
|
||||||
|
repeat:
|
||||||
|
fdt = files_fdtable(files);
|
||||||
|
fd = start;
|
||||||
|
if (fd < files->next_fd)
|
||||||
|
fd = files->next_fd;
|
||||||
|
|
||||||
|
if (fd < fdt->max_fds)
|
||||||
|
fd = find_next_zero_bit(fdt->open_fds->fds_bits,
|
||||||
|
fdt->max_fds, fd);
|
||||||
|
|
||||||
|
error = expand_files(files, fd);
|
||||||
|
if (error < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we needed to expand the fs array we
|
||||||
|
* might have blocked - try again.
|
||||||
|
*/
|
||||||
|
if (error)
|
||||||
|
goto repeat;
|
||||||
|
|
||||||
|
if (start <= files->next_fd)
|
||||||
|
files->next_fd = fd + 1;
|
||||||
|
|
||||||
|
FD_SET(fd, fdt->open_fds);
|
||||||
|
if (flags & O_CLOEXEC)
|
||||||
|
FD_SET(fd, fdt->close_on_exec);
|
||||||
|
else
|
||||||
|
FD_CLR(fd, fdt->close_on_exec);
|
||||||
|
error = fd;
|
||||||
|
#if 1
|
||||||
|
/* Sanity check */
|
||||||
|
if (rcu_dereference(fdt->fd[fd]) != NULL) {
|
||||||
|
printk(KERN_WARNING "alloc_fd: slot %d not NULL!\n", fd);
|
||||||
|
rcu_assign_pointer(fdt->fd[fd], NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
out:
|
||||||
|
spin_unlock(&files->file_lock);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_unused_fd(void)
|
||||||
|
{
|
||||||
|
return alloc_fd(0, 0);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(get_unused_fd);
|
||||||
|
56
fs/open.c
56
fs/open.c
@ -963,62 +963,6 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dentry_open);
|
EXPORT_SYMBOL(dentry_open);
|
||||||
|
|
||||||
/*
|
|
||||||
* Find an empty file descriptor entry, and mark it busy.
|
|
||||||
*/
|
|
||||||
int get_unused_fd_flags(int flags)
|
|
||||||
{
|
|
||||||
struct files_struct * files = current->files;
|
|
||||||
int fd, error;
|
|
||||||
struct fdtable *fdt;
|
|
||||||
|
|
||||||
spin_lock(&files->file_lock);
|
|
||||||
|
|
||||||
repeat:
|
|
||||||
fdt = files_fdtable(files);
|
|
||||||
fd = find_next_zero_bit(fdt->open_fds->fds_bits, fdt->max_fds,
|
|
||||||
files->next_fd);
|
|
||||||
|
|
||||||
/* Do we need to expand the fd array or fd set? */
|
|
||||||
error = expand_files(files, fd);
|
|
||||||
if (error < 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
/*
|
|
||||||
* If we needed to expand the fs array we
|
|
||||||
* might have blocked - try again.
|
|
||||||
*/
|
|
||||||
goto repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
FD_SET(fd, fdt->open_fds);
|
|
||||||
if (flags & O_CLOEXEC)
|
|
||||||
FD_SET(fd, fdt->close_on_exec);
|
|
||||||
else
|
|
||||||
FD_CLR(fd, fdt->close_on_exec);
|
|
||||||
files->next_fd = fd + 1;
|
|
||||||
#if 1
|
|
||||||
/* Sanity check */
|
|
||||||
if (fdt->fd[fd] != NULL) {
|
|
||||||
printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd);
|
|
||||||
fdt->fd[fd] = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
error = fd;
|
|
||||||
|
|
||||||
out:
|
|
||||||
spin_unlock(&files->file_lock);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
int get_unused_fd(void)
|
|
||||||
{
|
|
||||||
return get_unused_fd_flags(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT_SYMBOL(get_unused_fd);
|
|
||||||
|
|
||||||
static void __put_unused_fd(struct files_struct *files, unsigned int fd)
|
static void __put_unused_fd(struct files_struct *files, unsigned int fd)
|
||||||
{
|
{
|
||||||
struct fdtable *fdt = files_fdtable(files);
|
struct fdtable *fdt = files_fdtable(files);
|
||||||
|
@ -34,8 +34,9 @@ extern struct file *fget(unsigned int fd);
|
|||||||
extern struct file *fget_light(unsigned int fd, int *fput_needed);
|
extern struct file *fget_light(unsigned int fd, int *fput_needed);
|
||||||
extern void set_close_on_exec(unsigned int fd, int flag);
|
extern void set_close_on_exec(unsigned int fd, int flag);
|
||||||
extern void put_filp(struct file *);
|
extern void put_filp(struct file *);
|
||||||
|
extern int alloc_fd(unsigned start, unsigned flags);
|
||||||
extern int get_unused_fd(void);
|
extern int get_unused_fd(void);
|
||||||
extern int get_unused_fd_flags(int flags);
|
#define get_unused_fd_flags(flags) alloc_fd(0, (flags))
|
||||||
extern void put_unused_fd(unsigned int fd);
|
extern void put_unused_fd(unsigned int fd);
|
||||||
|
|
||||||
extern void fd_install(unsigned int fd, struct file *file);
|
extern void fd_install(unsigned int fd, struct file *file);
|
||||||
|
Loading…
Reference in New Issue
Block a user