lkml.org 
[lkml]   [1998]   [Feb]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subjectpatch for 2.1.88 fd file access
The attached patch adds calls to fget() and fput() to protect access to files in
the fd array, and takes care of most of the non-arch specific accesses to the fd
array. These changes will protect the use of a file structure in a clone task in
case another clone closes the file's fd.

Regards,
Bill--- linux-2.1.88/include/linux/file.h.old Sat Feb 21 09:25:02 1998
+++ linux-2.1.88/include/linux/file.h Sat Feb 21 13:38:35 1998
@@ -47,4 +47,12 @@
}
}

+/*
+ * Install a file pointer in the files structure.
+ */
+extern inline void fd_install(unsigned long fd, struct file *file)
+{
+ current->files->fd[fd] = file;
+}
+
#endif
--- linux-2.1.88/include/linux/fs.h.old Sat Feb 21 09:50:12 1998
+++ linux-2.1.88/include/linux/fs.h Sat Feb 21 13:28:33 1998
@@ -638,14 +638,20 @@
extern int register_filesystem(struct file_system_type *);
extern int unregister_filesystem(struct file_system_type *);

+/* fs/open.c */
+
asmlinkage int sys_open(const char *, int, int);
asmlinkage int sys_close(unsigned int); /* yes, it's really unsigned */
-
-extern void kill_fasync(struct fasync_struct *fa, int sig);
+extern int do_truncate(struct dentry *, unsigned long);
+extern int get_unused_fd(void);
+extern void put_unused_fd(unsigned int);
+extern int __fput(struct file *);
+extern int close_fp(struct file *);

extern char * getname(const char * filename);
extern void putname(char * name);
-extern int do_truncate(struct dentry *, unsigned long);
+
+extern void kill_fasync(struct fasync_struct *fa, int sig);
extern int register_blkdev(unsigned int, const char *, struct file_operations *);
extern int unregister_blkdev(unsigned int major, const char * name);
extern int blkdev_open(struct inode * inode, struct file * filp);
@@ -755,32 +761,6 @@
#define namei(pathname) __namei(pathname, 1)
#define lnamei(pathname) __namei(pathname, 0)

-#include <asm/semaphore.h>
-
-/* Intended for short locks of the global data structures in inode.c.
- * Could be replaced with spinlocks completely, since there is
- * no blocking during manipulation of the static data; however the
- * lock in invalidate_inodes() may last relatively long.
- */
-extern struct semaphore vfs_sem;
-extern inline void vfs_lock(void)
-{
-#if 0
-#ifdef __SMP__
- down(&vfs_sem);
-#endif
-#endif
-}
-
-extern inline void vfs_unlock(void)
-{
-#if 0
-#ifdef __SMP__
- up(&vfs_sem);
-#endif
-#endif
-}
-
extern void iput(struct inode *);
extern struct inode * iget(struct super_block *, unsigned long);
extern void clear_inode(struct inode *);
@@ -788,10 +768,7 @@

extern void insert_inode_hash(struct inode *);
extern void remove_inode_hash(struct inode *);
-extern int get_unused_fd(void);
-extern void put_unused_fd(int);
extern struct file * get_empty_filp(void);
-extern int close_fp(struct file *);
extern struct buffer_head * get_hash_table(kdev_t, int, int);
extern struct buffer_head * getblk(kdev_t, int, int);
extern struct buffer_head * find_buffer(kdev_t dev, int block, int size);
--- linux-2.1.88/fs/open.c.old Sat Feb 21 09:25:00 1998
+++ linux-2.1.88/fs/open.c Sat Feb 21 14:03:59 1998
@@ -47,24 +47,31 @@

asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf)
{
+ struct file * file;
struct inode * inode;
struct dentry * dentry;
- struct file * file;
+ struct super_block * sb;
int error;

lock_kernel();
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
- error = -EBADF;
- else if (!(dentry = file->f_dentry))
- error = -ENOENT;
- else if (!(inode = dentry->d_inode))
- error = -ENOENT;
- else if (!inode->i_sb)
- error = -ENODEV;
- else if (!inode->i_sb->s_op->statfs)
- error = -ENOSYS;
- else
- error = inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
+ error = -EBADF;
+ file = fget(fd);
+ if (!file)
+ goto out;
+ error = -ENOENT;
+ if (!(dentry = file->f_dentry))
+ goto out_putf;
+ if (!(inode = dentry->d_inode))
+ goto out_putf;
+ error = -ENODEV;
+ if (!(sb = inode->i_sb))
+ goto out_putf;
+ error = -ENOSYS;
+ if (sb->s_op->statfs)
+ error = sb->s_op->statfs(sb, buf, sizeof(struct statfs));
+out_putf:
+ fput(file);
+out:
unlock_kernel();
return error;
}
@@ -147,23 +154,29 @@
int error;

lock_kernel();
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
- error = -EBADF;
- else if (!(dentry = file->f_dentry))
- error = -ENOENT;
- else if (!(inode = dentry->d_inode))
- error = -ENOENT;
- else if (S_ISDIR(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
- error = -EACCES;
- else if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
- error = -EPERM;
- else {
- error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
- length<inode->i_size ? length : inode->i_size,
- abs(inode->i_size - length));
- if (!error)
- error = do_truncate(dentry, length);
- }
+ error = -EBADF;
+ file = fget(fd);
+ if (!file)
+ goto out;
+ error = -ENOENT;
+ if (!(dentry = file->f_dentry))
+ goto out_putf;
+ if (!(inode = dentry->d_inode))
+ goto out_putf;
+ error = -EACCES;
+ if (S_ISDIR(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
+ goto out_putf;
+ error = -EPERM;
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+ goto out_putf;
+ error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
+ length<inode->i_size ? length : inode->i_size,
+ abs(inode->i_size - length));
+ if (!error)
+ error = do_truncate(dentry, length);
+out_putf:
+ fput(file);
+out:
unlock_kernel();
return error;
}
@@ -347,30 +360,28 @@
lock_kernel();

error = -EBADF;
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ file = fget(fd);
+ if (!file)
goto out;

error = -ENOENT;
if (!(dentry = file->f_dentry))
- goto out;
+ goto out_putf;
if (!(inode = dentry->d_inode))
- goto out;
+ goto out_putf;

error = -ENOTDIR;
if (!S_ISDIR(inode->i_mode))
- goto out;
-
- error = permission(inode,MAY_EXEC);
- if (error)
- goto out;
+ goto out_putf;

- {
- struct dentry *tmp;
-
- tmp = current->fs->pwd;
+ error = permission(inode, MAY_EXEC);
+ if (!error) {
+ struct dentry *tmp = current->fs->pwd;
current->fs->pwd = dget(dentry);
dput(tmp);
}
+out_putf:
+ fput(file);
out:
unlock_kernel();
return error;
@@ -421,28 +432,34 @@
struct inode * inode;
struct dentry * dentry;
struct file * file;
- struct iattr newattrs;
int err = -EBADF;
+ struct iattr newattrs;

lock_kernel();
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ file = fget(fd);
+ if (!file)
goto out;
+
err = -ENOENT;
if (!(dentry = file->f_dentry))
- goto out;
+ goto out_putf;
if (!(inode = dentry->d_inode))
- goto out;
+ goto out_putf;
+
err = -EROFS;
if (IS_RDONLY(inode))
- goto out;
+ goto out_putf;
err = -EPERM;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
- goto out;
+ goto out_putf;
if (mode == (mode_t) -1)
mode = inode->i_mode;
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
err = notify_change(dentry, &newattrs);
+
+out_putf:
+ fput(file);
out:
unlock_kernel();
return err;
@@ -487,8 +504,8 @@
static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
{
struct inode * inode;
- struct iattr newattrs;
int error;
+ struct iattr newattrs;

error = -ENOENT;
if (!(inode = dentry->d_inode)) {
@@ -581,13 +598,13 @@
int error = -EBADF;

lock_kernel();
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ file = fget(fd);
+ if (!file)
goto out;
error = -ENOENT;
- if (!(dentry = file->f_dentry))
- goto out;
-
- error = chown_common(dentry, user, group);
+ if ((dentry = file->f_dentry) != NULL)
+ error = chown_common(dentry, user, group);
+ fput(file);

out:
unlock_kernel();
@@ -608,16 +625,17 @@
* for the internal routines (ie open_namei()/follow_link() etc). 00 is
* used by symlinks.
*/
-static int do_open(const char * filename,int flags,int mode, int fd)
+static int do_open(const char * filename, int flags, int mode, int fd)
{
struct inode * inode;
struct dentry * dentry;
struct file * f;
int flag,error;

+ error = -ENFILE;
f = get_empty_filp();
if (!f)
- return -ENFILE;
+ goto out;
f->f_flags = flag = flags;
f->f_mode = (flag+1) & O_ACCMODE;
if (f->f_mode)
@@ -648,7 +666,7 @@
}
f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);

- current->files->fd[fd] = f;
+ fd_install(fd, f);
return 0;

cleanup_all:
@@ -658,6 +676,7 @@
dput(dentry);
cleanup_file:
put_filp(f);
+out:
return error;
}

@@ -670,6 +689,10 @@
struct files_struct * files = current->files;

fd = find_first_zero_bit(&files->open_fds, NR_OPEN);
+ /*
+ * N.B. For clone tasks sharing a files structure, this test
+ * will limit the total number of files that can be opened.
+ */
if (fd < current->rlim[RLIMIT_NOFILE].rlim_cur) {
FD_SET(fd, &files->open_fds);
FD_CLR(fd, &files->close_on_exec);
@@ -678,36 +701,37 @@
return -EMFILE;
}

-inline void put_unused_fd(int fd)
+inline void put_unused_fd(unsigned int fd)
{
FD_CLR(fd, &current->files->open_fds);
}

-asmlinkage int sys_open(const char * filename,int flags,int mode)
+asmlinkage int sys_open(const char * filename, int flags, int mode)
{
char * tmp;
int fd, error;

lock_kernel();
- error = get_unused_fd();
- if (error < 0)
+ fd = get_unused_fd();
+ if (fd < 0)
goto out;

- fd = error;
tmp = getname(filename);
error = PTR_ERR(tmp);
- if (!IS_ERR(tmp)) {
- error = do_open(tmp,flags,mode,fd);
- putname(tmp);
- if (!error) {
- error = fd;
- goto out;
- }
- }
- put_unused_fd(fd);
+ if (IS_ERR(tmp))
+ goto out_fail;
+ error = do_open(tmp, flags, mode, fd);
+ putname(tmp);
+ if (error)
+ goto out_fail;
out:
unlock_kernel();
- return error;
+ return fd;
+
+out_fail:
+ put_unused_fd(fd);
+ fd = error;
+ goto out;
}

#ifndef __alpha__
@@ -728,11 +752,14 @@

#endif

+/*
+ * Called when retiring the last use of a file pointer.
+ */
int __fput(struct file *filp)
{
- int error = 0;
struct dentry * dentry = filp->f_dentry;
struct inode * inode = dentry->d_inode;
+ int error = 0;

if (filp->f_op && filp->f_op->release)
error = filp->f_op->release(inode, filp);
@@ -756,6 +783,11 @@
return fput(filp);
}

+/*
+ * Careful here! We test whether the file pointer is NULL before
+ * releasing the fd. This ensures that one clone task can't release
+ * an fd while another clone is opening it.
+ */
asmlinkage int sys_close(unsigned int fd)
{
int error;
--- linux-2.1.88/fs/read_write.c.old Sun Nov 30 11:24:44 1997
+++ linux-2.1.88/fs/read_write.c Sat Feb 21 13:48:08 1998
@@ -62,14 +62,18 @@

lock_kernel();
retval = -EBADF;
- if (fd >= NR_OPEN ||
- !(file = current->files->fd[fd]) ||
- !(dentry = file->f_dentry) ||
- !(inode = dentry->d_inode))
+ file = fget(fd);
+ if (!file)
goto bad;
+ /* N.B. Shouldn't this be ENOENT?? */
+ if (!(dentry = file->f_dentry) ||
+ !(inode = dentry->d_inode))
+ goto out_putf;
retval = -EINVAL;
if (origin <= 2)
retval = llseek(file, offset, origin);
+out_putf:
+ fput(file);
bad:
unlock_kernel();
return retval;
@@ -88,24 +92,28 @@

lock_kernel();
retval = -EBADF;
- if (fd >= NR_OPEN ||
- !(file = current->files->fd[fd]) ||
- !(dentry = file->f_dentry) ||
- !(inode = dentry->d_inode))
+ file = fget(fd);
+ if (!file)
goto bad;
+ /* N.B. Shouldn't this be ENOENT?? */
+ if (!(dentry = file->f_dentry) ||
+ !(inode = dentry->d_inode))
+ goto out_putf;
retval = -EINVAL;
if (origin > 2)
- goto bad;
+ goto out_putf;

offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
origin);

retval = (int)offset & INT_MAX;
if (offset >= 0) {
- retval = copy_to_user(result, &offset, sizeof(offset));
- if (retval)
- retval = -EFAULT;
+ retval = -EFAULT;
+ if (!copy_to_user(result, &offset, sizeof(offset)))
+ retval = 0;
}
+out_putf:
+ fput(file);
bad:
unlock_kernel();
return retval;
@@ -201,9 +209,10 @@
if (count > UIO_MAXIOV)
goto out_nofree;
if (count > UIO_FASTIOV) {
- iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
ret = -ENOMEM;
- if (!iov) goto out_nofree;
+ iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
+ if (!iov)
+ goto out_nofree;
}
ret = -EFAULT;
if (copy_from_user(iov, vector, count*sizeof(*vector)))
@@ -280,11 +289,10 @@
file = fget(fd);
if (!file)
goto bad_file;
- if (!(file->f_mode & FMODE_READ))
- goto out;
- ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
-out:
+ if (file->f_mode & FMODE_READ)
+ ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
fput(file);
+
bad_file:
unlock_kernel();
return ret;
@@ -302,15 +310,13 @@
file = fget(fd);
if (!file)
goto bad_file;
- if (!(file->f_mode & FMODE_WRITE))
- goto out;
-
- down(&file->f_dentry->d_inode->i_sem);
- ret = do_readv_writev(VERIFY_READ, file, vector, count);
- up(&file->f_dentry->d_inode->i_sem);
-
-out:
+ if (file->f_mode & FMODE_WRITE) {
+ down(&file->f_dentry->d_inode->i_sem);
+ ret = do_readv_writev(VERIFY_READ, file, vector, count);
+ up(&file->f_dentry->d_inode->i_sem);
+ }
fput(file);
+
bad_file:
unlock_kernel();
return ret;
--- linux-2.1.88/fs/stat.c.old Tue Jan 6 11:39:08 1998
+++ linux-2.1.88/fs/stat.c Sat Feb 21 13:49:46 1998
@@ -4,13 +4,14 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/

+#include <linux/sched.h>
+#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/fs.h>
-#include <linux/sched.h>
+#include <linux/file.h>
#include <linux/kernel.h>
-#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>

@@ -220,12 +221,14 @@
int err = -EBADF;

lock_kernel();
- if (fd < NR_OPEN && (f = current->files->fd[fd]) != NULL) {
+ f = fget(fd);
+ if (f) {
struct dentry * dentry = f->f_dentry;

err = do_revalidate(dentry);
if (!err)
err = cp_old_stat(dentry->d_inode, statbuf);
+ fput(f);
}
unlock_kernel();
return err;
@@ -239,12 +242,14 @@
int err = -EBADF;

lock_kernel();
- if (fd < NR_OPEN && (f = current->files->fd[fd]) != NULL) {
+ f = fget(fd);
+ if (f) {
struct dentry * dentry = f->f_dentry;

err = do_revalidate(dentry);
if (!err)
err = cp_new_stat(dentry->d_inode, statbuf);
+ fput(f);
}
unlock_kernel();
return err;
--- linux-2.1.88/fs/readdir.c.old Sat Sep 20 15:21:34 1997
+++ linux-2.1.88/fs/readdir.c Sat Feb 21 14:11:21 1998
@@ -4,12 +4,13 @@
* Copyright (C) 1995 Linus Torvalds
*/

+#include <linux/sched.h>
+#include <linux/mm.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/stat.h>
+#include <linux/file.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>

@@ -65,27 +66,24 @@

lock_kernel();
error = -EBADF;
- if (fd >= NR_OPEN)
- goto out;
-
- file = current->files->fd[fd];
+ file = fget(fd);
if (!file)
goto out;

dentry = file->f_dentry;
if (!dentry)
- goto out;
+ goto out_putf;

inode = dentry->d_inode;
if (!inode)
- goto out;
+ goto out_putf;

buf.count = 0;
buf.dirent = dirent;

error = -ENOTDIR;
if (!file->f_op || !file->f_op->readdir)
- goto out;
+ goto out_putf;

/*
* Get the inode's semaphore to prevent changes
@@ -95,8 +93,11 @@
error = file->f_op->readdir(file, &buf, fillonedir);
up(&inode->i_sem);
if (error < 0)
- goto out;
+ goto out_putf;
error = buf.count;
+
+out_putf:
+ fput(file);
out:
unlock_kernel();
return error;
@@ -155,20 +156,17 @@

lock_kernel();
error = -EBADF;
- if (fd >= NR_OPEN)
- goto out;
-
- file = current->files->fd[fd];
+ file = fget(fd);
if (!file)
goto out;

dentry = file->f_dentry;
if (!dentry)
- goto out;
+ goto out_putf;

inode = dentry->d_inode;
if (!inode)
- goto out;
+ goto out_putf;

buf.current_dir = (struct linux_dirent *) dirent;
buf.previous = NULL;
@@ -177,7 +175,7 @@

error = -ENOTDIR;
if (!file->f_op || !file->f_op->readdir)
- goto out;
+ goto out_putf;

/*
* Get the inode's semaphore to prevent changes
@@ -187,13 +185,16 @@
error = file->f_op->readdir(file, &buf, filldir);
up(&inode->i_sem);
if (error < 0)
- goto out;
- lastdirent = buf.previous;
+ goto out_putf;
error = buf.error;
+ lastdirent = buf.previous;
if (lastdirent) {
put_user(file->f_pos, &lastdirent->d_off);
error = count - buf.count;
}
+
+out_putf:
+ fput(file);
out:
unlock_kernel();
return error;
--- linux-2.1.88/fs/ioctl.c.old Mon Jul 14 00:20:10 1997
+++ linux-2.1.88/fs/ioctl.c Sat Feb 21 13:52:06 1998
@@ -13,6 +13,7 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/fcntl.h> /* for f_flags values */
+#include <linux/file.h>

#include <asm/uaccess.h>

@@ -52,7 +53,8 @@
int on, error = -EBADF;

lock_kernel();
- if (fd >= NR_OPEN || !(filp = current->files->fd[fd]))
+ filp = fget(fd);
+ if (!filp)
goto out;
error = 0;
switch (cmd) {
@@ -90,13 +92,16 @@
break;

default:
- if (filp->f_dentry && filp->f_dentry->d_inode && S_ISREG(filp->f_dentry->d_inode->i_mode))
+ error = -ENOTTY;
+ if (!filp->f_dentry || !filp->f_dentry->d_inode)
+ error = -ENOENT;
+ else if (S_ISREG(filp->f_dentry->d_inode->i_mode))
error = file_ioctl(filp, cmd, arg);
else if (filp->f_op && filp->f_op->ioctl)
error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
- else
- error = -ENOTTY;
}
+ fput(filp);
+
out:
unlock_kernel();
return error;
--- linux-2.1.88/fs/locks.c.old Sat Feb 21 09:25:00 1998
+++ linux-2.1.88/fs/locks.c Sat Feb 21 13:50:11 1998
@@ -111,6 +111,7 @@
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
+#include <linux/file.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>

@@ -289,15 +290,21 @@
int error;

lock_kernel();
- if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
- error = -EBADF;
- else if (!flock_make_lock(filp, &file_lock, cmd))
- error = -EINVAL;
- else if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3))
- error = -EBADF;
- else
- error = flock_lock_file(filp, &file_lock,
- (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1);
+ error = -EBADF;
+ filp = fget(fd);
+ if (!filp)
+ goto out;
+ error = -EINVAL;
+ if (!flock_make_lock(filp, &file_lock, cmd))
+ goto out_putf;
+ error = -EBADF;
+ if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3))
+ goto out_putf;
+ error = flock_lock_file(filp, &file_lock,
+ (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1);
+out_putf:
+ fput(filp);
+out:
unlock_kernel();
return (error);
}
@@ -307,36 +314,34 @@
*/
int fcntl_getlk(unsigned int fd, struct flock *l)
{
- struct flock flock;
struct file *filp;
- struct dentry *dentry;
- struct inode *inode;
struct file_lock *fl,file_lock;
+ struct flock flock;
int error;

- if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
- return -EBADF;
+ error = -EFAULT;
if (copy_from_user(&flock, l, sizeof(flock)))
- return -EFAULT;
-
+ goto out;
+ error = -EINVAL;
if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))
- return -EINVAL;
+ goto out;

- dentry = filp->f_dentry;
- if (!dentry)
- return -EINVAL;
-
- inode = dentry->d_inode;
- if (!inode)
- return -EINVAL;
+ error = -EBADF;
+ filp = fget(fd);
+ if (!filp)
+ goto out;
+
+ error = -EINVAL;
+ if (!filp->f_dentry || !filp->f_dentry->d_inode)
+ goto out_putf;

if (!posix_make_lock(filp, &file_lock, &flock))
- return -EINVAL;
+ goto out_putf;

if (filp->f_op->lock) {
error = filp->f_op->lock(filp, F_GETLK, &file_lock);
if (error < 0)
- return error;
+ goto out_putf;
fl = &file_lock;
} else {
fl = posix_test_lock(filp, &file_lock);
@@ -351,8 +356,14 @@
flock.l_whence = 0;
flock.l_type = fl->fl_type;
}
+ error = -EFAULT;
+ if (!copy_to_user(l, &flock, sizeof(flock)))
+ error = 0;

- return (copy_to_user(l, &flock, sizeof(flock)) ? -EFAULT : 0);
+out_putf:
+ fput(filp);
+out:
+ return error;
}

/* Apply the lock described by l to an open file descriptor.
@@ -367,22 +378,26 @@
struct inode *inode;
int error;

+ /*
+ * This might block, so we do it before checking the inode.
+ */
+ error = -EFAULT;
+ if (copy_from_user(&flock, l, sizeof(flock)))
+ goto out;
+
/* Get arguments and validate them ...
*/

