diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-04-05 11:23:36 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-04-05 11:23:36 +0000 |
commit | 4318fbda2a7ee51caafdc4eb1f8028a3f0605142 (patch) | |
tree | cddb50a81d7d1a628cc400519162080c6d87868e /fs | |
parent | 36ea5120664550fae6d31f1c6f695e4f8975cb06 (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.c | 71 | ||||
-rw-r--r-- | fs/buffer.c | 23 | ||||
-rw-r--r-- | fs/exec.c | 11 | ||||
-rw-r--r-- | fs/ext2/truncate.c | 9 | ||||
-rw-r--r-- | fs/minix/truncate.c | 15 | ||||
-rw-r--r-- | fs/pipe.c | 8 | ||||
-rw-r--r-- | fs/proc/array.c | 5 | ||||
-rw-r--r-- | fs/proc/fd.c | 105 | ||||
-rw-r--r-- | fs/proc/inode.c | 47 | ||||
-rw-r--r-- | fs/proc/link.c | 54 | ||||
-rw-r--r-- | fs/select.c | 63 |
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), @@ -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; } @@ -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); |