summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-04-05 11:23:36 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-04-05 11:23:36 +0000
commit4318fbda2a7ee51caafdc4eb1f8028a3f0605142 (patch)
treecddb50a81d7d1a628cc400519162080c6d87868e /fs
parent36ea5120664550fae6d31f1c6f695e4f8975cb06 (diff)
o Merge with Linux 2.1.91.
o First round of bugfixes for the SC/MC CPUs. o FPU context switch fixes. o Lazy context switches. o Faster syscalls. o Removed dead code. o Shitloads of other things I forgot ...
Diffstat (limited to 'fs')
-rw-r--r--fs/binfmt_aout.c71
-rw-r--r--fs/buffer.c23
-rw-r--r--fs/exec.c11
-rw-r--r--fs/ext2/truncate.c9
-rw-r--r--fs/minix/truncate.c15
-rw-r--r--fs/pipe.c8
-rw-r--r--fs/proc/array.c5
-rw-r--r--fs/proc/fd.c105
-rw-r--r--fs/proc/inode.c47
-rw-r--r--fs/proc/link.c54
-rw-r--r--fs/select.c63
11 files changed, 228 insertions, 183 deletions
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index 9a4a460e8..be58c11ed 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -6,7 +6,6 @@
#include <linux/module.h>
-#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
@@ -15,6 +14,8 @@
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/file.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
@@ -401,10 +402,10 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
printk(KERN_NOTICE "executable not page aligned\n");
fd = open_dentry(bprm->dentry, O_RDONLY);
-
if (fd < 0)
return fd;
- file = current->files->fd[fd];
+ file = fcheck(fd);
+
if (!file->f_op || !file->f_op->mmap) {
sys_close(fd);
do_mmap(NULL, 0, ex.a_text+ex.a_data,
@@ -479,48 +480,44 @@ static inline int
do_load_aout_library(int fd)
{
struct file * file;
- struct exec ex;
- struct dentry * dentry;
struct inode * inode;
- unsigned int len;
- unsigned int bss;
- unsigned int start_addr;
+ unsigned long bss, start_addr, len;
unsigned long error;
+ int retval;
+ loff_t offset = 0;
+ struct exec ex;
- file = current->files->fd[fd];
-
- if (!file || !file->f_op)
- return -EACCES;
-
- dentry = file->f_dentry;
- inode = dentry->d_inode;
-
- /* Seek into the file */
- if (file->f_op->llseek) {
- if ((error = file->f_op->llseek(file, 0, 0)) != 0)
- return -ENOEXEC;
- } else
- file->f_pos = 0;
+ retval = -EACCES;
+ file = fget(fd);
+ if (!file)
+ goto out;
+ if (!file->f_op)
+ goto out_putf;
+ inode = file->f_dentry->d_inode;
+ retval = -ENOEXEC;
+ /* N.B. Save current fs? */
set_fs(KERNEL_DS);
- error = file->f_op->read(file, (char *) &ex, sizeof(ex), &file->f_pos);
+ error = file->f_op->read(file, (char *) &ex, sizeof(ex), &offset);
set_fs(USER_DS);
if (error != sizeof(ex))
- return -ENOEXEC;
+ goto out_putf;
/* We come in here for the regular a.out style of shared libraries */
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) ||
N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
- return -ENOEXEC;
+ goto out_putf;
}
+
if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) &&
(N_TXTOFF(ex) < inode->i_sb->s_blocksize)) {
printk("N_TXTOFF < BLOCK_SIZE. Please convert library\n");
- return -ENOEXEC;
+ goto out_putf;
}
- if (N_FLAGS(ex)) return -ENOEXEC;
+ if (N_FLAGS(ex))
+ goto out_putf;
/* For QMAGIC, the starting address is 0x20 into the page. We mask
this off to get the starting address for the page */
@@ -532,18 +529,26 @@ do_load_aout_library(int fd)
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
N_TXTOFF(ex));
+ retval = error;
if (error != start_addr)
- return error;
+ goto out_putf;
+
len = PAGE_ALIGN(ex.a_text + ex.a_data);
bss = ex.a_text + ex.a_data + ex.a_bss;
if (bss > len) {
- error = do_mmap(NULL, start_addr + len, bss-len,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_PRIVATE|MAP_FIXED, 0);
+ error = do_mmap(NULL, start_addr + len, bss - len,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_FIXED, 0);
+ retval = error;
if (error != start_addr + len)
- return error;
+ goto out_putf;
}
- return 0;
+ retval = 0;
+
+out_putf:
+ fput(file);
+out:
+ return retval;
}
static int
diff --git a/fs/buffer.c b/fs/buffer.c
index ec844de9f..1d58146ae 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -55,12 +55,9 @@ static char buffersize_index[17] =
number of unused buffer heads */
/*
- * How large a hash table do we need?
+ * Hash table mask..
*/
-#define HASH_PAGES_ORDER 4
-#define HASH_PAGES (1UL << HASH_PAGES_ORDER)
-#define NR_HASH (HASH_PAGES*PAGE_SIZE/sizeof(struct buffer_head *))
-#define HASH_MASK (NR_HASH-1)
+static unsigned long bh_hash_mask = 0;
static int grow_buffers(int pri, int size);
@@ -421,7 +418,7 @@ void invalidate_buffers(kdev_t dev)
}
}
-#define _hashfn(dev,block) (((unsigned)(HASHDEV(dev)^block))&HASH_MASK)
+#define _hashfn(dev,block) (((unsigned)(HASHDEV(dev)^block)) & bh_hash_mask)
#define hash(dev,block) hash_table[_hashfn(dev,block)]
static inline void remove_from_hash_queue(struct buffer_head * bh)
@@ -732,7 +729,7 @@ static void refill_freelist(int size)
needed = bdf_prm.b_un.nrefill * size;
while ((nr_free_pages > freepages.min*2) &&
- BUFFER_MEM < (buffer_mem.max_percent * num_physpages / 100) &&
+ (buffermem >> PAGE_SHIFT) * 100 < (buffer_mem.max_percent * num_physpages) &&
grow_buffers(GFP_BUFFER, size)) {
obtained += PAGE_SIZE;
if (obtained >= needed)
@@ -817,7 +814,6 @@ repeat:
*/
while (obtained < (needed >> 1) &&
nr_free_pages > freepages.min + 5 &&
- BUFFER_MEM < (buffer_mem.max_percent * num_physpages / 100) &&
grow_buffers(GFP_BUFFER, size))
obtained += PAGE_SIZE;
@@ -1707,11 +1703,16 @@ void show_buffers(void)
*/
void buffer_init(void)
{
- hash_table = (struct buffer_head **)
- __get_free_pages(GFP_ATOMIC, HASH_PAGES_ORDER);
+ int order = 5; /* Currently maximum order.. */
+ unsigned int nr_hash;
+
+ nr_hash = (1UL << order) * PAGE_SIZE / sizeof(struct buffer_head *);
+ hash_table = (struct buffer_head **) __get_free_pages(GFP_ATOMIC, order);
+
if (!hash_table)
panic("Failed to allocate buffer hash table\n");
- memset(hash_table,0,NR_HASH*sizeof(struct buffer_head *));
+ memset(hash_table, 0, nr_hash * sizeof(struct buffer_head *));
+ bh_hash_mask = nr_hash-1;
bh_cachep = kmem_cache_create("buffer_head",
sizeof(struct buffer_head),
diff --git a/fs/exec.c b/fs/exec.c
index c3d420973..f67c028ff 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -142,10 +142,9 @@ int unregister_binfmt(struct linux_binfmt * fmt)
/* N.B. Error returns must be < 0 */
int open_dentry(struct dentry * dentry, int mode)
{
- int fd;
struct inode * inode = dentry->d_inode;
struct file * f;
- int error;
+ int fd, error;
error = -EINVAL;
if (!inode->i_op || !inode->i_op->default_file_ops)
@@ -167,7 +166,7 @@ int open_dentry(struct dentry * dentry, int mode)
if (error)
goto out_filp;
}
- current->files->fd[fd] = f;
+ fd_install(fd, f);
dget(dentry);
}
return fd;
@@ -199,18 +198,20 @@ asmlinkage int sys_uselib(const char * library)
retval = fd;
if (fd < 0)
goto out;
- file = current->files->fd[fd];
+ file = fget(fd);
retval = -ENOEXEC;
if (file && file->f_dentry && file->f_op && file->f_op->read) {
for (fmt = formats ; fmt ; fmt = fmt->next) {
int (*fn)(int) = fmt->load_shlib;
if (!fn)
continue;
+ /* N.B. Should use file instead of fd */
retval = fn(fd);
if (retval != -ENOEXEC)
break;
}
}
+ fput(file);
sys_close(fd);
out:
unlock_kernel();
@@ -495,7 +496,7 @@ static inline void flush_old_files(struct files_struct * files)
unsigned long set, i;
i = j * __NFDBITS;
- if (i >= NR_OPEN)
+ if (i >= files->max_fds)
break;
set = files->close_on_exec.fds_bits[j];
files->close_on_exec.fds_bits[j] = 0;
diff --git a/fs/ext2/truncate.c b/fs/ext2/truncate.c
index 3b168cd75..442518af3 100644
--- a/fs/ext2/truncate.c
+++ b/fs/ext2/truncate.c
@@ -181,7 +181,7 @@ repeat:
for (i = 0; i < addr_per_block; i++)
if (le32_to_cpu(*(ind++)))
break;
- if (i >= addr_per_block)
+ if (i >= addr_per_block) {
if (ind_bh->b_count != 1)
retry = 1;
else {
@@ -193,6 +193,7 @@ repeat:
bforget(ind_bh);
ind_bh = NULL;
}
+ }
if (IS_SYNC(inode) && ind_bh && buffer_dirty(ind_bh)) {
ll_rw_block (WRITE, 1, &ind_bh);
wait_on_buffer (ind_bh);
@@ -243,7 +244,7 @@ repeat:
for (i = 0; i < addr_per_block; i++)
if (le32_to_cpu(*(dind++)))
break;
- if (i >= addr_per_block)
+ if (i >= addr_per_block) {
if (dind_bh->b_count != 1)
retry = 1;
else {
@@ -255,6 +256,7 @@ repeat:
bforget(dind_bh);
dind_bh = 0;
}
+ }
if (IS_SYNC(inode) && dind_bh && buffer_dirty(dind_bh)) {
ll_rw_block (WRITE, 1, &dind_bh);
wait_on_buffer (dind_bh);
@@ -304,7 +306,7 @@ repeat:
for (i = 0; i < addr_per_block; i++)
if (le32_to_cpu(*(tind++)))
break;
- if (i >= addr_per_block)
+ if (i >= addr_per_block) {
if (tind_bh->b_count != 1)
retry = 1;
else {
@@ -316,6 +318,7 @@ repeat:
bforget(tind_bh);
tind_bh = 0;
}
+ }
if (IS_SYNC(inode) && tind_bh && buffer_dirty(tind_bh)) {
ll_rw_block (WRITE, 1, &tind_bh);
wait_on_buffer (tind_bh);
diff --git a/fs/minix/truncate.c b/fs/minix/truncate.c
index 298d6c155..56b490841 100644
--- a/fs/minix/truncate.c
+++ b/fs/minix/truncate.c
@@ -117,7 +117,7 @@ repeat:
for (i = 0; i < 512; i++)
if (*(ind++))
break;
- if (i >= 512)
+ if (i >= 512) {
if (ind_bh->b_count != 1)
retry = 1;
else {
@@ -125,6 +125,7 @@ repeat:
*p = 0;
minix_free_block(inode->i_sb,tmp);
}
+ }
brelse(ind_bh);
return retry;
}
@@ -161,7 +162,7 @@ repeat:
for (i = 0; i < 512; i++)
if (*(dind++))
break;
- if (i >= 512)
+ if (i >= 512) {
if (dind_bh->b_count != 1)
retry = 1;
else {
@@ -170,6 +171,7 @@ repeat:
mark_inode_dirty(inode);
minix_free_block(inode->i_sb,tmp);
}
+ }
brelse(dind_bh);
return retry;
}
@@ -279,7 +281,7 @@ repeat:
for (i = 0; i < 256; i++)
if (*(ind++))
break;
- if (i >= 256)
+ if (i >= 256) {
if (ind_bh->b_count != 1)
retry = 1;
else {
@@ -287,6 +289,7 @@ repeat:
*p = 0;
minix_free_block(inode->i_sb,tmp);
}
+ }
brelse(ind_bh);
return retry;
}
@@ -323,7 +326,7 @@ repeat:
for (i = 0; i < 256; i++)
if (*(dind++))
break;
- if (i >= 256)
+ if (i >= 256) {
if (dind_bh->b_count != 1)
retry = 1;
else {
@@ -332,6 +335,7 @@ repeat:
mark_inode_dirty(inode);
minix_free_block(inode->i_sb,tmp);
}
+ }
brelse(dind_bh);
return retry;
}
@@ -368,7 +372,7 @@ repeat:
for (i = 0; i < 256; i++)
if (*(tind++))
break;
- if (i >= 256)
+ if (i >= 256) {
if (tind_bh->b_count != 1)
retry = 1;
else {
@@ -377,6 +381,7 @@ repeat:
mark_inode_dirty(inode);
minix_free_block(inode->i_sb,tmp);
}
+ }
brelse(tind_bh);
return retry;
}
diff --git a/fs/pipe.c b/fs/pipe.c
index cb8a84d84..cf0c44b6e 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -46,11 +46,12 @@ static ssize_t pipe_read(struct file * filp, char * buf,
if (filp->f_flags & O_NONBLOCK) {
if (PIPE_LOCK(*inode))
return -EAGAIN;
- if (PIPE_EMPTY(*inode))
+ if (PIPE_EMPTY(*inode)) {
if (PIPE_WRITERS(*inode))
return -EAGAIN;
else
return 0;
+ }
} else while (PIPE_EMPTY(*inode) || PIPE_LOCK(*inode)) {
if (PIPE_EMPTY(*inode)) {
if (!PIPE_WRITERS(*inode))
@@ -485,8 +486,9 @@ int do_pipe(int *fd)
f2->f_flags = O_WRONLY;
f2->f_op = &write_pipe_fops;
f2->f_mode = 2;
- current->files->fd[i] = f1;
- current->files->fd[j] = f2;
+
+ fd_install(i, f1);
+ fd_install(j, f2);
fd[0] = i;
fd[1] = j;
return 0;
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 33df2c56a..26621a6e5 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -597,8 +597,9 @@ static unsigned long get_wchan(struct task_struct *p)
#elif defined(__mips__)
# define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg \
- sizeof(struct pt_regs))
-# define KSTK_EIP(tsk) (*(unsigned long *)((tsk)->tss.ksp + PT_REG(cp0_epc)))
-# define KSTK_ESP(tsk) (*(unsigned long *)((tsk)->tss.ksp + PT_REG(regs[29])))
+#define KSTK_TOS(tsk) ((unsigned long)(tsk) + KERNEL_STACK_SIZE - 32)
+# define KSTK_EIP(tsk) (*(unsigned long *)(KSTK_TOS(tsk) + PT_REG(cp0_epc)))
+# define KSTK_ESP(tsk) (*(unsigned long *)(KSTK_TOS(tsk) + PT_REG(regs[29])))
#endif
/* Gcc optimizes away "strlen(x)" for constant x */
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index 8897578d6..ab9948a62 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -6,13 +6,14 @@
* proc fd directory handling functions
*/
-#include <asm/uaccess.h>
-
#include <linux/errno.h>
#include <linux/sched.h>
+#include <linux/file.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
+#include <asm/uaccess.h>
+
static int proc_readfd(struct file *, void *, filldir_t);
static int proc_lookupfd(struct inode *, struct dentry *);
@@ -65,19 +66,20 @@ static int proc_lookupfd(struct inode * dir, struct dentry * dentry)
{
unsigned int ino, pid, fd, c;
struct task_struct * p;
- struct super_block * sb;
+ struct file * file;
struct inode *inode;
const char *name;
- int len;
+ int len, err;
+ err = -ENOENT;
+ if (!dir)
+ goto out;
ino = dir->i_ino;
pid = ino >> 16;
ino &= 0x0000ffff;
- if (!dir)
- return -ENOENT;
- sb = dir->i_sb;
+
if (!pid || ino != PROC_PID_FD || !S_ISDIR(dir->i_mode))
- return -ENOENT;
+ goto out;
fd = 0;
len = dentry->d_name.len;
@@ -85,22 +87,20 @@ static int proc_lookupfd(struct inode * dir, struct dentry * dentry)
while (len-- > 0) {
c = *name - '0';
name++;
- if (c > 9) {
- fd = 0xfffff;
- break;
- }
+ if (c > 9)
+ goto out;
fd *= 10;
fd += c;
- if (fd & 0xffff0000) {
- fd = 0xfffff;
- break;
- }
+ if (fd & 0xffff0000)
+ goto out;
}
+
read_lock(&tasklist_lock);
+ file = NULL;
p = find_task_by_pid(pid);
- read_unlock(&tasklist_lock); /* FIXME!! This should be done only after not using 'p' any more */
- if (!pid || !p)
- return -ENOENT;
+ if (p)
+ file = fcheck_task(p, fd);
+ read_unlock(&tasklist_lock);
/*
* File handle is invalid if it is out of range, if the process
@@ -108,60 +108,61 @@ static int proc_lookupfd(struct inode * dir, struct dentry * dentry)
* is NULL
*/
- if (fd >= NR_OPEN ||
- !p->files ||
- !p->files->fd[fd] ||
- !p->files->fd[fd]->f_dentry)
- return -ENOENT;
+ if (!file || !file->f_dentry)
+ goto out;
+ /* N.B. What happens if fd > 255?? */
ino = (pid << 16) + (PROC_PID_FD_DIR << 8) + fd;
-
- inode = proc_get_inode(sb, ino, NULL);
- if (!inode)
- return -ENOENT;
-
- d_add(dentry, inode);
- return 0;
+ inode = proc_get_inode(dir->i_sb, ino, NULL);
+ if (inode) {
+ d_add(dentry, inode);
+ err = 0;
+ }
+out:
+ return err;
}
#define NUMBUF 10
-static int proc_readfd(struct file * filp,
- void * dirent, filldir_t filldir)
+static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
{
- char buf[NUMBUF];
+ struct inode *inode = filp->f_dentry->d_inode;
struct task_struct * p, **tarrayp;
unsigned int fd, pid, ino;
- unsigned long i,j;
- struct inode *inode = filp->f_dentry->d_inode;
+ int retval;
+ char buf[NUMBUF];
+ retval = -EBADF;
if (!inode || !S_ISDIR(inode->i_mode))
- return -EBADF;
+ goto out;
+
+ retval = 0;
ino = inode->i_ino;
pid = ino >> 16;
ino &= 0x0000ffff;
if (ino != PROC_PID_FD)
- return 0;
+ goto out;
for (fd = filp->f_pos; fd < 2; fd++, filp->f_pos++) {
unsigned long ino = inode->i_ino;
if (fd)
ino = (ino & 0xffff0000) | PROC_PID_INO;
if (filldir(dirent, "..", fd+1, fd, ino) < 0)
- return 0;
+ goto out;
}
read_lock(&tasklist_lock);
p = find_task_by_pid(pid);
- read_unlock(&tasklist_lock); /* FIXME!! This should be done only after not using 'p' any more */
- if(!p)
- return 0;
+ if (!p)
+ goto out_unlock;
tarrayp = p->tarray_ptr;
- for (fd -= 2 ; fd < NR_OPEN; fd++, filp->f_pos++) {
- if (!p->files)
- break;
- if (!p->files->fd[fd] || !p->files->fd[fd]->f_dentry)
+ for (fd -= 2 ; p->files && fd < p->files->max_fds; fd++, filp->f_pos++)
+ {
+ struct file * file = fcheck_task(p, fd);
+ unsigned int i,j;
+
+ if (!file || !file->f_dentry)
continue;
j = NUMBUF;
@@ -172,13 +173,21 @@ static int proc_readfd(struct file * filp,
i /= 10;
} while (i);
+ /* Drop the task lock, as the filldir function may block */
+ read_unlock(&tasklist_lock);
+
ino = (pid << 16) + (PROC_PID_FD_DIR << 8) + fd;
if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino) < 0)
- break;
+ goto out;
+ read_lock(&tasklist_lock);
/* filldir() might have slept, so we must re-validate "p" */
if (p != *tarrayp || p->pid != pid)
break;
}
- return 0;
+out_unlock:
+ read_unlock(&tasklist_lock);
+
+out:
+ return retval;
}
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 9a0e29a84..16ee84225 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -10,6 +10,7 @@
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
+#include <linux/file.h>
#include <linux/locks.h>
#include <linux/limits.h>
#include <linux/config.h>
@@ -250,24 +251,24 @@ void proc_read_inode(struct inode * inode)
inode->i_blocks = 0;
inode->i_blksize = 1024;
ino = inode->i_ino;
- if (ino >= PROC_OPENPROM_FIRST && ino < PROC_OPENPROM_FIRST + PROC_NOPENPROM)
- return;
+ if (ino >= PROC_OPENPROM_FIRST &&
+ ino < PROC_OPENPROM_FIRST + PROC_NOPENPROM)
+ goto out;
inode->i_op = NULL;
inode->i_mode = 0;
inode->i_uid = 0;
inode->i_gid = 0;
inode->i_nlink = 1;
inode->i_size = 0;
- pid = ino >> 16;
+ pid = ino >> 16;
if (!pid)
- return;
+ goto out;
+
read_lock(&tasklist_lock);
p = find_task_by_pid(pid);
- read_unlock(&tasklist_lock); /* FIXME!! This should be done only after we have stopped using 'p' */
-
if (!p)
- return;
+ goto out_unlock;
ino &= 0x0000ffff;
if (ino == PROC_PID_INO || p->dumpable) {
@@ -275,19 +276,27 @@ void proc_read_inode(struct inode * inode)
inode->i_gid = p->egid;
}
switch (ino >> 8) {
- case PROC_PID_FD_DIR:
- ino &= 0xff;
- if (ino >= NR_OPEN || !p->files->fd[ino])
- return;
- inode->i_op = &proc_link_inode_operations;
- inode->i_size = 64;
- inode->i_mode = S_IFLNK;
- if (p->files->fd[ino]->f_mode & 1)
- inode->i_mode |= S_IRUSR | S_IXUSR;
- if (p->files->fd[ino]->f_mode & 2)
- inode->i_mode |= S_IWUSR | S_IXUSR;
- return;
+ struct file * file;
+ case PROC_PID_FD_DIR:
+ ino &= 0xff;
+ file = fcheck_task(p, ino);
+ if (!file)
+ goto out_unlock;
+
+ inode->i_op = &proc_link_inode_operations;
+ inode->i_size = 64;
+ inode->i_mode = S_IFLNK;
+ if (file->f_mode & 1)
+ inode->i_mode |= S_IRUSR | S_IXUSR;
+ if (file->f_mode & 2)
+ inode->i_mode |= S_IWUSR | S_IXUSR;
}
+out_unlock:
+ /* Defer unlocking until we're done with the task */
+ read_unlock(&tasklist_lock);
+
+out:
+ return;
}
void proc_write_inode(struct inode * inode)
diff --git a/fs/proc/link.c b/fs/proc/link.c
index 66a01e1af..2f4abc945 100644
--- a/fs/proc/link.c
+++ b/fs/proc/link.c
@@ -10,8 +10,9 @@
#include <linux/errno.h>
#include <linux/sched.h>
-#include <linux/fs.h>
#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/file.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
@@ -81,53 +82,58 @@ static struct dentry * proc_follow_link(struct dentry *dentry,
pid = ino >> 16;
ino &= 0x0000ffff;
- p = find_task_by_pid(pid);
result = ERR_PTR(-ENOENT);
+ read_lock(&tasklist_lock);
+ p = find_task_by_pid(pid);
if (!p)
- goto out;
+ goto out_unlock;
switch (ino) {
case PROC_PID_CWD:
if (!p->fs || !p->fs->pwd)
- break;
- result = dget(p->fs->pwd);
- break;
+ goto out_unlock;
+ result = p->fs->pwd;
+ goto out_dget;
case PROC_PID_ROOT:
if (!p->fs || !p->fs->root)
- break;
- result = dget(p->fs->root);
- break;
+ goto out_unlock;
+ result = p->fs->root;
+ goto out_dget;
case PROC_PID_EXE: {
struct vm_area_struct * vma;
if (!p->mm)
- break;
+ goto out_unlock;
vma = p->mm->mmap;
while (vma) {
- if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file)
- return dget(vma->vm_file->f_dentry);
-
+ if ((vma->vm_flags & VM_EXECUTABLE) &&
+ vma->vm_file) {
+ result = vma->vm_file->f_dentry;
+ goto out_dget;
+ }
vma = vma->vm_next;
}
- break;
+ goto out_unlock;
}
default:
switch (ino >> 8) {
+ struct file * file;
case PROC_PID_FD_DIR:
- if (!p->files)
- break;
ino &= 0xff;
- if (ino >= NR_OPEN)
- break;
- if (!p->files->fd[ino])
- break;
- if (!p->files->fd[ino]->f_dentry)
- break;
- result = dget(p->files->fd[ino]->f_dentry);
- break;
+ file = fcheck_task(p, ino);
+ if (!file || !file->f_dentry)
+ goto out_unlock;
+ result = file->f_dentry;
+ goto out_dget;
}
}
+out_dget:
+ result = dget(result);
+
+out_unlock:
+ read_unlock(&tasklist_lock);
+
out:
return result;
}
diff --git a/fs/select.c b/fs/select.c
index 1328660b0..a4e847e64 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -41,7 +41,7 @@
* sleep/wakeup mechanism works.
*
* Two very simple procedures, poll_wait() and free_wait() make all the
- * work. poll_wait() is an inline-function defined in <linux/sched.h>,
+ * work. poll_wait() is an inline-function defined in <linux/poll.h>,
* as all select/poll functions have to call it to add an entry to the
* poll table.
*/
@@ -152,9 +152,8 @@ int do_select(int n, fd_set_buffer *fds, unsigned long timeout)
n = retval;
retval = 0;
for (;;) {
- struct file ** fd = current->files->fd;
current->state = TASK_INTERRUPTIBLE;
- for (i = 0 ; i < n ; i++, fd++) {
+ for (i = 0 ; i < n; i++) {
unsigned long bit = BIT(i);
unsigned long *in = MEM(i,fds->in);
unsigned long mask;
@@ -162,8 +161,12 @@ int do_select(int n, fd_set_buffer *fds, unsigned long timeout)
if (!(bit & BITS(in)))
continue;
-
- file = *fd;
+ /*
+ * The poll_wait routine will increment f_count if
+ * the file is added to the wait table, so we don't
+ * need to increment it now.
+ */
+ file = fcheck(i);
mask = POLLNVAL;
if (file) {
mask = DEFAULT_POLLMASK;
@@ -286,23 +289,21 @@ out_nofds:
static int do_poll(unsigned int nfds, struct pollfd *fds, poll_table *wait)
{
- int count;
- struct file ** fd = current->files->fd;
+ int count = 0;
- count = 0;
for (;;) {
unsigned int j;
struct pollfd * fdpnt;
current->state = TASK_INTERRUPTIBLE;
for (fdpnt = fds, j = 0; j < nfds; j++, fdpnt++) {
- unsigned int i;
unsigned int mask;
struct file * file;
mask = POLLNVAL;
- i = fdpnt->fd;
- if (i < NR_OPEN && (file = fd[i]) != NULL) {
+ /* poll_wait increments f_count if needed */
+ file = fcheck(fdpnt->fd);
+ if (file != NULL) {
mask = DEFAULT_POLLMASK;
if (file->f_op && file->f_op->poll)
mask = file->f_op->poll(file, wait);
@@ -326,18 +327,22 @@ static int do_poll(unsigned int nfds, struct pollfd *fds, poll_table *wait)
asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout)
{
- int i, count, fdcount, err;
+ int i, fdcount, err, size;
struct pollfd * fds, *fds1;
- poll_table wait_table, *wait;
+ poll_table wait_table, *wait = NULL;
lock_kernel();
+ /* Do a sanity check on nfds ... */
+ err = -EINVAL;
+ if (nfds > NR_OPEN)
+ goto out;
+
if (timeout < 0)
timeout = 0x7fffffff;
else if (timeout)
timeout = ((unsigned long)timeout*HZ+999)/1000+jiffies+1;
- err = -ENOMEM;
- wait = NULL;
+ err = -ENOMEM;
if (timeout) {
struct poll_table_entry *entry;
entry = (struct poll_table_entry *) __get_free_page(GFP_KERNEL);
@@ -347,34 +352,32 @@ asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout)
wait_table.entry = entry;
wait = &wait_table;
}
- fds = (struct pollfd *) kmalloc(nfds*sizeof(struct pollfd), GFP_KERNEL);
- if (!fds) {
+
+ size = nfds * sizeof(struct pollfd);
+ fds = (struct pollfd *) kmalloc(size, GFP_KERNEL);
+ if (!fds)
goto out;
- }
err = -EFAULT;
- if (copy_from_user(fds, ufds, nfds*sizeof(struct pollfd))) {
- kfree(fds);
- goto out;
- }
+ if (copy_from_user(fds, ufds, size))
+ goto out_fds;
current->timeout = timeout;
-
- count = 0;
-
fdcount = do_poll(nfds, fds, wait);
current->timeout = 0;
/* OK, now copy the revents fields back to user space. */
fds1 = fds;
- for(i=0; i < (int)nfds; i++, ufds++, fds++) {
- __put_user(fds->revents, &ufds->revents);
+ for(i=0; i < (int)nfds; i++, ufds++, fds1++) {
+ __put_user(fds1->revents, &ufds->revents);
}
- kfree(fds1);
+
+ err = fdcount;
if (!fdcount && signal_pending(current))
err = -EINTR;
- else
- err = fdcount;
+
+out_fds:
+ kfree(fds);
out:
if (wait) {
free_wait(&wait_table);