- if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
- return -EBADF;
+ error = -EBADF;
+ filp = fget(fd);
+ if (!filp)
+ goto out;

+ error = -EINVAL;
if (!(dentry = filp->f_dentry))
- return -EINVAL;
-
+ goto out_putf;
if (!(inode = dentry->d_inode))
- return -EINVAL;
- /*
- * This might block, so we do it before checking the inode.
- */
- if (copy_from_user(&flock, l, sizeof(flock)))
- return (-EFAULT);
+ goto out_putf;

/* Don't allow mandatory locks on files that may be memory mapped
* and shared.
@@ -391,23 +406,26 @@
(inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
inode->i_mmap) {
struct vm_area_struct *vma = inode->i_mmap;
+ error = -EAGAIN;
do {
if (vma->vm_flags & VM_MAYSHARE)
- return (-EAGAIN);
+ goto out_putf;
} while ((vma = vma->vm_next_share) != NULL);
}

+ error = -EINVAL;
if (!posix_make_lock(filp, &file_lock, &flock))
- return (-EINVAL);
+ goto out_putf;

+ error = -EBADF;
switch (flock.l_type) {
case F_RDLCK:
if (!(filp->f_mode & FMODE_READ))
- return (-EBADF);
+ goto out_putf;
break;
case F_WRLCK:
if (!(filp->f_mode & FMODE_WRITE))
- return (-EBADF);
+ goto out_putf;
break;
case F_UNLCK:
break;
@@ -425,20 +443,25 @@
}
}
if (!(filp->f_mode & 3))
- return (-EBADF);
+ goto out_putf;
break;
#endif
default:
- return (-EINVAL);
+ error = -EINVAL;
+ goto out_putf;
}

if (filp->f_op->lock != NULL) {
error = filp->f_op->lock(filp, cmd, &file_lock);
if (error < 0)
- return (error);
+ goto out_putf;
}
+ error = posix_lock_file(filp, &file_lock, cmd == F_SETLKW);

- return (posix_lock_file(filp, &file_lock, cmd == F_SETLKW));
+out_putf:
+ fput(filp);
+out:
+ return error;
}

/*
\
 
 \ /
  Last update: 2005-03-22 13:41    [W:0.054 / U:0.476 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site