patch-2.0.2 linux/fs/open.c

Next file: linux/fs/pipe.c
Previous file: linux/fs/fcntl.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.1/linux/fs/open.c linux/fs/open.c
@@ -19,6 +19,7 @@
 #include <linux/mm.h>
 
 #include <asm/segment.h>
+#include <asm/bitops.h>
 
 asmlinkage int sys_statfs(const char * path, struct statfs * buf)
 {
@@ -496,11 +497,11 @@
  * for the internal routines (ie open_namei()/follow_link() etc). 00 is
  * used by symlinks.
  */
-int do_open(const char * filename,int flags,int mode)
+static int do_open(const char * filename,int flags,int mode, int fd)
 {
 	struct inode * inode;
 	struct file * f;
-	int flag,error,fd;
+	int flag,error;
 
 	f = get_empty_filp();
 	if (!f)
@@ -533,21 +534,9 @@
 	}
 	f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
 
-	/*
-	 * We have to do this last, because we mustn't export
-	 * an incomplete fd to other processes which may share
-	 * the same file table with us.
-	 */
-	for(fd = 0; fd < NR_OPEN && fd < current->rlim[RLIMIT_NOFILE].rlim_cur; fd++) {
-		if (!current->files->fd[fd]) {
-			current->files->fd[fd] = f;
-			FD_CLR(fd,&current->files->close_on_exec);
-			return fd;
-		}
-	}
-	error = -EMFILE;
-	if (f->f_op && f->f_op->release)
-		f->f_op->release(inode,f);
+	current->files->fd[fd] = f;
+	return 0;
+
 cleanup_all:
 	if (f->f_mode & FMODE_WRITE)
 		put_write_access(inode);
@@ -558,16 +547,44 @@
 	return error;
 }
 
+/*
+ * Find a empty file descriptor entry, and mark it busy
+ */
+int get_unused_fd(void)
+{
+	int fd;
+	struct files_struct * files = current->files;
+
+	fd = find_first_zero_bit(&files->open_fds, NR_OPEN);
+	if (fd < current->rlim[RLIMIT_NOFILE].rlim_cur) {
+		FD_SET(fd, &files->open_fds);
+		FD_CLR(fd, &files->close_on_exec);
+		return fd;
+	}
+	return -EMFILE;
+}
+
+inline void put_unused_fd(int fd)
+{
+	FD_CLR(fd, &current->files->open_fds);
+}
+
 asmlinkage int sys_open(const char * filename,int flags,int mode)
 {
 	char * tmp;
-	int error;
+	int fd, error;
 
+	fd = get_unused_fd();
+	if (fd < 0)
+		return fd;
 	error = getname(filename, &tmp);
-	if (error)
-		return error;
-	error = do_open(tmp,flags,mode);
-	putname(tmp);
+	if (!error) {
+		error = do_open(tmp,flags,mode, fd);
+		putname(tmp);
+		if (!error)
+			return fd;
+	}
+	put_unused_fd(fd);
 	return error;
 }
 
@@ -610,16 +627,20 @@
 }
 
 asmlinkage int sys_close(unsigned int fd)
-{	
+{
+	int error;
 	struct file * filp;
+	struct files_struct * files;
 
-	if (fd >= NR_OPEN)
-		return -EBADF;
-	FD_CLR(fd, &current->files->close_on_exec);
-	if (!(filp = current->files->fd[fd]))
-		return -EBADF;
-	current->files->fd[fd] = NULL;
-	return (close_fp (filp));
+	files = current->files;
+	error = -EBADF;
+	if (fd < NR_OPEN && (filp = files->fd[fd]) != NULL) {
+		put_unused_fd(fd);
+		FD_CLR(fd, &files->close_on_exec);
+		files->fd[fd] = NULL;
+		error = close_fp(filp);
+	}
+	return error;
 }
 
 /*

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov