Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1027abe8 authored by Al Viro's avatar Al Viro
Browse files

[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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent a1bc6eb4
Loading
Loading
Loading
Loading
+14 −73
Original line number Diff line number Diff line
@@ -49,73 +49,6 @@ static int get_close_on_exec(unsigned int fd)
	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)
{
	int err = -EBADF;
@@ -196,8 +129,13 @@ asmlinkage long sys_dup(unsigned int fildes)
	int ret = -EBADF;
	struct file *file = fget(fildes);

	if (file)
		ret = dupfd(file, 0, 0);
	if (file) {
		ret = get_unused_fd();
		if (ret >= 0)
			fd_install(ret, file);
		else
			fput(file);
	}
	return ret;
}

@@ -322,8 +260,11 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
	case F_DUPFD_CLOEXEC:
		if (arg >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
			break;
		err = alloc_fd(arg, cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0);
		if (err >= 0) {
			get_file(filp);
		err = dupfd(filp, arg, cmd == F_DUPFD_CLOEXEC);
			fd_install(err, filp);
		}
		break;
	case F_GETFD:
		err = get_close_on_exec(fd) ? FD_CLOEXEC : 0;
+61 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
 *  Manage the dynamic fd arrays in the process files_struct.
 */

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/time.h>
@@ -432,3 +433,63 @@ struct files_struct init_files = {
	},
	.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);
+0 −56
Original line number Diff line number Diff line
@@ -963,62 +963,6 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
}
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)
{
	struct fdtable *fdt = files_fdtable(files);
+2 −1
Original line number Diff line number Diff line
@@ -34,8 +34,9 @@ extern struct file *fget(unsigned int fd);
extern struct file *fget_light(unsigned int fd, int *fput_needed);
extern void set_close_on_exec(unsigned int fd, int flag);
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_flags(int flags);
#define get_unused_fd_flags(flags) alloc_fd(0, (flags))
extern void put_unused_fd(unsigned int fd);

extern void fd_install(unsigned int fd, struct file *file);