patch for 2.1.88 fd file access

Bill Hawes (whawes@star.net)
Mon, 23 Feb 1998 10:03:16 -0500


This is a multi-part message in MIME format.
--------------4BF9B151DB25DB02F6465B79
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

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
--------------4BF9B151DB25DB02F6465B79
Content-Type: text/plain; charset=us-ascii; name="fd_files88-patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="fd_files88-patch"

--- 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;
}

/*

--------------4BF9B151DB25DB02F6465B79--

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu