patch-2.1.60 linux/fs/read_write.c
Next file: linux/fs/smbfs/dir.c
Previous file: linux/fs/proc/scsi.c
Back to the patch index
Back to the overall index
- Lines: 476
- Date:
Tue Oct 21 08:57:29 1997
- Orig file:
v2.1.59/linux/fs/read_write.c
- Orig date:
Tue Sep 23 16:48:49 1997
diff -u --recursive --new-file v2.1.59/linux/fs/read_write.c linux/fs/read_write.c
@@ -16,10 +16,11 @@
#include <linux/malloc.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/limits.h>
#include <asm/uaccess.h>
-static long long default_llseek(struct file *file, long long offset, int origin)
+static loff_t default_llseek(struct file *file, loff_t offset, int origin)
{
long long retval;
@@ -42,9 +43,9 @@
return retval;
}
-static inline long long llseek(struct file *file, long long offset, unsigned int origin)
+static inline loff_t llseek(struct file *file, loff_t offset, int origin)
{
- long long (*fn)(struct file *, long long, int);
+ loff_t (*fn)(struct file *, loff_t, int);
fn = default_llseek;
if (file->f_op && file->f_op->llseek)
@@ -52,9 +53,9 @@
return fn(file, offset, origin);
}
-asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
+asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
{
- long retval;
+ off_t retval;
struct file * file;
struct dentry * dentry;
struct inode * inode;
@@ -67,23 +68,23 @@
!(inode = dentry->d_inode))
goto bad;
retval = -EINVAL;
- if (origin > 2)
- goto bad;
- retval = llseek(file, offset, origin);
+ if (origin <= 2)
+ retval = llseek(file, offset, origin);
bad:
unlock_kernel();
return retval;
}
+#if !defined(__alpha__) && !defined(__sparc_v9__)
asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
unsigned long offset_low, loff_t * result,
unsigned int origin)
{
- long retval;
+ int retval;
struct file * file;
struct dentry * dentry;
struct inode * inode;
- long long offset;
+ loff_t offset;
lock_kernel();
retval = -EBADF;
@@ -96,10 +97,10 @@
if (origin > 2)
goto bad;
- offset = llseek(file, (((unsigned long long) offset_high << 32) | offset_low),
- origin);
+ offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
+ origin);
- retval = offset;
+ retval = (int)offset & INT_MAX;
if (offset >= 0) {
retval = copy_to_user(result, &offset, sizeof(offset));
if (retval)
@@ -109,120 +110,114 @@
unlock_kernel();
return retval;
}
+#endif
-asmlinkage long sys_read(unsigned int fd, char * buf, unsigned long count)
+asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
{
- int error;
+ ssize_t ret;
struct file * file;
- struct dentry * dentry;
- struct inode * inode;
- long (*read)(struct inode *, struct file *, char *, unsigned long);
+ ssize_t (*read)(struct file *, char *, size_t, loff_t *);
lock_kernel();
- error = -EBADF;
+
+ ret = -EBADF;
file = fget(fd);
if (!file)
goto bad_file;
- dentry = file->f_dentry;
- if (!dentry)
+ ret = -EBADF;
+ if (!(file->f_mode & FMODE_READ))
goto out;
- inode = dentry->d_inode;
- if (!inode)
+ ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
+ file, file->f_pos, count);
+ if (ret)
goto out;
- error = -EBADF;
- if (!(file->f_mode & 1))
- goto out;
- error = locks_verify_area(FLOCK_VERIFY_READ,inode,file,file->f_pos,count);
- if (error)
- goto out;
- error = -EINVAL;
+ ret = -EINVAL;
if (!file->f_op || !(read = file->f_op->read))
goto out;
- error = read(inode,file,buf,count);
+ ret = read(file, buf, count, &file->f_pos);
out:
fput(file);
bad_file:
unlock_kernel();
- return error;
+ return ret;
}
-asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count)
+asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
{
- int error;
+ ssize_t ret;
struct file * file;
- struct dentry * dentry;
struct inode * inode;
- long (*write)(struct inode *, struct file *, const char *, unsigned long);
+ ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
lock_kernel();
- error = -EBADF;
+
+ ret = -EBADF;
file = fget(fd);
if (!file)
goto bad_file;
- dentry = file->f_dentry;
- if (!dentry)
- goto out;
- inode = dentry->d_inode;
- if (!inode)
+ if (!(file->f_mode & FMODE_WRITE))
goto out;
- if (!(file->f_mode & 2))
+ inode = file->f_dentry->d_inode;
+ ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
+ file->f_pos, count);
+ if (ret)
goto out;
- error = locks_verify_area(FLOCK_VERIFY_WRITE,inode,file,file->f_pos,count);
- if (error)
- goto out;
- error = -EINVAL;
+ ret = -EINVAL;
if (!file->f_op || !(write = file->f_op->write))
goto out;
+
down(&inode->i_sem);
- error = write(inode,file,buf,count);
+ ret = write(file, buf, count, &file->f_pos);
up(&inode->i_sem);
out:
fput(file);
bad_file:
unlock_kernel();
- return error;
+ return ret;
}
-typedef long (*IO_fn_t)(struct inode *, struct file *, char *, unsigned long);
-static long do_readv_writev(int type, struct inode * inode, struct file * file,
- const struct iovec * vector, unsigned long count)
+static ssize_t do_readv_writev(int type, struct file *file,
+ const struct iovec * vector,
+ unsigned long count)
{
- unsigned long tot_len;
+ typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
+
+ size_t tot_len;
struct iovec iovstack[UIO_FASTIOV];
struct iovec *iov=iovstack;
- long retval, i;
- IO_fn_t fn;
+ ssize_t ret, i;
+ io_fn_t fn;
+ struct inode *inode;
/*
* First get the "struct iovec" from user memory and
* verify all the pointers
*/
+ ret = 0;
if (!count)
- return 0;
+ goto out_nofree;
+ ret = -EINVAL;
if (count > UIO_MAXIOV)
- return -EINVAL;
+ goto out_nofree;
if (count > UIO_FASTIOV) {
iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
- if (!iov)
- return -ENOMEM;
- }
- if (copy_from_user(iov, vector, count*sizeof(*vector))) {
- if (iov != iovstack)
- kfree(iov);
- return -EFAULT;
+ ret = -ENOMEM;
+ if (!iov) goto out_nofree;
}
+ ret = -EFAULT;
+ if (copy_from_user(iov, vector, count*sizeof(*vector)))
+ goto out;
+
tot_len = 0;
for (i = 0 ; i < count ; i++)
tot_len += iov[i].iov_len;
- retval = locks_verify_area(type == VERIFY_READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
- inode, file, file->f_pos, tot_len);
- if (retval) {
- if (iov != iovstack)
- kfree(iov);
- return retval;
- }
+ inode = file->f_dentry->d_inode;
+ ret = locks_verify_area((type == VERIFY_READ
+ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
+ inode, file, file->f_pos, tot_len);
+ if (ret) goto out;
/*
* Then do the actual IO. Note that sockets need to be handled
@@ -230,116 +225,165 @@
* iovec's natively
*/
if (inode->i_sock) {
- int err;
- err = sock_readv_writev(type, inode, file, iov, count, tot_len);
- if (iov != iovstack)
- kfree(iov);
- return err;
+ ret = sock_readv_writev(type,inode,file,iov,count,tot_len);
+ goto out;
}
- if (!file->f_op) {
- if (iov != iovstack)
- kfree(iov);
- return -EINVAL;
- }
+ ret = -EINVAL;
+ if (!file->f_op)
+ goto out;
+
/* VERIFY_WRITE actually means a read, as we write to user space */
fn = file->f_op->read;
if (type == VERIFY_READ)
- fn = (IO_fn_t) file->f_op->write;
+ fn = (io_fn_t) file->f_op->write;
+
+ ret = 0;
vector = iov;
while (count > 0) {
void * base;
- int len, nr;
+ size_t len;
+ ssize_t nr;
base = vector->iov_base;
len = vector->iov_len;
vector++;
count--;
- /* Any particular reason why we do not grab the inode semaphore
- * when doing writes here? -DaveM
- */
- nr = fn(inode, file, base, len);
+ nr = fn(file, base, len, &file->f_pos);
+
if (nr < 0) {
- if (retval)
- break;
- retval = nr;
+ if (!ret) ret = nr;
break;
}
- retval += nr;
+ ret += nr;
if (nr != len)
break;
}
+
+out:
if (iov != iovstack)
kfree(iov);
- return retval;
+out_nofree:
+ return ret;
}
-asmlinkage long sys_readv(unsigned long fd, const struct iovec * vector, unsigned long count)
+asmlinkage ssize_t sys_readv(unsigned long fd, const struct iovec * vector,
+ unsigned long count)
{
struct file * file;
- struct dentry * dentry;
- struct inode * inode;
- long err;
+ ssize_t ret;
lock_kernel();
- err = -EBADF;
- if (fd >= NR_OPEN)
- goto out;
- file = current->files->fd[fd];
+ ret = -EBADF;
+ 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:
+ fput(file);
+bad_file:
+ unlock_kernel();
+ return ret;
+}
- if (!(file->f_mode & 1))
- goto out;
+asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
+ unsigned long count)
+{
+ struct file * file;
+ ssize_t ret;
- dentry = file->f_dentry;
- if (!dentry)
- goto out;
+ lock_kernel();
- inode = dentry->d_inode;
- if (!inode)
+ ret = -EBADF;
+ file = fget(fd);
+ if (!file)
+ goto bad_file;
+ if (!(file->f_mode & FMODE_WRITE))
goto out;
- err = do_readv_writev(VERIFY_WRITE, inode, file, vector, count);
+ 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:
+ fput(file);
+bad_file:
unlock_kernel();
- return err;
+ return ret;
}
-asmlinkage long sys_writev(unsigned long fd, const struct iovec * vector, unsigned long count)
+/* From the Single Unix Spec: pread & pwrite act like lseek to pos + op +
+ lseek back to original location. They fail just like lseek does on
+ non-seekable files. */
+
+asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
+ size_t count, loff_t pos)
{
- long error;
+ ssize_t ret;
struct file * file;
- struct dentry * dentry;
- struct inode * inode;
+ ssize_t (*read)(struct file *, char *, size_t, loff_t *);
lock_kernel();
- error = -EBADF;
- if (fd >= NR_OPEN)
+ ret = -EBADF;
+ file = fget(fd);
+ if (!file)
+ goto bad_file;
+ if (!(file->f_mode & FMODE_READ))
+ goto out;
+ ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
+ file, pos, count);
+ if (ret)
goto out;
+ ret = -EINVAL;
+ if (!file->f_op || !(read = file->f_op->read))
+ goto out;
+ if (pos < 0)
+ goto out;
+ ret = read(file, buf, count, &pos);
+out:
+ fput(file);
+bad_file:
+ unlock_kernel();
+ return ret;
+}
+
+asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
+ size_t count, loff_t pos)
+{
+ ssize_t ret;
+ struct file * file;
+ ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
+
+ lock_kernel();
- file = current->files->fd[fd];
+ ret = -EBADF;
+ file = fget(fd);
if (!file)
+ goto bad_file;
+ if (!(file->f_mode & FMODE_WRITE))
goto out;
-
- if (!(file->f_mode & 2))
+ ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
+ file, pos, count);
+ if (ret)
goto out;
-
- dentry = file->f_dentry;
- if (!dentry)
+ ret = -EINVAL;
+ if (!file->f_op || !(write = file->f_op->write))
goto out;
-
- inode = dentry->d_inode;
- if (!inode)
+ if (pos < 0)
goto out;
- down(&inode->i_sem);
- error = do_readv_writev(VERIFY_READ, inode, file, vector, count);
- up(&inode->i_sem);
+ down(&file->f_dentry->d_inode->i_sem);
+ ret = write(file, buf, count, &pos);
+ up(&file->f_dentry->d_inode->i_sem);
+
out:
+ fput(file);
+bad_file:
unlock_kernel();
- return error;
+ return ret;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov