Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
[firefly-linux-kernel-4.4.55.git] / fs / ceph / file.c
index 905986dd4c3c9dabaf5bf3ea5e584e0ecc719a5b..a3d774b351494b64b2f03c6db2d9270017defc76 100644 (file)
@@ -275,10 +275,10 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
        err = ceph_mdsc_do_request(mdsc,
                                   (flags & (O_CREAT|O_TRUNC)) ? dir : NULL,
                                   req);
+       err = ceph_handle_snapdir(req, dentry, err);
        if (err)
                goto out_req;
 
-       err = ceph_handle_snapdir(req, dentry, err);
        if (err == 0 && (flags & O_CREAT) && !req->r_reply_info.head->is_dentry)
                err = ceph_handle_notrace_create(dir, dentry);
 
@@ -392,13 +392,14 @@ more:
        if (ret >= 0) {
                int didpages;
                if (was_short && (pos + ret < inode->i_size)) {
-                       u64 tmp = min(this_len - ret,
-                                       inode->i_size - pos - ret);
+                       int zlen = min(this_len - ret,
+                                      inode->i_size - pos - ret);
+                       int zoff = (o_direct ? buf_align : io_align) +
+                                   read + ret;
                        dout(" zero gap %llu to %llu\n",
-                               pos + ret, pos + ret + tmp);
-                       ceph_zero_page_vector_range(page_align + read + ret,
-                                                       tmp, pages);
-                       ret += tmp;
+                               pos + ret, pos + ret + zlen);
+                       ceph_zero_page_vector_range(zoff, zlen, pages);
+                       ret += zlen;
                }
 
                didpages = (page_align + ret) >> PAGE_CACHE_SHIFT;
@@ -878,28 +879,34 @@ again:
 
                i_size = i_size_read(inode);
                if (retry_op == READ_INLINE) {
-                       /* does not support inline data > PAGE_SIZE */
-                       if (i_size > PAGE_CACHE_SIZE) {
-                               ret = -EIO;
-                       } else if (iocb->ki_pos < i_size) {
+                       BUG_ON(ret > 0 || read > 0);
+                       if (iocb->ki_pos < i_size &&
+                           iocb->ki_pos < PAGE_CACHE_SIZE) {
                                loff_t end = min_t(loff_t, i_size,
                                                   iocb->ki_pos + len);
+                               end = min_t(loff_t, end, PAGE_CACHE_SIZE);
                                if (statret < end)
                                        zero_user_segment(page, statret, end);
                                ret = copy_page_to_iter(page,
                                                iocb->ki_pos & ~PAGE_MASK,
                                                end - iocb->ki_pos, to);
                                iocb->ki_pos += ret;
-                       } else {
-                               ret = 0;
+                               read += ret;
+                       }
+                       if (iocb->ki_pos < i_size && read < len) {
+                               size_t zlen = min_t(size_t, len - read,
+                                                   i_size - iocb->ki_pos);
+                               ret = iov_iter_zero(zlen, to);
+                               iocb->ki_pos += ret;
+                               read += ret;
                        }
                        __free_pages(page, 0);
-                       return ret;
+                       return read;
                }
 
                /* hit EOF or hole? */
                if (retry_op == CHECK_EOF && iocb->ki_pos < i_size &&
-                       ret < len) {
+                   ret < len) {
                        dout("sync_read hit hole, ppos %lld < size %lld"
                             ", reading more\n", iocb->ki_pos,
                             inode->i_size);