Hi Al,

Today's linux-next merge of the vfs tree got a conflict in:

  fs/ceph/dir.c

between commit:

  fdd4e15838e5 ("ceph: rework dcache readdir")

from the ceph tree and commit:

  dc3f4198eac1 ("make simple_positive() public")

from the vfs tree.

I fixed it up (I think - see below) and can carry the fix as necessary (no 
action
is required).

Sage: that ceph tree commit has no Signed-off-by from its
committer :-(  The same is true for almost all the commits in the ceph
tree ... and the committer (Ilya) is not listed as a maintainer of that
tree ... and its on github :-(
-- 
Cheers,
Stephen Rothwell                    s...@canb.auug.org.au

diff --cc fs/ceph/dir.c
index 9314b4ea2375,edbb8da02a6a..000000000000
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@@ -144,110 -123,101 +144,110 @@@ static int __dcache_readdir(struct fil
        struct ceph_file_info *fi = file->private_data;
        struct dentry *parent = file->f_path.dentry;
        struct inode *dir = d_inode(parent);
 -      struct list_head *p;
 -      struct dentry *dentry, *last;
 +      struct dentry *dentry, *last = NULL;
        struct ceph_dentry_info *di;
 +      unsigned nsize = PAGE_CACHE_SIZE / sizeof(struct dentry *);
        int err = 0;
 +      loff_t ptr_pos = 0;
 +      struct ceph_readdir_cache_control cache_ctl = {};
  
 -      /* claim ref on last dentry we returned */
 -      last = fi->dentry;
 -      fi->dentry = NULL;
 -
 -      dout("__dcache_readdir %p v%u at %llu (last %p)\n",
 -           dir, shared_gen, ctx->pos, last);
 +      dout("__dcache_readdir %p v%u at %llu\n", dir, shared_gen, ctx->pos);
  
 -      spin_lock(&parent->d_lock);
 -
 -      /* start at beginning? */
 -      if (ctx->pos == 2 || last == NULL ||
 -          fpos_cmp(ctx->pos, ceph_dentry(last)->offset) < 0) {
 -              if (list_empty(&parent->d_subdirs))
 -                      goto out_unlock;
 -              p = parent->d_subdirs.prev;
 -              dout(" initial p %p/%p\n", p->prev, p->next);
 -      } else {
 -              p = last->d_child.prev;
 +      /* we can calculate cache index for the first dirfrag */
 +      if (ceph_frag_is_leftmost(fpos_frag(ctx->pos))) {
 +              cache_ctl.index = fpos_off(ctx->pos) - 2;
 +              BUG_ON(cache_ctl.index < 0);
 +              ptr_pos = cache_ctl.index * sizeof(struct dentry *);
        }
  
 -more:
 -      dentry = list_entry(p, struct dentry, d_child);
 -      di = ceph_dentry(dentry);
 -      while (1) {
 -              dout(" p %p/%p %s d_subdirs %p/%p\n", p->prev, p->next,
 -                   d_unhashed(dentry) ? "!hashed" : "hashed",
 -                   parent->d_subdirs.prev, parent->d_subdirs.next);
 -              if (p == &parent->d_subdirs) {
 +      while (true) {
 +              pgoff_t pgoff;
 +              bool emit_dentry;
 +
 +              if (ptr_pos >= i_size_read(dir)) {
                        fi->flags |= CEPH_F_ATEND;
 -                      goto out_unlock;
 +                      err = 0;
 +                      break;
 +              }
 +
 +              err = -EAGAIN;
 +              pgoff = ptr_pos >> PAGE_CACHE_SHIFT;
 +              if (!cache_ctl.page || pgoff != page_index(cache_ctl.page)) {
 +                      ceph_readdir_cache_release(&cache_ctl);
 +                      cache_ctl.page = find_lock_page(&dir->i_data, pgoff);
 +                      if (!cache_ctl.page) {
 +                              dout(" page %lu not found\n", pgoff);
 +                              break;
 +                      }
 +                      /* reading/filling the cache are serialized by
 +                       * i_mutex, no need to use page lock */
 +                      unlock_page(cache_ctl.page);
 +                      cache_ctl.dentries = kmap(cache_ctl.page);
                }
 -              spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
 +
 +              rcu_read_lock();
 +              spin_lock(&parent->d_lock);
 +              /* check i_size again here, because empty directory can be
 +               * marked as complete while not holding the i_mutex. */
 +              if (ceph_dir_is_complete_ordered(dir) &&
 +                  ptr_pos < i_size_read(dir))
 +                      dentry = cache_ctl.dentries[cache_ctl.index % nsize];
 +              else
 +                      dentry = NULL;
 +              spin_unlock(&parent->d_lock);
 +              if (dentry && !lockref_get_not_dead(&dentry->d_lockref))
 +                      dentry = NULL;
 +              rcu_read_unlock();
 +              if (!dentry)
 +                      break;
 +
 +              emit_dentry = false;
 +              di = ceph_dentry(dentry);
 +              spin_lock(&dentry->d_lock);
                if (di->lease_shared_gen == shared_gen &&
-                   d_really_is_positive(dentry) &&
+                   simple_positive(dentry) &&
                    ceph_snap(d_inode(dentry)) != CEPH_SNAPDIR &&
                    ceph_ino(d_inode(dentry)) != CEPH_INO_CEPH &&
 -                  fpos_cmp(ctx->pos, di->offset) <= 0)
 -                      break;
 -              dout(" skipping %p %pd at %llu (%llu)%s%s\n", dentry,
 -                   dentry, di->offset,
 -                   ctx->pos, d_unhashed(dentry) ? " unhashed" : "",
 -                   !d_inode(dentry) ? " null" : "");
 +                  fpos_cmp(ctx->pos, di->offset) <= 0) {
 +                      emit_dentry = true;
 +              }
                spin_unlock(&dentry->d_lock);
 -              p = p->prev;
 -              dentry = list_entry(p, struct dentry, d_child);
 -              di = ceph_dentry(dentry);
 -      }
 -
 -      dget_dlock(dentry);
 -      spin_unlock(&dentry->d_lock);
 -      spin_unlock(&parent->d_lock);
  
 -      /* make sure a dentry wasn't dropped while we didn't have parent lock */
 -      if (!ceph_dir_is_complete_ordered(dir)) {
 -              dout(" lost dir complete on %p; falling back to mds\n", dir);
 -              dput(dentry);
 -              err = -EAGAIN;
 -              goto out;
 -      }
 +              if (emit_dentry) {
 +                      dout(" %llu (%llu) dentry %p %pd %p\n", di->offset, 
ctx->pos,
 +                           dentry, dentry, d_inode(dentry));
 +                      ctx->pos = di->offset;
 +                      if (!dir_emit(ctx, dentry->d_name.name,
 +                                    dentry->d_name.len,
 +                                    ceph_translate_ino(dentry->d_sb,
 +                                                       
d_inode(dentry)->i_ino),
 +                                    d_inode(dentry)->i_mode >> 12)) {
 +                              dput(dentry);
 +                              err = 0;
 +                              break;
 +                      }
 +                      ctx->pos++;
  
 -      dout(" %llu (%llu) dentry %p %pd %p\n", di->offset, ctx->pos,
 -           dentry, dentry, d_inode(dentry));
 -      if (!dir_emit(ctx, dentry->d_name.name,
 -                    dentry->d_name.len,
 -                    ceph_translate_ino(dentry->d_sb, d_inode(dentry)->i_ino),
 -                    d_inode(dentry)->i_mode >> 12)) {
 -              if (last) {
 -                      /* remember our position */
 -                      fi->dentry = last;
 -                      fi->next_offset = fpos_off(di->offset);
 +                      if (last)
 +                              dput(last);
 +                      last = dentry;
 +              } else {
 +                      dput(dentry);
                }
 -              dput(dentry);
 -              return 0;
 -      }
 -
 -      ctx->pos = di->offset + 1;
  
 -      if (last)
 -              dput(last);
 -      last = dentry;
 -
 -      spin_lock(&parent->d_lock);
 -      p = p->prev;    /* advance to next dentry */
 -      goto more;
 -
 -out_unlock:
 -      spin_unlock(&parent->d_lock);
 -out:
 -      if (last)
 +              cache_ctl.index++;
 +              ptr_pos += sizeof(struct dentry *);
 +      }
 +      ceph_readdir_cache_release(&cache_ctl);
 +      if (last) {
 +              int ret;
 +              di = ceph_dentry(last);
 +              ret = note_last_dentry(fi, last->d_name.name, last->d_name.len,
 +                                     fpos_off(di->offset) + 1);
 +              if (ret < 0)
 +                      err = ret;
                dput(last);
 +      }
        return err;
  }
  

Attachment: pgp5lvd2pDDaJ.pgp
Description: OpenPGP digital signature

Reply via email to