genirq/timings: Optimize the period detection speed
[linux-2.6-microblaze.git] / fs / read_write.c
index 61b43ad..c543d96 100644 (file)
@@ -365,29 +365,37 @@ out_putf:
 int rw_verify_area(int read_write, struct file *file, const loff_t *ppos, size_t count)
 {
        struct inode *inode;
-       loff_t pos;
        int retval = -EINVAL;
 
        inode = file_inode(file);
        if (unlikely((ssize_t) count < 0))
                return retval;
-       pos = *ppos;
-       if (unlikely(pos < 0)) {
-               if (!unsigned_offsets(file))
-                       return retval;
-               if (count >= -pos) /* both values are in 0..LLONG_MAX */
-                       return -EOVERFLOW;
-       } else if (unlikely((loff_t) (pos + count) < 0)) {
-               if (!unsigned_offsets(file))
-                       return retval;
-       }
 
-       if (unlikely(inode->i_flctx && mandatory_lock(inode))) {
-               retval = locks_mandatory_area(inode, file, pos, pos + count - 1,
-                               read_write == READ ? F_RDLCK : F_WRLCK);
-               if (retval < 0)
-                       return retval;
+       /*
+        * ranged mandatory locking does not apply to streams - it makes sense
+        * only for files where position has a meaning.
+        */
+       if (ppos) {
+               loff_t pos = *ppos;
+
+               if (unlikely(pos < 0)) {
+                       if (!unsigned_offsets(file))
+                               return retval;
+                       if (count >= -pos) /* both values are in 0..LLONG_MAX */
+                               return -EOVERFLOW;
+               } else if (unlikely((loff_t) (pos + count) < 0)) {
+                       if (!unsigned_offsets(file))
+                               return retval;
+               }
+
+               if (unlikely(inode->i_flctx && mandatory_lock(inode))) {
+                       retval = locks_mandatory_area(inode, file, pos, pos + count - 1,
+                                       read_write == READ ? F_RDLCK : F_WRLCK);
+                       if (retval < 0)
+                               return retval;
+               }
        }
+
        return security_file_permission(file,
                                read_write == READ ? MAY_READ : MAY_WRITE);
 }
@@ -400,12 +408,13 @@ static ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, lo
        ssize_t ret;
 
        init_sync_kiocb(&kiocb, filp);
-       kiocb.ki_pos = *ppos;
+       kiocb.ki_pos = (ppos ? *ppos : 0);
        iov_iter_init(&iter, READ, &iov, 1, len);
 
        ret = call_read_iter(filp, &kiocb, &iter);
        BUG_ON(ret == -EIOCBQUEUED);
-       *ppos = kiocb.ki_pos;
+       if (ppos)
+               *ppos = kiocb.ki_pos;
        return ret;
 }
 
@@ -468,12 +477,12 @@ static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t
        ssize_t ret;
 
        init_sync_kiocb(&kiocb, filp);
-       kiocb.ki_pos = *ppos;
+       kiocb.ki_pos = (ppos ? *ppos : 0);
        iov_iter_init(&iter, WRITE, &iov, 1, len);
 
        ret = call_write_iter(filp, &kiocb, &iter);
        BUG_ON(ret == -EIOCBQUEUED);
-       if (ret > 0)
+       if (ret > 0 && ppos)
                *ppos = kiocb.ki_pos;
        return ret;
 }
@@ -558,15 +567,10 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_
        return ret;
 }
 
-static inline loff_t file_pos_read(struct file *file)
-{
-       return file->f_mode & FMODE_STREAM ? 0 : file->f_pos;
-}
-
-static inline void file_pos_write(struct file *file, loff_t pos)
+/* file_ppos returns &file->f_pos or NULL if file is stream */
+static inline loff_t *file_ppos(struct file *file)
 {
-       if ((file->f_mode & FMODE_STREAM) == 0)
-               file->f_pos = pos;
+       return file->f_mode & FMODE_STREAM ? NULL : &file->f_pos;
 }
 
 ssize_t ksys_read(unsigned int fd, char __user *buf, size_t count)
