Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[sfrench/cifs-2.6.git] / fs / ceph / dir.c
index 3e9ad501addfe92f171a40dffb93c65209819cbe..e071d23f61481bf23fc4407d72ea75c9d1ec2430 100644 (file)
@@ -294,7 +294,7 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
        struct ceph_mds_client *mdsc = fsc->mdsc;
        int i;
        int err;
-       u32 ftype;
+       unsigned frag = -1;
        struct ceph_mds_reply_info_parsed *rinfo;
 
        dout("readdir %p file %p pos %llx\n", inode, file, ctx->pos);
@@ -341,7 +341,6 @@ more:
        /* do we have the correct frag content buffered? */
        if (need_send_readdir(fi, ctx->pos)) {
                struct ceph_mds_request *req;
-               unsigned frag;
                int op = ceph_snap(inode) == CEPH_SNAPDIR ?
                        CEPH_MDS_OP_LSSNAP : CEPH_MDS_OP_READDIR;
 
@@ -352,8 +351,11 @@ more:
                }
 
                if (is_hash_order(ctx->pos)) {
-                       frag = ceph_choose_frag(ci, fpos_hash(ctx->pos),
-                                               NULL, NULL);
+                       /* fragtree isn't always accurate. choose frag
+                        * based on previous reply when possible. */
+                       if (frag == (unsigned)-1)
+                               frag = ceph_choose_frag(ci, fpos_hash(ctx->pos),
+                                                       NULL, NULL);
                } else {
                        frag = fpos_frag(ctx->pos);
                }
@@ -378,7 +380,11 @@ more:
                                ceph_mdsc_put_request(req);
                                return -ENOMEM;
                        }
+               } else if (is_hash_order(ctx->pos)) {
+                       req->r_args.readdir.offset_hash =
+                               cpu_to_le32(fpos_hash(ctx->pos));
                }
+
                req->r_dir_release_cnt = fi->dir_release_count;
                req->r_dir_ordered_cnt = fi->dir_ordered_count;
                req->r_readdir_cache_idx = fi->readdir_cache_idx;
@@ -476,6 +482,7 @@ more:
                struct ceph_mds_reply_dir_entry *rde = rinfo->dir_entries + i;
                struct ceph_vino vino;
                ino_t ino;
+               u32 ftype;
 
                BUG_ON(rde->offset < ctx->pos);
 
@@ -498,15 +505,17 @@ more:
                ctx->pos++;
        }
 
+       ceph_mdsc_put_request(fi->last_readdir);
+       fi->last_readdir = NULL;
+
        if (fi->next_offset > 2) {
-               ceph_mdsc_put_request(fi->last_readdir);
-               fi->last_readdir = NULL;
+               frag = fi->frag;
                goto more;
        }
 
        /* more frags? */
        if (!ceph_frag_is_rightmost(fi->frag)) {
-               unsigned frag = ceph_frag_next(fi->frag);
+               frag = ceph_frag_next(fi->frag);
                if (is_hash_order(ctx->pos)) {
                        loff_t new_pos = ceph_make_fpos(ceph_frag_value(frag),
                                                        fi->next_offset, true);