Merge branch 'timecounter-next'
[cascardo/linux.git] / fs / ceph / inode.c
index a5593d5..f61a741 100644 (file)
@@ -387,8 +387,10 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
        spin_lock_init(&ci->i_ceph_lock);
 
        ci->i_version = 0;
+       ci->i_inline_version = 0;
        ci->i_time_warp_seq = 0;
        ci->i_ceph_flags = 0;
+       ci->i_ordered_count = 0;
        atomic_set(&ci->i_release_count, 1);
        atomic_set(&ci->i_complete_count, 0);
        ci->i_symlink = NULL;
@@ -657,7 +659,7 @@ void ceph_fill_file_time(struct inode *inode, int issued,
  * Populate an inode based on info from mds.  May be called on new or
  * existing inodes.
  */
-static int fill_inode(struct inode *inode,
+static int fill_inode(struct inode *inode, struct page *locked_page,
                      struct ceph_mds_reply_info_in *iinfo,
                      struct ceph_mds_reply_dirfrag *dirinfo,
                      struct ceph_mds_session *session,
@@ -675,6 +677,7 @@ static int fill_inode(struct inode *inode,
        bool wake = false;
        bool queue_trunc = false;
        bool new_version = false;
+       bool fill_inline = false;
 
        dout("fill_inode %p ino %llx.%llx v %llu had %llu\n",
             inode, ceph_vinop(inode), le64_to_cpu(info->version),
@@ -845,7 +848,8 @@ static int fill_inode(struct inode *inode,
            (issued & CEPH_CAP_FILE_EXCL) == 0 &&
            !__ceph_dir_is_complete(ci)) {
                dout(" marking %p complete (empty)\n", inode);
-               __ceph_dir_set_complete(ci, atomic_read(&ci->i_release_count));
+               __ceph_dir_set_complete(ci, atomic_read(&ci->i_release_count),
+                                       ci->i_ordered_count);
        }
 
        /* were we issued a capability? */
@@ -873,8 +877,23 @@ static int fill_inode(struct inode *inode,
                           ceph_vinop(inode));
                __ceph_get_fmode(ci, cap_fmode);
        }
+
+       if (iinfo->inline_version > 0 &&
+           iinfo->inline_version >= ci->i_inline_version) {
+               int cache_caps = CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO;
+               ci->i_inline_version = iinfo->inline_version;
+               if (ci->i_inline_version != CEPH_INLINE_NONE &&
+                   (locked_page ||
+                    (le32_to_cpu(info->cap.caps) & cache_caps)))
+                       fill_inline = true;
+       }
+
        spin_unlock(&ci->i_ceph_lock);
 
+       if (fill_inline)
+               ceph_fill_inline_data(inode, locked_page,
+                                     iinfo->inline_data, iinfo->inline_len);
+
        if (wake)
                wake_up_all(&ci->i_cap_wq);
 
@@ -1062,7 +1081,8 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
                struct inode *dir = req->r_locked_dir;
 
                if (dir) {
-                       err = fill_inode(dir, &rinfo->diri, rinfo->dirfrag,
+                       err = fill_inode(dir, NULL,
+                                        &rinfo->diri, rinfo->dirfrag,
                                         session, req->r_request_started, -1,
                                         &req->r_caps_reservation);
                        if (err < 0)
@@ -1132,7 +1152,7 @@ retry_lookup:
                }
                req->r_target_inode = in;
 
-               err = fill_inode(in, &rinfo->targeti, NULL,
+               err = fill_inode(in, req->r_locked_page, &rinfo->targeti, NULL,
                                session, req->r_request_started,
                                (!req->r_aborted && rinfo->head->result == 0) ?
                                req->r_fmode : -1,
@@ -1204,8 +1224,8 @@ retry_lookup:
                        ceph_invalidate_dentry_lease(dn);
 
                        /* d_move screws up sibling dentries' offsets */
-                       ceph_dir_clear_complete(dir);
-                       ceph_dir_clear_complete(olddir);
+                       ceph_dir_clear_ordered(dir);
+                       ceph_dir_clear_ordered(olddir);
 
                        dout("dn %p gets new offset %lld\n", req->r_old_dentry,
                             ceph_dentry(req->r_old_dentry)->offset);
@@ -1217,6 +1237,7 @@ retry_lookup:
                if (!rinfo->head->is_target) {
                        dout("fill_trace null dentry\n");
                        if (dn->d_inode) {
+                               ceph_dir_clear_ordered(dir);
                                dout("d_delete %p\n", dn);
                                d_delete(dn);
                        } else {
@@ -1233,7 +1254,7 @@ retry_lookup:
 
                /* attach proper inode */
                if (!dn->d_inode) {
-                       ceph_dir_clear_complete(dir);
+                       ceph_dir_clear_ordered(dir);
                        ihold(in);
                        dn = splice_dentry(dn, in, &have_lease);
                        if (IS_ERR(dn)) {
@@ -1263,7 +1284,7 @@ retry_lookup:
                BUG_ON(!dir);
                BUG_ON(ceph_snap(dir) != CEPH_SNAPDIR);
                dout(" linking snapped dir %p to dn %p\n", in, dn);
-               ceph_dir_clear_complete(dir);
+               ceph_dir_clear_ordered(dir);
                ihold(in);
                dn = splice_dentry(dn, in, NULL);
                if (IS_ERR(dn)) {
@@ -1300,7 +1321,7 @@ static int readdir_prepopulate_inodes_only(struct ceph_mds_request *req,
                        dout("new_inode badness got %d\n", err);
                        continue;
                }
-               rc = fill_inode(in, &rinfo->dir_in[i], NULL, session,
+               rc = fill_inode(in, NULL, &rinfo->dir_in[i], NULL, session,
                                req->r_request_started, -1,
                                &req->r_caps_reservation);
                if (rc < 0) {
@@ -1416,7 +1437,7 @@ retry_lookup:
                        }
                }
 
-               if (fill_inode(in, &rinfo->dir_in[i], NULL, session,
+               if (fill_inode(in, NULL, &rinfo->dir_in[i], NULL, session,
                               req->r_request_started, -1,
                               &req->r_caps_reservation) < 0) {
                        pr_err("fill_inode badness on %p\n", in);
@@ -1899,7 +1920,8 @@ out_put:
  * Verify that we have a lease on the given mask.  If not,
  * do a getattr against an mds.
  */
-int ceph_do_getattr(struct inode *inode, int mask, bool force)
+int __ceph_do_getattr(struct inode *inode, struct page *locked_page,
+                     int mask, bool force)
 {
        struct ceph_fs_client *fsc = ceph_sb_to_client(inode->i_sb);
        struct ceph_mds_client *mdsc = fsc->mdsc;
@@ -1911,7 +1933,8 @@ int ceph_do_getattr(struct inode *inode, int mask, bool force)
                return 0;
        }
 
-       dout("do_getattr inode %p mask %s mode 0%o\n", inode, ceph_cap_string(mask), inode->i_mode);
+       dout("do_getattr inode %p mask %s mode 0%o\n",
+            inode, ceph_cap_string(mask), inode->i_mode);
        if (!force && ceph_caps_issued_mask(ceph_inode(inode), mask, 1))
                return 0;
 
@@ -1922,7 +1945,19 @@ int ceph_do_getattr(struct inode *inode, int mask, bool force)
        ihold(inode);
        req->r_num_caps = 1;
        req->r_args.getattr.mask = cpu_to_le32(mask);
+       req->r_locked_page = locked_page;
        err = ceph_mdsc_do_request(mdsc, NULL, req);
+       if (locked_page && err == 0) {
+               u64 inline_version = req->r_reply_info.targeti.inline_version;
+               if (inline_version == 0) {
+                       /* the reply is supposed to contain inline data */
+                       err = -EINVAL;
+               } else if (inline_version == CEPH_INLINE_NONE) {
+                       err = -ENODATA;
+               } else {
+                       err = req->r_reply_info.targeti.inline_len;
+               }
+       }
        ceph_mdsc_put_request(req);
        dout("do_getattr result=%d\n", err);
        return err;