@@ -575,10 +579,14 @@ ssize_t ksys_read(unsigned int fd, char __user *buf, size_t count)
        ssize_t ret = -EBADF;
 
        if (f.file) {
-               loff_t pos = file_pos_read(f.file);
-               ret = vfs_read(f.file, buf, count, &pos);
-               if (ret >= 0)
-                       file_pos_write(f.file, pos);
+               loff_t pos, *ppos = file_ppos(f.file);
+               if (ppos) {
+                       pos = *ppos;
+                       ppos = &pos;
+               }
+               ret = vfs_read(f.file, buf, count, ppos);
+               if (ret >= 0 && ppos)
+                       f.file->f_pos = pos;
                fdput_pos(f);
        }
        return ret;
@@ -595,10 +603,14 @@ ssize_t ksys_write(unsigned int fd, const char __user *buf, size_t count)
        ssize_t ret = -EBADF;
 
        if (f.file) {
-               loff_t pos = file_pos_read(f.file);
-               ret = vfs_write(f.file, buf, count, &pos);
-               if (ret >= 0)
-                       file_pos_write(f.file, pos);
+               loff_t pos, *ppos = file_ppos(f.file);
+               if (ppos) {
+                       pos = *ppos;
+                       ppos = &pos;
+               }
+               ret = vfs_write(f.file, buf, count, ppos);
+               if (ret >= 0 && ppos)
+                       f.file->f_pos = pos;
                fdput_pos(f);
        }
 
@@ -673,14 +685,15 @@ static ssize_t do_iter_readv_writev(struct file *filp, struct iov_iter *iter,
        ret = kiocb_set_rw_flags(&kiocb, flags);
        if (ret)
                return ret;
-       kiocb.ki_pos = *ppos;
+       kiocb.ki_pos = (ppos ? *ppos : 0);
 
        if (type == READ)
                ret = call_read_iter(filp, &kiocb, iter);
        else
                ret = call_write_iter(filp, &kiocb, iter);
        BUG_ON(ret == -EIOCBQUEUED);
-       *ppos = kiocb.ki_pos;
+       if (ppos)
+               *ppos = kiocb.ki_pos;
        return ret;
 }
 
@@ -1013,10 +1026,14 @@ static ssize_t do_readv(unsigned long fd, const struct iovec __user *vec,
        ssize_t ret = -EBADF;
 
        if (f.file) {
-               loff_t pos = file_pos_read(f.file);
-               ret = vfs_readv(f.file, vec, vlen, &pos, flags);
-               if (ret >= 0)
-                       file_pos_write(f.file, pos);
+               loff_t pos, *ppos = file_ppos(f.file);
+               if (ppos) {
+                       pos = *ppos;
+                       ppos = &pos;
+               }
+               ret = vfs_readv(f.file, vec, vlen, ppos, flags);
+               if (ret >= 0 && ppos)
+                       f.file->f_pos = pos;
                fdput_pos(f);
        }
 
@@ -1033,10 +1050,14 @@ static ssize_t do_writev(unsigned long fd, const struct iovec __user *vec,
        ssize_t ret = -EBADF;
 
        if (f.file) {
-               loff_t pos = file_pos_read(f.file);
-               ret = vfs_writev(f.file, vec, vlen, &pos, flags);
-               if (ret >= 0)
-                       file_pos_write(f.file, pos);
+               loff_t pos, *ppos = file_ppos(f.file);
+               if (ppos) {
+                       pos = *ppos;
+                       ppos = &pos;
+               }
+               ret = vfs_writev(f.file, vec, vlen, ppos, flags);
+               if (ret >= 0 && ppos)
+                       f.file->f_pos = pos;
                fdput_pos(f);
        }