patch-2.1.89 linux/fs/open.c
Next file: linux/fs/pipe.c
Previous file: linux/fs/ntfs/inode.c
Back to the patch index
Back to the overall index
- Lines: 359
- Date:
Sat Feb 28 10:47:59 1998
- Orig file:
v2.1.88/linux/fs/open.c
- Orig date:
Mon Feb 23 18:12:10 1998
diff -u --recursive --new-file v2.1.88/linux/fs/open.c linux/fs/open.c
@@ -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, ¤t->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);
@@ -743,7 +770,11 @@
return error;
}
-int close_fp(struct file *filp)
+/*
+ * "id" is the POSIX thread ID. We use the
+ * files pointer for this..
+ */
+int close_fp(struct file *filp, fl_owner_t id)
{
struct dentry *dentry = filp->f_dentry;
@@ -752,10 +783,15 @@
return 0;
}
if (dentry->d_inode)
- locks_remove_posix(current, filp);
+ locks_remove_posix(filp, id);
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;
@@ -769,7 +805,7 @@
put_unused_fd(fd);
FD_CLR(fd, &files->close_on_exec);
files->fd[fd] = NULL;
- error = close_fp(filp);
+ error = close_fp(filp, files);
}
unlock_kernel();
return error;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov